You need:
Windows 7
Kinect hardware
Microsoft Official Kinect SDK Beta v2
Visual Studio 2010
Irrlicht (I am using the latest 1.7.2)
DirectX June 2010 SDK
?Windows SDK 7.1
I trust you know how to add the Irrlicht AND Kinect SDK into your /include and /lib directories in your VS2010 project
CIrrDeviceKinect.h
Code: Select all
#ifndef __C_IRR_DEVICE_KINECT_INCLUDED__
#define __C_IRR_DEVICE_KINECT_INCLUDED__
#include <irrlicht.h>
#include <basetyps.h>
#include <WTypes.h>
#include "MSR_NuiApi.h"
#include <SDKDDKVer.h>
using namespace irr;
class CIrrDeviceKinect
{
public:
CIrrDeviceKinect(int id, IrrlichtDevice* p, DWORD flags);
CIrrDeviceKinect();
~CIrrDeviceKinect();
HRESULT Nui_Init();
void Nui_UnInit();
int getKinectID(){return Kinect;}
void setKinectID(int id){Kinect = id;}
// Call this function if you want the latest textures updated from the kinect
void Update();
static int getNumberOfKinects();
video::ITexture* m_tdepth;
video::ITexture* m_trgb;
// No idea what these two functions are for
//static void CALLBACK Nui_StatusProcThunk(const NuiStatusData *pStatusData);
//void CALLBACK Nui_StatusProc(const NuiStatusData *pStatusData);
private:
int Kinect;
BSTR m_instanceId;
POINT m_points[NUI_SKELETON_POSITION_COUNT];
INuiInstance* m_pNuiInstance;
DWORD nuiFlags;
video::IImage* m_depth;
video::IImage* m_rgb;
// Storage used during the separate thread Nui_ProcessThread
BYTE* m_parallel_depth;
BYTE* m_parallel_rgb;
static DWORD WINAPI Nui_ProcessThread(LPVOID pParam);
DWORD WINAPI Nui_ProcessThread();
void Nui_GotDepthAlert();
void Nui_GotVideoAlert();
void Nui_GotSkeletonAlert();
void Nui_Zero();
RGBQUAD Nui_DrawDepthImage(int x, int y, USHORT s);
// thread handling
HANDLE m_hThNuiProcess;
HANDLE m_hEvNuiProcessStop;
HANDLE m_hNextDepthFrameEvent;
HANDLE m_hNextVideoFrameEvent;
HANDLE m_hNextSkeletonEvent;
HANDLE m_pDepthStreamHandle;
HANDLE m_pVideoStreamHandle;
// Need for callback/events
IrrlichtDevice* parent;
video::IVideoDriver* driver;
};
#endif
Code: Select all
#include "CIrrDeviceKinect.h"
#include <mmsystem.h>
#include <assert.h>
CIrrDeviceKinect::CIrrDeviceKinect(int id, IrrlichtDevice* p, DWORD flags)
{
Kinect = id;
parent = p;
nuiFlags = flags;
driver = parent->getVideoDriver();
m_depth = driver->createImage(video::ECF_R8G8B8, core::vector2d<u32>(320,240));
m_rgb = driver->createImage(video::ECF_R8G8B8, core::vector2d<u32>(640,480));
m_tdepth = driver->addTexture("Depth", m_depth);
m_trgb = driver->addTexture("RGB", m_rgb);
m_parallel_depth = new BYTE[320*240*4];
m_parallel_rgb = new BYTE[640*480*4];
}
CIrrDeviceKinect::CIrrDeviceKinect()
{
Kinect = 0;
parent = NULL;
nuiFlags = 0;
}
CIrrDeviceKinect::~CIrrDeviceKinect()
{
Nui_UnInit();
Nui_Zero();
m_depth->drop();
m_rgb->drop();
delete [] m_parallel_depth;
delete [] m_parallel_rgb;
}
HRESULT CIrrDeviceKinect::Nui_Init()
{
HRESULT hr;
hr = MSR_NuiCreateInstanceByIndex(Kinect, &m_pNuiInstance);
if(FAILED(hr))
{
return hr;
}
m_instanceId = m_pNuiInstance->NuiInstanceName();
m_hNextDepthFrameEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hNextVideoFrameEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hNextSkeletonEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
hr = m_pNuiInstance->NuiInitialize(nuiFlags);
if (E_NUI_SKELETAL_ENGINE_BUSY == hr)
{
nuiFlags = NUI_INITIALIZE_FLAG_USES_DEPTH | NUI_INITIALIZE_FLAG_USES_COLOR;
hr = m_pNuiInstance->NuiInitialize(nuiFlags);
}
if(FAILED(hr))
{
return hr;
}
if (HasSkeletalEngine(m_pNuiInstance))
{
hr = m_pNuiInstance->NuiSkeletonTrackingEnable( m_hNextSkeletonEvent, 0 );
if( FAILED( hr ) )
{
return hr;
}
}
hr = m_pNuiInstance->NuiImageStreamOpen(
NUI_IMAGE_TYPE_COLOR,
NUI_IMAGE_RESOLUTION_640x480,
0,
2,
m_hNextVideoFrameEvent,
&m_pVideoStreamHandle );
if( FAILED( hr ) )
{
return hr;
}
hr = m_pNuiInstance->NuiImageStreamOpen(
HasSkeletalEngine(m_pNuiInstance) ? NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX : NUI_IMAGE_TYPE_DEPTH,
NUI_IMAGE_RESOLUTION_320x240,
0,
2,
m_hNextDepthFrameEvent,
&m_pDepthStreamHandle );
if( FAILED( hr ) )
{
return hr;
}
// Start the Nui processing thread
m_hEvNuiProcessStop=CreateEvent(NULL,FALSE,FALSE,NULL);
m_hThNuiProcess=CreateThread(NULL,0,Nui_ProcessThread,this,0,NULL);
return hr;
}
void CIrrDeviceKinect::Nui_UnInit()
{
if (m_pNuiInstance)
{
m_pNuiInstance->NuiShutdown();
}
}
void CIrrDeviceKinect::Nui_GotDepthAlert()
{
const NUI_IMAGE_FRAME * pImageFrame = NULL;
HRESULT hr = m_pNuiInstance->NuiImageStreamGetNextFrame(
m_pDepthStreamHandle,
0,
&pImageFrame );
if( FAILED( hr ) )
{
return;
}
INuiFrameTexture * pTexture = pImageFrame->pFrameTexture;
NUI_LOCKED_RECT LockedRect;
pTexture->LockRect( 0, &LockedRect, NULL, 0 );
if( LockedRect.Pitch != 0 )
{
BYTE * pBuffer = (BYTE*) LockedRect.pBits;
BYTE * write = m_parallel_depth;
USHORT * pBufferRun = (USHORT*) pBuffer;
for( int y = 0 ; y < 240 ; y++ )
{
for( int x = 0 ; x < 320 ; x++ )
{
RGBQUAD q = Nui_DrawDepthImage(x, y, *pBufferRun );
*write = q.rgbRed;
write++;
*write = q.rgbGreen;
write++;
*write = q.rgbBlue;
write++;
write++; // last channel is alpha/unused
pBufferRun++;
}
}
}
m_pNuiInstance->NuiImageStreamReleaseFrame( m_pDepthStreamHandle, pImageFrame );
}
void CIrrDeviceKinect::Nui_GotVideoAlert()
{
const NUI_IMAGE_FRAME * pImageFrame = NULL;
HRESULT hr = m_pNuiInstance->NuiImageStreamGetNextFrame(
m_pVideoStreamHandle,
0,
&pImageFrame );
if( FAILED( hr ) )
{
return;
}
INuiFrameTexture * pTexture = pImageFrame->pFrameTexture;
NUI_LOCKED_RECT LockedRect;
pTexture->LockRect( 0, &LockedRect, NULL, 0 );
if( LockedRect.Pitch != 0 )
{
BYTE * pBuffer = (BYTE*) LockedRect.pBits;
BYTE * write = m_parallel_rgb;
RGBQUAD * test = (RGBQUAD* )pBuffer;
for(int y = 0; y < 480; y++)
{
for(int x = 0; x < 640; x++)
{
*write = test->rgbBlue;
write++;
*write = test->rgbGreen;
write++;
*write = test->rgbRed;
write++;
write++; // skipping reserved
test++;
}
}
}
m_pNuiInstance->NuiImageStreamReleaseFrame( m_pVideoStreamHandle, pImageFrame );
}
void CIrrDeviceKinect::Nui_GotSkeletonAlert()
{
NUI_SKELETON_FRAME SkeletonFrame;
bool bFoundSkeleton = false;
if( SUCCEEDED(m_pNuiInstance->NuiSkeletonGetNextFrame( 0, &SkeletonFrame )) )
{
for( int i = 0 ; i < NUI_SKELETON_COUNT ; i++ )
{
if( SkeletonFrame.SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED )
{
bFoundSkeleton = true;
}
}
}
}
void CIrrDeviceKinect::Nui_Zero()
{
m_pNuiInstance = NULL;
m_hThNuiProcess = NULL;
m_hEvNuiProcessStop = NULL;
m_hNextDepthFrameEvent = NULL;
m_hNextVideoFrameEvent = NULL;
m_hNextSkeletonEvent = NULL;
m_pDepthStreamHandle = NULL;
m_pVideoStreamHandle = NULL;
ZeroMemory(m_points, sizeof(m_points));
}
DWORD WINAPI CIrrDeviceKinect::Nui_ProcessThread(LPVOID pParam)
{
CIrrDeviceKinect* pthis = (CIrrDeviceKinect*) pParam;
return pthis->Nui_ProcessThread();
}
DWORD WINAPI CIrrDeviceKinect::Nui_ProcessThread()
{
HANDLE hEvents[4];
int nEventIdx;
hEvents[0] = m_hEvNuiProcessStop;
hEvents[1] = m_hNextDepthFrameEvent;
hEvents[2] = m_hNextVideoFrameEvent;
hEvents[3] = m_hNextSkeletonEvent;
// Kinect sensory loop
while(TRUE)
{
// Wait for an event to be signalled
nEventIdx = WaitForMultipleObjects(sizeof(hEvents) / sizeof(hEvents[0]), hEvents, FALSE, 1000);
// If the stop event, stop looping and exit
if(nEventIdx == 0)
break;
// Process signal events
switch(nEventIdx)
{
case 1:
Nui_GotDepthAlert();
break;
case 2:
Nui_GotVideoAlert();
break;
case 3:
Nui_GotSkeletonAlert();
break;
}
}
return (0);
}
RGBQUAD CIrrDeviceKinect::Nui_DrawDepthImage(int x, int y, USHORT s )
{
bool hasPlayerData = HasSkeletalEngine(m_pNuiInstance);
USHORT RealDepth = hasPlayerData ? (s & 0xfff8) >> 3 : s & 0xffff;
USHORT Player = hasPlayerData ? s & 7 : 0;
// transform 13-bit depth information into an 8-bit intensity appropriate
// for display (we disregard information in most significant bit)
BYTE l = 255 - (BYTE)(256*RealDepth/0x0fff);
RGBQUAD q;
q.rgbRed = q.rgbBlue = q.rgbGreen = 0;
switch( Player )
{
case 0:
q.rgbRed = l / 2;
q.rgbBlue = l / 2;
q.rgbGreen = l / 2;
break;
case 1:
q.rgbRed = l;
break;
case 2:
q.rgbGreen = l;
break;
case 3:
q.rgbRed = l / 4;
q.rgbGreen = l;
q.rgbBlue = l;
break;
case 4:
q.rgbRed = l;
q.rgbGreen = l;
q.rgbBlue = l / 4;
break;
case 5:
q.rgbRed = l;
q.rgbGreen = l / 4;
q.rgbBlue = l;
break;
case 6:
q.rgbRed = l / 2;
q.rgbGreen = l / 2;
q.rgbBlue = l;
break;
case 7:
q.rgbRed = 255 - ( l / 2 );
q.rgbGreen = 255 - ( l / 2 );
q.rgbBlue = 255 - ( l / 2 );
}
//m_pdepth->setPixel(x, y, video::SColor(255, q.rgbRed, q.rgbGreen, q.rgbBlue));
return q;
}
void CIrrDeviceKinect::Update()
{
// TODO: Critical section or mutex locks?
BYTE* write = (BYTE*)m_tdepth->lock();
memcpy(write, m_parallel_depth, 320*240*4);
write = 0;
m_tdepth->unlock();
write = (BYTE*) m_trgb->lock();
memcpy(write, m_parallel_rgb, 640*480*4);
write = 0;
m_trgb->unlock();
}
int CIrrDeviceKinect::getNumberOfKinects()
{
int numberOfKinects = 0;
MSR_NUIGetDeviceCount(&numberOfKinects);
return numberOfKinects;
}