summaryrefslogtreecommitdiffhomepage
path: root/faceapi
diff options
context:
space:
mode:
Diffstat (limited to 'faceapi')
-rw-r--r--faceapi/FaceAPI2FSX_vc8.vcproj233
-rw-r--r--faceapi/FaceAPI2FSX_vc9.vcproj232
-rw-r--r--faceapi/build_options.h8
-rw-r--r--faceapi/lock.h35
-rw-r--r--faceapi/lockfree.h65
-rw-r--r--faceapi/main.cpp543
-rw-r--r--faceapi/mutex.h44
-rw-r--r--faceapi/stdafx.cpp8
-rw-r--r--faceapi/stdafx.h21
-rw-r--r--faceapi/utils.h346
10 files changed, 1535 insertions, 0 deletions
diff --git a/faceapi/FaceAPI2FSX_vc8.vcproj b/faceapi/FaceAPI2FSX_vc8.vcproj
new file mode 100644
index 00000000..8e2fc936
--- /dev/null
+++ b/faceapi/FaceAPI2FSX_vc8.vcproj
@@ -0,0 +1,233 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="FTNoIR_FaceAPI_EXE"
+ ProjectGUID="{EF743D32-0980-44D9-BA9E-B9D2456251AC}"
+ RootNamespace="TestAppConsole"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(ProjectDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectDir)$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ CommandLine=""
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine=""
+ Outputs=""
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;C:\Program Files (x86)\SeeingMachines\FaceTrackingAPI_NC 3.2\API\include&quot;;&quot;$(SolutionDir)\ftnoir_tracker_base&quot;"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="smft32.lib user32.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="&quot;C:\Program Files (x86)\SeeingMachines\FaceTrackingAPI_NC 3.2\API\bin&quot;"
+ IgnoreDefaultLibraryNames=""
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(ProjectDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectDir)$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ CommandLine=""
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;C:\Program Files (x86)\SeeingMachines\FaceTrackingAPI_NC 3.2\API\include&quot;;..\FTNoIR_Tracker_Base"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="smft32.lib user32.lib"
+ OutputFile="..\bin\$(ProjectName).exe"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="&quot;C:\Program Files (x86)\SeeingMachines\FaceTrackingAPI_NC 3.2\API\bin&quot;"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine=""
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Headers"
+ >
+ <File
+ RelativePath=".\build_options.h"
+ >
+ </File>
+ <File
+ RelativePath="..\FTNoIR_Tracker_Base\ftnoir_tracker_sm_types.h"
+ >
+ </File>
+ <File
+ RelativePath=".\lock.h"
+ >
+ </File>
+ <File
+ RelativePath=".\lockfree.h"
+ >
+ </File>
+ <File
+ RelativePath=".\mutex.h"
+ >
+ </File>
+ <File
+ RelativePath=".\stdafx.h"
+ >
+ </File>
+ <File
+ RelativePath=".\utils.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Sources"
+ >
+ <File
+ RelativePath=".\main.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\stdafx.cpp"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/faceapi/FaceAPI2FSX_vc9.vcproj b/faceapi/FaceAPI2FSX_vc9.vcproj
new file mode 100644
index 00000000..227d872d
--- /dev/null
+++ b/faceapi/FaceAPI2FSX_vc9.vcproj
@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="FTNoIR_FaceAPI_EXE"
+ ProjectGUID="{EF743D32-0980-44D9-BA9E-B9D2456251AC}"
+ RootNamespace="TestAppConsole"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(ProjectDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectDir)$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ CommandLine=""
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine=""
+ Outputs=""
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="C:\Program Files\SeeingMachines\FaceTrackingAPI_NC 3.2\API\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="smft32.lib user32.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="..\..\FaceAPI\bin;..\..\SimConnect"
+ IgnoreDefaultLibraryNames=""
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(ProjectDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectDir)$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ CommandLine=""
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;D:\Program Files (x86)\SeeingMachines\FaceTrackingAPI_NC 3.2\API\include&quot;;..\FTNoIR_Tracker_Base"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="smft32.lib user32.lib"
+ OutputFile="..\bin\$(ProjectName).exe"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="&quot;D:\Program Files (x86)\SeeingMachines\FaceTrackingAPI_NC 3.2\API\bin&quot;"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine=""
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Headers"
+ >
+ <File
+ RelativePath=".\build_options.h"
+ >
+ </File>
+ <File
+ RelativePath="..\FTNoIR_Tracker_Base\ftnoir_tracker_sm_types.h"
+ >
+ </File>
+ <File
+ RelativePath=".\lock.h"
+ >
+ </File>
+ <File
+ RelativePath=".\lockfree.h"
+ >
+ </File>
+ <File
+ RelativePath=".\mutex.h"
+ >
+ </File>
+ <File
+ RelativePath=".\stdafx.h"
+ >
+ </File>
+ <File
+ RelativePath=".\utils.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Sources"
+ >
+ <File
+ RelativePath=".\main.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\stdafx.cpp"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/faceapi/build_options.h b/faceapi/build_options.h
new file mode 100644
index 00000000..6bc6a44c
--- /dev/null
+++ b/faceapi/build_options.h
@@ -0,0 +1,8 @@
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Build Options
+//
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+//controls whether or not FaceAPI should use the callback or poll
+#define USE_HEADPOSE_CALLBACK 1
diff --git a/faceapi/lock.h b/faceapi/lock.h
new file mode 100644
index 00000000..efe38605
--- /dev/null
+++ b/faceapi/lock.h
@@ -0,0 +1,35 @@
+#ifndef SM_API_TESTAPPCONSOLE_LOCK_H
+#define SM_API_TESTAPPCONSOLE_LOCK_H
+
+#include "mutex.h"
+
+namespace sm
+{
+ namespace faceapi
+ {
+ namespace samplecode
+ {
+ // A very simple scoped-lock class for sample code purposes.
+ // It is recommended that you use the boost threads library.
+ class Lock
+ {
+ public:
+ Lock(const Mutex &mutex): _mutex(mutex)
+ {
+ _mutex.lock();
+ }
+ ~Lock()
+ {
+ _mutex.unlock();
+ }
+ private:
+ // Noncopyable
+ Lock(const Lock &);
+ Lock &operator=(const Lock &);
+ private:
+ const Mutex &_mutex;
+ };
+ }
+ }
+}
+#endif
diff --git a/faceapi/lockfree.h b/faceapi/lockfree.h
new file mode 100644
index 00000000..ce7d2a64
--- /dev/null
+++ b/faceapi/lockfree.h
@@ -0,0 +1,65 @@
+//lock free queue template class by Herb Sutter
+//Dr Dobbs Journal article http://www.drdobbs.com/cpp/210604448;jsessionid=OQGQPSMNL4X4XQE1GHPSKH4ATMY32JVN?pgno=1
+
+template <typename T> class LockFreeQueue
+{
+private:
+ struct Node
+ {
+ Node( T val ) : value(val), next(nullptr) { }
+ T value;
+ Node* next;
+ };
+
+ Node* first; // for producer only
+ Node* divider, last; // shared
+
+ //not working in VC2008
+ //atomic<Node*> divider, last; // shared
+
+public:
+ LockFreeQueue()
+ {
+ // add dummy separator
+ first = divider = last = new Node( T() );
+ }
+
+ ~LockFreeQueue()
+ {
+ while( first != nullptr )
+ {
+ // release the list
+ Node* tmp = first;
+ first = tmp->next;
+ delete tmp;
+ }
+ }
+
+ void Produce( const T& t )
+ {
+ last->next = new Node(t); // add the new item
+ last = last->next; // publish it
+
+ while( first != divider )
+ {
+ // trim unused nodes
+ Node* tmp = first;
+ first = first->next;
+ delete tmp;
+ }
+ }
+
+ bool Consume( T& result )
+ {
+ if( divider != last )
+ {
+ // if queue is nonempty
+ result = divider->next->value; // copy it back
+ divider = divider->next; // publish that we took it
+ return true; // and report success
+ }
+
+ return false; // else report empty
+ }
+};
+
diff --git a/faceapi/main.cpp b/faceapi/main.cpp
new file mode 100644
index 00000000..46732cb3
--- /dev/null
+++ b/faceapi/main.cpp
@@ -0,0 +1,543 @@
+/********************************************************************************
+* FaceTrackNoIR This program is a private project of the some enthusiastic *
+* gamers from Holland, who don't like to pay much for *
+* head-tracking. *
+* *
+* Copyright (C) 2013 Wim Vriend (Developing) *
+* Ron Hendriks (Researching and Testing) *
+* *
+* Homepage *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the *
+* Free Software Foundation; either version 3 of the License, or (at your *
+* option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but *
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program; if not, see <http://www.gnu.org/licenses/>. *
+*********************************************************************************/
+/*
+ Modifications (last one on top):
+ 20130105 - WVR: Set engine state to TERMINATED, when EXIT.
+ 20110501 - WVR: Added some command to be handled from FaceTrackNoIR (settings dialog).
+ 20110322 - WVR: Somehow the video-widget of faceAPI version 3.2.6. does not
+ work with FaceTrackNoIR (Qt issue?!). To be able to use
+ release 3.2.6 of faceAPI anyway, this console-app is used.
+ It exchanges data with FaceTrackNoIR via shared-memory...
+*/
+
+//Precompiled header
+#include "stdafx.h"
+
+//FaceAPI headers
+#include <sm_api.h>
+#include "ftnoir_tracker_sm_types.h"
+#include "utils.h"
+
+//local headers
+#include "build_options.h"
+
+//namespaces
+using namespace std;
+using namespace sm::faceapi::samplecode;
+
+//
+// global variables
+//
+HANDLE hSMMemMap = NULL;
+SMMemMap *pMemData;
+HANDLE hSMMutex;
+smEngineHeadPoseData new_head_pose;
+bool stopCommand = false;
+bool ftnoirConnected = false;
+
+//enums
+enum GROUP_ID
+{
+ GROUP0=0,
+};
+
+enum EVENT_ID
+{
+ EVENT_PING=0,
+ EVENT_INIT,
+};
+
+enum INPUT_ID
+{
+ INPUT0=0,
+};
+
+//function definitions
+void updateHeadPose(smEngineHeadPoseData* temp_head_pose);
+bool SMCreateMapping();
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+//FaceAPI function implementations
+//
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void STDCALL receiveLogMessage(void *, const char *buf, int /*buf_len*/)
+{
+ Lock lock(g_mutex); // serialize logging calls from different threads to avoid garbled output.
+ //cout << string(buf);
+}
+
+// Callback function for face-data
+void STDCALL receiveFaceData(void *, smEngineFaceData face_data, smCameraVideoFrame video_frame)
+{
+ Lock lock(g_mutex);
+
+ // Get info including data pointer to original image from camera
+ smImageInfo video_frame_image_info;
+ THROW_ON_ERROR(smImageGetInfo(video_frame.image_handle, &video_frame_image_info)); // reentrant, so ok
+
+ // video_frame_image_info.plane_addr[*] now point to the image memory planes.
+ // The memory is only valid until the end of this routine unless you call smImageAddRef(video_frame.image_handle).
+ // So you can deep copy the image data here, or use smImageAddRef() and just copy the pointer.
+ // If you use smImageAddRef() you are responsible for calling smImageDestroy() to avoid a memory leak later.
+
+ // In this callback you will typically want to copy the smEngineFaceData data into your own data-structure.
+ // Since the smEngineFaceData contains multiple pod types copying it is not atomic and
+ // a mutex is required to avoid the race-condition with any thread simultaneously
+ // reading from your data-structure.
+ // Such a race condition will not crash your code but will create weird noise in the tracking data.
+
+ if (g_do_face_data_printing)
+ {
+ //cout << video_frame << " " << face_data;
+
+ // Save any face texture to a PNG file
+ if (face_data.texture)
+ {
+ // Create a unique filename
+ std::stringstream filename;
+ filename << "face_" << video_frame.frame_num << ".png";
+ // Try saving to a file
+ if (saveToPNGFile(filename.str(), face_data.texture->image_info) == SM_API_OK)
+ {
+ cout << "Saved face-texture to " << filename.str() << std::endl;
+ }
+ else
+ {
+ cout << "Error saving face-texture to " << filename.str() << std::endl;
+ }
+ }
+ }
+}
+
+// Callback function for head-pose
+void STDCALL receiveHeadPose(void *,smEngineHeadPoseData head_pose, smCameraVideoFrame video_frame)
+{
+ Lock lock(g_mutex);
+
+ // Get info including data pointer to original image from camera
+ smImageInfo video_frame_image_info;
+ THROW_ON_ERROR(smImageGetInfo(video_frame.image_handle, &video_frame_image_info)); // reentrant, so ok
+
+ // video_frame_image_info.plane_addr[*] now point to the image memory planes.
+ // The memory is only valid until the end of this routine unless you call smImageAddRef(video_frame.image_handle).
+ // So you can deep copy the image data here, or use smImageAddRef() and just copy the pointer.
+ // If you use smImageAddRef() you are responsible for calling smImageDestroy() to avoid a memory leak later.
+
+ // In this callback you will typically want to copy the smEngineFaceData data into your own data-structure.
+ // Since the smEngineFaceData contains multiple pod types copying it is not atomic and
+ // a mutex is required to avoid the race-condition with any thread simultaneously
+ // reading from your data-structure.
+ // Such a race condition will not crash your code but will create weird noise in the tracking data.
+
+ if (g_do_head_pose_printing)
+ {
+ //cout << video_frame << " " << head_pose << std::endl;
+ }
+
+ //make a copy of the new head pose data and send it to simconnect
+ //when we get a simmconnect frame event the new offset will be applied to the camera
+ updateHeadPose(&head_pose);
+}
+
+// Create the first available camera detected on the system, and return its handle
+smCameraHandle createFirstCamera()
+{
+ // Detect cameras
+ smCameraInfoList info_list;
+ THROW_ON_ERROR(smCameraCreateInfoList(&info_list));
+
+ if (info_list.num_cameras == 0)
+ {
+ throw runtime_error("No cameras were detected");
+ }
+ else
+ {
+ cout << "The followings cameras were detected: " << endl;
+ for (int i=0; i<info_list.num_cameras; ++i)
+ {
+ char buf[1024];
+ cout << " " << i << ". Type: " << info_list.info[i].type;
+ THROW_ON_ERROR(smStringWriteBuffer(info_list.info[i].model,buf,1024));
+ cout << " Model: " << string(buf);
+ cout << " Instance: " << info_list.info[i].instance_index << endl;
+ // Print all the possible formats for the camera
+ for (int j=0; j<info_list.info[i].num_formats; j++)
+ {
+ smCameraVideoFormat video_format = info_list.info[i].formats[j];
+ cout << " - Format: ";
+ cout << " res (" << video_format.res.w << "," << video_format.res.h << ")";
+ cout << " image code " << video_format.format;
+ cout << " framerate " << video_format.framerate << "(hz)";
+ cout << " upside-down? " << (video_format.is_upside_down ? "y":"n") << endl;
+ }
+ }
+ }
+
+ // Create the first camera detected on the system
+ smCameraHandle camera_handle = 0;
+ THROW_ON_ERROR(smCameraCreate(&info_list.info[0], // Use first camera
+ 0, // Use default settings for lens
+ &camera_handle));
+
+ // Destroy the info list
+ smCameraDestroyInfoList(&info_list);
+
+ return camera_handle;
+}
+
+// The main function: setup a tracking engine and show a video window, then loop on the keyboard.
+void run()
+{
+ char msg[100];
+ int state;
+
+ // Capture control-C
+// signal(SIGINT, CtrlCHandler);
+
+ // Make the console window a bit bigger (see utils.h)
+ initConsole();
+
+ #ifdef _DEBUG
+ // Log API debugging information to a file
+ THROW_ON_ERROR(smLoggingSetFileOutputEnable(SM_API_TRUE));
+
+ // Hook up log message callback
+ THROW_ON_ERROR(smLoggingRegisterCallback(0,receiveLogMessage));
+ #endif
+
+ // Get the version
+ int major, minor, maint;
+ THROW_ON_ERROR(smAPIVersion(&major, &minor, &maint));
+ cout << endl << "API VERSION: " << major << "." << minor << "." << maint << "." << endl << endl;
+ // Print detailed license info
+ char *buff;
+ int size;
+ THROW_ON_ERROR(smAPILicenseInfoString(0,&size,SM_API_TRUE));
+ buff = new char[size];
+ THROW_ON_ERROR(smAPILicenseInfoString(buff,&size,SM_API_TRUE));
+ cout << "LICENSE: " << buff << endl << endl;
+ // Determine if non-commercial restrictions apply
+ const bool non_commercial_license = smAPINonCommercialLicense() == SM_API_TRUE;
+
+ // Initialize the API
+ THROW_ON_ERROR(smAPIInit());
+
+ #ifdef _DEBUG
+ // Get the path to the logfile
+ smStringHandle logfile_path_handle = 0;
+ THROW_ON_ERROR(smStringCreate(&logfile_path_handle));
+ THROW_ON_ERROR(smLoggingGetPath(logfile_path_handle));
+ int buf_len = 0;
+ unsigned short *buf = 0;
+ THROW_ON_ERROR(smStringGetBufferW(logfile_path_handle,(wchar_t **)&buf,&buf_len));
+ wcout << "Writing log to file: " << wstring((wchar_t *)buf) << endl;
+ THROW_ON_ERROR(smStringDestroy(&logfile_path_handle));
+ #endif
+
+ // Register the WDM category of cameras
+ THROW_ON_ERROR(smCameraRegisterType(SM_API_CAMERA_TYPE_WDM));
+
+ smEngineHandle engine_handle = 0;
+ smCameraHandle camera_handle = 0;
+ if (non_commercial_license)
+ {
+ // Create a new Head-Tracker engine that uses the camera
+ THROW_ON_ERROR(smEngineCreate(SM_API_ENGINE_LATEST_HEAD_TRACKER,&engine_handle));
+ }
+ else
+ {
+ // Print out a list of connected cameras, and choose the first camera on the system
+ camera_handle = createFirstCamera();
+ // Create a new Head-Tracker engine that uses the camera
+ THROW_ON_ERROR(smEngineCreateWithCamera(SM_API_ENGINE_LATEST_HEAD_TRACKER,camera_handle,&engine_handle));
+ }
+
+ // Check license for particular engine version (always ok for non-commercial license)
+ const bool engine_licensed = smEngineIsLicensed(engine_handle) == SM_API_OK;
+
+ cout << "-----------------------------------------------------" << endl;
+ cout << "Press 'r' to restart tracking" << endl;
+ cout << "Press 'a' to toggle auto-restart mode" << endl;
+ if (!non_commercial_license)
+ {
+ cout << "Press 'l' to toggle lip-tracking" << endl;
+ cout << "Press 'e' to toggle eyebrow-tracking" << endl;
+ }
+ if (engine_licensed)
+ {
+ cout << "Press 'h' to toggle printing of head-pose data" << endl;
+ cout << "Press 'f' to toggle printing of face-landmark data" << endl;
+ }
+ cout << "Press '1' to toggle face coordinate frame axes" << endl;
+ cout << "Press '2' to toggle performance info" << endl;
+ cout << "Press '3' to toggle face mask" << endl;
+ cout << "Press '4' to toggle face landmarks" << endl;
+ cout << "Press CTRL-C or 'q' to quit" << endl;
+ cout << "-----------------------------------------------------" << endl;
+
+ // Hook up callbacks to receive output data from engine.
+ // These functions will return errors if the engine is not licensed.
+ if (engine_licensed)
+ {
+ #if (USE_HEADPOSE_CALLBACK==1)
+ #pragma message("Using Headpose Callback")
+ THROW_ON_ERROR(smHTRegisterHeadPoseCallback(engine_handle,0,receiveHeadPose));
+ #endif
+ if (!non_commercial_license)
+ {
+ THROW_ON_ERROR(smHTRegisterFaceDataCallback(engine_handle,0,receiveFaceData));
+ }
+ }
+ else
+ {
+ cout << "Engine is not licensed, cannot obtain any output data." << endl;
+ }
+
+ if (!non_commercial_license)
+ {
+ // Enable lip and eyebrow tracking
+ THROW_ON_ERROR(smHTSetLipTrackingEnabled(engine_handle,SM_API_TRUE));
+ THROW_ON_ERROR(smHTSetEyebrowTrackingEnabled(engine_handle,SM_API_TRUE));
+ }
+
+ // Create and show a video-display window
+ // Set the initial filter-level, from the INI-file
+ smVideoDisplayHandle video_display_handle = 0;
+ if (pMemData) {
+ THROW_ON_ERROR(smVideoDisplayCreate(engine_handle,&video_display_handle,(smWindowHandle) pMemData->handle,TRUE));
+ THROW_ON_ERROR(smHTV2SetHeadPoseFilterLevel(engine_handle, pMemData->initial_filter_level));
+ pMemData->handshake = 0;
+ }
+ else {
+ THROW_ON_ERROR(smVideoDisplayCreate(engine_handle,&video_display_handle,0,TRUE));
+ }
+
+ // Setup the VideoDisplay
+ THROW_ON_ERROR(smVideoDisplaySetFlags(video_display_handle,g_overlay_flags));
+
+ // Get the handle to the window and change the title to "Hello World"
+ smWindowHandle win_handle = 0;
+ THROW_ON_ERROR(smVideoDisplayGetWindowHandle(video_display_handle,&win_handle));
+ SetWindowText(win_handle, _T("faceAPI Video-widget"));
+ MoveWindow(win_handle, 0, 0, 250, 180, true);
+
+ // Loop on the keyboard
+ while (processKeyPress(engine_handle, video_display_handle) && !stopCommand)
+ {
+ // Read and print the current head-pose (if not using the callback mechanism)
+ #if (USE_HEADPOSE_CALLBACK==0)
+ #pragma message("Polling Headpose Manually")
+ if (engine_licensed)
+ {
+ smEngineHeadPoseData head_pose;
+ Lock lock(g_mutex);
+
+ THROW_ON_ERROR(smHTCurrentHeadPose(engine_handle,&head_pose));
+ if (g_do_head_pose_printing)
+ {
+ std::cout << head_pose << std::endl;
+ }
+
+ }
+ #endif
+
+ // NOTE: If you have a windows event loop in your program you
+ // will not need to call smAPIProcessEvents(). This manually redraws the video window.
+ THROW_ON_ERROR(smAPIProcessEvents());
+
+ // Prevent CPU overload in our simple loop.
+ const int frame_period_ms = 10;
+ Sleep(frame_period_ms);
+
+ //
+ // Process the command sent by FaceTrackNoIR.
+ //
+ if (ftnoirConnected && (pMemData != 0)) {
+
+ sprintf_s(msg, "Command: %d, \n", pMemData->command, pMemData->par_val_int);
+ OutputDebugStringA(msg);
+ std::cout << msg;
+
+ //
+ //
+ // Determine the trackers' state and send it to FaceTrackNoIR.
+ //
+ THROW_ON_ERROR(smEngineGetState(engine_handle, &state));
+ pMemData->state = state;
+ pMemData->handshake += 1;
+
+ //
+ // Check if FaceTrackNoIR is still 'in contact'.
+ // FaceTrackNoIR will reset the handshake, every time in writes data.
+ // If the value rises too high, this exe will stop itself...
+ //
+ if ( pMemData->handshake > 200) {
+ stopCommand = TRUE;
+ }
+
+ //
+ // Check if a command was issued and do something with it!
+ //
+ switch (pMemData->command) {
+ case FT_SM_START:
+
+ //
+ // Only execute Start, if the engine is not yet tracking.
+ //
+ if (state != SM_API_ENGINE_STATE_HT_TRACKING) {
+ THROW_ON_ERROR(smEngineStart(engine_handle)); // Start tracking
+ }
+ pMemData->command = 0; // Reset
+ break;
+
+ case FT_SM_STOP:
+ THROW_ON_ERROR(smEngineStop(engine_handle)); // Stop tracking
+ pMemData->command = 0; // Reset
+ break;
+
+ case FT_SM_EXIT:
+ THROW_ON_ERROR(smEngineStop(engine_handle)); // Stop tracking
+ stopCommand = TRUE;
+ pMemData->command = 0; // Reset
+ pMemData->state = SM_API_ENGINE_STATE_TERMINATED; // One last update, before quitting...
+ break;
+
+ case FT_SM_SET_PAR_FILTER:
+ THROW_ON_ERROR(smHTV2SetHeadPoseFilterLevel(engine_handle, pMemData->par_val_int));
+ pMemData->command = 0; // Reset
+ break;
+
+ case FT_SM_SHOW_CAM:
+ THROW_ON_ERROR(smEngineShowCameraControlPanel(engine_handle));
+ pMemData->command = 0; // Reset
+ break;
+
+ default:
+ pMemData->command = 0; // Reset
+ // should never be reached
+ break;
+ }
+ }
+ } // While(1)
+
+ // Destroy engine
+ THROW_ON_ERROR(smEngineDestroy(&engine_handle));
+ // Destroy video display
+ THROW_ON_ERROR(smVideoDisplayDestroy(&video_display_handle));
+
+ if (ftnoirConnected) {
+ if ( pMemData != NULL ) {
+ UnmapViewOfFile ( pMemData );
+ }
+
+ if (hSMMutex != 0) {
+ CloseHandle( hSMMutex );
+ }
+ hSMMutex = 0;
+
+ if (hSMMemMap != 0) {
+ CloseHandle( hSMMemMap );
+ }
+ hSMMemMap = 0;
+ }
+
+} // run()
+
+// Application entry point
+int _tmain(int /*argc*/, _TCHAR** /*argv*/)
+{
+ OutputDebugString(_T("_tmain() says: Starting Function\n"));
+
+ try
+ {
+ if (SMCreateMapping()) {
+ run();
+ }
+ }
+ catch (exception &e)
+ {
+ cerr << e.what() << endl;
+ }
+
+ return smAPIQuit();
+}
+
+//
+// This is called exactly once for each FaceAPI callback and must be within an exclusive lock
+//
+void updateHeadPose(smEngineHeadPoseData* temp_head_pose)
+{
+ //
+ // Check if the pointer is OK and wait for the Mutex.
+ //
+ if ( (pMemData != NULL) && (WaitForSingleObject(hSMMutex, 100) == WAIT_OBJECT_0) ) {
+
+ //
+ // Copy the Raw measurements directly to the client.
+ //
+ if (temp_head_pose->confidence > 0.0f)
+ {
+ memcpy(&pMemData->data.new_pose,temp_head_pose,sizeof(smEngineHeadPoseData));
+ }
+ ReleaseMutex(hSMMutex);
+ }
+};
+
+//
+// Create a memory-mapping to the faceAPI data.
+// It contains the tracking data, a command-code from FaceTrackNoIR
+//
+//
+bool SMCreateMapping()
+{
+ OutputDebugString(_T("FTCreateMapping says: Starting Function\n"));
+
+ //
+ // A FileMapping is used to create 'shared memory' between the faceAPI and FaceTrackNoIR.
+ // FaceTrackNoIR creates the mapping, this program only opens it.
+ // If it's not there: the program was apparently started by the user instead of FaceTrackNoIR...
+ //
+ // Open an existing FileMapping, Read/Write access
+ //
+ hSMMemMap = OpenFileMappingA( FILE_MAP_ALL_ACCESS , false , (LPCSTR) SM_MM_DATA );
+ if ( ( hSMMemMap != 0 ) ) {
+ ftnoirConnected = true;
+ OutputDebugString(_T("FTCreateMapping says: FileMapping opened successfully...\n"));
+ pMemData = (SMMemMap *) MapViewOfFile(hSMMemMap, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(TFaceData));
+ if (pMemData != NULL) {
+ OutputDebugString(_T("FTCreateMapping says: MapViewOfFile OK.\n"));
+ pMemData->state = 0;
+ }
+ hSMMutex = CreateMutexA(NULL, false, SM_MUTEX);
+ }
+ else {
+ OutputDebugString(_T("FTCreateMapping says: FileMapping not opened...FaceTrackNoIR not connected!\n"));
+ ftnoirConnected = false;
+ pMemData = 0;
+ }
+
+ return true;
+}
diff --git a/faceapi/mutex.h b/faceapi/mutex.h
new file mode 100644
index 00000000..11aabafc
--- /dev/null
+++ b/faceapi/mutex.h
@@ -0,0 +1,44 @@
+#ifndef SM_API_TESTAPPCONSOLE_MUTEX_H
+#define SM_API_TESTAPPCONSOLE_MUTEX_H
+
+namespace sm
+{
+ namespace faceapi
+ {
+ namespace samplecode
+ {
+ // A very simple mutex class for sample code purposes.
+ // It is recommended that you use the boost threads library.
+ class Mutex
+ {
+ public:
+ Mutex()
+ {
+ if (!InitializeCriticalSectionAndSpinCount(&_cs,0x80000400))
+ {
+ throw std::runtime_error("Failed to initialize Mutex");
+ }
+ }
+ ~Mutex()
+ {
+ DeleteCriticalSection(&_cs);
+ }
+ void lock() const
+ {
+ EnterCriticalSection(&_cs);
+ }
+ void unlock() const
+ {
+ LeaveCriticalSection(&_cs);
+ }
+ private:
+ // Noncopyable
+ Mutex(const Mutex &);
+ Mutex &operator=(const Mutex &);
+ private:
+ mutable CRITICAL_SECTION _cs;
+ };
+ }
+ }
+}
+#endif
diff --git a/faceapi/stdafx.cpp b/faceapi/stdafx.cpp
new file mode 100644
index 00000000..b4263f59
--- /dev/null
+++ b/faceapi/stdafx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// TestAppConsole.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/faceapi/stdafx.h b/faceapi/stdafx.h
new file mode 100644
index 00000000..d97c9353
--- /dev/null
+++ b/faceapi/stdafx.h
@@ -0,0 +1,21 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
+#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
+#endif
+
+#include <stdio.h>
+#include <tchar.h>
+
+// TODO: reference additional headers your program requires here
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <cassert>
+#include <conio.h>
+#include <sm_api.h>
diff --git a/faceapi/utils.h b/faceapi/utils.h
new file mode 100644
index 00000000..1fdb35b5
--- /dev/null
+++ b/faceapi/utils.h
@@ -0,0 +1,346 @@
+#ifndef SM_API_TESTAPPCONSOLE_UTILS_H
+#define SM_API_TESTAPPCONSOLE_UTILS_H
+
+#include "lock.h"
+
+#define THROW_ON_ERROR(x) \
+{ \
+ smReturnCode result = (x); \
+ if (result < 0) \
+ { \
+ std::stringstream s; \
+ s << "API error code: " << result; \
+ throw std::runtime_error(s.str()); \
+ } \
+}
+
+namespace sm
+{
+ namespace faceapi
+ {
+ namespace samplecode
+ {
+ // Global variables
+ Mutex g_mutex;
+ bool g_ctrl_c_detected(false);
+ bool g_do_head_pose_printing(false);
+ bool g_do_face_data_printing(false);
+ unsigned short g_overlay_flags(SM_API_VIDEO_DISPLAY_HEAD_MESH | SM_API_VIDEO_DISPLAY_PERFORMANCE);
+
+ // CTRL-C handler function
+ void __cdecl CtrlCHandler(int)
+ {
+ Lock lock(g_mutex);
+ std::cout << "Ctrl-C detected, stopping..." << std::endl;
+ g_ctrl_c_detected = true;
+ }
+
+ // Radians to degrees conversion
+ float rad2deg(float rad)
+ {
+ return rad*57.2957795f;
+ }
+
+ void toggleFlag(unsigned short &val, unsigned short flag)
+ {
+ if (val & flag)
+ {
+ val = val & ~flag;
+ }
+ else
+ {
+ val = val | flag;
+ }
+ }
+
+ // Save an image to PNG file
+ smReturnCode saveToPNGFile(const std::string& filepath, smImageInfo image_info)
+ {
+ smBool ok;
+ smReturnCode error;
+
+ // Create an API string
+ smStringHandle filepath_handle = 0;
+ ok = (error = smStringCreate(&filepath_handle)) == SM_API_OK;
+ ok = ok && (error = smStringReadBuffer(filepath_handle,filepath.c_str(),filepath.size())) == SM_API_OK;
+
+ // Create an API image
+ smImageHandle image_handle = 0;
+ smImageMemoryCopyMode copy_mode = SM_API_IMAGE_MEMORYCOPYMODE_AUTO;
+ ok = ok && (error = smImageCreateFromInfo(&image_info,&copy_mode,&image_handle)) == SM_API_OK;
+
+ // Save the image as PNG
+ ok = ok && (error = smImageSaveToPNG(image_handle,filepath_handle)) == SM_API_OK;
+
+ // Destroy the image and string
+ smStringDestroy(&filepath_handle);
+ smImageDestroy(&image_handle);
+ return error;
+ }
+
+ // Stream operators for printing
+
+ std::ostream &operator<<(std::ostream & os, const smSize2i &s)
+ {
+ return os << "[" << s.h << "," << s.h << "]";
+ }
+
+ std::ostream &operator<<(std::ostream & os, const smCoord3f &pos)
+ {
+ return os << "(" << pos.x << "," << pos.y << "," << pos.z << ")";
+ }
+
+ std::ostream &operator<<(std::ostream & os, const smRotEuler &rot)
+ {
+ return os << "(" << rad2deg(rot.x_rads) << "," << rad2deg(rot.y_rads) << "," << rad2deg(rot.z_rads) << ")";
+ }
+
+ std::ostream &operator<<(std::ostream & os, const smPixel &p)
+ {
+ return os << "[" << static_cast<int>(p.x) << "," << static_cast<int>(p.y) << "]";
+ }
+
+ std::ostream &operator<<(std::ostream & os, const smFaceTexCoord &ftc)
+ {
+ return os << "{" << ftc.u << "," << ftc.v << "}";
+ }
+
+ std::ostream &operator<<(std::ostream & os, const smFaceLandmark &lm)
+ {
+ return os << "id "<< lm.id << " fc" << lm.fc << " ftc" << lm.ftc << " pc" << lm.pc << " wc" << lm.wc;
+ }
+
+ std::ostream &operator<<(std::ostream & os, const smImageInfo &im)
+ {
+ os << "format ";
+ switch (im.format)
+ {
+ case SM_API_IMAGECODE_GRAY_8U:
+ os << "GRAY_8U";
+ break;
+ case SM_API_IMAGECODE_GRAY_16U:
+ os << "GRAY_16U";
+ break;
+ case SM_API_IMAGECODE_YUY2:
+ os << "YUY2";
+ break;
+ case SM_API_IMAGECODE_I420:
+ os << "I420";
+ break;
+ case SM_API_IMAGECODE_BGRA_32U:
+ os << "BGRA_32U";
+ break;
+ case SM_API_IMAGECODE_ARGB_32U:
+ os << "ARGB_32U";
+ break;
+ case SM_API_IMAGECODE_BGR_24U:
+ os << "BGR_24U";
+ break;
+ case SM_API_IMAGECODE_RGB_24U:
+ os << "RGB_24U";
+ break;
+ default:
+ os << "unknown";
+ break;
+ }
+ os << " res" << im.res;
+ os << " plane_addr(" << static_cast<void *>(im.plane_addr[0]) << ","
+ << static_cast<void *>(im.plane_addr[1]) << ","
+ << static_cast<void *>(im.plane_addr[2]) << ","
+ << static_cast<void *>(im.plane_addr[3]) << ")";
+ os << " step_bytes(" << im.step_bytes[0] << "," << im.step_bytes[1] << "," << im.step_bytes[2] << "," << im.step_bytes[3] << ")";
+ os << " user_data " << im.user_data;
+ return os;
+ }
+
+ std::ostream &operator<<(std::ostream & os, const smFaceTexture &t)
+ {
+ os << "type ";
+ switch (t.type)
+ {
+ case SM_ORTHOGRAPHIC_PROJECTION:
+ os << "orthographic";
+ break;
+ default:
+ os << "unknown";
+ break;
+ }
+ os << " origin" << t.origin << " scale" << t.scale << std::endl;
+ os << " image_info " << t.image_info << std::endl;
+ os << " num_mask_landmarks " << t.num_mask_landmarks << std::endl;
+ for (int i=0; i<t.num_mask_landmarks; i++)
+ {
+ os << " " << t.mask_landmarks[i] << std::endl;
+ }
+ return os;
+ }
+
+ // Stream operator for printing face landmarks
+ std::ostream &operator<<(std::ostream &os, const smEngineFaceData &face_data)
+ {
+ fixed(os);
+ showpos(os);
+ os.precision(2);
+ os << "Face Data: "
+ << "origin_wc" << face_data.origin_wc << " "
+ << "num_landmarks " << face_data.num_landmarks
+ << std::endl;
+ for (int i=0; i<face_data.num_landmarks; i++)
+ {
+ os << " " << face_data.landmarks[i] << std::endl;
+ }
+ // Print any face texture info
+ if (face_data.texture)
+ {
+ os << "Face Texture: " << *face_data.texture;
+ }
+ return os;
+ }
+
+ // Stream operator for printing head-pose data
+ std::ostream &operator<<(std::ostream & os, const smEngineHeadPoseData &head_pose)
+ {
+ fixed(os);
+ showpos(os);
+ os.precision(2);
+ return os << "Head Pose: "
+ << "head_pos" << head_pose.head_pos << " "
+ << "head_rot" << head_pose.head_rot << " "
+ << "left_eye_pos" << head_pose.left_eye_pos << " "
+ << "right_eye_pos" << head_pose.right_eye_pos << " "
+ << "confidence " << head_pose.confidence;
+ }
+
+ std::ostream &operator<<(std::ostream & os, const smCameraVideoFrame &vf)
+ {
+ fixed(os);
+ showpos(os);
+ os.precision(2);
+ return os << "Framenum: " << vf.frame_num;
+ }
+
+ // Handles keyboard events: return false if quit.
+ bool processKeyPress(smEngineHandle engine_handle, smVideoDisplayHandle video_display_handle)
+ {
+ Lock lock(g_mutex);
+ if (g_ctrl_c_detected)
+ {
+ return false;
+ }
+ if (!_kbhit())
+ {
+ return true;
+ }
+ int key = _getch();
+ switch (key)
+ {
+ case 'q':
+ return false;
+ case 'r':
+ {
+ // Manually restart the tracking
+ THROW_ON_ERROR(smEngineStart(engine_handle));
+ std::cout << "Restarting tracking" << std::endl;
+ }
+ return true;
+ case 'a':
+ {
+ // Toggle auto-restart mode
+ int on;
+ THROW_ON_ERROR(smHTGetAutoRestartMode(engine_handle,&on));
+ THROW_ON_ERROR(smHTSetAutoRestartMode(engine_handle,!on));
+ std::cout << "Autorestart-mode is " << (on?"on":"off") << std::endl;
+ }
+ return true;
+ case '1':
+ toggleFlag(g_overlay_flags,SM_API_VIDEO_DISPLAY_REFERENCE_FRAME);
+ THROW_ON_ERROR(smVideoDisplaySetFlags(video_display_handle,g_overlay_flags));
+ return true;
+ case '2':
+ toggleFlag(g_overlay_flags,SM_API_VIDEO_DISPLAY_PERFORMANCE);
+ THROW_ON_ERROR(smVideoDisplaySetFlags(video_display_handle,g_overlay_flags));
+ return true;
+ case '3':
+ toggleFlag(g_overlay_flags,SM_API_VIDEO_DISPLAY_HEAD_MESH);
+ THROW_ON_ERROR(smVideoDisplaySetFlags(video_display_handle,g_overlay_flags));
+ return true;
+ case '4':
+ toggleFlag(g_overlay_flags,SM_API_VIDEO_DISPLAY_LANDMARKS);
+ THROW_ON_ERROR(smVideoDisplaySetFlags(video_display_handle,g_overlay_flags));
+ return true;
+ case 'l':
+ if (smAPINonCommercialLicense() == SM_API_TRUE)
+ {
+ return false;
+ }
+ else
+ {
+ int on;
+ THROW_ON_ERROR(smHTGetLipTrackingEnabled(engine_handle,&on));
+ THROW_ON_ERROR(smHTSetLipTrackingEnabled(engine_handle,!on));
+ }
+ return true;
+ case 'e':
+ if (smAPINonCommercialLicense() == SM_API_TRUE)
+ {
+ return false;
+ }
+ else
+ {
+ int on;
+ THROW_ON_ERROR(smHTGetEyebrowTrackingEnabled(engine_handle,&on));
+ THROW_ON_ERROR(smHTSetEyebrowTrackingEnabled(engine_handle,!on));
+ }
+ return true;
+ case 'h':
+ if (smEngineIsLicensed(engine_handle) != SM_API_OK)
+ {
+ return false;
+ }
+ else
+ {
+ g_do_head_pose_printing = !g_do_head_pose_printing;
+ std::cout << "HeadPose printing is " << (g_do_head_pose_printing?"on":"off") << std::endl;
+ }
+ return true;
+ case 'f':
+ if (smEngineIsLicensed(engine_handle) != SM_API_OK)
+ {
+ return false;
+ }
+ else
+ {
+ g_do_face_data_printing = !g_do_face_data_printing;
+ std::cout << "FaceData printing is " << (g_do_face_data_printing?"on":"off") << std::endl;
+ }
+ return true;
+ default:
+ return true;
+ }
+ }
+
+ // Setup console window geometry / font etc
+ void initConsole()
+ {
+ HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+ // Buffer of 255 x 1024
+ COORD buffer_size;
+ buffer_size.X = 255;
+ buffer_size.Y = 1024;
+ SetConsoleScreenBufferSize(console_handle, buffer_size);
+ // Window size of 120 x 50
+ SMALL_RECT window_size;
+ window_size.Left = 0;
+ window_size.Right = 120;
+ window_size.Top = 0;
+ window_size.Bottom = 50;
+ SetConsoleWindowInfo(console_handle,TRUE,&window_size);
+ // Green text
+ SetConsoleTextAttribute(console_handle, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
+// ShowWindow(GetConsoleWindow(), SW_HIDE);
+ }
+ }
+ }
+}
+
+#endif