summaryrefslogtreecommitdiffhomepage
path: root/facetracknoir
diff options
context:
space:
mode:
Diffstat (limited to 'facetracknoir')
-rw-r--r--facetracknoir/facetracknoir.cpp3126
-rw-r--r--facetracknoir/facetracknoir.h588
-rw-r--r--facetracknoir/main.cpp114
-rw-r--r--facetracknoir/rotation.h128
-rw-r--r--facetracknoir/tracker.cpp436
-rw-r--r--facetracknoir/tracker.h290
-rw-r--r--facetracknoir/tracker_types.cpp88
-rw-r--r--facetracknoir/tracker_types.h82
8 files changed, 2426 insertions, 2426 deletions
diff --git a/facetracknoir/facetracknoir.cpp b/facetracknoir/facetracknoir.cpp
index f3ec8fce..fe8ce36b 100644
--- a/facetracknoir/facetracknoir.cpp
+++ b/facetracknoir/facetracknoir.cpp
@@ -1,1563 +1,1563 @@
-/********************************************************************************
-* 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) 2011 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/>. *
-*********************************************************************************/
-#include "facetracknoir.h"
-#include "tracker.h"
-#include <ftnoir_tracker_ht/ht-api.h>
-#include <QDebug>
-
-#if defined(__WIN32) || defined(_WIN32)
-# include <windows.h>
-#endif
-
-#if defined(__APPLE__)
-# define SONAME "dylib"
-#elif defined(_WIN32) || defined(__WIN32)
-# define SONAME "dll"
-#else
-# define SONAME "so"
-#endif
-
-#include <iostream>
-
-#if defined(__WIN32) || defined(_WIN32)
-#undef DIRECTINPUT_VERSION
-#define DIRECTINPUT_VERSION 0x0800
-#include <dshow.h>
-#include <dinput.h>
-
-KeybindingWorkerDummy::~KeybindingWorkerDummy() {
- if (dinkeyboard) {
- dinkeyboard->Unacquire();
- dinkeyboard->Release();
- }
- if (din)
- din->Release();
-}
-
-KeybindingWorkerDummy::KeybindingWorkerDummy(FaceTrackNoIR& w, Key keyCenter)
-: kCenter(keyCenter), window(w), should_quit(true), din(0), dinkeyboard(0)
-{
- if (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&din, NULL) != DI_OK) {
- qDebug() << "setup DirectInput8 Creation failed!" << GetLastError();
- return;
- }
- if (din->CreateDevice(GUID_SysKeyboard, &dinkeyboard, NULL) != DI_OK) {
- din->Release();
- din = 0;
- qDebug() << "setup CreateDevice function failed!" << GetLastError();
- return;
- }
- if (dinkeyboard->SetDataFormat(&c_dfDIKeyboard) != DI_OK) {
- qDebug() << "setup SetDataFormat function failed!" << GetLastError();
- dinkeyboard->Release();
- dinkeyboard = 0;
- din->Release();
- din = 0;
- return;
- }
-
- if (dinkeyboard->SetCooperativeLevel(window.winId(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK) {
- dinkeyboard->Release();
- din->Release();
- din = 0;
- dinkeyboard = 0;
- qDebug() << "setup SetCooperativeLevel function failed!" << GetLastError();
- return;
- }
- if (dinkeyboard->Acquire() != DI_OK)
- {
- dinkeyboard->Release();
- din->Release();
- din = 0;
- dinkeyboard = 0;
- qDebug() << "setup dinkeyboard Acquire failed!" << GetLastError();
- return;
- }
- should_quit = false;
-}
-
-#define PROCESS_KEY(k, s) \
- if (isKeyPressed(&k, keystate) && (!k.ever_pressed ? (k.timer.start(), k.ever_pressed = true) : k.timer.restart() > 100)) \
- window.s();
-
-static bool isKeyPressed( const Key *key, const BYTE *keystate ) {
- bool shift;
- bool ctrl;
- bool alt;
-
- if (keystate[key->keycode] & 0x80) {
- shift = ( (keystate[DIK_LSHIFT] & 0x80) || (keystate[DIK_RSHIFT] & 0x80) );
- ctrl = ( (keystate[DIK_LCONTROL] & 0x80) || (keystate[DIK_RCONTROL] & 0x80) );
- alt = ( (keystate[DIK_LALT] & 0x80) || (keystate[DIK_RALT] & 0x80) );
-
- //
- // If one of the modifiers is needed and not pressed, return false.
- //
- if (key->shift && !shift) return false;
- if (key->ctrl && !ctrl) return false;
- if (key->alt && !alt) return false;
-
- //
- // All is well!
- //
- return true;
- }
- return false;
-}
-
-void KeybindingWorkerDummy::run() {
- BYTE keystate[256];
- while (!should_quit)
- {
- if (dinkeyboard->GetDeviceState(256, (LPVOID)keystate) != DI_OK) {
- qDebug() << "Tracker::run GetDeviceState function failed!" << GetLastError();
- Sleep(25);
- continue;
- }
-
- PROCESS_KEY(kCenter, shortcutRecentered);
-
- Sleep(25);
- }
-}
-#else
-#endif
-
-#ifdef _MSC_VER
-# define LIB_PREFIX ""
-#else
-# define LIB_PREFIX "lib"
-#endif
-
-//
-// Setup the Main Dialog
-//
-FaceTrackNoIR::FaceTrackNoIR(QWidget *parent, Qt::WFlags flags) :
- #if defined(__WIN32) || defined(_WIN32)
- keybindingWorker(NULL),
- #else
- keyCenter(0),
- #endif
- QMainWindow(parent, flags),
- pTrackerDialog(NULL),
- pSecondTrackerDialog(NULL),
- pProtocolDialog(NULL),
- pFilterDialog(NULL),
- looping(false),
- timUpdateHeadPose(this)
-{
- ui.setupUi(this);
- cameraDetected = false;
-
- //
- // Initialize Widget handles, to prevent memory-access errors.
- //
- _keyboard_shortcuts = 0;
- _curve_config = 0;
-
- tracker = 0;
-
- setupFaceTrackNoIR();
-
- //Q_INIT_RESOURCE(PoseWidget);
-
- ui.lblX->setVisible(false);
- ui.lblY->setVisible(false);
- ui.lblZ->setVisible(false);
- ui.lblRotX->setVisible(false);
- ui.lblRotY->setVisible(false);
- ui.lblRotZ->setVisible(false);
-
- ui.lcdNumOutputPosX->setVisible(false);
- ui.lcdNumOutputPosY->setVisible(false);
- ui.lcdNumOutputPosZ->setVisible(false);
- ui.lcdNumOutputRotX->setVisible(false);
- ui.lcdNumOutputRotY->setVisible(false);
- ui.lcdNumOutputRotZ->setVisible(false);
-}
-
-/** sets up all objects and connections to buttons */
-void FaceTrackNoIR::setupFaceTrackNoIR() {
- // if we simply place a global variable with THeadPoseData,
- // it gets initialized and pulls in QSettings before
- // main() starts. program can and will crash.
-
- ui.headPoseWidget->show();
- ui.video_frame->hide();
-
- // menu objects will be connected with the functions in FaceTrackNoIR class
- connect(ui.btnLoad, SIGNAL(clicked()), this, SLOT(open()));
- connect(ui.btnSave, SIGNAL(clicked()), this, SLOT(save()));
- connect(ui.btnSaveAs, SIGNAL(clicked()), this, SLOT(saveAs()));
-
- connect(ui.btnEditCurves, SIGNAL(clicked()), this, SLOT(showCurveConfiguration()));
- connect(ui.btnShortcuts, SIGNAL(clicked()), this, SLOT(showKeyboardShortcuts()));
- connect(ui.btnShowEngineControls, SIGNAL(clicked()), this, SLOT(showTrackerSettings()));
- connect(ui.btnShowSecondTrackerSettings, SIGNAL(clicked()), this, SLOT(showSecondTrackerSettings()));
- connect(ui.btnShowServerControls, SIGNAL(clicked()), this, SLOT(showServerControls()));
- connect(ui.btnShowFilterControls, SIGNAL(clicked()), this, SLOT(showFilterControls()));
-
- // Connect checkboxes
- connect(ui.chkInvertYaw, SIGNAL(stateChanged(int)), this, SLOT(setInvertYaw(int)));
- connect(ui.chkInvertRoll, SIGNAL(stateChanged(int)), this, SLOT(setInvertRoll(int)));
- connect(ui.chkInvertPitch, SIGNAL(stateChanged(int)), this, SLOT(setInvertPitch(int)));
- connect(ui.chkInvertX, SIGNAL(stateChanged(int)), this, SLOT(setInvertX(int)));
- connect(ui.chkInvertY, SIGNAL(stateChanged(int)), this, SLOT(setInvertY(int)));
- connect(ui.chkInvertZ, SIGNAL(stateChanged(int)), this, SLOT(setInvertZ(int)));
-
- // button methods connect with methods in this class
- connect(ui.btnStartTracker, SIGNAL(clicked()), this, SLOT(startTracker()));
- connect(ui.btnStopTracker, SIGNAL(clicked()), this, SLOT(stopTracker()));
-
- //read the camera-name, using DirectShow
- GetCameraNameDX();
-
- //Create the system-tray and connect the events for that.
- createIconGroupBox();
-
- //Load the tracker-settings, from the INI-file
- loadSettings();
-
- connect(ui.iconcomboProtocol, SIGNAL(currentIndexChanged(int)), this, SLOT(protocolSelected(int)));
- connect(ui.iconcomboProfile, SIGNAL(currentIndexChanged(int)), this, SLOT(profileSelected(int)));
- connect(ui.iconcomboTrackerSource, SIGNAL(currentIndexChanged(int)), this, SLOT(trackingSourceSelected(int)));
- connect(ui.iconcomboFilter, SIGNAL(currentIndexChanged(int)), this, SLOT(filterSelected(int)));
-
- //Setup the timer for showing the headpose.
- connect(&timUpdateHeadPose, SIGNAL(timeout()), this, SLOT(showHeadPose()));
- settingsDirty = false;
-}
-
-/** destructor stops the engine and quits the faceapi **/
-FaceTrackNoIR::~FaceTrackNoIR() {
-
- //
- // Stop the tracker, by simulating a button-push
- //
- stopTracker();
- save();
-}
-
-//
-// Update the Settings, after a value has changed. This way, the Tracker does not have to re-start.
-//
-void FaceTrackNoIR::updateSettings() {
- if ( tracker != NULL ) {
- tracker->loadSettings();
- }
-}
-
-//
-// Get a pointer to the video-widget, to use in the DLL
-//
-QFrame *FaceTrackNoIR::get_video_widget() {
- return ui.video_frame;
-}
-
-/** read the name of the first video-capturing device at start up **/
-/** FaceAPI can only use this first one... **/
-void FaceTrackNoIR::GetCameraNameDX() {
-#if defined(_WIN32)
- ui.cameraName->setText("No video-capturing device was found in your system: check if it's connected!");
-
- // Create the System Device Enumerator.
- HRESULT hr;
- ICreateDevEnum *pSysDevEnum = NULL;
- hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum);
- if (FAILED(hr))
- {
- qDebug() << "GetWDM says: CoCreateInstance Failed!";
- return;
- }
-
- qDebug() << "GetWDM says: CoCreateInstance succeeded!";
-
- // Obtain a class enumerator for the video compressor category.
- IEnumMoniker *pEnumCat = NULL;
- hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
-
- if (hr == S_OK) {
- qDebug() << "GetWDM says: CreateClassEnumerator succeeded!";
-
- // Enumerate the monikers.
- IMoniker *pMoniker = NULL;
- ULONG cFetched;
- if (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) {
- IPropertyBag *pPropBag;
- hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
- if (SUCCEEDED(hr)) {
- // To retrieve the filter's friendly name, do the following:
- VARIANT varName;
- VariantInit(&varName);
- hr = pPropBag->Read(L"FriendlyName", &varName, 0);
- if (SUCCEEDED(hr))
- {
- // Display the name in your UI somehow.
- QString str((QChar*)varName.bstrVal, wcslen(varName.bstrVal));
- qDebug() << "GetWDM says: Moniker found:" << str;
- ui.cameraName->setText(str);
- }
- VariantClear(&varName);
-
- ////// To create an instance of the filter, do the following:
- ////IBaseFilter *pFilter;
- ////hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter,
- //// (void**)&pFilter);
- // Now add the filter to the graph.
- //Remember to release pFilter later.
- pPropBag->Release();
- }
- pMoniker->Release();
- }
- pEnumCat->Release();
- }
- pSysDevEnum->Release();
-#endif
-}
-
-//
-// Open an INI-file with the QFileDialog
-// If succesfull, the settings in it will be read
-//
-void FaceTrackNoIR::open() {
- QFileDialog dialog(this);
- dialog.setFileMode(QFileDialog::ExistingFile);
-
- QString fileName = dialog.getOpenFileName(
- this,
- tr("Select one FTNoir settings file"),
- QCoreApplication::applicationDirPath() + "/Settings/",
- tr("Settings file (*.ini);;All Files (*)"),
- NULL);
-
- //
- // If a file was selected, save it's name and read it's contents.
- //
- if (! fileName.isEmpty() ) {
- QSettings settings("opentrack"); // Registry settings (in HK_USER)
- settings.setValue ("SettingsFile", QFileInfo(fileName).absoluteFilePath());
- loadSettings();
- }
-}
-
-//
-// Save the current Settings to the currently 'active' INI-file.
-//
-void FaceTrackNoIR::save() {
-
- QSettings settings("opentrack"); // 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 ( "Tracking" );
- iniFile.setValue ( "invertYaw", ui.chkInvertYaw->isChecked() );
- iniFile.setValue ( "invertPitch", ui.chkInvertPitch->isChecked() );
- iniFile.setValue ( "invertRoll", ui.chkInvertRoll->isChecked() );
- iniFile.setValue ( "invertX", ui.chkInvertX->isChecked() );
- iniFile.setValue ( "invertY", ui.chkInvertY->isChecked() );
- iniFile.setValue ( "invertZ", ui.chkInvertZ->isChecked() );
- iniFile.endGroup ();
-
- iniFile.beginGroup ( "GameProtocol" );
- {
- DynamicLibrary* proto = dlopen_protocols.value( ui.iconcomboProtocol->currentIndex(), (DynamicLibrary*) NULL);
- iniFile.setValue ( "DLL", proto == NULL ? "" : proto->filename);
- }
- iniFile.endGroup ();
-
- iniFile.beginGroup ( "TrackerSource" );
- {
- DynamicLibrary* tracker = dlopen_trackers.value( ui.iconcomboTrackerSource->currentIndex(), (DynamicLibrary*) NULL);
- iniFile.setValue ( "DLL", tracker == NULL ? "" : tracker->filename);
- }
- {
- DynamicLibrary* tracker = dlopen_trackers.value( ui.cbxSecondTrackerSource->currentIndex() - 1, (DynamicLibrary*) NULL);
- iniFile.setValue ( "2ndDLL", tracker == NULL ? "" : tracker->filename);
- }
- iniFile.endGroup ();
-
- //
- // Save the name of the filter in the INI-file.
- //
- iniFile.beginGroup ( "Filter" );
- {
- DynamicLibrary* filter = dlopen_filters.value( ui.iconcomboFilter->currentIndex(), (DynamicLibrary*) NULL);
- iniFile.setValue ( "DLL", filter == NULL ? "" : filter->filename);
- }
- iniFile.endGroup ();
-
- settingsDirty = false;
-}
-
-//
-// Get the new name of the INI-file and save the settings to it.
-//
-// The user may choose to overwrite an existing file. This will be deleted, before copying the current file to it.
-//
-void FaceTrackNoIR::saveAs()
-{
- //
- // Get the current filename of the INI-file.
- //
- QSettings settings("opentrack"); // Registry settings (in HK_USER)
- QString oldFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
-
- //
- // Get the new filename of the INI-file.
- //
- QString fileName = QFileDialog::getSaveFileName(this, tr("Save file"),
- oldFile,
-// QCoreApplication::applicationDirPath() + "/Settings",
- tr("Settings file (*.ini);;All Files (*)"));
- if (!fileName.isEmpty()) {
-
- //
- // Remove the file, if it already exists.
- //
- QFileInfo newFileInfo ( fileName );
- if ((newFileInfo.exists()) && (oldFile != fileName)) {
- QFile newFileFile ( fileName );
- newFileFile.remove();
- }
-
- //
- // Copy the current INI-file to the new name.
- //
- QFileInfo oldFileInfo ( oldFile );
- if (oldFileInfo.exists()) {
- QFile oldFileFile ( oldFile );
- oldFileFile.copy( fileName );
- }
-
- //
- // Write the new name to the Registry and save the other INI-values.
- //
- settings.setValue ("SettingsFile", fileName);
- save();
-
- //
- // Reload the settings, to get the GUI right again...
- //
- loadSettings();
- }
-}
-
-//
-// Load the current Settings from the currently 'active' INI-file.
-//
-void FaceTrackNoIR::loadSettings() {
- looping = true;
- qDebug() << "loadSettings says: Starting ";
- QSettings settings("opentrack"); // Registry settings (in HK_USER)
-
- QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
- qDebug() << "Config file now" << currentFile;
- QSettings iniFile( currentFile, QSettings::IniFormat ); // Application settings (in INI-file)
-
- //
- // Put the filename in the window-title.
- //
- QFileInfo pathInfo ( currentFile );
- setWindowTitle ( "opentrack (1.8 alpha) - " + pathInfo.fileName() );
-
- //
- // Get a List of all the INI-files in the (currently active) Settings-folder.
- //
- QDir settingsDir( pathInfo.dir() );
- QStringList filters;
- filters << "*.ini";
- iniFileList.clear();
- iniFileList = settingsDir.entryList( filters, QDir::Files, QDir::Name );
-
- //
- // Add strings to the Listbox.
- //
- ui.iconcomboProfile->clear();
- for ( int i = 0; i < iniFileList.size(); i++) {
- ui.iconcomboProfile->addItem(QIcon(":/images/settings16.png"), iniFileList.at(i));
- if (iniFileList.at(i) == pathInfo.fileName()) {
- ui.iconcomboProfile->setItemIcon(i, QIcon(":/images/settingsopen16.png"));
- ui.iconcomboProfile->setCurrentIndex( i );
- }
- }
-
- qDebug() << "loadSettings says: iniFile = " << currentFile;
-
- iniFile.beginGroup ( "Tracking" );
- ui.chkInvertYaw->setChecked (iniFile.value ( "invertYaw", 0 ).toBool());
- ui.chkInvertPitch->setChecked (iniFile.value ( "invertPitch", 0 ).toBool());
- ui.chkInvertRoll->setChecked (iniFile.value ( "invertRoll", 0 ).toBool());
- ui.chkInvertX->setChecked (iniFile.value ( "invertX", 0 ).toBool());
- ui.chkInvertY->setChecked (iniFile.value ( "invertY", 0 ).toBool());
- ui.chkInvertZ->setChecked (iniFile.value ( "invertZ", 0 ).toBool());
- iniFile.endGroup ();
-
- // Read the currently selected Protocol from the INI-file.
- // If the setting "DLL" isn't found (pre-1.7 version of INI), then the setting 'Selection' is evaluated.
- //
- iniFile.beginGroup ( "GameProtocol" );
- QString selectedProtocolName = iniFile.value ( "DLL", "" ).toString();
- iniFile.endGroup ();
-
- //
- // Find the Index of the DLL and set the selection.
- //
- for ( int i = 0; i < dlopen_protocols.size(); i++) {
- if (dlopen_protocols.at(i)->filename.compare( selectedProtocolName, Qt::CaseInsensitive ) == 0) {
- ui.iconcomboProtocol->setCurrentIndex( i );
- break;
- }
- }
-
- //
- // Read the currently selected Tracker from the INI-file.
- // If the setting "DLL" isn't found (pre-1.7 version), then the setting 'Selection' is evaluated.
- //
- iniFile.beginGroup ( "TrackerSource" );
- QString selectedTrackerName = iniFile.value ( "DLL", "" ).toString();
- qDebug() << "loadSettings says: selectedTrackerName = " << selectedTrackerName;
- QString secondTrackerName = iniFile.value ( "2ndDLL", "None" ).toString();
- qDebug() << "loadSettings says: secondTrackerName = " << secondTrackerName;
- iniFile.endGroup ();
-
- for ( int i = 0; i < dlopen_trackers.size(); i++) {
- DynamicLibrary* foo = dlopen_trackers.at(i);
- if (foo && foo->filename.compare( selectedTrackerName, Qt::CaseInsensitive ) == 0) {
- ui.iconcomboTrackerSource->setCurrentIndex( i );
- }
- if (foo && foo->filename.compare( secondTrackerName, Qt::CaseInsensitive ) == 0) {
- ui.cbxSecondTrackerSource->setCurrentIndex( i + 1 );
- }
- }
-
- //
- // Read the currently selected Filter from the INI-file.
- //
- iniFile.beginGroup ( "Filter" );
- QString selectedFilterName = iniFile.value ( "DLL", "" ).toString();
- qDebug() << "createIconGroupBox says: selectedFilterName = " << selectedFilterName;
- iniFile.endGroup ();
-
- //
- // Find the Index of the DLL and set the selection.
- //
- for ( int i = 0; i < dlopen_filters.size(); i++) {
- DynamicLibrary* foo = dlopen_filters.at(i);
- if (foo && foo->filename.compare( selectedFilterName, Qt::CaseInsensitive ) == 0) {
- ui.iconcomboFilter->setCurrentIndex( i );
- break;
- }
- }
-
- settingsDirty = false;
- looping = false;
-}
-
-/** start tracking the face **/
-void FaceTrackNoIR::startTracker( ) {
- bindKeyboardShortcuts();
-
- //
- // Disable buttons
- //
- ui.iconcomboProfile->setEnabled ( false );
- ui.btnLoad->setEnabled ( false );
- ui.btnSave->setEnabled ( false );
- ui.btnSaveAs->setEnabled ( false );
- ui.btnShowFilterControls->setEnabled ( true );
-
- //
- // Create the Tracker and setup
- //
-
- if (Libraries)
- delete Libraries;
- Libraries = new SelectedLibraries(this);
-
- if (!Libraries->correct)
- {
- QMessageBox::warning(this, "Something went wrong", "Tracking can't be initialized, probably protocol prerequisites missing", QMessageBox::Ok, QMessageBox::NoButton);
- stopTracker();
- return;
- }
-
-#if defined(_WIN32) || defined(__WIN32)
- keybindingWorker = new KeybindingWorker(*this, keyCenter);
- keybindingWorker->start();
-#endif
-
- if (tracker) {
- tracker->wait();
- delete tracker;
- }
-
- QSettings settings("opentrack"); // 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)
-
- for (int i = 0; i < 6; i++)
- {
- axis(i).curve.loadSettings(iniFile);
- axis(i).curveAlt.loadSettings(iniFile);
- }
-
- static const char* names[] = {
- "tx_alt",
- "ty_alt",
- "tz_alt",
- "rx_alt",
- "ry_alt",
- "rz_alt",
- };
-
- static const char* invert_names[] = {
- "invertX",
- "invertY",
- "invertZ",
- "invertYaw",
- "invertPitch",
- "invertRoll"
- };
-
- iniFile.beginGroup("Tracking");
-
- for (int i = 0; i < 6; i++) {
- axis(i).altp = iniFile.value(names[i], false).toBool();
- axis(i).invert = iniFile.value(invert_names[i], false).toBool() ? 1 : -1;
- }
-
- iniFile.endGroup();
-
- tracker = new Tracker ( this );
-
- //
- // Setup the Tracker and send the settings.
- // This is necessary, because the events are only triggered 'on change'
- //
- tracker->setInvertAxis(Yaw, ui.chkInvertYaw->isChecked() );
- tracker->setInvertAxis(Pitch, ui.chkInvertPitch->isChecked() );
- tracker->setInvertAxis(Roll, ui.chkInvertRoll->isChecked() );
- tracker->setInvertAxis(TX, ui.chkInvertX->isChecked() );
- tracker->setInvertAxis(TY, ui.chkInvertY->isChecked() );
- tracker->setInvertAxis(TZ, ui.chkInvertZ->isChecked() );
-
- //
- // Register the Tracker instance with the Tracker Dialog (if open)
- //
- if (pTrackerDialog && Libraries->pTracker) {
- pTrackerDialog->registerTracker( Libraries->pTracker );
- }
-
- if (pFilterDialog && Libraries->pFilter)
- pFilterDialog->registerFilter(Libraries->pFilter);
-
- tracker->start();
-
- ui.headPoseWidget->show();
-
- //
- ui.btnStartTracker->setEnabled ( false );
- ui.btnStopTracker->setEnabled ( true );
-
- // Enable/disable Protocol-server Settings
- ui.iconcomboTrackerSource->setEnabled ( false );
- ui.cbxSecondTrackerSource->setEnabled ( false );
- ui.iconcomboProtocol->setEnabled ( false );
- ui.btnShowServerControls->setEnabled ( false );
- ui.iconcomboFilter->setEnabled ( false );
-
- //
- // Update the camera-name, FaceAPI can only use the 1st one found!
- //
- GetCameraNameDX();
-
- //
- // Start the timer to update the head-pose (digits and 'man in black')
- //
- timUpdateHeadPose.start(40);
-
- ui.lblX->setVisible(true);
- ui.lblY->setVisible(true);
- ui.lblZ->setVisible(true);
- ui.lblRotX->setVisible(true);
- ui.lblRotY->setVisible(true);
- ui.lblRotZ->setVisible(true);
-
- ui.lcdNumOutputPosX->setVisible(true);
- ui.lcdNumOutputPosY->setVisible(true);
- ui.lcdNumOutputPosZ->setVisible(true);
- ui.lcdNumOutputRotX->setVisible(true);
- ui.lcdNumOutputRotY->setVisible(true);
- ui.lcdNumOutputRotZ->setVisible(true);
-}
-
-/** stop tracking the face **/
-void FaceTrackNoIR::stopTracker( ) {
- ui.game_name->setText("Not connected");
-#if defined(_WIN32) || defined(__WIN32)
- if (keybindingWorker)
- {
- keybindingWorker->should_quit = true;
- keybindingWorker->wait();
- delete keybindingWorker;
- keybindingWorker = NULL;
- }
-#endif
- //
- // Stop displaying the head-pose.
- //
- timUpdateHeadPose.stop();
- ui.pose_display->rotateBy(0, 0, 0);
-
- ui.lblX->setVisible(false);
- ui.lblY->setVisible(false);
- ui.lblZ->setVisible(false);
- ui.lblRotX->setVisible(false);
- ui.lblRotY->setVisible(false);
- ui.lblRotZ->setVisible(false);
-
- ui.lcdNumOutputPosX->setVisible(false);
- ui.lcdNumOutputPosY->setVisible(false);
- ui.lcdNumOutputPosZ->setVisible(false);
- ui.lcdNumOutputRotX->setVisible(false);
- ui.lcdNumOutputRotY->setVisible(false);
- ui.lcdNumOutputRotZ->setVisible(false);
-
- //
- // UnRegister the Tracker instance with the Tracker Dialog (if open)
- //
- if (pTrackerDialog) {
- pTrackerDialog->unRegisterTracker();
- }
- if (pProtocolDialog) {
- pProtocolDialog->unRegisterProtocol();
- }
- if (pFilterDialog)
- pFilterDialog->unregisterFilter();
-
- //
- // Delete the tracker (after stopping things and all).
- //
- if ( tracker ) {
- qDebug() << "Done with tracking";
- tracker->should_quit = true;
- tracker->wait();
-
- qDebug() << "stopTracker says: Deleting tracker!";
- delete tracker;
- qDebug() << "stopTracker says: Tracker deleted!";
- tracker = 0;
- if (Libraries) {
- delete Libraries;
- Libraries = NULL;
- }
- }
- ui.btnStartTracker->setEnabled ( true );
- ui.btnStopTracker->setEnabled ( false );
-// ui.btnShowEngineControls->setEnabled ( false );
- ui.iconcomboProtocol->setEnabled ( true );
- ui.iconcomboTrackerSource->setEnabled ( true );
- ui.cbxSecondTrackerSource->setEnabled ( true );
- ui.iconcomboFilter->setEnabled ( true );
-
- // Enable/disable Protocol-server Settings
- ui.btnShowServerControls->setEnabled ( true );
- ui.video_frame->hide();
-
- //
- ui.iconcomboProfile->setEnabled ( true );
- ui.btnLoad->setEnabled ( true );
- ui.btnSave->setEnabled ( true );
- ui.btnSaveAs->setEnabled ( true );
- ui.btnShowFilterControls->setEnabled ( true );
-}
-
-/** set the invert from the checkbox **/
-void FaceTrackNoIR::setInvertAxis(Axis axis, int invert ) {
- if (tracker)
- tracker->setInvertAxis (axis, (invert != 0)?true:false );
- settingsDirty = true;
-}
-
-/** Show the headpose in the widget (triggered by timer) **/
-void FaceTrackNoIR::showHeadPose() {
- double newdata[6];
-
- ui.lblX->setVisible(true);
- ui.lblY->setVisible(true);
- ui.lblZ->setVisible(true);
- ui.lblRotX->setVisible(true);
- ui.lblRotY->setVisible(true);
- ui.lblRotZ->setVisible(true);
-
- ui.lcdNumOutputPosX->setVisible(true);
- ui.lcdNumOutputPosY->setVisible(true);
- ui.lcdNumOutputPosZ->setVisible(true);
- ui.lcdNumOutputRotX->setVisible(true);
- ui.lcdNumOutputRotY->setVisible(true);
- ui.lcdNumOutputRotZ->setVisible(true);
-
- //
- // Get the pose and also display it.
- // Updating the pose from within the Tracker-class caused crashes...
- //
- tracker->getHeadPose(newdata);
- ui.lcdNumX->display(QString("%1").arg(newdata[TX], 0, 'f', 1));
- ui.lcdNumY->display(QString("%1").arg(newdata[TY], 0, 'f', 1));
- ui.lcdNumZ->display(QString("%1").arg(newdata[TZ], 0, 'f', 1));
-
-
- ui.lcdNumRotX->display(QString("%1").arg(newdata[Yaw], 0, 'f', 1));
- ui.lcdNumRotY->display(QString("%1").arg(newdata[Pitch], 0, 'f', 1));
- ui.lcdNumRotZ->display(QString("%1").arg(newdata[Roll], 0, 'f', 1));
-
- //
- // Get the output-pose and also display it.
- //
- tracker->getOutputHeadPose(newdata);
-
- ui.pose_display->rotateBy(newdata[Yaw], newdata[Roll], newdata[Pitch]);
-
- ui.lcdNumOutputPosX->display(QString("%1").arg(newdata[TX], 0, 'f', 1));
- ui.lcdNumOutputPosY->display(QString("%1").arg(newdata[TY], 0, 'f', 1));
- ui.lcdNumOutputPosZ->display(QString("%1").arg(newdata[TZ], 0, 'f', 1));
-
-
- ui.lcdNumOutputRotX->display(QString("%1").arg(newdata[Yaw], 0, 'f', 1));
- ui.lcdNumOutputRotY->display(QString("%1").arg(newdata[Pitch], 0, 'f', 1));
- ui.lcdNumOutputRotZ->display(QString("%1").arg(newdata[Roll], 0, 'f', 1));
-
- //
- // Update the curves in the curve-configurator. This shows the ball with the red lines.
- //
- if (_curve_config) {
- _curve_config->update();
- }
- if (Libraries->pProtocol)
- {
- QString name = Libraries->pProtocol->getGameName();
- ui.game_name->setText(name);
- }
-}
-
-/** toggles Video Widget **/
-void FaceTrackNoIR::showVideoWidget() {
- if(ui.video_frame->isHidden())
- ui.video_frame->show();
- else
- ui.video_frame->hide();
-}
-
-/** toggles Video Widget **/
-void FaceTrackNoIR::showHeadPoseWidget() {
- if(ui.headPoseWidget->isHidden())
- ui.headPoseWidget->show();
- else
- ui.headPoseWidget->hide();
-}
-
-/** toggles Engine Controls Dialog **/
-void FaceTrackNoIR::showTrackerSettings() {
- if (pTrackerDialog) {
- delete pTrackerDialog;
- pTrackerDialog = NULL;
- }
-
- DynamicLibrary* lib = dlopen_trackers.value(ui.iconcomboTrackerSource->currentIndex(), (DynamicLibrary*) NULL);
-
- if (lib) {
- pTrackerDialog = (ITrackerDialog*) lib->Dialog();
- if (pTrackerDialog) {
- if (Libraries && Libraries->pTracker)
- pTrackerDialog->registerTracker(Libraries->pTracker);
- pTrackerDialog->Initialize(this);
- }
- }
-}
-
-// Show the Settings dialog for the secondary Tracker
-void FaceTrackNoIR::showSecondTrackerSettings() {
- if (pSecondTrackerDialog) {
- delete pSecondTrackerDialog;
- pSecondTrackerDialog = NULL;
- }
-
- DynamicLibrary* lib = dlopen_trackers.value(ui.cbxSecondTrackerSource->currentIndex() - 1, (DynamicLibrary*) NULL);
-
- if (lib) {
- pSecondTrackerDialog = (ITrackerDialog*) lib->Dialog();
- if (pSecondTrackerDialog) {
- if (Libraries && Libraries->pSecondTracker)
- pSecondTrackerDialog->registerTracker(Libraries->pSecondTracker);
- pSecondTrackerDialog->Initialize(this);
- }
- }
-}
-
-/** toggles Server Controls Dialog **/
-void FaceTrackNoIR::showServerControls() {
- if (pProtocolDialog) {
- delete pProtocolDialog;
- pProtocolDialog = NULL;
- }
-
- DynamicLibrary* lib = dlopen_protocols.value(ui.iconcomboProtocol->currentIndex(), (DynamicLibrary*) NULL);
-
- if (lib && lib->Dialog) {
- pProtocolDialog = (IProtocolDialog*) lib->Dialog();
- if (pProtocolDialog) {
- pProtocolDialog->Initialize(this);
- }
- }
-}
-
-/** toggles Filter Controls Dialog **/
-void FaceTrackNoIR::showFilterControls() {
- if (pFilterDialog) {
- delete pFilterDialog;
- pFilterDialog = NULL;
- }
-
- DynamicLibrary* lib = dlopen_filters.value(ui.iconcomboFilter->currentIndex(), (DynamicLibrary*) NULL);
-
- if (lib && lib->Dialog) {
- pFilterDialog = (IFilterDialog*) lib->Dialog();
- if (pFilterDialog) {
- pFilterDialog->Initialize(this);
- if (Libraries && Libraries->pFilter)
- pFilterDialog->registerFilter(Libraries->pFilter);
- }
- }
-}
-/** toggles Keyboard Shortcut Dialog **/
-void FaceTrackNoIR::showKeyboardShortcuts() {
-
- // Create if new
- if (!_keyboard_shortcuts)
- {
- _keyboard_shortcuts = new KeyboardShortcutDialog( this, this, Qt::Dialog );
- }
-
- // Show if already created
- if (_keyboard_shortcuts) {
- _keyboard_shortcuts->show();
- _keyboard_shortcuts->raise();
- }
-}
-
-/** toggles Curve Configuration Dialog **/
-void FaceTrackNoIR::showCurveConfiguration() {
-
- // Create if new
- if (!_curve_config)
- {
- _curve_config = new CurveConfigurationDialog( this, this, Qt::Dialog );
- }
-
- // Show if already created
- if (_curve_config) {
- _curve_config->show();
- _curve_config->raise();
- }
-}
-
-/** exit application **/
-void FaceTrackNoIR::exit() {
- QCoreApplication::exit(0);
-}
-
-static bool get_metadata(DynamicLibrary* lib, QString& longName, QIcon& icon)
-{
- Metadata* meta;
- if (!lib->Metadata || ((meta = lib->Metadata()), !meta))
- {
- delete lib;
- return false;
- }
- meta->getFullName(&longName);
- meta->getIcon(&icon);
- delete meta;
- return true;
-}
-
-static void fill_combobox(const QString& filter, QList<DynamicLibrary*>& list, QComboBox* cbx, QComboBox* cbx2)
-{
- QDir settingsDir( QCoreApplication::applicationDirPath() );
- QStringList filenames = settingsDir.entryList( QStringList() << (LIB_PREFIX + filter + SONAME), QDir::Files, QDir::Name );
- for ( int i = 0; i < filenames.size(); i++) {
- QIcon icon;
- QString longName;
- QString str = filenames.at(i);
- DynamicLibrary* lib = new DynamicLibrary(str);
- qDebug() << "Loading" << str;
- std::cout.flush();
- if (!get_metadata(lib, longName, icon))
- {
- delete lib;
- continue;
- }
- list.push_back(lib);
- cbx->addItem(icon, longName);
- if (cbx2)
- cbx2->addItem(icon, longName);
- }
-}
-
-//
-// Setup the icons for the comboBoxes
-//
-void FaceTrackNoIR::createIconGroupBox()
-{
- ui.cbxSecondTrackerSource->addItem(QIcon(), "None");
- dlopen_filters.push_back((DynamicLibrary*) NULL);
- ui.iconcomboFilter->addItem(QIcon(), "None");
-
- fill_combobox("opentrack-proto-*.", dlopen_protocols, ui.iconcomboProtocol, NULL);
- fill_combobox("opentrack-tracker-*.", dlopen_trackers, ui.iconcomboTrackerSource, ui.cbxSecondTrackerSource);
- fill_combobox("opentrack-filter-*.", dlopen_filters, ui.iconcomboFilter, NULL);
-
- connect(ui.iconcomboProtocol, SIGNAL(currentIndexChanged(int)), this, SLOT(protocolSelected(int)));
- connect(ui.iconcomboTrackerSource, SIGNAL(currentIndexChanged(int)), this, SLOT(trackingSourceSelected(int)));
- connect(ui.iconcomboFilter, SIGNAL(currentIndexChanged(int)), this, SLOT(filterSelected(int)));
- connect(ui.cbxSecondTrackerSource, SIGNAL(currentIndexChanged(int)), this, SLOT(trackingSourceSelected(int)));
-}
-
-//
-// Handle changes of the Protocol selection
-//
-void FaceTrackNoIR::protocolSelected(int index)
-{
- settingsDirty = true;
- ui.btnShowServerControls->setEnabled ( true );
-
- //setWindowIcon(QIcon(":/images/FaceTrackNoIR.png"));
- //breaks with transparency -sh
- //ui.btnShowServerControls->setIcon(icon);]
-}
-
-//
-// Handle changes of the Tracking Source selection
-//
-void FaceTrackNoIR::trackingSourceSelected(int index)
-{
- settingsDirty = true;
- ui.btnShowEngineControls->setEnabled ( true );
-}
-
-//
-// Handle changes of the Profile selection
-//
-void FaceTrackNoIR::profileSelected(int index)
-{
- if (looping)
- return;
- //
- // Read the current INI-file setting, to get the folder in which it's located...
- //
- QSettings settings("opentrack"); // Registry settings (in HK_USER)
- QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
- QFileInfo pathInfo ( currentFile );
-
- //
- // Save the name of the INI-file in the Registry.
- //
- settings.setValue ("SettingsFile", pathInfo.absolutePath() + "/" + iniFileList.value(ui.iconcomboProfile->currentIndex(), ""));
- loadSettings();
-}
-
-//
-// Handle changes of the Filter selection
-//
-void FaceTrackNoIR::filterSelected(int index)
-{
- settingsDirty = true;
-
- //QSettings settings("opentrack"); // 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)
-
- ui.btnShowFilterControls->setEnabled ( true );
-}
-
-//**************************************************************************************************//
-//**************************************************************************************************//
-//
-// Constructor for Keyboard-shortcuts-dialog
-//
-KeyboardShortcutDialog::KeyboardShortcutDialog( FaceTrackNoIR *ftnoir, QWidget *parent, Qt::WindowFlags f ) :
-QWidget( parent , f)
-{
- ui.setupUi( this );
-
- QPoint offsetpos(100, 100);
- this->move(parent->pos() + offsetpos);
-
- mainApp = ftnoir; // Preserve a pointer to FTNoIR
-
- // Connect Qt signals to member-functions
- connect(ui.btnOK, SIGNAL(clicked()), this, SLOT(doOK()));
- connect(ui.btnCancel, SIGNAL(clicked()), this, SLOT(doCancel()));
-
- // Clear the Lists with key-descriptions and keycodes and build the Lists
- // The strings will all be added to the ListBoxes for each Shortkey
- //
-
- // Add strings to the Listboxes.
- //
-
- for ( int i = 0; i < global_key_sequences.size(); i++) {
- ui.cbxCenterKey->addItem(global_key_sequences.at(i));
- }
-
- // Load the settings from the current .INI-file
- loadSettings();
-}
-
-//
-// Destructor for server-dialog
-//
-KeyboardShortcutDialog::~KeyboardShortcutDialog() {
- qDebug() << "~KeyboardShortcutDialog() says: started";
-}
-
-//
-// OK clicked on server-dialog
-//
-void KeyboardShortcutDialog::doOK() {
- save();
- this->close();
- mainApp->bindKeyboardShortcuts();
-}
-
-// override show event
-void KeyboardShortcutDialog::showEvent ( QShowEvent * event ) {
- loadSettings();
-}
-
-//
-// Cancel clicked on server-dialog
-//
-void KeyboardShortcutDialog::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();
- }
-}
-
-void FaceTrackNoIR::bindKeyboardShortcuts()
-{
- QSettings settings("opentrack"); // 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 ( "KB_Shortcuts" );
- int idxCenter = iniFile.value("Key_index_Center", 0).toInt();
-
-#if !defined(_WIN32) && !defined(__WIN32)
- if (keyCenter) {
- delete keyCenter;
- keyCenter = NULL;
- }
-
- if (idxCenter > 0)
- {
- QString seq(global_key_sequences.value(idxCenter, ""));
- if (!seq.isEmpty())
- {
- if (iniFile.value("Shift_Center", false).toBool())
- seq = "Shift+" + seq;
- if (iniFile.value("Alt_Center", false).toBool())
- seq = "Alt+" + seq;
- if (iniFile.value("Ctrl_Center", false).toBool())
- seq = "Ctrl+" + seq;
- keyCenter = new QxtGlobalShortcut(QKeySequence(seq));
- connect(keyCenter, SIGNAL(activated()), this, SLOT(shortcutRecentered()));
- }
- }
-
-#else
- keyCenter.keycode = 0;
- keyCenter.shift = keyCenter.alt = keyCenter.ctrl = 0;
- if (idxCenter > 0 && idxCenter < global_windows_key_sequences.size())
- keyCenter.keycode = global_windows_key_sequences[idxCenter];
- keyCenter.shift = iniFile.value("Shift_Center", false).toBool();
- keyCenter.alt = iniFile.value("Alt_Center", false).toBool();
- keyCenter.ctrl = iniFile.value("Ctrl_Center", false).toBool();
-#endif
- iniFile.endGroup ();
-
- if (tracker) /* running already */
- {
-#if defined(_WIN32) || defined(__WIN32)
- if (keybindingWorker)
- {
- keybindingWorker->should_quit = true;
- keybindingWorker->wait();
- delete keybindingWorker;
- keybindingWorker = NULL;
- }
- keybindingWorker = new KeybindingWorker(*this, keyCenter);
- keybindingWorker->start();
-#endif
- }
-}
-
-//
-// Load the current Settings from the currently 'active' INI-file.
-//
-void KeyboardShortcutDialog::loadSettings() {
- qDebug() << "loadSettings says: Starting ";
- QSettings settings("opentrack"); // 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 ( "KB_Shortcuts" );
-
- ui.chkCenterShift->setChecked (iniFile.value ( "Shift_Center", 0 ).toBool());
- ui.chkCenterCtrl->setChecked (iniFile.value ( "Ctrl_Center", 0 ).toBool());
- ui.chkCenterAlt->setChecked (iniFile.value ( "Alt_Center", 0 ).toBool());
-
- ui.cbxCenterKey->setCurrentIndex(iniFile.value("Key_index_Center", 0).toInt());
-
- iniFile.endGroup ();
-
- settingsDirty = false;
-
-}
-
-//
-// Save the current Settings to the currently 'active' INI-file.
-//
-void KeyboardShortcutDialog::save() {
-
- qDebug() << "save() says: started";
-
- QSettings settings("opentrack"); // 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 ( "KB_Shortcuts" );
- iniFile.setValue ( "Key_index_Center", ui.cbxCenterKey->currentIndex() );
- iniFile.setValue ( "Shift_Center", ui.chkCenterShift->isChecked() );
- iniFile.setValue ( "Ctrl_Center", ui.chkCenterCtrl->isChecked() );
- iniFile.setValue ( "Alt_Center", ui.chkCenterAlt->isChecked() );
-
- iniFile.endGroup ();
-
- settingsDirty = false;
-
- //
- // Send a message to the main program, to update the Settings (for the tracker)
- //
- mainApp->updateSettings();
-}
-
-//**************************************************************************************************//
-//**************************************************************************************************//
-//
-// Constructor for Curve-configuration-dialog
-//
-CurveConfigurationDialog::CurveConfigurationDialog( FaceTrackNoIR *ftnoir, QWidget *parent, Qt::WindowFlags f ) :
-QWidget( parent , f)
-{
- ui.setupUi( this );
-
- QPoint offsetpos(120, 30);
- this->move(parent->pos() + offsetpos);
-
- mainApp = ftnoir; // Preserve a pointer to FTNoIR
-
- QSettings settings("opentrack"); // Registry settings (in HK_USER)
- QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
-
- QFunctionConfigurator* configs[6] = {
- ui.txconfig,
- ui.tyconfig,
- ui.tzconfig,
- ui.rxconfig,
- ui.ryconfig,
- ui.rzconfig
- };
-
- QFunctionConfigurator* alt_configs[6] = {
- ui.txconfig_alt,
- ui.tyconfig_alt,
- ui.tzconfig_alt,
- ui.rxconfig_alt,
- ui.ryconfig_alt,
- ui.rzconfig_alt
- };
-
- QCheckBox* checkboxes[6] = {
- ui.rx_altp,
- ui.ry_altp,
- ui.rz_altp,
- ui.tx_altp,
- ui.ty_altp,
- ui.tz_altp
- };
-
- for (int i = 0; i < 6; i++)
- {
- configs[i]->setConfig(&mainApp->axis(i).curve, currentFile);
- alt_configs[i]->setConfig(&mainApp->axis(i).curveAlt, currentFile);
- connect(configs[i], SIGNAL(CurveChanged(bool)), this, SLOT(curveChanged(bool)));
- connect(alt_configs[i], SIGNAL(CurveChanged(bool)), this, SLOT(curveChanged(bool)));
- connect(checkboxes[i], SIGNAL(stateChanged(int)), this, SLOT(curveChanged(int)));
- }
-
- // Connect Qt signals to member-functions
- connect(ui.btnOK, SIGNAL(clicked()), this, SLOT(doOK()));
- connect(ui.btnCancel, SIGNAL(clicked()), this, SLOT(doCancel()));
-
- // Load the settings from the current .INI-file
- loadSettings();
-}
-
-//
-// Destructor for server-dialog
-//
-CurveConfigurationDialog::~CurveConfigurationDialog() {
- qDebug() << "~CurveConfigurationDialog() says: started";
-}
-
-//
-// OK clicked on server-dialog
-//
-void CurveConfigurationDialog::doOK() {
- save();
- this->close();
-}
-
-// override show event
-void CurveConfigurationDialog::showEvent ( QShowEvent * event ) {
- loadSettings();
-}
-
-//
-// Cancel clicked on server-dialog
-//
-void CurveConfigurationDialog::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 CurveConfigurationDialog::loadSettings() {
- qDebug() << "loadSettings says: Starting ";
- QSettings settings("opentrack"); // 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;
-
- static const char* names[] = {
- "tx_alt",
- "ty_alt",
- "tz_alt",
- "rx_alt",
- "ry_alt",
- "rz_alt"
- };
-
- iniFile.beginGroup("Tracking");
-
- for (int i = 0; i < 6; i++)
- mainApp->axis(i).altp = iniFile.value(names[i], false).toBool();
-
- QCheckBox* widgets[] = {
- ui.tx_altp,
- ui.ty_altp,
- ui.tz_altp,
- ui.rx_altp,
- ui.ry_altp,
- ui.rz_altp
- };
-
- for (int i = 0; i < 6; i++)
- widgets[i]->setChecked(mainApp->axis(i).altp);
-
- QDoubleSpinBox* widgets2[] = {
- ui.pos_tx,
- ui.pos_ty,
- ui.pos_tz,
- ui.pos_tx,
- ui.pos_ry,
- ui.pos_rz
- };
-
- const char* names2[] = {
- "zero_tx",
- "zero_ty",
- "zero_tz",
- "zero_rx",
- "zero_ry",
- "zero_rz"
- };
-
- for (int i = 0; i < 6; i++)
- widgets2[i]->setValue(iniFile.value(names2[i], 0).toDouble());
-
- iniFile.endGroup();
-
- settingsDirty = false;
-}
-
-//
-// Save the current Settings to the currently 'active' INI-file.
-//
-void CurveConfigurationDialog::save() {
-
- qDebug() << "save() says: started";
-
- QSettings settings("opentrack"); // Registry settings (in HK_USER)
-
- QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
-
- ui.rxconfig->saveSettings(currentFile);
- ui.ryconfig->saveSettings(currentFile);
- ui.rzconfig->saveSettings(currentFile);
- ui.txconfig->saveSettings(currentFile);
- ui.tyconfig->saveSettings(currentFile);
- ui.tzconfig->saveSettings(currentFile);
-
- ui.txconfig_alt->saveSettings(currentFile);
- ui.tyconfig_alt->saveSettings(currentFile);
- ui.tzconfig_alt->saveSettings(currentFile);
- ui.rxconfig_alt->saveSettings(currentFile);
- ui.ryconfig_alt->saveSettings(currentFile);
- ui.rzconfig_alt->saveSettings(currentFile);
-
- QSettings iniFile( currentFile, QSettings::IniFormat ); // Application settings (in INI-file)
-
- iniFile.beginGroup("Tracking");
-
- iniFile.setValue("rx_alt", ui.rx_altp->checkState() != Qt::Unchecked);
- iniFile.setValue("ry_alt", ui.ry_altp->checkState() != Qt::Unchecked);
- iniFile.setValue("rz_alt", ui.rz_altp->checkState() != Qt::Unchecked);
- iniFile.setValue("tx_alt", ui.tx_altp->checkState() != Qt::Unchecked);
- iniFile.setValue("ty_alt", ui.ty_altp->checkState() != Qt::Unchecked);
- iniFile.setValue("tz_alt", ui.tz_altp->checkState() != Qt::Unchecked);
-
- QDoubleSpinBox* widgets2[] = {
- ui.pos_tx,
- ui.pos_ty,
- ui.pos_tz,
- ui.pos_tx,
- ui.pos_ry,
- ui.pos_rz
- };
-
- const char* names2[] = {
- "zero_tx",
- "zero_ty",
- "zero_tz",
- "zero_rx",
- "zero_ry",
- "zero_rz"
- };
-
- for (int i = 0; i < 6; i++)
- iniFile.setValue(names2[i], widgets2[i]->value());
-
- iniFile.endGroup();
-
- settingsDirty = false;
-
- //
- // Send a message to the main program, to update the Settings (for the tracker)
- //
- mainApp->updateSettings();
-}
-
-void FaceTrackNoIR::shortcutRecentered()
-{
- if (tracker)
- {
-#if defined(__WIN32) || defined(_WIN32)
- MessageBeep(MB_OK);
-#else
- QApplication::beep();
-#endif
- qDebug() << "Center";
- tracker->do_center = true;
- }
-}
+/********************************************************************************
+* 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) 2011 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/>. *
+*********************************************************************************/
+#include "facetracknoir.h"
+#include "tracker.h"
+#include <ftnoir_tracker_ht/ht-api.h>
+#include <QDebug>
+
+#if defined(__WIN32) || defined(_WIN32)
+# include <windows.h>
+#endif
+
+#if defined(__APPLE__)
+# define SONAME "dylib"
+#elif defined(_WIN32) || defined(__WIN32)
+# define SONAME "dll"
+#else
+# define SONAME "so"
+#endif
+
+#include <iostream>
+
+#if defined(__WIN32) || defined(_WIN32)
+#undef DIRECTINPUT_VERSION
+#define DIRECTINPUT_VERSION 0x0800
+#include <dshow.h>
+#include <dinput.h>
+
+KeybindingWorkerDummy::~KeybindingWorkerDummy() {
+ if (dinkeyboard) {
+ dinkeyboard->Unacquire();
+ dinkeyboard->Release();
+ }
+ if (din)
+ din->Release();
+}
+
+KeybindingWorkerDummy::KeybindingWorkerDummy(FaceTrackNoIR& w, Key keyCenter)
+: kCenter(keyCenter), window(w), should_quit(true), din(0), dinkeyboard(0)
+{
+ if (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&din, NULL) != DI_OK) {
+ qDebug() << "setup DirectInput8 Creation failed!" << GetLastError();
+ return;
+ }
+ if (din->CreateDevice(GUID_SysKeyboard, &dinkeyboard, NULL) != DI_OK) {
+ din->Release();
+ din = 0;
+ qDebug() << "setup CreateDevice function failed!" << GetLastError();
+ return;
+ }
+ if (dinkeyboard->SetDataFormat(&c_dfDIKeyboard) != DI_OK) {
+ qDebug() << "setup SetDataFormat function failed!" << GetLastError();
+ dinkeyboard->Release();
+ dinkeyboard = 0;
+ din->Release();
+ din = 0;
+ return;
+ }
+
+ if (dinkeyboard->SetCooperativeLevel(window.winId(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK) {
+ dinkeyboard->Release();
+ din->Release();
+ din = 0;
+ dinkeyboard = 0;
+ qDebug() << "setup SetCooperativeLevel function failed!" << GetLastError();
+ return;
+ }
+ if (dinkeyboard->Acquire() != DI_OK)
+ {
+ dinkeyboard->Release();
+ din->Release();
+ din = 0;
+ dinkeyboard = 0;
+ qDebug() << "setup dinkeyboard Acquire failed!" << GetLastError();
+ return;
+ }
+ should_quit = false;
+}
+
+#define PROCESS_KEY(k, s) \
+ if (isKeyPressed(&k, keystate) && (!k.ever_pressed ? (k.timer.start(), k.ever_pressed = true) : k.timer.restart() > 100)) \
+ window.s();
+
+static bool isKeyPressed( const Key *key, const BYTE *keystate ) {
+ bool shift;
+ bool ctrl;
+ bool alt;
+
+ if (keystate[key->keycode] & 0x80) {
+ shift = ( (keystate[DIK_LSHIFT] & 0x80) || (keystate[DIK_RSHIFT] & 0x80) );
+ ctrl = ( (keystate[DIK_LCONTROL] & 0x80) || (keystate[DIK_RCONTROL] & 0x80) );
+ alt = ( (keystate[DIK_LALT] & 0x80) || (keystate[DIK_RALT] & 0x80) );
+
+ //
+ // If one of the modifiers is needed and not pressed, return false.
+ //
+ if (key->shift && !shift) return false;
+ if (key->ctrl && !ctrl) return false;
+ if (key->alt && !alt) return false;
+
+ //
+ // All is well!
+ //
+ return true;
+ }
+ return false;
+}
+
+void KeybindingWorkerDummy::run() {
+ BYTE keystate[256];
+ while (!should_quit)
+ {
+ if (dinkeyboard->GetDeviceState(256, (LPVOID)keystate) != DI_OK) {
+ qDebug() << "Tracker::run GetDeviceState function failed!" << GetLastError();
+ Sleep(25);
+ continue;
+ }
+
+ PROCESS_KEY(kCenter, shortcutRecentered);
+
+ Sleep(25);
+ }
+}
+#else
+#endif
+
+#ifdef _MSC_VER
+# define LIB_PREFIX ""
+#else
+# define LIB_PREFIX "lib"
+#endif
+
+//
+// Setup the Main Dialog
+//
+FaceTrackNoIR::FaceTrackNoIR(QWidget *parent, Qt::WFlags flags) :
+ #if defined(__WIN32) || defined(_WIN32)
+ keybindingWorker(NULL),
+ #else
+ keyCenter(0),
+ #endif
+ QMainWindow(parent, flags),
+ pTrackerDialog(NULL),
+ pSecondTrackerDialog(NULL),
+ pProtocolDialog(NULL),
+ pFilterDialog(NULL),
+ looping(false),
+ timUpdateHeadPose(this)
+{
+ ui.setupUi(this);
+ cameraDetected = false;
+
+ //
+ // Initialize Widget handles, to prevent memory-access errors.
+ //
+ _keyboard_shortcuts = 0;
+ _curve_config = 0;
+
+ tracker = 0;
+
+ setupFaceTrackNoIR();
+
+ //Q_INIT_RESOURCE(PoseWidget);
+
+ ui.lblX->setVisible(false);
+ ui.lblY->setVisible(false);
+ ui.lblZ->setVisible(false);
+ ui.lblRotX->setVisible(false);
+ ui.lblRotY->setVisible(false);
+ ui.lblRotZ->setVisible(false);
+
+ ui.lcdNumOutputPosX->setVisible(false);
+ ui.lcdNumOutputPosY->setVisible(false);
+ ui.lcdNumOutputPosZ->setVisible(false);
+ ui.lcdNumOutputRotX->setVisible(false);
+ ui.lcdNumOutputRotY->setVisible(false);
+ ui.lcdNumOutputRotZ->setVisible(false);
+}
+
+/** sets up all objects and connections to buttons */
+void FaceTrackNoIR::setupFaceTrackNoIR() {
+ // if we simply place a global variable with THeadPoseData,
+ // it gets initialized and pulls in QSettings before
+ // main() starts. program can and will crash.
+
+ ui.headPoseWidget->show();
+ ui.video_frame->hide();
+
+ // menu objects will be connected with the functions in FaceTrackNoIR class
+ connect(ui.btnLoad, SIGNAL(clicked()), this, SLOT(open()));
+ connect(ui.btnSave, SIGNAL(clicked()), this, SLOT(save()));
+ connect(ui.btnSaveAs, SIGNAL(clicked()), this, SLOT(saveAs()));
+
+ connect(ui.btnEditCurves, SIGNAL(clicked()), this, SLOT(showCurveConfiguration()));
+ connect(ui.btnShortcuts, SIGNAL(clicked()), this, SLOT(showKeyboardShortcuts()));
+ connect(ui.btnShowEngineControls, SIGNAL(clicked()), this, SLOT(showTrackerSettings()));
+ connect(ui.btnShowSecondTrackerSettings, SIGNAL(clicked()), this, SLOT(showSecondTrackerSettings()));
+ connect(ui.btnShowServerControls, SIGNAL(clicked()), this, SLOT(showServerControls()));
+ connect(ui.btnShowFilterControls, SIGNAL(clicked()), this, SLOT(showFilterControls()));
+
+ // Connect checkboxes
+ connect(ui.chkInvertYaw, SIGNAL(stateChanged(int)), this, SLOT(setInvertYaw(int)));
+ connect(ui.chkInvertRoll, SIGNAL(stateChanged(int)), this, SLOT(setInvertRoll(int)));
+ connect(ui.chkInvertPitch, SIGNAL(stateChanged(int)), this, SLOT(setInvertPitch(int)));
+ connect(ui.chkInvertX, SIGNAL(stateChanged(int)), this, SLOT(setInvertX(int)));
+ connect(ui.chkInvertY, SIGNAL(stateChanged(int)), this, SLOT(setInvertY(int)));
+ connect(ui.chkInvertZ, SIGNAL(stateChanged(int)), this, SLOT(setInvertZ(int)));
+
+ // button methods connect with methods in this class
+ connect(ui.btnStartTracker, SIGNAL(clicked()), this, SLOT(startTracker()));
+ connect(ui.btnStopTracker, SIGNAL(clicked()), this, SLOT(stopTracker()));
+
+ //read the camera-name, using DirectShow
+ GetCameraNameDX();
+
+ //Create the system-tray and connect the events for that.
+ createIconGroupBox();
+
+ //Load the tracker-settings, from the INI-file
+ loadSettings();
+
+ connect(ui.iconcomboProtocol, SIGNAL(currentIndexChanged(int)), this, SLOT(protocolSelected(int)));
+ connect(ui.iconcomboProfile, SIGNAL(currentIndexChanged(int)), this, SLOT(profileSelected(int)));
+ connect(ui.iconcomboTrackerSource, SIGNAL(currentIndexChanged(int)), this, SLOT(trackingSourceSelected(int)));
+ connect(ui.iconcomboFilter, SIGNAL(currentIndexChanged(int)), this, SLOT(filterSelected(int)));
+
+ //Setup the timer for showing the headpose.
+ connect(&timUpdateHeadPose, SIGNAL(timeout()), this, SLOT(showHeadPose()));
+ settingsDirty = false;
+}
+
+/** destructor stops the engine and quits the faceapi **/
+FaceTrackNoIR::~FaceTrackNoIR() {
+
+ //
+ // Stop the tracker, by simulating a button-push
+ //
+ stopTracker();
+ save();
+}
+
+//
+// Update the Settings, after a value has changed. This way, the Tracker does not have to re-start.
+//
+void FaceTrackNoIR::updateSettings() {
+ if ( tracker != NULL ) {
+ tracker->loadSettings();
+ }
+}
+
+//
+// Get a pointer to the video-widget, to use in the DLL
+//
+QFrame *FaceTrackNoIR::get_video_widget() {
+ return ui.video_frame;
+}
+
+/** read the name of the first video-capturing device at start up **/
+/** FaceAPI can only use this first one... **/
+void FaceTrackNoIR::GetCameraNameDX() {
+#if defined(_WIN32)
+ ui.cameraName->setText("No video-capturing device was found in your system: check if it's connected!");
+
+ // Create the System Device Enumerator.
+ HRESULT hr;
+ ICreateDevEnum *pSysDevEnum = NULL;
+ hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum);
+ if (FAILED(hr))
+ {
+ qDebug() << "GetWDM says: CoCreateInstance Failed!";
+ return;
+ }
+
+ qDebug() << "GetWDM says: CoCreateInstance succeeded!";
+
+ // Obtain a class enumerator for the video compressor category.
+ IEnumMoniker *pEnumCat = NULL;
+ hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
+
+ if (hr == S_OK) {
+ qDebug() << "GetWDM says: CreateClassEnumerator succeeded!";
+
+ // Enumerate the monikers.
+ IMoniker *pMoniker = NULL;
+ ULONG cFetched;
+ if (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) {
+ IPropertyBag *pPropBag;
+ hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
+ if (SUCCEEDED(hr)) {
+ // To retrieve the filter's friendly name, do the following:
+ VARIANT varName;
+ VariantInit(&varName);
+ hr = pPropBag->Read(L"FriendlyName", &varName, 0);
+ if (SUCCEEDED(hr))
+ {
+ // Display the name in your UI somehow.
+ QString str((QChar*)varName.bstrVal, wcslen(varName.bstrVal));
+ qDebug() << "GetWDM says: Moniker found:" << str;
+ ui.cameraName->setText(str);
+ }
+ VariantClear(&varName);
+
+ ////// To create an instance of the filter, do the following:
+ ////IBaseFilter *pFilter;
+ ////hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter,
+ //// (void**)&pFilter);
+ // Now add the filter to the graph.
+ //Remember to release pFilter later.
+ pPropBag->Release();
+ }
+ pMoniker->Release();
+ }
+ pEnumCat->Release();
+ }
+ pSysDevEnum->Release();
+#endif
+}
+
+//
+// Open an INI-file with the QFileDialog
+// If succesfull, the settings in it will be read
+//
+void FaceTrackNoIR::open() {
+ QFileDialog dialog(this);
+ dialog.setFileMode(QFileDialog::ExistingFile);
+
+ QString fileName = dialog.getOpenFileName(
+ this,
+ tr("Select one FTNoir settings file"),
+ QCoreApplication::applicationDirPath() + "/Settings/",
+ tr("Settings file (*.ini);;All Files (*)"),
+ NULL);
+
+ //
+ // If a file was selected, save it's name and read it's contents.
+ //
+ if (! fileName.isEmpty() ) {
+ QSettings settings("opentrack"); // Registry settings (in HK_USER)
+ settings.setValue ("SettingsFile", QFileInfo(fileName).absoluteFilePath());
+ loadSettings();
+ }
+}
+
+//
+// Save the current Settings to the currently 'active' INI-file.
+//
+void FaceTrackNoIR::save() {
+
+ QSettings settings("opentrack"); // 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 ( "Tracking" );
+ iniFile.setValue ( "invertYaw", ui.chkInvertYaw->isChecked() );
+ iniFile.setValue ( "invertPitch", ui.chkInvertPitch->isChecked() );
+ iniFile.setValue ( "invertRoll", ui.chkInvertRoll->isChecked() );
+ iniFile.setValue ( "invertX", ui.chkInvertX->isChecked() );
+ iniFile.setValue ( "invertY", ui.chkInvertY->isChecked() );
+ iniFile.setValue ( "invertZ", ui.chkInvertZ->isChecked() );
+ iniFile.endGroup ();
+
+ iniFile.beginGroup ( "GameProtocol" );
+ {
+ DynamicLibrary* proto = dlopen_protocols.value( ui.iconcomboProtocol->currentIndex(), (DynamicLibrary*) NULL);
+ iniFile.setValue ( "DLL", proto == NULL ? "" : proto->filename);
+ }
+ iniFile.endGroup ();
+
+ iniFile.beginGroup ( "TrackerSource" );
+ {
+ DynamicLibrary* tracker = dlopen_trackers.value( ui.iconcomboTrackerSource->currentIndex(), (DynamicLibrary*) NULL);
+ iniFile.setValue ( "DLL", tracker == NULL ? "" : tracker->filename);
+ }
+ {
+ DynamicLibrary* tracker = dlopen_trackers.value( ui.cbxSecondTrackerSource->currentIndex() - 1, (DynamicLibrary*) NULL);
+ iniFile.setValue ( "2ndDLL", tracker == NULL ? "" : tracker->filename);
+ }
+ iniFile.endGroup ();
+
+ //
+ // Save the name of the filter in the INI-file.
+ //
+ iniFile.beginGroup ( "Filter" );
+ {
+ DynamicLibrary* filter = dlopen_filters.value( ui.iconcomboFilter->currentIndex(), (DynamicLibrary*) NULL);
+ iniFile.setValue ( "DLL", filter == NULL ? "" : filter->filename);
+ }
+ iniFile.endGroup ();
+
+ settingsDirty = false;
+}
+
+//
+// Get the new name of the INI-file and save the settings to it.
+//
+// The user may choose to overwrite an existing file. This will be deleted, before copying the current file to it.
+//
+void FaceTrackNoIR::saveAs()
+{
+ //
+ // Get the current filename of the INI-file.
+ //
+ QSettings settings("opentrack"); // Registry settings (in HK_USER)
+ QString oldFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
+
+ //
+ // Get the new filename of the INI-file.
+ //
+ QString fileName = QFileDialog::getSaveFileName(this, tr("Save file"),
+ oldFile,
+// QCoreApplication::applicationDirPath() + "/Settings",
+ tr("Settings file (*.ini);;All Files (*)"));
+ if (!fileName.isEmpty()) {
+
+ //
+ // Remove the file, if it already exists.
+ //
+ QFileInfo newFileInfo ( fileName );
+ if ((newFileInfo.exists()) && (oldFile != fileName)) {
+ QFile newFileFile ( fileName );
+ newFileFile.remove();
+ }
+
+ //
+ // Copy the current INI-file to the new name.
+ //
+ QFileInfo oldFileInfo ( oldFile );
+ if (oldFileInfo.exists()) {
+ QFile oldFileFile ( oldFile );
+ oldFileFile.copy( fileName );
+ }
+
+ //
+ // Write the new name to the Registry and save the other INI-values.
+ //
+ settings.setValue ("SettingsFile", fileName);
+ save();
+
+ //
+ // Reload the settings, to get the GUI right again...
+ //
+ loadSettings();
+ }
+}
+
+//
+// Load the current Settings from the currently 'active' INI-file.
+//
+void FaceTrackNoIR::loadSettings() {
+ looping = true;
+ qDebug() << "loadSettings says: Starting ";
+ QSettings settings("opentrack"); // Registry settings (in HK_USER)
+
+ QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
+ qDebug() << "Config file now" << currentFile;
+ QSettings iniFile( currentFile, QSettings::IniFormat ); // Application settings (in INI-file)
+
+ //
+ // Put the filename in the window-title.
+ //
+ QFileInfo pathInfo ( currentFile );
+ setWindowTitle ( "opentrack (1.8 alpha) - " + pathInfo.fileName() );
+
+ //
+ // Get a List of all the INI-files in the (currently active) Settings-folder.
+ //
+ QDir settingsDir( pathInfo.dir() );
+ QStringList filters;
+ filters << "*.ini";
+ iniFileList.clear();
+ iniFileList = settingsDir.entryList( filters, QDir::Files, QDir::Name );
+
+ //
+ // Add strings to the Listbox.
+ //
+ ui.iconcomboProfile->clear();
+ for ( int i = 0; i < iniFileList.size(); i++) {
+ ui.iconcomboProfile->addItem(QIcon(":/images/settings16.png"), iniFileList.at(i));
+ if (iniFileList.at(i) == pathInfo.fileName()) {
+ ui.iconcomboProfile->setItemIcon(i, QIcon(":/images/settingsopen16.png"));
+ ui.iconcomboProfile->setCurrentIndex( i );
+ }
+ }
+
+ qDebug() << "loadSettings says: iniFile = " << currentFile;
+
+ iniFile.beginGroup ( "Tracking" );
+ ui.chkInvertYaw->setChecked (iniFile.value ( "invertYaw", 0 ).toBool());
+ ui.chkInvertPitch->setChecked (iniFile.value ( "invertPitch", 0 ).toBool());
+ ui.chkInvertRoll->setChecked (iniFile.value ( "invertRoll", 0 ).toBool());
+ ui.chkInvertX->setChecked (iniFile.value ( "invertX", 0 ).toBool());
+ ui.chkInvertY->setChecked (iniFile.value ( "invertY", 0 ).toBool());
+ ui.chkInvertZ->setChecked (iniFile.value ( "invertZ", 0 ).toBool());
+ iniFile.endGroup ();
+
+ // Read the currently selected Protocol from the INI-file.
+ // If the setting "DLL" isn't found (pre-1.7 version of INI), then the setting 'Selection' is evaluated.
+ //
+ iniFile.beginGroup ( "GameProtocol" );
+ QString selectedProtocolName = iniFile.value ( "DLL", "" ).toString();
+ iniFile.endGroup ();
+
+ //
+ // Find the Index of the DLL and set the selection.
+ //
+ for ( int i = 0; i < dlopen_protocols.size(); i++) {
+ if (dlopen_protocols.at(i)->filename.compare( selectedProtocolName, Qt::CaseInsensitive ) == 0) {
+ ui.iconcomboProtocol->setCurrentIndex( i );
+ break;
+ }
+ }
+
+ //
+ // Read the currently selected Tracker from the INI-file.
+ // If the setting "DLL" isn't found (pre-1.7 version), then the setting 'Selection' is evaluated.
+ //
+ iniFile.beginGroup ( "TrackerSource" );
+ QString selectedTrackerName = iniFile.value ( "DLL", "" ).toString();
+ qDebug() << "loadSettings says: selectedTrackerName = " << selectedTrackerName;
+ QString secondTrackerName = iniFile.value ( "2ndDLL", "None" ).toString();
+ qDebug() << "loadSettings says: secondTrackerName = " << secondTrackerName;
+ iniFile.endGroup ();
+
+ for ( int i = 0; i < dlopen_trackers.size(); i++) {
+ DynamicLibrary* foo = dlopen_trackers.at(i);
+ if (foo && foo->filename.compare( selectedTrackerName, Qt::CaseInsensitive ) == 0) {
+ ui.iconcomboTrackerSource->setCurrentIndex( i );
+ }
+ if (foo && foo->filename.compare( secondTrackerName, Qt::CaseInsensitive ) == 0) {
+ ui.cbxSecondTrackerSource->setCurrentIndex( i + 1 );
+ }
+ }
+
+ //
+ // Read the currently selected Filter from the INI-file.
+ //
+ iniFile.beginGroup ( "Filter" );
+ QString selectedFilterName = iniFile.value ( "DLL", "" ).toString();
+ qDebug() << "createIconGroupBox says: selectedFilterName = " << selectedFilterName;
+ iniFile.endGroup ();
+
+ //
+ // Find the Index of the DLL and set the selection.
+ //
+ for ( int i = 0; i < dlopen_filters.size(); i++) {
+ DynamicLibrary* foo = dlopen_filters.at(i);
+ if (foo && foo->filename.compare( selectedFilterName, Qt::CaseInsensitive ) == 0) {
+ ui.iconcomboFilter->setCurrentIndex( i );
+ break;
+ }
+ }
+
+ settingsDirty = false;
+ looping = false;
+}
+
+/** start tracking the face **/
+void FaceTrackNoIR::startTracker( ) {
+ bindKeyboardShortcuts();
+
+ //
+ // Disable buttons
+ //
+ ui.iconcomboProfile->setEnabled ( false );
+ ui.btnLoad->setEnabled ( false );
+ ui.btnSave->setEnabled ( false );
+ ui.btnSaveAs->setEnabled ( false );
+ ui.btnShowFilterControls->setEnabled ( true );
+
+ //
+ // Create the Tracker and setup
+ //
+
+ if (Libraries)
+ delete Libraries;
+ Libraries = new SelectedLibraries(this);
+
+ if (!Libraries->correct)
+ {
+ QMessageBox::warning(this, "Something went wrong", "Tracking can't be initialized, probably protocol prerequisites missing", QMessageBox::Ok, QMessageBox::NoButton);
+ stopTracker();
+ return;
+ }
+
+#if defined(_WIN32) || defined(__WIN32)
+ keybindingWorker = new KeybindingWorker(*this, keyCenter);
+ keybindingWorker->start();
+#endif
+
+ if (tracker) {
+ tracker->wait();
+ delete tracker;
+ }
+
+ QSettings settings("opentrack"); // 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)
+
+ for (int i = 0; i < 6; i++)
+ {
+ axis(i).curve.loadSettings(iniFile);
+ axis(i).curveAlt.loadSettings(iniFile);
+ }
+
+ static const char* names[] = {
+ "tx_alt",
+ "ty_alt",
+ "tz_alt",
+ "rx_alt",
+ "ry_alt",
+ "rz_alt",
+ };
+
+ static const char* invert_names[] = {
+ "invertX",
+ "invertY",
+ "invertZ",
+ "invertYaw",
+ "invertPitch",
+ "invertRoll"
+ };
+
+ iniFile.beginGroup("Tracking");
+
+ for (int i = 0; i < 6; i++) {
+ axis(i).altp = iniFile.value(names[i], false).toBool();
+ axis(i).invert = iniFile.value(invert_names[i], false).toBool() ? 1 : -1;
+ }
+
+ iniFile.endGroup();
+
+ tracker = new Tracker ( this );
+
+ //
+ // Setup the Tracker and send the settings.
+ // This is necessary, because the events are only triggered 'on change'
+ //
+ tracker->setInvertAxis(Yaw, ui.chkInvertYaw->isChecked() );
+ tracker->setInvertAxis(Pitch, ui.chkInvertPitch->isChecked() );
+ tracker->setInvertAxis(Roll, ui.chkInvertRoll->isChecked() );
+ tracker->setInvertAxis(TX, ui.chkInvertX->isChecked() );
+ tracker->setInvertAxis(TY, ui.chkInvertY->isChecked() );
+ tracker->setInvertAxis(TZ, ui.chkInvertZ->isChecked() );
+
+ //
+ // Register the Tracker instance with the Tracker Dialog (if open)
+ //
+ if (pTrackerDialog && Libraries->pTracker) {
+ pTrackerDialog->registerTracker( Libraries->pTracker );
+ }
+
+ if (pFilterDialog && Libraries->pFilter)
+ pFilterDialog->registerFilter(Libraries->pFilter);
+
+ tracker->start();
+
+ ui.headPoseWidget->show();
+
+ //
+ ui.btnStartTracker->setEnabled ( false );
+ ui.btnStopTracker->setEnabled ( true );
+
+ // Enable/disable Protocol-server Settings
+ ui.iconcomboTrackerSource->setEnabled ( false );
+ ui.cbxSecondTrackerSource->setEnabled ( false );
+ ui.iconcomboProtocol->setEnabled ( false );
+ ui.btnShowServerControls->setEnabled ( false );
+ ui.iconcomboFilter->setEnabled ( false );
+
+ //
+ // Update the camera-name, FaceAPI can only use the 1st one found!
+ //
+ GetCameraNameDX();
+
+ //
+ // Start the timer to update the head-pose (digits and 'man in black')
+ //
+ timUpdateHeadPose.start(40);
+
+ ui.lblX->setVisible(true);
+ ui.lblY->setVisible(true);
+ ui.lblZ->setVisible(true);
+ ui.lblRotX->setVisible(true);
+ ui.lblRotY->setVisible(true);
+ ui.lblRotZ->setVisible(true);
+
+ ui.lcdNumOutputPosX->setVisible(true);
+ ui.lcdNumOutputPosY->setVisible(true);
+ ui.lcdNumOutputPosZ->setVisible(true);
+ ui.lcdNumOutputRotX->setVisible(true);
+ ui.lcdNumOutputRotY->setVisible(true);
+ ui.lcdNumOutputRotZ->setVisible(true);
+}
+
+/** stop tracking the face **/
+void FaceTrackNoIR::stopTracker( ) {
+ ui.game_name->setText("Not connected");
+#if defined(_WIN32) || defined(__WIN32)
+ if (keybindingWorker)
+ {
+ keybindingWorker->should_quit = true;
+ keybindingWorker->wait();
+ delete keybindingWorker;
+ keybindingWorker = NULL;
+ }
+#endif
+ //
+ // Stop displaying the head-pose.
+ //
+ timUpdateHeadPose.stop();
+ ui.pose_display->rotateBy(0, 0, 0);
+
+ ui.lblX->setVisible(false);
+ ui.lblY->setVisible(false);
+ ui.lblZ->setVisible(false);
+ ui.lblRotX->setVisible(false);
+ ui.lblRotY->setVisible(false);
+ ui.lblRotZ->setVisible(false);
+
+ ui.lcdNumOutputPosX->setVisible(false);
+ ui.lcdNumOutputPosY->setVisible(false);
+ ui.lcdNumOutputPosZ->setVisible(false);
+ ui.lcdNumOutputRotX->setVisible(false);
+ ui.lcdNumOutputRotY->setVisible(false);
+ ui.lcdNumOutputRotZ->setVisible(false);
+
+ //
+ // UnRegister the Tracker instance with the Tracker Dialog (if open)
+ //
+ if (pTrackerDialog) {
+ pTrackerDialog->unRegisterTracker();
+ }
+ if (pProtocolDialog) {
+ pProtocolDialog->unRegisterProtocol();
+ }
+ if (pFilterDialog)
+ pFilterDialog->unregisterFilter();
+
+ //
+ // Delete the tracker (after stopping things and all).
+ //
+ if ( tracker ) {
+ qDebug() << "Done with tracking";
+ tracker->should_quit = true;
+ tracker->wait();
+
+ qDebug() << "stopTracker says: Deleting tracker!";
+ delete tracker;
+ qDebug() << "stopTracker says: Tracker deleted!";
+ tracker = 0;
+ if (Libraries) {
+ delete Libraries;
+ Libraries = NULL;
+ }
+ }
+ ui.btnStartTracker->setEnabled ( true );
+ ui.btnStopTracker->setEnabled ( false );
+// ui.btnShowEngineControls->setEnabled ( false );
+ ui.iconcomboProtocol->setEnabled ( true );
+ ui.iconcomboTrackerSource->setEnabled ( true );
+ ui.cbxSecondTrackerSource->setEnabled ( true );
+ ui.iconcomboFilter->setEnabled ( true );
+
+ // Enable/disable Protocol-server Settings
+ ui.btnShowServerControls->setEnabled ( true );
+ ui.video_frame->hide();
+
+ //
+ ui.iconcomboProfile->setEnabled ( true );
+ ui.btnLoad->setEnabled ( true );
+ ui.btnSave->setEnabled ( true );
+ ui.btnSaveAs->setEnabled ( true );
+ ui.btnShowFilterControls->setEnabled ( true );
+}
+
+/** set the invert from the checkbox **/
+void FaceTrackNoIR::setInvertAxis(Axis axis, int invert ) {
+ if (tracker)
+ tracker->setInvertAxis (axis, (invert != 0)?true:false );
+ settingsDirty = true;
+}
+
+/** Show the headpose in the widget (triggered by timer) **/
+void FaceTrackNoIR::showHeadPose() {
+ double newdata[6];
+
+ ui.lblX->setVisible(true);
+ ui.lblY->setVisible(true);
+ ui.lblZ->setVisible(true);
+ ui.lblRotX->setVisible(true);
+ ui.lblRotY->setVisible(true);
+ ui.lblRotZ->setVisible(true);
+
+ ui.lcdNumOutputPosX->setVisible(true);
+ ui.lcdNumOutputPosY->setVisible(true);
+ ui.lcdNumOutputPosZ->setVisible(true);
+ ui.lcdNumOutputRotX->setVisible(true);
+ ui.lcdNumOutputRotY->setVisible(true);
+ ui.lcdNumOutputRotZ->setVisible(true);
+
+ //
+ // Get the pose and also display it.
+ // Updating the pose from within the Tracker-class caused crashes...
+ //
+ tracker->getHeadPose(newdata);
+ ui.lcdNumX->display(QString("%1").arg(newdata[TX], 0, 'f', 1));
+ ui.lcdNumY->display(QString("%1").arg(newdata[TY], 0, 'f', 1));
+ ui.lcdNumZ->display(QString("%1").arg(newdata[TZ], 0, 'f', 1));
+
+
+ ui.lcdNumRotX->display(QString("%1").arg(newdata[Yaw], 0, 'f', 1));
+ ui.lcdNumRotY->display(QString("%1").arg(newdata[Pitch], 0, 'f', 1));
+ ui.lcdNumRotZ->display(QString("%1").arg(newdata[Roll], 0, 'f', 1));
+
+ //
+ // Get the output-pose and also display it.
+ //
+ tracker->getOutputHeadPose(newdata);
+
+ ui.pose_display->rotateBy(newdata[Yaw], newdata[Roll], newdata[Pitch]);
+
+ ui.lcdNumOutputPosX->display(QString("%1").arg(newdata[TX], 0, 'f', 1));
+ ui.lcdNumOutputPosY->display(QString("%1").arg(newdata[TY], 0, 'f', 1));
+ ui.lcdNumOutputPosZ->display(QString("%1").arg(newdata[TZ], 0, 'f', 1));
+
+
+ ui.lcdNumOutputRotX->display(QString("%1").arg(newdata[Yaw], 0, 'f', 1));
+ ui.lcdNumOutputRotY->display(QString("%1").arg(newdata[Pitch], 0, 'f', 1));
+ ui.lcdNumOutputRotZ->display(QString("%1").arg(newdata[Roll], 0, 'f', 1));
+
+ //
+ // Update the curves in the curve-configurator. This shows the ball with the red lines.
+ //
+ if (_curve_config) {
+ _curve_config->update();
+ }
+ if (Libraries->pProtocol)
+ {
+ QString name = Libraries->pProtocol->getGameName();
+ ui.game_name->setText(name);
+ }
+}
+
+/** toggles Video Widget **/
+void FaceTrackNoIR::showVideoWidget() {
+ if(ui.video_frame->isHidden())
+ ui.video_frame->show();
+ else
+ ui.video_frame->hide();
+}
+
+/** toggles Video Widget **/
+void FaceTrackNoIR::showHeadPoseWidget() {
+ if(ui.headPoseWidget->isHidden())
+ ui.headPoseWidget->show();
+ else
+ ui.headPoseWidget->hide();
+}
+
+/** toggles Engine Controls Dialog **/
+void FaceTrackNoIR::showTrackerSettings() {
+ if (pTrackerDialog) {
+ delete pTrackerDialog;
+ pTrackerDialog = NULL;
+ }
+
+ DynamicLibrary* lib = dlopen_trackers.value(ui.iconcomboTrackerSource->currentIndex(), (DynamicLibrary*) NULL);
+
+ if (lib) {
+ pTrackerDialog = (ITrackerDialog*) lib->Dialog();
+ if (pTrackerDialog) {
+ if (Libraries && Libraries->pTracker)
+ pTrackerDialog->registerTracker(Libraries->pTracker);
+ pTrackerDialog->Initialize(this);
+ }
+ }
+}
+
+// Show the Settings dialog for the secondary Tracker
+void FaceTrackNoIR::showSecondTrackerSettings() {
+ if (pSecondTrackerDialog) {
+ delete pSecondTrackerDialog;
+ pSecondTrackerDialog = NULL;
+ }
+
+ DynamicLibrary* lib = dlopen_trackers.value(ui.cbxSecondTrackerSource->currentIndex() - 1, (DynamicLibrary*) NULL);
+
+ if (lib) {
+ pSecondTrackerDialog = (ITrackerDialog*) lib->Dialog();
+ if (pSecondTrackerDialog) {
+ if (Libraries && Libraries->pSecondTracker)
+ pSecondTrackerDialog->registerTracker(Libraries->pSecondTracker);
+ pSecondTrackerDialog->Initialize(this);
+ }
+ }
+}
+
+/** toggles Server Controls Dialog **/
+void FaceTrackNoIR::showServerControls() {
+ if (pProtocolDialog) {
+ delete pProtocolDialog;
+ pProtocolDialog = NULL;
+ }
+
+ DynamicLibrary* lib = dlopen_protocols.value(ui.iconcomboProtocol->currentIndex(), (DynamicLibrary*) NULL);
+
+ if (lib && lib->Dialog) {
+ pProtocolDialog = (IProtocolDialog*) lib->Dialog();
+ if (pProtocolDialog) {
+ pProtocolDialog->Initialize(this);
+ }
+ }
+}
+
+/** toggles Filter Controls Dialog **/
+void FaceTrackNoIR::showFilterControls() {
+ if (pFilterDialog) {
+ delete pFilterDialog;
+ pFilterDialog = NULL;
+ }
+
+ DynamicLibrary* lib = dlopen_filters.value(ui.iconcomboFilter->currentIndex(), (DynamicLibrary*) NULL);
+
+ if (lib && lib->Dialog) {
+ pFilterDialog = (IFilterDialog*) lib->Dialog();
+ if (pFilterDialog) {
+ pFilterDialog->Initialize(this);
+ if (Libraries && Libraries->pFilter)
+ pFilterDialog->registerFilter(Libraries->pFilter);
+ }
+ }
+}
+/** toggles Keyboard Shortcut Dialog **/
+void FaceTrackNoIR::showKeyboardShortcuts() {
+
+ // Create if new
+ if (!_keyboard_shortcuts)
+ {
+ _keyboard_shortcuts = new KeyboardShortcutDialog( this, this, Qt::Dialog );
+ }
+
+ // Show if already created
+ if (_keyboard_shortcuts) {
+ _keyboard_shortcuts->show();
+ _keyboard_shortcuts->raise();
+ }
+}
+
+/** toggles Curve Configuration Dialog **/
+void FaceTrackNoIR::showCurveConfiguration() {
+
+ // Create if new
+ if (!_curve_config)
+ {
+ _curve_config = new CurveConfigurationDialog( this, this, Qt::Dialog );
+ }
+
+ // Show if already created
+ if (_curve_config) {
+ _curve_config->show();
+ _curve_config->raise();
+ }
+}
+
+/** exit application **/
+void FaceTrackNoIR::exit() {
+ QCoreApplication::exit(0);
+}
+
+static bool get_metadata(DynamicLibrary* lib, QString& longName, QIcon& icon)
+{
+ Metadata* meta;
+ if (!lib->Metadata || ((meta = lib->Metadata()), !meta))
+ {
+ delete lib;
+ return false;
+ }
+ meta->getFullName(&longName);
+ meta->getIcon(&icon);
+ delete meta;
+ return true;
+}
+
+static void fill_combobox(const QString& filter, QList<DynamicLibrary*>& list, QComboBox* cbx, QComboBox* cbx2)
+{
+ QDir settingsDir( QCoreApplication::applicationDirPath() );
+ QStringList filenames = settingsDir.entryList( QStringList() << (LIB_PREFIX + filter + SONAME), QDir::Files, QDir::Name );
+ for ( int i = 0; i < filenames.size(); i++) {
+ QIcon icon;
+ QString longName;
+ QString str = filenames.at(i);
+ DynamicLibrary* lib = new DynamicLibrary(str);
+ qDebug() << "Loading" << str;
+ std::cout.flush();
+ if (!get_metadata(lib, longName, icon))
+ {
+ delete lib;
+ continue;
+ }
+ list.push_back(lib);
+ cbx->addItem(icon, longName);
+ if (cbx2)
+ cbx2->addItem(icon, longName);
+ }
+}
+
+//
+// Setup the icons for the comboBoxes
+//
+void FaceTrackNoIR::createIconGroupBox()
+{
+ ui.cbxSecondTrackerSource->addItem(QIcon(), "None");
+ dlopen_filters.push_back((DynamicLibrary*) NULL);
+ ui.iconcomboFilter->addItem(QIcon(), "None");
+
+ fill_combobox("opentrack-proto-*.", dlopen_protocols, ui.iconcomboProtocol, NULL);
+ fill_combobox("opentrack-tracker-*.", dlopen_trackers, ui.iconcomboTrackerSource, ui.cbxSecondTrackerSource);
+ fill_combobox("opentrack-filter-*.", dlopen_filters, ui.iconcomboFilter, NULL);
+
+ connect(ui.iconcomboProtocol, SIGNAL(currentIndexChanged(int)), this, SLOT(protocolSelected(int)));
+ connect(ui.iconcomboTrackerSource, SIGNAL(currentIndexChanged(int)), this, SLOT(trackingSourceSelected(int)));
+ connect(ui.iconcomboFilter, SIGNAL(currentIndexChanged(int)), this, SLOT(filterSelected(int)));
+ connect(ui.cbxSecondTrackerSource, SIGNAL(currentIndexChanged(int)), this, SLOT(trackingSourceSelected(int)));
+}
+
+//
+// Handle changes of the Protocol selection
+//
+void FaceTrackNoIR::protocolSelected(int index)
+{
+ settingsDirty = true;
+ ui.btnShowServerControls->setEnabled ( true );
+
+ //setWindowIcon(QIcon(":/images/FaceTrackNoIR.png"));
+ //breaks with transparency -sh
+ //ui.btnShowServerControls->setIcon(icon);]
+}
+
+//
+// Handle changes of the Tracking Source selection
+//
+void FaceTrackNoIR::trackingSourceSelected(int index)
+{
+ settingsDirty = true;
+ ui.btnShowEngineControls->setEnabled ( true );
+}
+
+//
+// Handle changes of the Profile selection
+//
+void FaceTrackNoIR::profileSelected(int index)
+{
+ if (looping)
+ return;
+ //
+ // Read the current INI-file setting, to get the folder in which it's located...
+ //
+ QSettings settings("opentrack"); // Registry settings (in HK_USER)
+ QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
+ QFileInfo pathInfo ( currentFile );
+
+ //
+ // Save the name of the INI-file in the Registry.
+ //
+ settings.setValue ("SettingsFile", pathInfo.absolutePath() + "/" + iniFileList.value(ui.iconcomboProfile->currentIndex(), ""));
+ loadSettings();
+}
+
+//
+// Handle changes of the Filter selection
+//
+void FaceTrackNoIR::filterSelected(int index)
+{
+ settingsDirty = true;
+
+ //QSettings settings("opentrack"); // 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)
+
+ ui.btnShowFilterControls->setEnabled ( true );
+}
+
+//**************************************************************************************************//
+//**************************************************************************************************//
+//
+// Constructor for Keyboard-shortcuts-dialog
+//
+KeyboardShortcutDialog::KeyboardShortcutDialog( FaceTrackNoIR *ftnoir, QWidget *parent, Qt::WindowFlags f ) :
+QWidget( parent , f)
+{
+ ui.setupUi( this );
+
+ QPoint offsetpos(100, 100);
+ this->move(parent->pos() + offsetpos);
+
+ mainApp = ftnoir; // Preserve a pointer to FTNoIR
+
+ // Connect Qt signals to member-functions
+ connect(ui.btnOK, SIGNAL(clicked()), this, SLOT(doOK()));
+ connect(ui.btnCancel, SIGNAL(clicked()), this, SLOT(doCancel()));
+
+ // Clear the Lists with key-descriptions and keycodes and build the Lists
+ // The strings will all be added to the ListBoxes for each Shortkey
+ //
+
+ // Add strings to the Listboxes.
+ //
+
+ for ( int i = 0; i < global_key_sequences.size(); i++) {
+ ui.cbxCenterKey->addItem(global_key_sequences.at(i));
+ }
+
+ // Load the settings from the current .INI-file
+ loadSettings();
+}
+
+//
+// Destructor for server-dialog
+//
+KeyboardShortcutDialog::~KeyboardShortcutDialog() {
+ qDebug() << "~KeyboardShortcutDialog() says: started";
+}
+
+//
+// OK clicked on server-dialog
+//
+void KeyboardShortcutDialog::doOK() {
+ save();
+ this->close();
+ mainApp->bindKeyboardShortcuts();
+}
+
+// override show event
+void KeyboardShortcutDialog::showEvent ( QShowEvent * event ) {
+ loadSettings();
+}
+
+//
+// Cancel clicked on server-dialog
+//
+void KeyboardShortcutDialog::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();
+ }
+}
+
+void FaceTrackNoIR::bindKeyboardShortcuts()
+{
+ QSettings settings("opentrack"); // 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 ( "KB_Shortcuts" );
+ int idxCenter = iniFile.value("Key_index_Center", 0).toInt();
+
+#if !defined(_WIN32) && !defined(__WIN32)
+ if (keyCenter) {
+ delete keyCenter;
+ keyCenter = NULL;
+ }
+
+ if (idxCenter > 0)
+ {
+ QString seq(global_key_sequences.value(idxCenter, ""));
+ if (!seq.isEmpty())
+ {
+ if (iniFile.value("Shift_Center", false).toBool())
+ seq = "Shift+" + seq;
+ if (iniFile.value("Alt_Center", false).toBool())
+ seq = "Alt+" + seq;
+ if (iniFile.value("Ctrl_Center", false).toBool())
+ seq = "Ctrl+" + seq;
+ keyCenter = new QxtGlobalShortcut(QKeySequence(seq));
+ connect(keyCenter, SIGNAL(activated()), this, SLOT(shortcutRecentered()));
+ }
+ }
+
+#else
+ keyCenter.keycode = 0;
+ keyCenter.shift = keyCenter.alt = keyCenter.ctrl = 0;
+ if (idxCenter > 0 && idxCenter < global_windows_key_sequences.size())
+ keyCenter.keycode = global_windows_key_sequences[idxCenter];
+ keyCenter.shift = iniFile.value("Shift_Center", false).toBool();
+ keyCenter.alt = iniFile.value("Alt_Center", false).toBool();
+ keyCenter.ctrl = iniFile.value("Ctrl_Center", false).toBool();
+#endif
+ iniFile.endGroup ();
+
+ if (tracker) /* running already */
+ {
+#if defined(_WIN32) || defined(__WIN32)
+ if (keybindingWorker)
+ {
+ keybindingWorker->should_quit = true;
+ keybindingWorker->wait();
+ delete keybindingWorker;
+ keybindingWorker = NULL;
+ }
+ keybindingWorker = new KeybindingWorker(*this, keyCenter);
+ keybindingWorker->start();
+#endif
+ }
+}
+
+//
+// Load the current Settings from the currently 'active' INI-file.
+//
+void KeyboardShortcutDialog::loadSettings() {
+ qDebug() << "loadSettings says: Starting ";
+ QSettings settings("opentrack"); // 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 ( "KB_Shortcuts" );
+
+ ui.chkCenterShift->setChecked (iniFile.value ( "Shift_Center", 0 ).toBool());
+ ui.chkCenterCtrl->setChecked (iniFile.value ( "Ctrl_Center", 0 ).toBool());
+ ui.chkCenterAlt->setChecked (iniFile.value ( "Alt_Center", 0 ).toBool());
+
+ ui.cbxCenterKey->setCurrentIndex(iniFile.value("Key_index_Center", 0).toInt());
+
+ iniFile.endGroup ();
+
+ settingsDirty = false;
+
+}
+
+//
+// Save the current Settings to the currently 'active' INI-file.
+//
+void KeyboardShortcutDialog::save() {
+
+ qDebug() << "save() says: started";
+
+ QSettings settings("opentrack"); // 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 ( "KB_Shortcuts" );
+ iniFile.setValue ( "Key_index_Center", ui.cbxCenterKey->currentIndex() );
+ iniFile.setValue ( "Shift_Center", ui.chkCenterShift->isChecked() );
+ iniFile.setValue ( "Ctrl_Center", ui.chkCenterCtrl->isChecked() );
+ iniFile.setValue ( "Alt_Center", ui.chkCenterAlt->isChecked() );
+
+ iniFile.endGroup ();
+
+ settingsDirty = false;
+
+ //
+ // Send a message to the main program, to update the Settings (for the tracker)
+ //
+ mainApp->updateSettings();
+}
+
+//**************************************************************************************************//
+//**************************************************************************************************//
+//
+// Constructor for Curve-configuration-dialog
+//
+CurveConfigurationDialog::CurveConfigurationDialog( FaceTrackNoIR *ftnoir, QWidget *parent, Qt::WindowFlags f ) :
+QWidget( parent , f)
+{
+ ui.setupUi( this );
+
+ QPoint offsetpos(120, 30);
+ this->move(parent->pos() + offsetpos);
+
+ mainApp = ftnoir; // Preserve a pointer to FTNoIR
+
+ QSettings settings("opentrack"); // Registry settings (in HK_USER)
+ QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
+
+ QFunctionConfigurator* configs[6] = {
+ ui.txconfig,
+ ui.tyconfig,
+ ui.tzconfig,
+ ui.rxconfig,
+ ui.ryconfig,
+ ui.rzconfig
+ };
+
+ QFunctionConfigurator* alt_configs[6] = {
+ ui.txconfig_alt,
+ ui.tyconfig_alt,
+ ui.tzconfig_alt,
+ ui.rxconfig_alt,
+ ui.ryconfig_alt,
+ ui.rzconfig_alt
+ };
+
+ QCheckBox* checkboxes[6] = {
+ ui.rx_altp,
+ ui.ry_altp,
+ ui.rz_altp,
+ ui.tx_altp,
+ ui.ty_altp,
+ ui.tz_altp
+ };
+
+ for (int i = 0; i < 6; i++)
+ {
+ configs[i]->setConfig(&mainApp->axis(i).curve, currentFile);
+ alt_configs[i]->setConfig(&mainApp->axis(i).curveAlt, currentFile);
+ connect(configs[i], SIGNAL(CurveChanged(bool)), this, SLOT(curveChanged(bool)));
+ connect(alt_configs[i], SIGNAL(CurveChanged(bool)), this, SLOT(curveChanged(bool)));
+ connect(checkboxes[i], SIGNAL(stateChanged(int)), this, SLOT(curveChanged(int)));
+ }
+
+ // Connect Qt signals to member-functions
+ connect(ui.btnOK, SIGNAL(clicked()), this, SLOT(doOK()));
+ connect(ui.btnCancel, SIGNAL(clicked()), this, SLOT(doCancel()));
+
+ // Load the settings from the current .INI-file
+ loadSettings();
+}
+
+//
+// Destructor for server-dialog
+//
+CurveConfigurationDialog::~CurveConfigurationDialog() {
+ qDebug() << "~CurveConfigurationDialog() says: started";
+}
+
+//
+// OK clicked on server-dialog
+//
+void CurveConfigurationDialog::doOK() {
+ save();
+ this->close();
+}
+
+// override show event
+void CurveConfigurationDialog::showEvent ( QShowEvent * event ) {
+ loadSettings();
+}
+
+//
+// Cancel clicked on server-dialog
+//
+void CurveConfigurationDialog::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 CurveConfigurationDialog::loadSettings() {
+ qDebug() << "loadSettings says: Starting ";
+ QSettings settings("opentrack"); // 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;
+
+ static const char* names[] = {
+ "tx_alt",
+ "ty_alt",
+ "tz_alt",
+ "rx_alt",
+ "ry_alt",
+ "rz_alt"
+ };
+
+ iniFile.beginGroup("Tracking");
+
+ for (int i = 0; i < 6; i++)
+ mainApp->axis(i).altp = iniFile.value(names[i], false).toBool();
+
+ QCheckBox* widgets[] = {
+ ui.tx_altp,
+ ui.ty_altp,
+ ui.tz_altp,
+ ui.rx_altp,
+ ui.ry_altp,
+ ui.rz_altp
+ };
+
+ for (int i = 0; i < 6; i++)
+ widgets[i]->setChecked(mainApp->axis(i).altp);
+
+ QDoubleSpinBox* widgets2[] = {
+ ui.pos_tx,
+ ui.pos_ty,
+ ui.pos_tz,
+ ui.pos_tx,
+ ui.pos_ry,
+ ui.pos_rz
+ };
+
+ const char* names2[] = {
+ "zero_tx",
+ "zero_ty",
+ "zero_tz",
+ "zero_rx",
+ "zero_ry",
+ "zero_rz"
+ };
+
+ for (int i = 0; i < 6; i++)
+ widgets2[i]->setValue(iniFile.value(names2[i], 0).toDouble());
+
+ iniFile.endGroup();
+
+ settingsDirty = false;
+}
+
+//
+// Save the current Settings to the currently 'active' INI-file.
+//
+void CurveConfigurationDialog::save() {
+
+ qDebug() << "save() says: started";
+
+ QSettings settings("opentrack"); // Registry settings (in HK_USER)
+
+ QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
+
+ ui.rxconfig->saveSettings(currentFile);
+ ui.ryconfig->saveSettings(currentFile);
+ ui.rzconfig->saveSettings(currentFile);
+ ui.txconfig->saveSettings(currentFile);
+ ui.tyconfig->saveSettings(currentFile);
+ ui.tzconfig->saveSettings(currentFile);
+
+ ui.txconfig_alt->saveSettings(currentFile);
+ ui.tyconfig_alt->saveSettings(currentFile);
+ ui.tzconfig_alt->saveSettings(currentFile);
+ ui.rxconfig_alt->saveSettings(currentFile);
+ ui.ryconfig_alt->saveSettings(currentFile);
+ ui.rzconfig_alt->saveSettings(currentFile);
+
+ QSettings iniFile( currentFile, QSettings::IniFormat ); // Application settings (in INI-file)
+
+ iniFile.beginGroup("Tracking");
+
+ iniFile.setValue("rx_alt", ui.rx_altp->checkState() != Qt::Unchecked);
+ iniFile.setValue("ry_alt", ui.ry_altp->checkState() != Qt::Unchecked);
+ iniFile.setValue("rz_alt", ui.rz_altp->checkState() != Qt::Unchecked);
+ iniFile.setValue("tx_alt", ui.tx_altp->checkState() != Qt::Unchecked);
+ iniFile.setValue("ty_alt", ui.ty_altp->checkState() != Qt::Unchecked);
+ iniFile.setValue("tz_alt", ui.tz_altp->checkState() != Qt::Unchecked);
+
+ QDoubleSpinBox* widgets2[] = {
+ ui.pos_tx,
+ ui.pos_ty,
+ ui.pos_tz,
+ ui.pos_tx,
+ ui.pos_ry,
+ ui.pos_rz
+ };
+
+ const char* names2[] = {
+ "zero_tx",
+ "zero_ty",
+ "zero_tz",
+ "zero_rx",
+ "zero_ry",
+ "zero_rz"
+ };
+
+ for (int i = 0; i < 6; i++)
+ iniFile.setValue(names2[i], widgets2[i]->value());
+
+ iniFile.endGroup();
+
+ settingsDirty = false;
+
+ //
+ // Send a message to the main program, to update the Settings (for the tracker)
+ //
+ mainApp->updateSettings();
+}
+
+void FaceTrackNoIR::shortcutRecentered()
+{
+ if (tracker)
+ {
+#if defined(__WIN32) || defined(_WIN32)
+ MessageBeep(MB_OK);
+#else
+ QApplication::beep();
+#endif
+ qDebug() << "Center";
+ tracker->do_center = true;
+ }
+}
diff --git a/facetracknoir/facetracknoir.h b/facetracknoir/facetracknoir.h
index ff0b3642..768f6107 100644
--- a/facetracknoir/facetracknoir.h
+++ b/facetracknoir/facetracknoir.h
@@ -1,295 +1,295 @@
-/********************************************************************************
-* 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) 2010 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/>. *
-*********************************************************************************/
-
-#ifndef FaceTrackNoIR_H
-#define FaceTrackNoIR_H
-
-#undef FTNOIR_PROTOCOL_BASE_LIB
-#undef FTNOIR_TRACKER_BASE_LIB
-#undef FTNOIR_FILTER_BASE_LIB
-#define FTNOIR_PROTOCOL_BASE_EXPORT Q_DECL_IMPORT
-#define FTNOIR_TRACKER_BASE_EXPORT Q_DECL_IMPORT
-#define FTNOIR_FILTER_BASE_EXPORT Q_DECL_IMPORT
-
-#include <QtGui/QMainWindow>
-#include <QApplication>
-#include <QFileDialog>
-#include <QListView>
-#include <QPainter>
-#include <QWidget>
-#include <QDialog>
-#include <QUrl>
-#include <QList>
-#include <QKeySequence>
-#include <QtGui>
-#include <QString>
-#if !defined(_WIN32) && !defined(__WIN32)
-# include <qxtglobalshortcut.h>
-#else
-# include <windows.h>
-#endif
-#include <QThread>
-#include <QDebug>
-#include <QElapsedTimer>
-
-
-#include "ui_facetracknoir.h"
-#include "ui_ftnoir_keyboardshortcuts.h"
-#include "ui_ftnoir_curves.h"
-
-#include "ftnoir_protocol_base/ftnoir_protocol_base.h"
-#include "ftnoir_tracker_base/ftnoir_tracker_base.h"
-#include "ftnoir_filter_base/ftnoir_filter_base.h"
-
-#include "global-settings.h"
-#include "tracker.h"
-
-class Tracker; // pre-define class to avoid circular includes
-class FaceTrackNoIR;
-
-class KeybindingWorker;
-
-#if defined(__WIN32) || defined(_WIN32)
-extern QList<int> global_windows_key_sequences;
-#undef DIRECTINPUT_VERSION
-#define DIRECTINPUT_VERSION 0x0800
-#include <dinput.h>
-struct Key {
- BYTE keycode;
- bool shift;
- bool ctrl;
- bool alt;
- bool ever_pressed;
- QElapsedTimer timer;
-public:
- Key() : keycode(0), shift(false), ctrl(false), alt(false), ever_pressed(false)
- {
- }
-};
-#else
-typedef unsigned char BYTE;
-struct Key { int foo; };
-#endif
-
-class FaceTrackNoIR : public QMainWindow, IDynamicLibraryProvider
-{
- Q_OBJECT
-
-public:
- FaceTrackNoIR(QWidget *parent = 0, Qt::WFlags flags = 0);
- ~FaceTrackNoIR();
-
- void updateSettings(); // Update the settings (let Tracker read INI-file).
-
- QFrame *get_video_widget(); // Get a pointer to the video-widget, to use in the DLL
- Tracker *tracker;
- void bindKeyboardShortcuts();
- DynamicLibrary* current_tracker1() {
- return dlopen_trackers.value(ui.iconcomboTrackerSource->currentIndex(), (DynamicLibrary*) NULL);
- }
- DynamicLibrary* current_tracker2() {
- return dlopen_trackers.value(ui.cbxSecondTrackerSource->currentIndex() - 1, (DynamicLibrary*) NULL);
- }
- DynamicLibrary* current_protocol() {
- return dlopen_protocols.value(ui.iconcomboProtocol->currentIndex(), (DynamicLibrary*) NULL);
- }
- DynamicLibrary* current_filter() {
- return dlopen_filters.value(ui.iconcomboFilter->currentIndex(), (DynamicLibrary*) NULL);
- }
- THeadPoseDOF& axis(int idx) {
- return *pose.axes[idx];
- }
-
-#if defined(_WIN32) || defined(__WIN32)
- Key keyCenter;
- KeybindingWorker* keybindingWorker;
-#else
- QxtGlobalShortcut* keyCenter;
-#endif
-public slots:
- void shortcutRecentered();
-
-private:
- HeadPoseData pose;
- Ui::FaceTrackNoIRClass ui;
- QTimer timUpdateHeadPose; // Timer to display headpose
- QStringList iniFileList; // List of INI-files, that are present in the Settings folder
-
- ITrackerDialog* pTrackerDialog; // Pointer to Tracker dialog instance (in DLL)
- ITrackerDialog* pSecondTrackerDialog; // Pointer to the second Tracker dialog instance (in DLL)
- IProtocolDialog* pProtocolDialog; // Pointer to Protocol dialog instance (in DLL)
- IFilterDialog* pFilterDialog; // Pointer to Filter dialog instance (in DLL)
-
- /** Widget variables **/
- QWidget *_keyboard_shortcuts;
- QWidget *_curve_config;
-
- void createIconGroupBox();
-// void createMessageGroupBox();
-
- /** helper **/
- bool cameraDetected;
- bool settingsDirty;
-
- void GetCameraNameDX();
- void loadSettings();
- void setupFaceTrackNoIR();
-
- QList<DynamicLibrary*> dlopen_filters;
- QList<DynamicLibrary*> dlopen_trackers;
- QList<DynamicLibrary*> dlopen_protocols;
-
- bool looping;
-
- private slots:
- //file menu
- void open();
- void save();
- void saveAs();
- void exit();
-// void setIcon(int index);
- void profileSelected(int index);
- void protocolSelected(int index);
- void filterSelected(int index);
- void trackingSourceSelected(int index);
-
- void showVideoWidget();
- void showHeadPoseWidget();
- void showTrackerSettings();
- void showSecondTrackerSettings();
-
- void showServerControls();
- void showFilterControls();
- void showKeyboardShortcuts();
- void showCurveConfiguration();
-
- void setInvertAxis( Axis axis, int invert );
- void setInvertYaw(int invert) {
- setInvertAxis(Yaw, invert);
- }
- void setInvertPitch(int invert) {
- setInvertAxis(Pitch, invert);
- }
- void setInvertRoll(int invert) {
- setInvertAxis(Roll, invert);
- }
- void setInvertX(int invert) {
- setInvertAxis(TX, invert);
- }
- void setInvertY(int invert) {
- setInvertAxis(TY, invert);
- }
- void setInvertZ(int invert) {
- setInvertAxis(TZ, invert);
- }
- void showHeadPose();
-
- void startTracker();
- void stopTracker();
-
-};
-
-class KeyboardShortcutDialog: public QWidget
-{
- Q_OBJECT
-public:
-
- explicit KeyboardShortcutDialog( FaceTrackNoIR *ftnoir, QWidget *parent=0, Qt::WindowFlags f=0 );
- virtual ~KeyboardShortcutDialog();
- void showEvent ( QShowEvent * event );
-
-private:
- Ui::UICKeyboardShortcutDialog ui;
- void loadSettings();
- void save();
-
- /** helper **/
- bool settingsDirty;
- FaceTrackNoIR *mainApp;
-
-private slots:
- void doOK();
- void doCancel();
-};
-
-// Widget that has controls for Keyboard shortcuts.
-class CurveConfigurationDialog: public QWidget
-{
- Q_OBJECT
-public:
-
- explicit CurveConfigurationDialog( FaceTrackNoIR *ftnoir, QWidget *parent=0, Qt::WindowFlags f=0 );
- virtual ~CurveConfigurationDialog();
- void showEvent ( QShowEvent * event );
-
-private:
- Ui::UICCurveConfigurationDialog ui;
- void loadSettings();
- void save();
-
- /** helper **/
- bool settingsDirty;
- FaceTrackNoIR *mainApp;
-
-private slots:
- void doOK();
- void doCancel();
- void curveChanged( bool change ) { settingsDirty = true; }
- void curveChanged( int change ) { settingsDirty = true; }
-};
-
-extern QList<QString> global_key_sequences;
-#if defined(__WIN32) || defined(_WIN32)
-class KeybindingWorkerDummy {
-private:
- LPDIRECTINPUT8 din;
- LPDIRECTINPUTDEVICE8 dinkeyboard;
- Key kCenter;
- FaceTrackNoIR& window;
-public:
- volatile bool should_quit;
- ~KeybindingWorkerDummy();
- KeybindingWorkerDummy(FaceTrackNoIR& w, Key keyCenter);
- void run();
-};
-#else
-class KeybindingWorkerDummy {
-public:
- KeybindingWorkerDummy(FaceTrackNoIR& w, Key keyCenter);
- void run() {}
-};
-#endif
-
-class KeybindingWorker : public QThread, public KeybindingWorkerDummy {
- Q_OBJECT
-public:
- KeybindingWorker(FaceTrackNoIR& w, Key keyCenter) : KeybindingWorkerDummy(w, keyCenter)
- {
- }
- void run() {
- KeybindingWorkerDummy::run();
- }
-};
-
+/********************************************************************************
+* 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) 2010 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/>. *
+*********************************************************************************/
+
+#ifndef FaceTrackNoIR_H
+#define FaceTrackNoIR_H
+
+#undef FTNOIR_PROTOCOL_BASE_LIB
+#undef FTNOIR_TRACKER_BASE_LIB
+#undef FTNOIR_FILTER_BASE_LIB
+#define FTNOIR_PROTOCOL_BASE_EXPORT Q_DECL_IMPORT
+#define FTNOIR_TRACKER_BASE_EXPORT Q_DECL_IMPORT
+#define FTNOIR_FILTER_BASE_EXPORT Q_DECL_IMPORT
+
+#include <QtGui/QMainWindow>
+#include <QApplication>
+#include <QFileDialog>
+#include <QListView>
+#include <QPainter>
+#include <QWidget>
+#include <QDialog>
+#include <QUrl>
+#include <QList>
+#include <QKeySequence>
+#include <QtGui>
+#include <QString>
+#if !defined(_WIN32) && !defined(__WIN32)
+# include <qxtglobalshortcut.h>
+#else
+# include <windows.h>
+#endif
+#include <QThread>
+#include <QDebug>
+#include <QElapsedTimer>
+
+
+#include "ui_facetracknoir.h"
+#include "ui_ftnoir_keyboardshortcuts.h"
+#include "ui_ftnoir_curves.h"
+
+#include "ftnoir_protocol_base/ftnoir_protocol_base.h"
+#include "ftnoir_tracker_base/ftnoir_tracker_base.h"
+#include "ftnoir_filter_base/ftnoir_filter_base.h"
+
+#include "global-settings.h"
+#include "tracker.h"
+
+class Tracker; // pre-define class to avoid circular includes
+class FaceTrackNoIR;
+
+class KeybindingWorker;
+
+#if defined(__WIN32) || defined(_WIN32)
+extern QList<int> global_windows_key_sequences;
+#undef DIRECTINPUT_VERSION
+#define DIRECTINPUT_VERSION 0x0800
+#include <dinput.h>
+struct Key {
+ BYTE keycode;
+ bool shift;
+ bool ctrl;
+ bool alt;
+ bool ever_pressed;
+ QElapsedTimer timer;
+public:
+ Key() : keycode(0), shift(false), ctrl(false), alt(false), ever_pressed(false)
+ {
+ }
+};
+#else
+typedef unsigned char BYTE;
+struct Key { int foo; };
+#endif
+
+class FaceTrackNoIR : public QMainWindow, IDynamicLibraryProvider
+{
+ Q_OBJECT
+
+public:
+ FaceTrackNoIR(QWidget *parent = 0, Qt::WFlags flags = 0);
+ ~FaceTrackNoIR();
+
+ void updateSettings(); // Update the settings (let Tracker read INI-file).
+
+ QFrame *get_video_widget(); // Get a pointer to the video-widget, to use in the DLL
+ Tracker *tracker;
+ void bindKeyboardShortcuts();
+ DynamicLibrary* current_tracker1() {
+ return dlopen_trackers.value(ui.iconcomboTrackerSource->currentIndex(), (DynamicLibrary*) NULL);
+ }
+ DynamicLibrary* current_tracker2() {
+ return dlopen_trackers.value(ui.cbxSecondTrackerSource->currentIndex() - 1, (DynamicLibrary*) NULL);
+ }
+ DynamicLibrary* current_protocol() {
+ return dlopen_protocols.value(ui.iconcomboProtocol->currentIndex(), (DynamicLibrary*) NULL);
+ }
+ DynamicLibrary* current_filter() {
+ return dlopen_filters.value(ui.iconcomboFilter->currentIndex(), (DynamicLibrary*) NULL);
+ }
+ THeadPoseDOF& axis(int idx) {
+ return *pose.axes[idx];
+ }
+
+#if defined(_WIN32) || defined(__WIN32)
+ Key keyCenter;
+ KeybindingWorker* keybindingWorker;
+#else
+ QxtGlobalShortcut* keyCenter;
+#endif
+public slots:
+ void shortcutRecentered();
+
+private:
+ HeadPoseData pose;
+ Ui::FaceTrackNoIRClass ui;
+ QTimer timUpdateHeadPose; // Timer to display headpose
+ QStringList iniFileList; // List of INI-files, that are present in the Settings folder
+
+ ITrackerDialog* pTrackerDialog; // Pointer to Tracker dialog instance (in DLL)
+ ITrackerDialog* pSecondTrackerDialog; // Pointer to the second Tracker dialog instance (in DLL)
+ IProtocolDialog* pProtocolDialog; // Pointer to Protocol dialog instance (in DLL)
+ IFilterDialog* pFilterDialog; // Pointer to Filter dialog instance (in DLL)
+
+ /** Widget variables **/
+ QWidget *_keyboard_shortcuts;
+ QWidget *_curve_config;
+
+ void createIconGroupBox();
+// void createMessageGroupBox();
+
+ /** helper **/
+ bool cameraDetected;
+ bool settingsDirty;
+
+ void GetCameraNameDX();
+ void loadSettings();
+ void setupFaceTrackNoIR();
+
+ QList<DynamicLibrary*> dlopen_filters;
+ QList<DynamicLibrary*> dlopen_trackers;
+ QList<DynamicLibrary*> dlopen_protocols;
+
+ bool looping;
+
+ private slots:
+ //file menu
+ void open();
+ void save();
+ void saveAs();
+ void exit();
+// void setIcon(int index);
+ void profileSelected(int index);
+ void protocolSelected(int index);
+ void filterSelected(int index);
+ void trackingSourceSelected(int index);
+
+ void showVideoWidget();
+ void showHeadPoseWidget();
+ void showTrackerSettings();
+ void showSecondTrackerSettings();
+
+ void showServerControls();
+ void showFilterControls();
+ void showKeyboardShortcuts();
+ void showCurveConfiguration();
+
+ void setInvertAxis( Axis axis, int invert );
+ void setInvertYaw(int invert) {
+ setInvertAxis(Yaw, invert);
+ }
+ void setInvertPitch(int invert) {
+ setInvertAxis(Pitch, invert);
+ }
+ void setInvertRoll(int invert) {
+ setInvertAxis(Roll, invert);
+ }
+ void setInvertX(int invert) {
+ setInvertAxis(TX, invert);
+ }
+ void setInvertY(int invert) {
+ setInvertAxis(TY, invert);
+ }
+ void setInvertZ(int invert) {
+ setInvertAxis(TZ, invert);
+ }
+ void showHeadPose();
+
+ void startTracker();
+ void stopTracker();
+
+};
+
+class KeyboardShortcutDialog: public QWidget
+{
+ Q_OBJECT
+public:
+
+ explicit KeyboardShortcutDialog( FaceTrackNoIR *ftnoir, QWidget *parent=0, Qt::WindowFlags f=0 );
+ virtual ~KeyboardShortcutDialog();
+ void showEvent ( QShowEvent * event );
+
+private:
+ Ui::UICKeyboardShortcutDialog ui;
+ void loadSettings();
+ void save();
+
+ /** helper **/
+ bool settingsDirty;
+ FaceTrackNoIR *mainApp;
+
+private slots:
+ void doOK();
+ void doCancel();
+};
+
+// Widget that has controls for Keyboard shortcuts.
+class CurveConfigurationDialog: public QWidget
+{
+ Q_OBJECT
+public:
+
+ explicit CurveConfigurationDialog( FaceTrackNoIR *ftnoir, QWidget *parent=0, Qt::WindowFlags f=0 );
+ virtual ~CurveConfigurationDialog();
+ void showEvent ( QShowEvent * event );
+
+private:
+ Ui::UICCurveConfigurationDialog ui;
+ void loadSettings();
+ void save();
+
+ /** helper **/
+ bool settingsDirty;
+ FaceTrackNoIR *mainApp;
+
+private slots:
+ void doOK();
+ void doCancel();
+ void curveChanged( bool change ) { settingsDirty = true; }
+ void curveChanged( int change ) { settingsDirty = true; }
+};
+
+extern QList<QString> global_key_sequences;
+#if defined(__WIN32) || defined(_WIN32)
+class KeybindingWorkerDummy {
+private:
+ LPDIRECTINPUT8 din;
+ LPDIRECTINPUTDEVICE8 dinkeyboard;
+ Key kCenter;
+ FaceTrackNoIR& window;
+public:
+ volatile bool should_quit;
+ ~KeybindingWorkerDummy();
+ KeybindingWorkerDummy(FaceTrackNoIR& w, Key keyCenter);
+ void run();
+};
+#else
+class KeybindingWorkerDummy {
+public:
+ KeybindingWorkerDummy(FaceTrackNoIR& w, Key keyCenter);
+ void run() {}
+};
+#endif
+
+class KeybindingWorker : public QThread, public KeybindingWorkerDummy {
+ Q_OBJECT
+public:
+ KeybindingWorker(FaceTrackNoIR& w, Key keyCenter) : KeybindingWorkerDummy(w, keyCenter)
+ {
+ }
+ void run() {
+ KeybindingWorkerDummy::run();
+ }
+};
+
#endif // FaceTrackNoIR_H \ No newline at end of file
diff --git a/facetracknoir/main.cpp b/facetracknoir/main.cpp
index 7ff9f29f..bc0f973b 100644
--- a/facetracknoir/main.cpp
+++ b/facetracknoir/main.cpp
@@ -1,57 +1,57 @@
-/********************************************************************************
-* 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) 2010 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/>. *
-*********************************************************************************/
-
-#include "facetracknoir.h"
-#include "tracker.h"
-#include <QtGui/QApplication>
-#include <QDesktopWidget>
-#include <QDebug>
-#include <QList>
-
-#if defined(_WIN32)
-#include <windows.h>
-//#pragma comment(linker, "/SUBSYSTEM:console /ENTRY:mainCRTStartup")
-#endif
-int main(int argc, char** argv)
-{
-#if defined(_WIN32)
- (void) timeBeginPeriod(1);
-#endif
- QApplication app(argc, argv);
- QFont font;
- font.setFamily(font.defaultFamily());
- font.setPointSize(9);
- app.setFont(font);
- FaceTrackNoIR w;
- //
- // Create the Main Window and DeskTop and Exec!
- //
- QDesktopWidget desktop;
- w.move(desktop.screenGeometry().width()/2-w.width()/2, 100);
- w.show();
- qApp->exec();
-
- return 0;
-}
-
+/********************************************************************************
+* 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) 2010 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/>. *
+*********************************************************************************/
+
+#include "facetracknoir.h"
+#include "tracker.h"
+#include <QtGui/QApplication>
+#include <QDesktopWidget>
+#include <QDebug>
+#include <QList>
+
+#if defined(_WIN32)
+#include <windows.h>
+//#pragma comment(linker, "/SUBSYSTEM:console /ENTRY:mainCRTStartup")
+#endif
+int main(int argc, char** argv)
+{
+#if defined(_WIN32)
+ (void) timeBeginPeriod(1);
+#endif
+ QApplication app(argc, argv);
+ QFont font;
+ font.setFamily(font.defaultFamily());
+ font.setPointSize(9);
+ app.setFont(font);
+ FaceTrackNoIR w;
+ //
+ // Create the Main Window and DeskTop and Exec!
+ //
+ QDesktopWidget desktop;
+ w.move(desktop.screenGeometry().width()/2-w.width()/2, 100);
+ w.show();
+ qApp->exec();
+
+ return 0;
+}
+
diff --git a/facetracknoir/rotation.h b/facetracknoir/rotation.h
index dd70ca77..e97ec0f0 100644
--- a/facetracknoir/rotation.h
+++ b/facetracknoir/rotation.h
@@ -1,64 +1,64 @@
-/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#ifndef ROTATION_H
-#define ROTATION_H
-#include <cmath>
-// ----------------------------------------------------------------------------
-class Rotation {
-
-public:
- Rotation() : a(1.0),b(0.0),c(0.0),d(0.0) {}
- Rotation(double yaw, double pitch, double roll) { fromEuler(yaw, pitch, roll); }
- Rotation(double a, double b, double c, double d) : a(a),b(b),c(c),d(d) {}
-
- Rotation inv(){ // inverse
- return Rotation(a,-b,-c, -d);
- }
-
-
- // conversions
- // see http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
- void fromEuler(double yaw, double pitch, double roll)
- {
-
- double sin_phi = sin(roll/2.0);
- double cos_phi = cos(roll/2.0);
- double sin_the = sin(pitch/2.0);
- double cos_the = cos(pitch/2.0);
- double sin_psi = sin(yaw/2.0);
- double cos_psi = cos(yaw/2.0);
-
- a = cos_phi*cos_the*cos_psi + sin_phi*sin_the*sin_psi;
- b = sin_phi*cos_the*cos_psi - cos_phi*sin_the*sin_psi;
- c = cos_phi*sin_the*cos_psi + sin_phi*cos_the*sin_psi;
- d = cos_phi*cos_the*sin_psi - sin_phi*sin_the*cos_psi;
- }
-
- void toEuler(double& yaw, double& pitch, double& roll)
- {
- roll = atan2(2.0*(a*b + c*d), 1.0 - 2.0*(b*b + c*c));
- pitch = asin(2.0*(a*c - b*d));
- yaw = atan2(2.0*(a*d + b*c), 1.0 - 2.0*(c*c + d*d));
- }
-
- const Rotation operator*(const Rotation& B)
- {
- const Rotation& A = *this;
- return Rotation(A.a*B.a - A.b*B.b - A.c*B.c - A.d*B.d, // quaternion multiplication
- A.a*B.b + A.b*B.a + A.c*B.d - A.d*B.c,
- A.a*B.c - A.b*B.d + A.c*B.a + A.d*B.b,
- A.a*B.d + A.b*B.c - A.c*B.b + A.d*B.a);
- }
-
-protected:
- double a,b,c,d; // quaternion coefficients
-};
-
-
-
-#endif //ROTATION_H
+/* Copyright (c) 2012 Patrick Ruoff
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ */
+
+#ifndef ROTATION_H
+#define ROTATION_H
+#include <cmath>
+// ----------------------------------------------------------------------------
+class Rotation {
+
+public:
+ Rotation() : a(1.0),b(0.0),c(0.0),d(0.0) {}
+ Rotation(double yaw, double pitch, double roll) { fromEuler(yaw, pitch, roll); }
+ Rotation(double a, double b, double c, double d) : a(a),b(b),c(c),d(d) {}
+
+ Rotation inv(){ // inverse
+ return Rotation(a,-b,-c, -d);
+ }
+
+
+ // conversions
+ // see http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
+ void fromEuler(double yaw, double pitch, double roll)
+ {
+
+ double sin_phi = sin(roll/2.0);
+ double cos_phi = cos(roll/2.0);
+ double sin_the = sin(pitch/2.0);
+ double cos_the = cos(pitch/2.0);
+ double sin_psi = sin(yaw/2.0);
+ double cos_psi = cos(yaw/2.0);
+
+ a = cos_phi*cos_the*cos_psi + sin_phi*sin_the*sin_psi;
+ b = sin_phi*cos_the*cos_psi - cos_phi*sin_the*sin_psi;
+ c = cos_phi*sin_the*cos_psi + sin_phi*cos_the*sin_psi;
+ d = cos_phi*cos_the*sin_psi - sin_phi*sin_the*cos_psi;
+ }
+
+ void toEuler(double& yaw, double& pitch, double& roll)
+ {
+ roll = atan2(2.0*(a*b + c*d), 1.0 - 2.0*(b*b + c*c));
+ pitch = asin(2.0*(a*c - b*d));
+ yaw = atan2(2.0*(a*d + b*c), 1.0 - 2.0*(c*c + d*d));
+ }
+
+ const Rotation operator*(const Rotation& B)
+ {
+ const Rotation& A = *this;
+ return Rotation(A.a*B.a - A.b*B.b - A.c*B.c - A.d*B.d, // quaternion multiplication
+ A.a*B.b + A.b*B.a + A.c*B.d - A.d*B.c,
+ A.a*B.c - A.b*B.d + A.c*B.a + A.d*B.b,
+ A.a*B.d + A.b*B.c - A.c*B.b + A.d*B.a);
+ }
+
+protected:
+ double a,b,c,d; // quaternion coefficients
+};
+
+
+
+#endif //ROTATION_H
diff --git a/facetracknoir/tracker.cpp b/facetracknoir/tracker.cpp
index f2b4845f..47daa697 100644
--- a/facetracknoir/tracker.cpp
+++ b/facetracknoir/tracker.cpp
@@ -1,218 +1,218 @@
-/********************************************************************************
-* 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) 2012 Wim Vriend (Developing) *
-* Ron Hendriks (Researching and Testing) *
-* *
-* Homepage: http://facetracknoir.sourceforge.net/home/default.htm *
-* *
-* 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/>. *
-*********************************************************************************/
-#include "tracker.h"
-#include "facetracknoir.h"
-
-/** constructor **/
-Tracker::Tracker( FaceTrackNoIR *parent ) :
- should_quit(false),
- do_center(false)
-{
- // Retieve the pointer to the parent
- mainApp = parent;
- // Load the settings from the INI-file
- loadSettings();
-}
-
-Tracker::~Tracker()
-{
-}
-
-static void get_curve(double pos, double& out, THeadPoseDOF& axis) {
- bool altp = (pos < 0) && axis.altp;
- if (altp) {
- out = axis.invert * axis.curveAlt.getValue(pos);
- axis.curve.setTrackingActive( false );
- axis.curveAlt.setTrackingActive( true );
- }
- else {
- out = axis.invert * axis.curve.getValue(pos);
- axis.curve.setTrackingActive( true );
- axis.curveAlt.setTrackingActive( false );
- }
- out += axis.zero;
-}
-
-/** QThread run method @override **/
-void Tracker::run() {
- T6DOF current_camera; // Used for filtering
- T6DOF target_camera;
- T6DOF new_camera;
-
- /** Direct Input variables **/
- T6DOF offset_camera;
- T6DOF gameoutput_camera;
-
- bool bTracker1Confid = false;
- bool bTracker2Confid = false;
-
- double newpose[6];
- double last_post_filter[6];
-
- forever
- {
- if (should_quit)
- break;
-
- for (int i = 0; i < 6; i++)
- newpose[i] = 0;
-
- //
- // The second tracker serves as 'secondary'. So if an axis is written by the second tracker it CAN be overwritten by the Primary tracker.
- // This is enforced by the sequence below.
- //
- if (Libraries->pSecondTracker) {
- bTracker2Confid = Libraries->pSecondTracker->GiveHeadPoseData(newpose);
- }
-
- if (Libraries->pTracker) {
- bTracker1Confid = Libraries->pTracker->GiveHeadPoseData(newpose);
- }
-
- {
- QMutexLocker foo(&mtx);
- const bool confid = bTracker1Confid || bTracker2Confid;
-
- if ( confid ) {
- for (int i = 0; i < 6; i++)
- mainApp->axis(i).headPos = newpose[i];
- }
-
- //
- // If Center is pressed, copy the current values to the offsets.
- //
- if (do_center) {
- //
- // Only copy valid values
- //
- for (int i = 0; i < 6; i++)
- offset_camera.axes[i] = mainApp->axis(i).headPos;
-
- Tracker::do_center = false;
-
- if (Libraries->pTracker)
- Libraries->pTracker->NotifyCenter();
-
- if (Libraries->pSecondTracker)
- Libraries->pSecondTracker->NotifyCenter();
-
- if (Libraries->pFilter)
- Libraries->pFilter->Initialize();
- }
-
- if (confid) {
- // get values
- for (int i = 0; i < 6; i++)
- target_camera.axes[i] = mainApp->axis(i).headPos;
-
- // do the centering
- target_camera = target_camera - offset_camera;
-
- //
- // Use advanced filtering, when a filter was selected.
- //
- if (Libraries->pFilter) {
- for (int i = 0; i < 6; i++)
- last_post_filter[i] = gameoutput_camera.axes[i];
- Libraries->pFilter->FilterHeadPoseData(current_camera.axes, target_camera.axes, new_camera.axes, last_post_filter);
- }
- else {
- new_camera = target_camera;
- }
-
- for (int i = 0; i < 6; i++) {
- get_curve(new_camera.axes[i], output_camera.axes[i], mainApp->axis(i));
- }
-
- //
- // Send the headpose to the game
- //
- if (Libraries->pProtocol) {
- gameoutput_camera = output_camera;
- Libraries->pProtocol->sendHeadposeToGame( gameoutput_camera.axes, newpose ); // degrees & centimeters
- }
- }
- }
-
- //for lower cpu load
- msleep(8);
- }
-
- for (int i = 0; i < 6; i++)
- {
- mainApp->axis(i).curve.setTrackingActive(false);
- mainApp->axis(i).curveAlt.setTrackingActive(false);
- }
-}
-
-//
-// Get the raw headpose, so it can be displayed.
-//
-void Tracker::getHeadPose( double *data ) {
- QMutexLocker foo(&mtx);
- for (int i = 0; i < 6; i++)
- {
- data[i] = mainApp->axis(i).headPos;
- }
-}
-
-//
-// Get the output-headpose, so it can be displayed.
-//
-void Tracker::getOutputHeadPose( double *data ) {
- QMutexLocker foo(&mtx);
- for (int i = 0; i < 6; i++)
- data[i] = output_camera.axes[i];
-}
-
-//
-// Load the current Settings from the currently 'active' INI-file.
-//
-void Tracker::loadSettings() {
- qDebug() << "Tracker::loadSettings says: Starting ";
- QSettings settings("opentrack"); // 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("Tracking");
-
- qDebug() << "loadSettings says: iniFile = " << currentFile;
-
- const char* names2[] = {
- "zero_tx",
- "zero_ty",
- "zero_tz",
- "zero_rx",
- "zero_ry",
- "zero_rz"
- };
-
- for (int i = 0; i < 6; i++)
- mainApp->axis(i).zero = iniFile.value(names2[i], 0).toDouble();
-
- iniFile.endGroup();
-}
-
-void Tracker::setInvertAxis(Axis axis, bool invert) { mainApp->axis(axis).invert = invert?-1.0f:1.0f; }
+/********************************************************************************
+* 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) 2012 Wim Vriend (Developing) *
+* Ron Hendriks (Researching and Testing) *
+* *
+* Homepage: http://facetracknoir.sourceforge.net/home/default.htm *
+* *
+* 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/>. *
+*********************************************************************************/
+#include "tracker.h"
+#include "facetracknoir.h"
+
+/** constructor **/
+Tracker::Tracker( FaceTrackNoIR *parent ) :
+ should_quit(false),
+ do_center(false)
+{
+ // Retieve the pointer to the parent
+ mainApp = parent;
+ // Load the settings from the INI-file
+ loadSettings();
+}
+
+Tracker::~Tracker()
+{
+}
+
+static void get_curve(double pos, double& out, THeadPoseDOF& axis) {
+ bool altp = (pos < 0) && axis.altp;
+ if (altp) {
+ out = axis.invert * axis.curveAlt.getValue(pos);
+ axis.curve.setTrackingActive( false );
+ axis.curveAlt.setTrackingActive( true );
+ }
+ else {
+ out = axis.invert * axis.curve.getValue(pos);
+ axis.curve.setTrackingActive( true );
+ axis.curveAlt.setTrackingActive( false );
+ }
+ out += axis.zero;
+}
+
+/** QThread run method @override **/
+void Tracker::run() {
+ T6DOF current_camera; // Used for filtering
+ T6DOF target_camera;
+ T6DOF new_camera;
+
+ /** Direct Input variables **/
+ T6DOF offset_camera;
+ T6DOF gameoutput_camera;
+
+ bool bTracker1Confid = false;
+ bool bTracker2Confid = false;
+
+ double newpose[6];
+ double last_post_filter[6];
+
+ forever
+ {
+ if (should_quit)
+ break;
+
+ for (int i = 0; i < 6; i++)
+ newpose[i] = 0;
+
+ //
+ // The second tracker serves as 'secondary'. So if an axis is written by the second tracker it CAN be overwritten by the Primary tracker.
+ // This is enforced by the sequence below.
+ //
+ if (Libraries->pSecondTracker) {
+ bTracker2Confid = Libraries->pSecondTracker->GiveHeadPoseData(newpose);
+ }
+
+ if (Libraries->pTracker) {
+ bTracker1Confid = Libraries->pTracker->GiveHeadPoseData(newpose);
+ }
+
+ {
+ QMutexLocker foo(&mtx);
+ const bool confid = bTracker1Confid || bTracker2Confid;
+
+ if ( confid ) {
+ for (int i = 0; i < 6; i++)
+ mainApp->axis(i).headPos = newpose[i];
+ }
+
+ //
+ // If Center is pressed, copy the current values to the offsets.
+ //
+ if (do_center) {
+ //
+ // Only copy valid values
+ //
+ for (int i = 0; i < 6; i++)
+ offset_camera.axes[i] = mainApp->axis(i).headPos;
+
+ Tracker::do_center = false;
+
+ if (Libraries->pTracker)
+ Libraries->pTracker->NotifyCenter();
+
+ if (Libraries->pSecondTracker)
+ Libraries->pSecondTracker->NotifyCenter();
+
+ if (Libraries->pFilter)
+ Libraries->pFilter->Initialize();
+ }
+
+ if (confid) {
+ // get values
+ for (int i = 0; i < 6; i++)
+ target_camera.axes[i] = mainApp->axis(i).headPos;
+
+ // do the centering
+ target_camera = target_camera - offset_camera;
+
+ //
+ // Use advanced filtering, when a filter was selected.
+ //
+ if (Libraries->pFilter) {
+ for (int i = 0; i < 6; i++)
+ last_post_filter[i] = gameoutput_camera.axes[i];
+ Libraries->pFilter->FilterHeadPoseData(current_camera.axes, target_camera.axes, new_camera.axes, last_post_filter);
+ }
+ else {
+ new_camera = target_camera;
+ }
+
+ for (int i = 0; i < 6; i++) {
+ get_curve(new_camera.axes[i], output_camera.axes[i], mainApp->axis(i));
+ }
+
+ //
+ // Send the headpose to the game
+ //
+ if (Libraries->pProtocol) {
+ gameoutput_camera = output_camera;
+ Libraries->pProtocol->sendHeadposeToGame( gameoutput_camera.axes, newpose ); // degrees & centimeters
+ }
+ }
+ }
+
+ //for lower cpu load
+ msleep(8);
+ }
+
+ for (int i = 0; i < 6; i++)
+ {
+ mainApp->axis(i).curve.setTrackingActive(false);
+ mainApp->axis(i).curveAlt.setTrackingActive(false);
+ }
+}
+
+//
+// Get the raw headpose, so it can be displayed.
+//
+void Tracker::getHeadPose( double *data ) {
+ QMutexLocker foo(&mtx);
+ for (int i = 0; i < 6; i++)
+ {
+ data[i] = mainApp->axis(i).headPos;
+ }
+}
+
+//
+// Get the output-headpose, so it can be displayed.
+//
+void Tracker::getOutputHeadPose( double *data ) {
+ QMutexLocker foo(&mtx);
+ for (int i = 0; i < 6; i++)
+ data[i] = output_camera.axes[i];
+}
+
+//
+// Load the current Settings from the currently 'active' INI-file.
+//
+void Tracker::loadSettings() {
+ qDebug() << "Tracker::loadSettings says: Starting ";
+ QSettings settings("opentrack"); // 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("Tracking");
+
+ qDebug() << "loadSettings says: iniFile = " << currentFile;
+
+ const char* names2[] = {
+ "zero_tx",
+ "zero_ty",
+ "zero_tz",
+ "zero_rx",
+ "zero_ry",
+ "zero_rz"
+ };
+
+ for (int i = 0; i < 6; i++)
+ mainApp->axis(i).zero = iniFile.value(names2[i], 0).toDouble();
+
+ iniFile.endGroup();
+}
+
+void Tracker::setInvertAxis(Axis axis, bool invert) { mainApp->axis(axis).invert = invert?-1.0f:1.0f; }
diff --git a/facetracknoir/tracker.h b/facetracknoir/tracker.h
index 7e2b84cd..eeb18dad 100644
--- a/facetracknoir/tracker.h
+++ b/facetracknoir/tracker.h
@@ -1,145 +1,145 @@
-/********************************************************************************
-* 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) 2010 - 2012 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/>. *
-*********************************************************************************/
-#ifndef __TRACKER_H__
-#define __TRACKER_H__
-
-#include <QThread>
-#include <QMessageBox>
-#include <QLineEdit>
-#include <QPoint>
-#include <QWaitCondition>
-#include <QList>
-#include <QPainterPath>
-#include <QDebug>
-#include <QMutex>
-#include "global-settings.h"
-#include <ftnoir_tracker_base/ftnoir_tracker_types.h>
-
-//#define DIRECTINPUT_VERSION 0x0800
-//#include <Dinput.h>
-#undef FTNOIR_PROTOCOL_BASE_LIB
-#undef FTNOIR_TRACKER_BASE_LIB
-#undef FTNOIR_FILTER_BASE_LIB
-#undef FTNOIR_PROTOCOL_BASE_EXPORT
-#undef FTNOIR_TRACKER_BASE_EXPORT
-#undef FTNOIR_FILTER_BASE_EXPORT
-#define FTNOIR_PROTOCOL_BASE_EXPORT Q_DECL_IMPORT
-#define FTNOIR_TRACKER_BASE_EXPORT Q_DECL_IMPORT
-#define FTNOIR_FILTER_BASE_EXPORT Q_DECL_IMPORT
-
-#include <qfunctionconfigurator/functionconfig.h>
-#include "ftnoir_tracker_base/ftnoir_tracker_base.h"
-#include "ftnoir_protocol_base/ftnoir_protocol_base.h"
-#include "ftnoir_filter_base/ftnoir_filter_base.h"
-#include "tracker_types.h"
-
-class FaceTrackNoIR; // pre-define parent-class to avoid circular includes
-
-//
-// Structure to hold all variables concerning one of 6 DOF's
-//
-class THeadPoseDOF {
-private:
- THeadPoseDOF(const THeadPoseDOF &) {}
-public:
- THeadPoseDOF() :
- headPos(0),
- invert(0),
- altp(false),
- zero(0)
- {
- }
-
- THeadPoseDOF(QString primary,
- QString secondary,
- int maxInput1,
- int maxOutput1,
- int maxInput2,
- int maxOutput2) :
- curve(primary, maxInput1, maxOutput1),
- curveAlt(secondary, maxInput2, maxOutput2),
- headPos(0),
- invert(1),
- zero(0)
- {
- QSettings settings("opentrack"); // Registry settings (in HK_USER)
- QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
- QSettings iniFile( currentFile, QSettings::IniFormat );
- curve.loadSettings(iniFile);
- curveAlt.loadSettings(iniFile);
-
- iniFile.beginGroup("Tracking");
- altp = iniFile.value(secondary).toBool();
- iniFile.endGroup();
- }
- double headPos; // Current position (from faceTracker, radials or meters)
- float invert; // Invert measured value (= 1.0f or -1.0f)
- FunctionConfig curve; // Function to translate input -> output
- FunctionConfig curveAlt;
- bool altp;
- double zero;
-};
-
-class Tracker : public QThread {
- Q_OBJECT
-
-private:
- FaceTrackNoIR *mainApp;
- QMutex mtx;
-
-protected:
- // qthread override run method
- void run();
-
-public:
- Tracker( FaceTrackNoIR *parent );
- ~Tracker();
- void loadSettings(); // Load settings from the INI-file
-
- void setInvertAxis(Axis axis, bool invert);
-
- void getHeadPose(double *data); // Return the current headpose data
- void getOutputHeadPose(double *data); // Return the current (processed) headpose data
-
- volatile bool should_quit;
- // following are now protected by hTrackMutex
- volatile bool do_center; // Center head-position, using the shortkey
-
- T6DOF output_camera;
-};
-
-class HeadPoseData {
-public:
- THeadPoseDOF* axes[6];
- HeadPoseData()
- {
- axes[TX] = new THeadPoseDOF("tx","tx_alt", 100, 100, 100, 100);
- axes[TY] = new THeadPoseDOF("ty","ty_alt", 100, 100, 100, 100);
- axes[TZ] = new THeadPoseDOF("tz","tz_alt", 100, 100, 100, 100);
- axes[Yaw] = new THeadPoseDOF("rx", "rx_alt", 180, 180, 180, 180);
- axes[Pitch] = new THeadPoseDOF("ry", "ry_alt", 90, 90, 90, 90);
- axes[Roll] = new THeadPoseDOF("rz", "rz_alt", 180, 180, 180, 180);
- }
-};
-
-#endif
+/********************************************************************************
+* 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) 2010 - 2012 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/>. *
+*********************************************************************************/
+#ifndef __TRACKER_H__
+#define __TRACKER_H__
+
+#include <QThread>
+#include <QMessageBox>
+#include <QLineEdit>
+#include <QPoint>
+#include <QWaitCondition>
+#include <QList>
+#include <QPainterPath>
+#include <QDebug>
+#include <QMutex>
+#include "global-settings.h"
+#include <ftnoir_tracker_base/ftnoir_tracker_types.h>
+
+//#define DIRECTINPUT_VERSION 0x0800
+//#include <Dinput.h>
+#undef FTNOIR_PROTOCOL_BASE_LIB
+#undef FTNOIR_TRACKER_BASE_LIB
+#undef FTNOIR_FILTER_BASE_LIB
+#undef FTNOIR_PROTOCOL_BASE_EXPORT
+#undef FTNOIR_TRACKER_BASE_EXPORT
+#undef FTNOIR_FILTER_BASE_EXPORT
+#define FTNOIR_PROTOCOL_BASE_EXPORT Q_DECL_IMPORT
+#define FTNOIR_TRACKER_BASE_EXPORT Q_DECL_IMPORT
+#define FTNOIR_FILTER_BASE_EXPORT Q_DECL_IMPORT
+
+#include <qfunctionconfigurator/functionconfig.h>
+#include "ftnoir_tracker_base/ftnoir_tracker_base.h"
+#include "ftnoir_protocol_base/ftnoir_protocol_base.h"
+#include "ftnoir_filter_base/ftnoir_filter_base.h"
+#include "tracker_types.h"
+
+class FaceTrackNoIR; // pre-define parent-class to avoid circular includes
+
+//
+// Structure to hold all variables concerning one of 6 DOF's
+//
+class THeadPoseDOF {
+private:
+ THeadPoseDOF(const THeadPoseDOF &) {}
+public:
+ THeadPoseDOF() :
+ headPos(0),
+ invert(0),
+ altp(false),
+ zero(0)
+ {
+ }
+
+ THeadPoseDOF(QString primary,
+ QString secondary,
+ int maxInput1,
+ int maxOutput1,
+ int maxInput2,
+ int maxOutput2) :
+ curve(primary, maxInput1, maxOutput1),
+ curveAlt(secondary, maxInput2, maxOutput2),
+ headPos(0),
+ invert(1),
+ zero(0)
+ {
+ QSettings settings("opentrack"); // Registry settings (in HK_USER)
+ QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
+ QSettings iniFile( currentFile, QSettings::IniFormat );
+ curve.loadSettings(iniFile);
+ curveAlt.loadSettings(iniFile);
+
+ iniFile.beginGroup("Tracking");
+ altp = iniFile.value(secondary).toBool();
+ iniFile.endGroup();
+ }
+ double headPos; // Current position (from faceTracker, radials or meters)
+ float invert; // Invert measured value (= 1.0f or -1.0f)
+ FunctionConfig curve; // Function to translate input -> output
+ FunctionConfig curveAlt;
+ bool altp;
+ double zero;
+};
+
+class Tracker : public QThread {
+ Q_OBJECT
+
+private:
+ FaceTrackNoIR *mainApp;
+ QMutex mtx;
+
+protected:
+ // qthread override run method
+ void run();
+
+public:
+ Tracker( FaceTrackNoIR *parent );
+ ~Tracker();
+ void loadSettings(); // Load settings from the INI-file
+
+ void setInvertAxis(Axis axis, bool invert);
+
+ void getHeadPose(double *data); // Return the current headpose data
+ void getOutputHeadPose(double *data); // Return the current (processed) headpose data
+
+ volatile bool should_quit;
+ // following are now protected by hTrackMutex
+ volatile bool do_center; // Center head-position, using the shortkey
+
+ T6DOF output_camera;
+};
+
+class HeadPoseData {
+public:
+ THeadPoseDOF* axes[6];
+ HeadPoseData()
+ {
+ axes[TX] = new THeadPoseDOF("tx","tx_alt", 100, 100, 100, 100);
+ axes[TY] = new THeadPoseDOF("ty","ty_alt", 100, 100, 100, 100);
+ axes[TZ] = new THeadPoseDOF("tz","tz_alt", 100, 100, 100, 100);
+ axes[Yaw] = new THeadPoseDOF("rx", "rx_alt", 180, 180, 180, 180);
+ axes[Pitch] = new THeadPoseDOF("ry", "ry_alt", 90, 90, 90, 90);
+ axes[Roll] = new THeadPoseDOF("rz", "rz_alt", 180, 180, 180, 180);
+ }
+};
+
+#endif
diff --git a/facetracknoir/tracker_types.cpp b/facetracknoir/tracker_types.cpp
index 11adc985..da246722 100644
--- a/facetracknoir/tracker_types.cpp
+++ b/facetracknoir/tracker_types.cpp
@@ -1,44 +1,44 @@
-#include "tracker_types.h"
-#include "rotation.h"
-
-#define PI 3.14159265358979323846264
-#define D2R PI/180.0
-#define R2D 180.0/PI
-
-T6DOF operator-(const T6DOF& A, const T6DOF& B)
-{
- Rotation R_A(A.axes[Yaw]*D2R, A.axes[Pitch]*D2R, A.axes[Roll]*D2R);
- Rotation R_B(B.axes[Yaw]*D2R, B.axes[Pitch]*D2R, B.axes[Roll]*D2R);
- Rotation R_C = R_A * R_B.inv();
-
- T6DOF C;
- R_C.toEuler(C.axes[Yaw], C.axes[Pitch], C.axes[Roll]);
- C.axes[Yaw] *= R2D;
- C.axes[Pitch] *= R2D;
- C.axes[Roll] *= R2D;
-
- C.axes[TX] = A.axes[TX] - B.axes[TX];
- C.axes[TY] = A.axes[TY] - B.axes[TY];
- C.axes[TZ] = A.axes[TZ] - B.axes[TZ];
- //C.frame_number?
- return C;
-}
-
-T6DOF operator+(const T6DOF& A, const T6DOF& B)
-{
- Rotation R_A(A.axes[Yaw]*D2R, A.axes[Pitch]*D2R, A.axes[Roll]*D2R);
- Rotation R_B(B.axes[Yaw]*D2R, B.axes[Pitch]*D2R, B.axes[Roll]*D2R);
- Rotation R_C = R_A * R_B;
-
- T6DOF C;
- R_C.toEuler(C.axes[Yaw], C.axes[Pitch], C.axes[Roll]);
- C.axes[Yaw] *= R2D;
- C.axes[Pitch] *= R2D;
- C.axes[Roll] *= R2D;
-
- C.axes[TX] = A.axes[TX] + B.axes[TX];
- C.axes[TY] = A.axes[TY] + B.axes[TY];
- C.axes[TZ] = A.axes[TZ] + B.axes[TZ];
- //C.frame_number?
- return C;
-}
+#include "tracker_types.h"
+#include "rotation.h"
+
+#define PI 3.14159265358979323846264
+#define D2R PI/180.0
+#define R2D 180.0/PI
+
+T6DOF operator-(const T6DOF& A, const T6DOF& B)
+{
+ Rotation R_A(A.axes[Yaw]*D2R, A.axes[Pitch]*D2R, A.axes[Roll]*D2R);
+ Rotation R_B(B.axes[Yaw]*D2R, B.axes[Pitch]*D2R, B.axes[Roll]*D2R);
+ Rotation R_C = R_A * R_B.inv();
+
+ T6DOF C;
+ R_C.toEuler(C.axes[Yaw], C.axes[Pitch], C.axes[Roll]);
+ C.axes[Yaw] *= R2D;
+ C.axes[Pitch] *= R2D;
+ C.axes[Roll] *= R2D;
+
+ C.axes[TX] = A.axes[TX] - B.axes[TX];
+ C.axes[TY] = A.axes[TY] - B.axes[TY];
+ C.axes[TZ] = A.axes[TZ] - B.axes[TZ];
+ //C.frame_number?
+ return C;
+}
+
+T6DOF operator+(const T6DOF& A, const T6DOF& B)
+{
+ Rotation R_A(A.axes[Yaw]*D2R, A.axes[Pitch]*D2R, A.axes[Roll]*D2R);
+ Rotation R_B(B.axes[Yaw]*D2R, B.axes[Pitch]*D2R, B.axes[Roll]*D2R);
+ Rotation R_C = R_A * R_B;
+
+ T6DOF C;
+ R_C.toEuler(C.axes[Yaw], C.axes[Pitch], C.axes[Roll]);
+ C.axes[Yaw] *= R2D;
+ C.axes[Pitch] *= R2D;
+ C.axes[Roll] *= R2D;
+
+ C.axes[TX] = A.axes[TX] + B.axes[TX];
+ C.axes[TY] = A.axes[TY] + B.axes[TY];
+ C.axes[TZ] = A.axes[TZ] + B.axes[TZ];
+ //C.frame_number?
+ return C;
+}
diff --git a/facetracknoir/tracker_types.h b/facetracknoir/tracker_types.h
index ebd89e7c..54d1841e 100644
--- a/facetracknoir/tracker_types.h
+++ b/facetracknoir/tracker_types.h
@@ -1,41 +1,41 @@
-/********************************************************************************
-* 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) 2010 - 2012 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/>. *
-*********************************************************************************/
-#ifndef __TRACKER_TYPES_H__
-#define __TRACKER_TYPES_H__
-
-#include "ftnoir_tracker_base/ftnoir_tracker_types.h"
-
-struct T6DOF {
-public:
- double axes[6];
-
- T6DOF() {
- for (int i = 0; i < 6; i++)
- axes[i] = 0;
- }
-};
-
-T6DOF operator-(const T6DOF& A, const T6DOF& B); // get new pose with respect to reference pose B
-T6DOF operator+(const T6DOF& A, const T6DOF& B); // get new pose with respect to reference pose B^-1
-
-#endif //__TRACKER_TYPES_H__
+/********************************************************************************
+* 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) 2010 - 2012 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/>. *
+*********************************************************************************/
+#ifndef __TRACKER_TYPES_H__
+#define __TRACKER_TYPES_H__
+
+#include "ftnoir_tracker_base/ftnoir_tracker_types.h"
+
+struct T6DOF {
+public:
+ double axes[6];
+
+ T6DOF() {
+ for (int i = 0; i < 6; i++)
+ axes[i] = 0;
+ }
+};
+
+T6DOF operator-(const T6DOF& A, const T6DOF& B); // get new pose with respect to reference pose B
+T6DOF operator+(const T6DOF& A, const T6DOF& B); // get new pose with respect to reference pose B^-1
+
+#endif //__TRACKER_TYPES_H__