// Render
void TracerApp::draw()
{
	// Add to accumulation buffer
	mFbo[ 0 ].bindFramebuffer();
	gl::setViewport( mFbo[ 0 ].getBounds() );
	gl::setMatricesWindow( mFbo[ 0 ].getSize() );
	gl::enableAlphaBlending();

	// Dim last frame
	gl::color( ColorAf( Colorf::black(), 0.03f ) );
	gl::drawSolidRect( Rectf( mFbo[ 0 ].getBounds() ) );

	// Draw finger tips into the accumulation buffer
	gl::setMatrices( mCamera );
	gl::enableAdditiveBlending();
	for ( RibbonMap::const_iterator iter = mRibbons.begin(); iter != mRibbons.end(); ++iter ) {
		iter->second.draw();
	}
	mFbo[ 0 ].unbindFramebuffer();

	// Blur the accumulation buffer
	gl::enable( GL_TEXTURE_2D );
	gl::enableAlphaBlending();
	gl::color( ColorAf::white() );
	Vec2f pixel	= Vec2f::one() / Vec2f( mFbo[ 0 ].getSize() );
	pixel		*= 3.0f;
	for ( size_t i = 0; i < 2; ++i ) {
		mFbo[ i + 1 ].bindFramebuffer();
		gl::clear();
		
		mShader[ i ].bind();
		mShader[ i ].uniform( "size",	pixel );
		mShader[ i ].uniform( "tex",	0 );
				
		gl::Texture& texture = mFbo[ i ].getTexture();
		texture.bind();
		gl::drawSolidRect( Rectf( mFbo[ i ].getBounds() ) );
		texture.unbind();
		
		mShader[ i ].unbind();
		mFbo[ i + 1 ].unbindFramebuffer();
	}

	// Draw blurred image
	gl::setMatricesWindow( getWindowSize(), false );
	gl::color( ColorAf::white() );
	mFbo[ 0 ].bindTexture();
	gl::drawSolidRect( Rectf( getWindowBounds() ) );
	mFbo[ 0 ].unbindTexture();
	
	gl::color( ColorAf( Colorf::white(), 0.8f ) );
	mFbo[ 2 ].bindTexture();
	gl::drawSolidRect( Rectf( getWindowBounds() ) );
	mFbo[ 2 ].unbindTexture();
	gl::disableAlphaBlending();
	gl::disable( GL_TEXTURE_2D );

	// Draw the interface
	mParams.draw();
}
示例#2
0
void Fluid2DTextureApp::draw()
{
	// clear out the window with black
	gl::clear( Color( 0, 0, 0 ) ); 
	gl::setMatricesWindow( getWindowWidth(), getWindowHeight() );

	// Update the positions and tex coords
	Rectf drawRect = getWindowBounds();
	int limX = mFluid2D.resX() - 1;
	int limY = mFluid2D.resY() - 1;
	float dx = drawRect.getWidth()/(float)limX;
	float dy = drawRect.getHeight()/(float)limY;
	
	for( int j = 0; j < mFluid2D.resY(); ++j ) {
		for( int i = 0; i < mFluid2D.resX(); ++i ) {
			vec2 P = vec2( i*dx, j*dy );
			vec2 uv = mFluid2D.texCoordAt( i, j );

			int idx = j*mFluid2D.resX() + i;
			mTriMesh->getPositions<2>()[idx] = P;
			mTriMesh->getTexCoords0<2>()[idx] = uv;
			
		}
	}

	mTex->bind();
	gl::bindStockShader( gl::ShaderDef().color().texture() );
	gl::draw( gl::VboMesh::create(*mTriMesh) );
	mTex->unbind();
	
	mParams.draw();	
}
void Fluid2DTextureApp::draw()
{
	// clear out the window with black
	gl::clear( Color( 0, 0, 0 ) ); 
	gl::setMatricesWindow( getWindowWidth(), getWindowHeight() );

	// Update the positions and tex coords
	Rectf drawRect = getWindowBounds();
	int limX = mFluid2D.resX() - 1;
	int limY = mFluid2D.resY() - 1;
	float dx = drawRect.getWidth()/(float)limX;
	float dy = drawRect.getHeight()/(float)limY;
	
	for( int j = 0; j < mFluid2D.resY(); ++j ) {
		for( int i = 0; i < mFluid2D.resX(); ++i ) {
			Vec2f P = Vec2f( i*dx, j*dy );
			Vec2f uv = mFluid2D.texCoordAt( i, j );

			int idx = j*mFluid2D.resX() + i;
			mTriMesh.getVertices()[idx] = P;
			mTriMesh.getTexCoords()[idx] = uv;
			
		}
	}

	mTex.bind();
	gl::draw( mTriMesh ); 
	mTex.unbind();
	
	mParams.draw();	
}
示例#4
0
// Render
void UiApp::draw()
{
	// Clear window
	gl::setViewport( getWindowBounds() );
	gl::clear( Colorf::white() );
	gl::setMatricesWindow( getWindowSize() );
	gl::color( ColorAf::white() );
	
	// Make PNG backgrounds transparent
	gl::enableAlphaBlending();
	gl::disableDepthRead();
	gl::disableDepthWrite();
	
	// Master offset
	gl::pushMatrices();
	
	// Draw buttons
	for ( size_t i = 0; i < 3; ++i ) {
		bool pressed = mButtonState[ i ];
		gl::pushMatrices();
		gl::translate( mButtonPosition[ i ] );
		gl::draw( mButton[ pressed ? 1 : 0 ] );
		gl::popMatrices();
	}
	
	// Draw slider
	gl::pushMatrices();
	gl::translate( mTrackPosition );
	gl::draw( mTrack );
	gl::popMatrices();
	gl::pushMatrices();
	gl::translate( mSliderPosition );
	gl::draw( mSlider );
	gl::popMatrices();
	
	// Draw cursor
	if ( mCursorType != CursorType::NONE ) {
		gl::color( ColorAf::white() );
		gl::pushMatrices();
		gl::translate( mCursorPosition );
		gl::draw( mTexture[ (size_t)mCursorType ] );
		gl::popMatrices();
	}
	
	gl::popMatrices();
	
	// Draw finger position for pressing buttons
	if ( mCursorType == CursorType::TOUCH )
	{
		gl::color( ColorAf( 1.0f, 0.7f, 0.0f ) );
		gl::drawSolidCircle( mFingerTipPosition, 20.0f );
		gl::drawStrokedCircle( mFingerTipPosition, 40.0f );
	}
	
	// Draw the interface
	mParams.draw();
}
示例#5
0
// Render
void UiApp::draw()
{
	// Clear window
	gl::setViewport( getWindowBounds() );
	gl::clear( Colorf::white() );
	gl::setMatrices( mCamera );
	
	// Make PNG backgrounds transparent
	gl::enableAlphaBlending();
	gl::disableDepthRead();
	gl::disableDepthWrite();
	
	// Master offset
	gl::pushMatrices();
	gl::translate( mOffset );
	
	// Draw buttons
	for ( size_t i = 0; i < 3; ++i ) {
		bool pressed = mButtonState[ i ];
		gl::pushMatrices();
		gl::translate( mButtonPosition[ i ] );
		gl::draw( mButton[ pressed ? 1 : 0 ] );
		gl::popMatrices();
	}
	
	// Draw slider
	gl::pushMatrices();
	gl::translate( mTrackPosition );
	gl::draw( mTrack );
	gl::popMatrices();
	gl::pushMatrices();
	gl::translate( mSliderPosition );
	gl::draw( mSlider );
	gl::popMatrices();
	
	// Draw cursor
	if ( mCursorType != CursorType::NONE ) {
		gl::color( ColorAf::white() );
		gl::pushMatrices();
		gl::translate( mCursorPosition );
		gl::draw( mTexture[ (size_t)mCursorType ] );
		gl::popMatrices();
	}
	
	gl::popMatrices();
	
	// Draw the interface
	mParams.draw();
}
示例#6
0
void Fluid2DRGBApp::draw()
{
	// clear out the window with black
	gl::clear( Color( 0, 0, 0 ) ); 

	//RenderFluidRgb( mFluid2D, getWindowBounds() );
	float* data = const_cast<float*>( (float*)mFluid2D.rgb().data() );
	Surface32f surf( data, mFluid2D.resX(), mFluid2D.resY(), mFluid2D.resX()*sizeof(Colorf), SurfaceChannelOrder::RGB );
	
	if ( ! mTex ) {
		mTex = gl::Texture::create( surf );
	} else {
		mTex->update( surf );
	}
	gl::draw( mTex, getWindowBounds() );
	
	mParams.draw();
}
示例#7
0
void BulletTestApp::draw()
{
	gl::enableDepthRead();
	gl::enableDepthWrite();

	gl::setViewport( getWindowBounds() );
	gl::clear( ColorAf::black() );
	gl::setMatrices( mCamera );
	gl::pushMatrices();
	gl::rotate( Vec3f( -45.0f, 0.0f, 0.0f ) );
	uint32_t i = 0;

	for ( bullet::Iter iter = mWorld->begin(); iter != mWorld->end(); ++iter, ++i ) {
		gl::pushMatrices();
		glMultMatrixf( iter->getTransformMatrix() );
		bindTexture( i );
		
		switch ( iter->getPrimitiveType() ) {
		case CollisionObject::PRIMITIVE_BOX:
			gl::draw( mCube );
			break;
		case CollisionObject::PRIMITIVE_CONE:
			gl::draw( mCone );
			break;
		case CollisionObject::PRIMITIVE_CYLINDER:
			gl::draw( mCylinder );
			break;
		case CollisionObject::PRIMITIVE_SPHERE:
			gl::draw( mSphere );
			break;
		default:
			if ( iter->isMeshBody() ) {
				gl::draw( bullet::calcTriMesh( iter ) );
			}
			break;
		}

		unbindTexture( i );
		gl::popMatrices();
	}
	gl::popMatrices();

	mParams.draw();
}
示例#8
0
void BulletTestApp::draw()
{
	gl::setViewport( getWindowBounds() );
	gl::clear( ColorAf::black() );
	gl::setMatrices( mCamera );
	gl::pushMatrices();
	gl::rotate( Vec3f( -45.0f, 0.0f, 0.0f ) );
	uint32_t i = 0;
	for ( bullet::Iter object = mWorld->begin(); object != mWorld->end(); ++object, i++ ) {
		gl::pushMatrices();
		glMultMatrixf( object->getTransformMatrix() );
		bindTexture( i );
		gl::draw( object->getVboMesh() );
		unbindTexture( i );
		gl::popMatrices();
	}
	gl::popMatrices();

	mParams.draw();
}
void cinderFFmpegApp::draw()
{
	Rectf imgRect;
	int posX;
	int posY;

	gl::clear();
	
	for(int i=0; i<m_Players.size(); i++)
	{
		if(m_Players[i]->hasVideo()) //&& m_Players[i]->isNewFrame())
		{	
		//	m_Players[i]->update();
			unsigned char* pImg = m_Players[i]->getVideoData().m_pData;
			if(pImg != nullptr)
			{		
				m_VideoTextures[i] = gl::Texture(ci::Surface(pImg, m_Players[i]->getWidth(), m_Players[i]->getHeight(), m_Players[i]->getWidth() * 3, ci::SurfaceChannelOrder::RGB) );
			}
		}
		posX = (i % m_iTilesDivisor) * m_iTileWidth;
		posY = ((int(float(i) / float(m_iTilesDivisor))) % m_iTilesDivisor) * m_iTileHeight;
		Rectf imgRect = Rectf(posX, posY, posX + m_iTileWidth, posY + m_iTileHeight);
		if(m_VideoTextures[i])
			ci::gl::draw( m_VideoTextures[i] , imgRect);
	}
	
	// draw green selection frame
	if(m_Players.size()>0)
	{
		posX = (m_iCurrentVideo % m_iTilesDivisor) * m_iTileWidth;
		posY = ((int(float(m_iCurrentVideo) / float(m_iTilesDivisor))) % m_iTilesDivisor) * m_iTileHeight;
		gl::color(0,1,0,1);
		glLineWidth(3);
		gl::drawStrokedRect(Rectf(posX, posY, posX + m_iTileWidth, posY + m_iTileHeight));
		gl::color(1,1,1,1);
	}
			
	// draw fps and gui
	gl::drawString( toString(getAverageFps()), Vec2f( float(getWindowWidth() - 240), 10.0 ), Color(1,0,0), m_Font);
	m_Gui.draw();
}
示例#10
0
void Fluid2DCamAppApp::draw()
{
	// clear out the window with black
	gl::clear( Color( 0, 0, 0 ) ); 
	gl::color( Colorf::white() );
	gl::setMatricesWindow( getWindowWidth(), getWindowHeight() );
	
	if( mTexCam ) {
		gl::draw( mTexCam, Rectf( 0*kDrawScale*mFluid2DResX, 0*kDrawScale*mFluid2DResY, 1*kDrawScale*mFluid2DResX, 1*kDrawScale*mFluid2DResY ) );
	}

	gl::draw( mTexVel0, Rectf( 0*kDrawScale*mFluid2DResX, 1*kDrawScale*mFluid2DResY, 1*kDrawScale*mFluid2DResX, 2*kDrawScale*mFluid2DResY ) );
	gl::draw( mTexVel1, Rectf( 1*kDrawScale*mFluid2DResX, 1*kDrawScale*mFluid2DResY, 2*kDrawScale*mFluid2DResX, 2*kDrawScale*mFluid2DResY ) );
	gl::draw( mTexDen0, Rectf( 2*kDrawScale*mFluid2DResX, 1*kDrawScale*mFluid2DResY, 3*kDrawScale*mFluid2DResX, 2*kDrawScale*mFluid2DResY ) );
	gl::draw( mTexDen1, Rectf( 3*kDrawScale*mFluid2DResX, 1*kDrawScale*mFluid2DResY, 4*kDrawScale*mFluid2DResX, 2*kDrawScale*mFluid2DResY ) );

	gl::draw( mTexDiv,     Rectf( 0*kDrawScale*mFluid2DResX, 2*kDrawScale*mFluid2DResY, 1*kDrawScale*mFluid2DResX, 4*kDrawScale*mFluid2DResY ) );
	gl::draw( mTexPrs,     Rectf( 1*kDrawScale*mFluid2DResX, 2*kDrawScale*mFluid2DResY, 2*kDrawScale*mFluid2DResX, 4*kDrawScale*mFluid2DResY ) );
	gl::draw( mTexCurl,    Rectf( 2*kDrawScale*mFluid2DResX, 2*kDrawScale*mFluid2DResY, 3*kDrawScale*mFluid2DResX, 4*kDrawScale*mFluid2DResY ) );
	gl::draw( mTexCurlLen, Rectf( 3*kDrawScale*mFluid2DResX, 2*kDrawScale*mFluid2DResY, 4*kDrawScale*mFluid2DResX, 4*kDrawScale*mFluid2DResY ) );

	mTexCurlLen.unbind();

	gl::color( Color( 1, 0, 0 ) );
	glLineWidth( 0.5f );
	glBegin( GL_LINES );
		glVertex2f( Vec2f( 0, 1*kDrawScale*mFluid2DResY ) );
		glVertex2f( Vec2f( (float)getWindowWidth(), 1*kDrawScale*mFluid2DResY ) );
		glVertex2f( Vec2f( 0, 2*kDrawScale*mFluid2DResY ) );
		glVertex2f( Vec2f( (float)getWindowWidth(), 2*kDrawScale*mFluid2DResY ) );

		glVertex2f( Vec2f( 1*kDrawScale*mFluid2DResX, 0 ) );
		glVertex2f( Vec2f( 1*kDrawScale*mFluid2DResX, (float)getWindowHeight() ) );
		glVertex2f( Vec2f( 2*kDrawScale*mFluid2DResX, 0 ) );
		glVertex2f( Vec2f( 2*kDrawScale*mFluid2DResX, (float)getWindowHeight() ) );
		glVertex2f( Vec2f( 3*kDrawScale*mFluid2DResX, 0 ) );
		glVertex2f( Vec2f( 3*kDrawScale*mFluid2DResX, (float)getWindowHeight() ) );
	glEnd();
	mParams.draw();
}
示例#11
0
// Render
void GestureApp::draw()
{
	// Clear window
	gl::setViewport( getWindowBounds() );
	gl::clear( mBackgroundColor + Colorf::gray( mBackgroundBrightness ) );
	gl::setMatricesWindow( getWindowSize() );
	gl::enableAlphaBlending();
	gl::color( Colorf::white() );
	
	// Draw everything
	gl::pushMatrices();
	gl::translate( mOffset );
	
	drawUi();
	drawGestures();
	drawPointables();
	
	gl::popMatrices();
	
	// Draw the interface
	mParams.draw();
}
示例#12
0
void BulletTestApp::draw()
{
    gl::setViewport( getWindowBounds() );
    gl::clear( ColorAf::black() );
    gl::setMatrices( mCamera );
    gl::pushMatrices();
    gl::rotate( Vec3f( (float)mViewX, (float)mViewY, (float)mViewZ ) );
    uint32_t i = 0;
    for( bullet::Iter object = mWorld->begin(); object != mWorld->end(); ++object, i++ )
    {
        TextureType type = TT_GROUND;

        if( i == 0 )
            type = TT_GROUND;
        else if( i == 1 )
            type = TT_BACKBOARD;
        else if( i == 2 || i == 3 )
            type = TT_RING;
        else
            type = TT_BASKETBALL;

        gl::pushMatrices();
        glMultMatrixf( object->getTransformMatrix() );
        bindTexture( type );
        gl::draw( object->getVboMesh() );
        unbindTexture( type );
        gl::popMatrices();
    }

    // draw the same torus
//	gl::translate( Vec3f( 0.0f, 13.0f, 0.0f ));
//	gl::rotate( Quatf( 0.0f, 0.0f, 1.14f, 1.0f ));
//	gl::drawTorus( 20, 3, 200, 200 );

    gl::popMatrices();

    mParams.draw();
}
void Fluid2DParticleSoupApp::draw()
{
	// clear out the window with black
	gl::clear( Color( 0, 0, 0 ) );
	gl::enableAdditiveBlending();
	
	gl::color( 1.0f, 1.0f, 1.0f, 1.0f );

	// Uncomment to see underlining density
	/*
	float* data = const_cast<float*>( (float*)mFluid2D.rgb().data() );
	Surface32f surf( data, mFluid2D.resX(), mFluid2D.resY(), mFluid2D.resX()*sizeof(Colorf), SurfaceChannelOrder::RGB );
	if ( ! mTex ) {
		mTex = gl::Texture( surf );
	} else {
		mTex.update( surf );
	}
	gl::draw( mTex, getWindowBounds() );
	mTex.unbind();
	*/

	mParticleSoup.draw();
	mParams.draw();
}
示例#14
0
// Render
void LeapApp::draw()
{
	// Clear window
	gl::setViewport( getWindowBounds() );
	gl::clear( Colorf::white() );
	gl::setMatrices( mCamera );

	// Enable depth
	gl::enableAlphaBlending();
	gl::enableDepthRead();
	gl::enableDepthWrite();
	
	// Iterate through hands
	float headLength = 6.0f;
	float headRadius = 3.0f;
	for ( const auto& handIter : mHands ) {
		const Hand& hand = handIter.second;

		// Hand sphere
		gl::enableWireframe();
		gl::color( ColorAf( Colorf::gray( 0.9f ), 0.5f ) );
		gl::drawSphere( hand.getSpherePosition(), hand.getSphereRadius(), 16 );
		gl::disableWireframe();

		// Hand plane
		gl::color( ColorAf( 0.75f, 0.0f, 0.75f, 0.25f ) );
		gl::pushMatrices();
		gl::translate( hand.getPosition() );
		gl::rotate( Quatf( hand.getPosition(), hand.getDirection() ) );
		for ( float i = 0.25f; i <= 1.0f; i += 0.25f ) {
			gl::drawStrokedCircle( Vec2f::zero(), hand.getSphereRadius() * i, 16 );
		}
		gl::popMatrices();

		// Hand direction
		gl::color( 1.0f, 0.0f, 1.0f, 0.5f );
		gl::drawVector( hand.getPosition(), hand.getPosition() + hand.getDirection() * 30.0f, headLength, headRadius );

		// Hand normal
		gl::color( 0.0f, 0.0f, 1.0f, 0.5f );
		gl::drawVector( hand.getPosition(), hand.getPosition() + hand.getNormal() * 30.0f, headLength, headRadius );

		// Hand velocity
		gl::color( 0.0f, 1.0f, 0.0f, 0.5f );
		gl::drawVector( hand.getPosition(), hand.getPosition() + hand.getVelocity() * 0.05f, headLength, headRadius );

		// Fingers
		const FingerMap& fingers = hand.getFingers();
		for ( const auto& fingerIter : fingers ) {
			const Finger& finger = fingerIter.second;

			// Finger
			Vec3f position = finger.getPosition() + finger.getDirection() * finger.getLength();
			gl::color( ColorAf::gray( 0.3f ) );
			gl::drawLine( finger.getPosition(), position );

			// Finger tip
			gl::color( ColorAf::black() );
			gl::pushMatrices();
			gl::translate( position );
			gl::drawStrokedCircle( Vec2f::zero(), finger.getWidth(), 16 );
			gl::popMatrices();

			// Finger velocity
			gl::color( 0.0f, 1.0f, 0.0f, 0.5f );
			gl::drawVector( position, position + finger.getVelocity() * 0.05f, headLength, headRadius );
		}
		
		// Tools
		const ToolMap& tools = hand.getTools();
		for ( const auto& toolIter : tools ) {
			const Finger& tool = toolIter.second;
			
			// Tool
			Vec3f position = tool.getPosition() + tool.getDirection() * tool.getLength();
			gl::color( ColorAf( 1.0f, 0.0f, 0.0f, 0.3f ) );
			gl::drawLine( tool.getPosition(), position );
			
			// Tool tip
			gl::color( ColorAf( 1.0f, 0.0f, 0.0f, 1.0f ) );
			gl::pushMatrices();
			gl::translate( position );
			gl::drawStrokedCircle( Vec2f::zero(), tool.getWidth(), 16 );
			gl::popMatrices();
			
			// Tool velocity
			gl::color( 0.0f, 1.0f, 0.0f, 0.5f );
			gl::drawVector( position, position + tool.getVelocity() * 0.05f, headLength, headRadius );
		}
	}
	
	// Draw the interface
	mParams.draw();
}
void VboMeshSampleApp::draw()
{
	// Set up window
	gl::setViewport( getWindowBounds() );
	gl::setMatrices( mCamera );
	gl::clear( ColorAf::gray( 0.6f ) );

	// Use arcball to rotate model view
	glMultMatrixf( mArcball.getQuat() );

	// Enabled lighting, texture mapping, wireframe
	if ( mLightEnabled ) {
		gl::enable( GL_LIGHTING );
	}
	if ( mTextureEnabled && mTexture ) {
		gl::enable( GL_TEXTURE_2D );
		mTexture.bind();
	}
	if ( mWireframe ) {
		gl::enableWireframe();
	}

	// Apply scale
	gl::pushMatrices();
	gl::scale( mScale );
	
	// Draw selected mesh
	switch ( (MeshType)mMeshIndex ) {
	case MESH_TYPE_CIRCLE:
		gl::draw( mCircle );
		break;
	case MESH_TYPE_CONE:
		gl::draw( mCone );
		break;
	case MESH_TYPE_CUBE:
		gl::draw( mCube );
		break;
	case MESH_TYPE_CUSTOM:
		gl::draw( mCustom );
		break;
	case MESH_TYPE_CYLINDER:
		gl::draw( mCylinder );
		break;
	case MESH_TYPE_RING:
		gl::draw( mRing );
		break;
	case MESH_TYPE_SPHERE:
		gl::draw( mSphere );
		break;
	case MESH_TYPE_SQUARE:
		gl::draw( mSquare );
		break;
	}
	
	// End scale
	gl::popMatrices();

	// Disable wireframe, texture mapping, lighting
	if ( mWireframe ) {
		gl::disableWireframe();
	}
	if ( mTextureEnabled && mTexture ) {
		mTexture.unbind();
		gl::disable( GL_TEXTURE_2D );
	}
	if ( mLightEnabled ) {
		gl::disable( GL_LIGHTING );
	}

	// Draw params GUI
	mParams.draw();
}
示例#16
0
// Render
void LeapApp::draw()
{
	// Clear window
	gl::setViewport( getWindowBounds() );
	gl::clear( Colorf::black() );
	gl::setMatrices( mCamera );

	// Enable depth
	gl::enableAlphaBlending();
	gl::enableDepthRead();
	gl::enableDepthWrite();
	
	// Iterate through hands
	float headLength = 6.0f;
	float headRadius = 3.0f;
	for ( HandMap::const_iterator handIter = mHands.begin(); handIter != mHands.end(); ++handIter ) {
		const Hand& hand = handIter->second;

		// Hand ball
		if ( hand.getBallRadius() > 0.0f ) {
			gl::color( ColorAf( 1.0f, 1.0f, 0.0f, 0.25f ) );
			gl::enableWireframe();
			gl::drawSphere( hand.getBallPosition(), hand.getBallRadius(), 16 );
			gl::disableWireframe();
		}

		// Hand direction
		gl::color( 1.0f, 0.0f, 1.0f, 1.0f );
		gl::drawVector( hand.getPosition(), hand.getPosition() + hand.getDirection() * 100.0f, headLength, headRadius );

		// Hand normal
		gl::color( 0.0f, 0.0f, 1.0f, 1.0f );
		gl::drawVector( hand.getPosition(), hand.getPosition() + hand.getNormal() * 100.0f, headLength, headRadius );

		// Hand velocity
		gl::color( 0.0f, 1.0f, 0.0f, 1.0f );
		gl::drawVector( hand.getPosition(), hand.getPosition() + hand.getVelocity() * 100.0f, headLength, headRadius );

		// Fingers
		const FingerMap& fingers = hand.getFingers();
		for ( FingerMap::const_iterator fingerIter = fingers.begin(); fingerIter != fingers.end(); ++fingerIter ) {
			const Finger& finger = fingerIter->second;

			// Finger
			Vec3f position = finger.getPosition() + finger.getDirection() * -finger.getLength() * 3.0f;
			gl::color( ColorAf::white() );
			gl::drawLine( finger.getPosition(), position );

			// Finger tip
			gl::pushMatrices();
			gl::translate( position );
			gl::drawStrokedCircle( Vec2f::zero(), finger.getWidth(), 16 );
			gl::popMatrices();

			// Finger velocity
			gl::color( 0.0f, 1.0f, 0.0f, 1.0f );
			gl::drawVector( position, position + finger.getVelocity() * 0.05f, headLength, headRadius );
		}
	}
	
	// Draw the interface
	mParams.draw();

}