From ee4f1ceb7741cc1b578dafe37e255f96e15a5a84 Mon Sep 17 00:00:00 2001 From: Wim Vriend Date: Sun, 1 May 2011 14:20:34 +0000 Subject: Added controls for faceAPI git-svn-id: svn+ssh://svn.code.sf.net/p/facetracknoir/code@82 19e81ba0-9b1a-49c3-bd6c-561e1906d5fb --- FTNoIR_Tracker_Base/ftnoir_tracker_sm_types.h | 2 + FTNoIR_Tracker_SM/FTNoIR_Tracker_SM.h | 59 +++++- FTNoIR_Tracker_SM/FTNoIR_Tracker_SM.vcproj | 70 ++++++- FTNoIR_Tracker_SM/ftnoir_tracker_faceapi.cpp | 258 ++++++++++++++++++++++++++ faceAPI/main.cpp | 22 ++- 5 files changed, 390 insertions(+), 21 deletions(-) diff --git a/FTNoIR_Tracker_Base/ftnoir_tracker_sm_types.h b/FTNoIR_Tracker_Base/ftnoir_tracker_sm_types.h index abc4a473..5f19f786 100644 --- a/FTNoIR_Tracker_Base/ftnoir_tracker_sm_types.h +++ b/FTNoIR_Tracker_Base/ftnoir_tracker_sm_types.h @@ -18,11 +18,13 @@ struct SMMemMap { int status; // Status from faceAPI TFaceData data; HANDLE handle; + int state; }; typedef SMMemMap * PSMMemMap; enum FTNoIR_Tracker_Command { FT_SM_START = 10, FT_SM_STOP = 20, + FT_SM_SHOW_CAM = 30, FT_SM_EXIT = 100 }; diff --git a/FTNoIR_Tracker_SM/FTNoIR_Tracker_SM.h b/FTNoIR_Tracker_SM/FTNoIR_Tracker_SM.h index 1edc612f..702f236e 100644 --- a/FTNoIR_Tracker_SM/FTNoIR_Tracker_SM.h +++ b/FTNoIR_Tracker_SM/FTNoIR_Tracker_SM.h @@ -1,6 +1,6 @@ #include "..\ftnoir_tracker_base\ftnoir_tracker_base.h" #include "..\ftnoir_tracker_base\ftnoir_tracker_sm_types.h" -#include "ui_FTNoIR_SMClientcontrols.h" +#include "ui_FTNoIR_SM_controls.h" #include #include @@ -27,14 +27,6 @@ public: bool setParameterValue(const int index, const float newvalue); private: - /** face api variables **/ - //APIScope *faceapi_scope; - // QSharedPointer _engine; - //VideoDisplayWidget *_display; - //QVBoxLayout *l; - //MainWindow *main_window; - //parameter list for the filter-function(s) - // // global variables // @@ -53,3 +45,52 @@ private: QList parameterValueAsFloat; }; + +// Widget that has controls for SMoIR protocol client-settings. +class SMClientControls: public QWidget, Ui::UICSMClientControls, public ITrackerDialog +{ + Q_OBJECT +public: + + explicit SMClientControls(); + virtual ~SMClientControls(); + void showEvent ( QShowEvent * event ); + + void Release(); // Member functions which are accessible from outside the DLL + void Initialize(QWidget *parent); + +private: + Ui::UICSMClientControls ui; + void loadSettings(); + void save(); + bool SMCreateMapping(); + void doCommand( int command ); + + /** helper **/ + bool settingsDirty; + + // + // global variables + // + HANDLE hSMMemMap; + SMMemMap *pMemData; + HANDLE hSMMutex; + smEngineHandle *engine_handle; + QTimer *timUpdateSettings; // Timer to display current settings + +private slots: + void doOK(); + void doCancel(); + void settingChanged() { settingsDirty = true; }; + void showSettings(); + void doStartEngine(){ + doCommand(FT_SM_START); + } + void doStopEngine(){ + doCommand(FT_SM_STOP); + } + void doShowCam(){ + doCommand(FT_SM_SHOW_CAM); + } +}; + diff --git a/FTNoIR_Tracker_SM/FTNoIR_Tracker_SM.vcproj b/FTNoIR_Tracker_SM/FTNoIR_Tracker_SM.vcproj index 9964af61..403d2044 100644 --- a/FTNoIR_Tracker_SM/FTNoIR_Tracker_SM.vcproj +++ b/FTNoIR_Tracker_SM/FTNoIR_Tracker_SM.vcproj @@ -185,10 +185,10 @@ > @@ -209,6 +209,32 @@ Filter="ui" UniqueIdentifier="{99349809-55BA-4b9d-BF79-8FDBB0286EB3}" > + + + + + + + + + + + + + + + + + + + + diff --git a/FTNoIR_Tracker_SM/ftnoir_tracker_faceapi.cpp b/FTNoIR_Tracker_SM/ftnoir_tracker_faceapi.cpp index 358ad962..9665890c 100644 --- a/FTNoIR_Tracker_SM/ftnoir_tracker_faceapi.cpp +++ b/FTNoIR_Tracker_SM/ftnoir_tracker_faceapi.cpp @@ -1,4 +1,5 @@ #include "ftnoir_tracker_sm.h" +//#include "sm_api_headtrackerv2controls.h" #include FTNoIR_Tracker_SM::FTNoIR_Tracker_SM() @@ -232,3 +233,260 @@ FTNOIR_TRACKER_BASE_EXPORT TRACKERHANDLE __stdcall GetTracker() { return new FTNoIR_Tracker_SM; } + +//******************************************************************************************************* +// faceAPI Client Settings-dialog. +//******************************************************************************************************* + +// +// Constructor for server-settings-dialog +// +SMClientControls::SMClientControls() : +QWidget() +{ + ui.setupUi( this ); + + // Connect Qt signals to member-functions + connect(ui.btnOK, SIGNAL(clicked()), this, SLOT(doOK())); + connect(ui.btnCancel, SIGNAL(clicked()), this, SLOT(doCancel())); + connect(ui.btnEngineStart, SIGNAL(clicked()), this, SLOT(doStartEngine())); + connect(ui.btnEngineStop, SIGNAL(clicked()), this, SLOT(doStopEngine())); + connect(ui.btnCameraSettings, SIGNAL(clicked()), this, SLOT(doShowCam())); + + if (SMCreateMapping()) { + qDebug() << "SMClientControls::Initialize Mapping created."; + } + else { + QMessageBox::warning(0,"FaceTrackNoIR Error","Memory mapping not created!",QMessageBox::Ok,QMessageBox::NoButton); + } + + // Load the settings from the current .INI-file + loadSettings(); + + //Setup the timer for showing the headpose. + timUpdateSettings = new QTimer(this); + connect(timUpdateSettings, SIGNAL(timeout()), this, SLOT(showSettings())); + timUpdateSettings->start(1000); + +} + +// +// Destructor for server-dialog +// +SMClientControls::~SMClientControls() { + qDebug() << "~SMClientControls() says: started"; +} + +void SMClientControls::Release() +{ + delete this; +} + +// +// Initialize tracker-client-dialog +// +void SMClientControls::Initialize(QWidget *parent) { + + QPoint offsetpos(100, 100); + if (parent) { + this->move(parent->pos() + offsetpos); + } + show(); +} + +// +// OK clicked on server-dialog +// +void SMClientControls::doOK() { + save(); + this->close(); +} + +// override show event +void SMClientControls::showEvent ( QShowEvent * event ) { + loadSettings(); +} + +// +// Cancel clicked on server-dialog +// +void SMClientControls::doCancel() { + // + // Ask if changed Settings should be saved + // + if (settingsDirty) { + int ret = QMessageBox::question ( this, "Settings have changed", "Do you want to save the settings?", QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Discard ); + + qDebug() << "doCancel says: answer =" << ret; + + switch (ret) { + case QMessageBox::Save: + save(); + this->close(); + break; + case QMessageBox::Discard: + this->close(); + break; + case QMessageBox::Cancel: + // Cancel was clicked + break; + default: + // should never be reached + break; + } + } + else { + this->close(); + } +} + +// +// Load the current Settings from the currently 'active' INI-file. +// +void SMClientControls::loadSettings() { + +// qDebug() << "loadSettings says: Starting "; + QSettings settings("Abbequerque Inc.", "FaceTrackNoIR"); // Registry settings (in HK_USER) + + QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString(); + QSettings iniFile( currentFile, QSettings::IniFormat ); // Application settings (in INI-file) + +// qDebug() << "loadSettings says: iniFile = " << currentFile; + + iniFile.beginGroup ( "SMClient" ); + +// ui.spinPortNumber->setValue( iniFile.value ( "PortNumber", 5550 ).toInt() ); + iniFile.endGroup (); + + settingsDirty = false; +} + +// +// Save the current Settings to the currently 'active' INI-file. +// +void SMClientControls::save() { + + QSettings settings("Abbequerque Inc.", "FaceTrackNoIR"); // Registry settings (in HK_USER) + + QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString(); + QSettings iniFile( currentFile, QSettings::IniFormat ); // Application settings (in INI-file) + + iniFile.beginGroup ( "SMClient" ); + iniFile.endGroup (); + + settingsDirty = false; +} + +// +// Create a memory-mapping to the faceAPI data. +// It contains the tracking data, a command-code from FaceTrackNoIR +// +// +bool SMClientControls::SMCreateMapping() +{ + qDebug() << "SMClientControls::FTCreateMapping says: Starting Function"; + + // + // A FileMapping is used to create 'shared memory' between the faceAPI and FaceTrackNoIR. + // + // Try to create a FileMapping to the Shared Memory. + // If one already exists: close it. + // + hSMMemMap = CreateFileMappingA( INVALID_HANDLE_VALUE , 00 , PAGE_READWRITE , 0 , + sizeof( TFaceData ) + sizeof( HANDLE ) + 100, + (LPCSTR) SM_MM_DATA ); + + if ( hSMMemMap != 0 ) { + qDebug() << "SMClientControls::FTCreateMapping says: FileMapping Created!"; + } + + if ( ( hSMMemMap != 0 ) && ( (long) GetLastError == ERROR_ALREADY_EXISTS ) ) { + CloseHandle( hSMMemMap ); + hSMMemMap = 0; + } + + // + // Create a new FileMapping, Read/Write access + // + hSMMemMap = OpenFileMappingA( FILE_MAP_ALL_ACCESS , false , (LPCSTR) SM_MM_DATA ); + if ( ( hSMMemMap != 0 ) ) { + qDebug() << "SMClientControls::FTCreateMapping says: FileMapping Created again..." << hSMMemMap; + pMemData = (SMMemMap *) MapViewOfFile(hSMMemMap, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(TFaceData)); + if (pMemData != NULL) { + qDebug() << "SMClientControls::FTCreateMapping says: MapViewOfFile OK."; +// pMemData->handle = handle; // The game uses the handle, to send a message that the Program-Name was set! + } + hSMMutex = CreateMutexA(NULL, false, SM_MUTEX); + } + else { + qDebug() << "SMClientControls::FTCreateMapping says: Error creating Shared Memory for faceAPI!"; + return false; + } + + //if (pMemData != NULL) { + // pMemData->data.DataID = 1; + // pMemData->data.CamWidth = 100; + // pMemData->data.CamHeight = 250; + //} + + return true; +} + +// +// Show the current engine-settings etc. +// +void SMClientControls::showSettings() +{ + qDebug() << "SMClientControls::showSettings says: Starting Function"; + switch (pMemData->state) + { + case SM_API_ENGINE_STATE_TERMINATED: + ui._engine_state_label->setText("TERMINATED"); + break; + case SM_API_ENGINE_STATE_INVALID: + ui._engine_state_label->setText("INVALID"); + break; + case SM_API_ENGINE_STATE_IDLE: + ui._engine_state_label->setText("IDLE"); + break; + case SM_API_ENGINE_STATE_HT_INITIALIZING: + ui._engine_state_label->setText("INITIALIZING"); + break; + case SM_API_ENGINE_STATE_HT_TRACKING: + ui._engine_state_label->setText("TRACKING"); + break; + case SM_API_ENGINE_STATE_HT_SEARCHING: + ui._engine_state_label->setText("SEARCHING"); + break; + default: + ui._engine_state_label->setText("Unknown State!"); + break; + } + +} + +// +// Start the tracking Engine. +// +void SMClientControls::doCommand(int command) +{ + if ( (pMemData != NULL) && (WaitForSingleObject(hSMMutex, 100) == WAIT_OBJECT_0) ) { + pMemData->command = command; // Send command + ReleaseMutex(hSMMutex); + } + return; +} + +//////////////////////////////////////////////////////////////////////////////// +// Factory function that creates instances if the Tracker-settings dialog object. + +// Export both decorated and undecorated names. +// GetTrackerDialog - Undecorated name, which can be easily used with GetProcAddress +// Win32 API function. +// _GetTrackerDialog@0 - Common name decoration for __stdcall functions in C language. +#pragma comment(linker, "/export:GetTrackerDialog=_GetTrackerDialog@0") + +FTNOIR_TRACKER_BASE_EXPORT TRACKERDIALOGHANDLE __stdcall GetTrackerDialog( ) +{ + return new SMClientControls; +} diff --git a/faceAPI/main.cpp b/faceAPI/main.cpp index 6d02b355..403340a5 100644 --- a/faceAPI/main.cpp +++ b/faceAPI/main.cpp @@ -23,6 +23,7 @@ *********************************************************************************/ /* Modifications (last one on top): + 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. @@ -372,20 +373,27 @@ void run() sprintf_s(msg, "Command: %d\n", pMemData->command); OutputDebugStringA(msg); if (pMemData) { + + // + // + // Determine the trackers' state and send it to FaceTrackNoIR. + // + THROW_ON_ERROR(smEngineGetState(engine_handle, &state)); + pMemData->state = state; + + // + // 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. // - THROW_ON_ERROR(smEngineGetState(engine_handle, &state)); if (state != SM_API_ENGINE_STATE_HT_TRACKING) { THROW_ON_ERROR(smEngineStart(engine_handle)); // Start tracking } pMemData->command = 0; // Reset - - THROW_ON_ERROR(smEngineShowCameraControlPanel(engine_handle)); - break; case FT_SM_STOP: @@ -399,6 +407,11 @@ void run() 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 @@ -505,6 +518,7 @@ bool SMCreateMapping() 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; // pMemData->handle = handle; // The game uses the handle, to send a message that the Program-Name was set! } hSMMutex = CreateMutexA(NULL, false, SM_MUTEX); -- cgit v1.2.3