From 4bf3fa56f81f254ac701430102eda7ad60575fd5 Mon Sep 17 00:00:00 2001 From: druiz17 Date: Sun, 16 Apr 2017 21:26:09 -0700 Subject: [PATCH 01/17] saving work --- .../src/controllers/InputRecorder.cpp | 18 ++++++++++++++++ .../src/controllers/InputRecorder.h | 21 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 libraries/controllers/src/controllers/InputRecorder.cpp create mode 100644 libraries/controllers/src/controllers/InputRecorder.h diff --git a/libraries/controllers/src/controllers/InputRecorder.cpp b/libraries/controllers/src/controllers/InputRecorder.cpp new file mode 100644 index 0000000000..c722563e7e --- /dev/null +++ b/libraries/controllers/src/controllers/InputRecorder.cpp @@ -0,0 +1,18 @@ +// +// Created by Dante Ruiz 2017/04/16 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "InputRecorder.h" + +InputRecorder::InputRecorder() {} + +InputRecorder::~InputRecorder() {} + +InputRecorder& InputRecorder::getInstance() { + static InputRecorder inputRecorder; + return inputRecorder; +} diff --git a/libraries/controllers/src/controllers/InputRecorder.h b/libraries/controllers/src/controllers/InputRecorder.h new file mode 100644 index 0000000000..17a222cd45 --- /dev/null +++ b/libraries/controllers/src/controllers/InputRecorder.h @@ -0,0 +1,21 @@ +// +// Created by Dante Ruiz on 2017/04/16 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_InputRecorder_h +#define hifi_InputRecorder_h +class InputRecorder { +public: + InputRecorder(); + ~InputRecorder(); + + InputRecorder& getInstance(); + + +}; + +#endif From c29888689632ac74a38acc270dd48ed2f5001d8f Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 18 Apr 2017 00:17:14 +0100 Subject: [PATCH 02/17] hooking up the input playback --- .../controllers/src/controllers/.#Input.h | Bin 0 -> 76 bytes .../src/controllers/InputRecorder.cpp | 73 ++++++++++++++++-- .../src/controllers/InputRecorder.h | 42 ++++++++-- .../src/controllers/ScriptingInterface.cpp | 21 +++++ .../src/controllers/ScriptingInterface.h | 4 + .../src/controllers/UserInputMapper.cpp | 6 +- .../impl/endpoints/ActionEndpoint.cpp | 11 +++ 7 files changed, 144 insertions(+), 13 deletions(-) create mode 100644 libraries/controllers/src/controllers/.#Input.h diff --git a/libraries/controllers/src/controllers/.#Input.h b/libraries/controllers/src/controllers/.#Input.h new file mode 100644 index 0000000000000000000000000000000000000000..1985e19fa47fbbd38823426b8e5f3897409e0dc5 GIT binary patch literal 76 zcmY$iDXz@T$;`{P`~S~{A(0`Ep@booL4hHNp_Cz$p^CwQ!G*zpUr7#J7;);A8J literal 0 HcmV?d00001 diff --git a/libraries/controllers/src/controllers/InputRecorder.cpp b/libraries/controllers/src/controllers/InputRecorder.cpp index c722563e7e..b60dd2387e 100644 --- a/libraries/controllers/src/controllers/InputRecorder.cpp +++ b/libraries/controllers/src/controllers/InputRecorder.cpp @@ -8,11 +8,74 @@ #include "InputRecorder.h" -InputRecorder::InputRecorder() {} +namespace controller { + + InputRecorder::InputRecorder() {} -InputRecorder::~InputRecorder() {} + InputRecorder::~InputRecorder() {} -InputRecorder& InputRecorder::getInstance() { - static InputRecorder inputRecorder; - return inputRecorder; + InputRecorder& InputRecorder::getInstance() { + static InputRecorder inputRecorder; + return inputRecorder; + } + + void InputRecorder::startRecording() { + _recording = true; + _framesRecorded = 0; + _poseStateList.clear(); + _actionStateList.clear(); + qDebug() << "-------------> input recording starting <---------------"; + } + + void InputRecorder::stopRecording() { + _recording = false; + qDebug() << "--------------> input recording stopping <-----------------"; + } + + void InputRecorder::startPlayback() { + _playback = true; + _recording = false; + qDebug() << "-----------------> starting playback <---------------"; + } + + void InputRecorder::stopPlayback() { + _playback = false; + _recording = false; + } + + void InputRecorder::setActionState(controller::Action action, float value) { + if (_recording) { + qDebug() << "-----------------> setiing action state <---------------"; + _actionStateList[_framesRecorded][toInt(action)] = value; + } + } + + void InputRecorder::setActionState(controller::Action action, const controller::Pose pose) { + if (_recording) { + qDebug() << "-----------------> setiing Pose state <---------------"; + _poseStateList[_framesRecorded][toInt(action)] = pose; + } + } + + float InputRecorder::getActionState(controller::Action action) { + return _actionStateList[_playCount][toInt(action)]; + } + + controller::Pose InputRecorder::getPoseState(controller::Action action) { + return _poseStateList[_playCount][toInt(action)]; + } + + void InputRecorder::frameTick() { + if (_recording) { + _framesRecorded++; + } + + if (_playback) { + if (_playCount < _framesRecorded) { + _playCount++; + } else { + _playCount = 0; + } + } + } } diff --git a/libraries/controllers/src/controllers/InputRecorder.h b/libraries/controllers/src/controllers/InputRecorder.h index 17a222cd45..ff5d2fa6bc 100644 --- a/libraries/controllers/src/controllers/InputRecorder.h +++ b/libraries/controllers/src/controllers/InputRecorder.h @@ -8,14 +8,44 @@ #ifndef hifi_InputRecorder_h #define hifi_InputRecorder_h -class InputRecorder { -public: - InputRecorder(); - ~InputRecorder(); - InputRecorder& getInstance(); +#include +#include +#include +#include "Pose.h" +#include "Actions.h" + +namespace controller { + class InputRecorder { + public: + using PoseStates = std::vector; + using ActionStates = std::vector; -}; + InputRecorder(); + ~InputRecorder(); + static InputRecorder& getInstance(); + void startRecording(); + void startPlayback(); + void stopPlayback(); + void stopRecording(); + bool isRecording() { return _recording; } + bool isPlayingback() { return _playback; } + void setActionState(controller::Action action, float value); + void setActionState(controller::Action action, const controller::Pose pose); + float getActionState(controller::Action action); + controller::Pose getPoseState(controller::Action action); + void frameTick(); + private: + bool _recording { false }; + bool _playback { false }; + std::vector _poseStateList; + std::vector _actionStateList; + + int _framesRecorded { 0 }; + int _playCount { 0 }; + + }; +} #endif diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp index d32acb3d82..c9b8810463 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.cpp +++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp @@ -23,6 +23,7 @@ #include "impl/MappingBuilderProxy.h" #include "Logging.h" #include "InputDevice.h" +#include "InputRecorder.h" static QRegularExpression SANITIZE_NAME_EXPRESSION{ "[\\(\\)\\.\\s]" }; @@ -154,6 +155,26 @@ namespace controller { return DependencyManager::get()->triggerHapticPulse(strength, SHORT_HAPTIC_DURATION_MS, hand); } + void ScriptingInterface::startInputRecording() { + auto inputRecorder = InputRecorder::getInstance(); + inputRecorder.startRecording(); + } + + void ScriptingInterface::stopInputRecording() { + auto inputRecorder = InputRecorder::getInstance(); + inputRecorder.stopRecording(); + } + + void ScriptingInterface::startInputPlayback() { + auto inputRecorder = InputRecorder::getInstance(); + inputRecorder.startPlayback(); + } + + void ScriptingInterface::stopInputPlayback() { + auto inputRecorder = InputRecorder::getInstance(); + inputRecorder.stopPlayback(); + } + bool ScriptingInterface::triggerHapticPulseOnDevice(unsigned int device, float strength, float duration, controller::Hand hand) const { return DependencyManager::get()->triggerHapticPulseOnDevice(device, strength, duration, hand); } diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h index b47a6fea31..961ed5ef72 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.h +++ b/libraries/controllers/src/controllers/ScriptingInterface.h @@ -99,6 +99,10 @@ namespace controller { Q_INVOKABLE const QVariantMap& getHardware() { return _hardware; } Q_INVOKABLE const QVariantMap& getActions() { return _actions; } Q_INVOKABLE const QVariantMap& getStandard() { return _standard; } + Q_INVOKABLE void startInputRecording(); + Q_INVOKABLE void stopInputRecording(); + Q_INVOKABLE void startInputPlayback(); + Q_INVOKABLE void stopInputPlayback(); bool isMouseCaptured() const { return _mouseCaptured; } bool isTouchCaptured() const { return _touchCaptured; } diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp index fe50f023c3..43990b3bf0 100755 --- a/libraries/controllers/src/controllers/UserInputMapper.cpp +++ b/libraries/controllers/src/controllers/UserInputMapper.cpp @@ -22,7 +22,7 @@ #include "StandardController.h" #include "StateController.h" - +#include "InputRecorder.h" #include "Logging.h" #include "impl/conditionals/AndConditional.h" @@ -243,7 +243,7 @@ void fixBisectedAxis(float& full, float& negative, float& positive) { void UserInputMapper::update(float deltaTime) { Locker locker(_lock); - + auto inputRecorder = InputRecorder::getInstance(); static uint64_t updateCount = 0; ++updateCount; @@ -298,6 +298,7 @@ void UserInputMapper::update(float deltaTime) { emit inputEvent(input.id, value); } } + inputRecorder.frameTick(); } Input::NamedVector UserInputMapper::getAvailableInputs(uint16 deviceID) const { @@ -571,6 +572,7 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) { } } // no filters yet for pose + qDebug() << "--------------> applying destination <----------------"; destination->apply(value, source); } else { // Fetch the value, may have been overriden by previous loopback routes diff --git a/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.cpp index b671d8e93c..c3c3631118 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.cpp +++ b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.cpp @@ -11,6 +11,7 @@ #include #include "../../UserInputMapper.h" +#include "../../InputRecorder.h" using namespace controller; @@ -20,10 +21,20 @@ void ActionEndpoint::apply(float newValue, const Pointer& source) { auto userInputMapper = DependencyManager::get(); userInputMapper->deltaActionState(Action(_input.getChannel()), newValue); } + auto inputRecorder = InputRecorder::getInstance(); + inputRecorder.setActionState(Action(_input.getChannel()), _currentValue); } void ActionEndpoint::apply(const Pose& value, const Pointer& source) { _currentPose = value; + auto inputRecorder = InputRecorder::getInstance(); + inputRecorder.setActionState(Action(_input.getChannel()), _currentPose); + qDebug << "<--------------- destination"; + if (inputRecorder.isPlayingback()) { + qDebug() << "-------------> playing back <--------------"; + _currentPose = inputRecorder.getPoseState(Action(_input.getChannel())); + } + if (!_currentPose.isValid()) { return; } From cd095915ef770ecec0e2322c18ffa6e0f34395b0 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 18 Apr 2017 00:32:30 +0100 Subject: [PATCH 03/17] removed emacs junk file from my repo --- libraries/controllers/src/controllers/.#Input.h | Bin 76 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 libraries/controllers/src/controllers/.#Input.h diff --git a/libraries/controllers/src/controllers/.#Input.h b/libraries/controllers/src/controllers/.#Input.h deleted file mode 100644 index 1985e19fa47fbbd38823426b8e5f3897409e0dc5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76 zcmY$iDXz@T$;`{P`~S~{A(0`Ep@booL4hHNp_Cz$p^CwQ!G*zpUr7#J7;);A8J From 5cd4007aaa4f28caf031de76ca28e5e1a4c382d7 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 18 Apr 2017 21:53:23 +0100 Subject: [PATCH 04/17] got input recording working --- interface/src/Application.cpp | 7 ++ .../src/controllers/InputRecorder.cpp | 80 +++++++++++++++---- .../src/controllers/InputRecorder.h | 14 +++- .../src/controllers/ScriptingInterface.cpp | 16 ++-- .../src/controllers/UserInputMapper.cpp | 7 +- .../impl/endpoints/ActionEndpoint.cpp | 18 +++-- 6 files changed, 105 insertions(+), 37 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 88278034d0..357bceb120 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -77,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -2731,6 +2732,9 @@ void Application::keyPressEvent(QKeyEvent* event) { if (isMeta) { auto offscreenUi = DependencyManager::get(); offscreenUi->load("Browser.qml"); + } else if (isOption) { + controller::InputRecorder* inputRecorder = controller::InputRecorder::getInstance(); + inputRecorder->togglePlayback(); } break; @@ -2929,6 +2933,9 @@ void Application::keyPressEvent(QKeyEvent* event) { Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, !isFirstPersonChecked); Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, isFirstPersonChecked); cameraMenuChanged(); + } else if (isOption) { + controller::InputRecorder* inputRecorder = controller::InputRecorder::getInstance(); + inputRecorder->toggleRecording(); } break; } diff --git a/libraries/controllers/src/controllers/InputRecorder.cpp b/libraries/controllers/src/controllers/InputRecorder.cpp index b60dd2387e..3ef6ef38ba 100644 --- a/libraries/controllers/src/controllers/InputRecorder.cpp +++ b/libraries/controllers/src/controllers/InputRecorder.cpp @@ -8,72 +8,122 @@ #include "InputRecorder.h" +#include +#include +#include +#include namespace controller { + + void poseToJsonObject(const Pose pose) { + } InputRecorder::InputRecorder() {} InputRecorder::~InputRecorder() {} - InputRecorder& InputRecorder::getInstance() { + InputRecorder* InputRecorder::getInstance() { static InputRecorder inputRecorder; - return inputRecorder; + return &inputRecorder; } void InputRecorder::startRecording() { _recording = true; + _playback = false; _framesRecorded = 0; _poseStateList.clear(); _actionStateList.clear(); - qDebug() << "-------------> input recording starting <---------------"; + } + + void InputRecorder::saveRecording() { + QJsonObject data; + data["frameCount"] = _framesRecorded; + + QJsonArray actionArrayList; + QJsonArray poseArrayList; + for(const ActionStates actionState _actionStateList) { + QJsonArray actionArray; + for (const float value, actionState) { + actionArray.append(value); + } + actionArrayList.append(actionArray); + } + + for (const PoseStates poseState, _poseStateList) { + QJsonArray poseArray; + for (const Pose pose, poseState) { + + } + poseArrayList.append(poseArray); + } + + } + + void InputRecorder::loadRecording() { } void InputRecorder::stopRecording() { _recording = false; - qDebug() << "--------------> input recording stopping <-----------------"; } void InputRecorder::startPlayback() { _playback = true; _recording = false; - qDebug() << "-----------------> starting playback <---------------"; } void InputRecorder::stopPlayback() { _playback = false; - _recording = false; } void InputRecorder::setActionState(controller::Action action, float value) { if (_recording) { - qDebug() << "-----------------> setiing action state <---------------"; - _actionStateList[_framesRecorded][toInt(action)] = value; + _currentFrameActions[toInt(action)] += value; } } void InputRecorder::setActionState(controller::Action action, const controller::Pose pose) { if (_recording) { - qDebug() << "-----------------> setiing Pose state <---------------"; - _poseStateList[_framesRecorded][toInt(action)] = pose; + _currentFramePoses[toInt(action)] = pose; } } + void InputRecorder::resetFrame() { + if (_recording) { + for(auto& channel : _currentFramePoses) { + channel = Pose(); + } + + for(auto& channel : _currentFrameActions) { + channel = 0.0f; + } + } + } + float InputRecorder::getActionState(controller::Action action) { - return _actionStateList[_playCount][toInt(action)]; + if (_actionStateList.size() > 0 ) { + return _actionStateList[_playCount][toInt(action)]; + } + + return 0.0f; } controller::Pose InputRecorder::getPoseState(controller::Action action) { - return _poseStateList[_playCount][toInt(action)]; + if (_poseStateList.size() > 0) { + return _poseStateList[_playCount][toInt(action)]; + } + + return Pose(); } void InputRecorder::frameTick() { if (_recording) { _framesRecorded++; + _poseStateList.push_back(_currentFramePoses); + _actionStateList.push_back(_currentFrameActions); } if (_playback) { - if (_playCount < _framesRecorded) { - _playCount++; - } else { + _playCount++; + if (_playCount == _framesRecorded) { _playCount = 0; } } diff --git a/libraries/controllers/src/controllers/InputRecorder.h b/libraries/controllers/src/controllers/InputRecorder.h index ff5d2fa6bc..f9ec944ff7 100644 --- a/libraries/controllers/src/controllers/InputRecorder.h +++ b/libraries/controllers/src/controllers/InputRecorder.h @@ -25,11 +25,17 @@ namespace controller { InputRecorder(); ~InputRecorder(); - static InputRecorder& getInstance(); + static InputRecorder* getInstance(); + + void saveRecording(); + void loadRecording(); void startRecording(); void startPlayback(); void stopPlayback(); void stopRecording(); + void toggleRecording() { _recording = !_recording; } + void togglePlayback() { _playback = !_playback; } + void resetFrame(); bool isRecording() { return _recording; } bool isPlayingback() { return _playback; } void setActionState(controller::Action action, float value); @@ -40,8 +46,10 @@ namespace controller { private: bool _recording { false }; bool _playback { false }; - std::vector _poseStateList; - std::vector _actionStateList; + std::vector _poseStateList = std::vector(); + std::vector _actionStateList = std::vector(); + PoseStates _currentFramePoses = PoseStates(toInt(Action::NUM_ACTIONS)); + ActionStates _currentFrameActions = ActionStates(toInt(Action::NUM_ACTIONS)); int _framesRecorded { 0 }; int _playCount { 0 }; diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp index c9b8810463..f09e366df8 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.cpp +++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp @@ -156,23 +156,23 @@ namespace controller { } void ScriptingInterface::startInputRecording() { - auto inputRecorder = InputRecorder::getInstance(); - inputRecorder.startRecording(); + InputRecorder* inputRecorder = InputRecorder::getInstance(); + inputRecorder->startRecording(); } void ScriptingInterface::stopInputRecording() { - auto inputRecorder = InputRecorder::getInstance(); - inputRecorder.stopRecording(); + InputRecorder* inputRecorder = InputRecorder::getInstance(); + inputRecorder->stopRecording(); } void ScriptingInterface::startInputPlayback() { - auto inputRecorder = InputRecorder::getInstance(); - inputRecorder.startPlayback(); + InputRecorder* inputRecorder = InputRecorder::getInstance(); + inputRecorder->startPlayback(); } void ScriptingInterface::stopInputPlayback() { - auto inputRecorder = InputRecorder::getInstance(); - inputRecorder.stopPlayback(); + InputRecorder* inputRecorder = InputRecorder::getInstance(); + inputRecorder->stopPlayback(); } bool ScriptingInterface::triggerHapticPulseOnDevice(unsigned int device, float strength, float duration, controller::Hand hand) const { diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp index 43990b3bf0..be10c46538 100755 --- a/libraries/controllers/src/controllers/UserInputMapper.cpp +++ b/libraries/controllers/src/controllers/UserInputMapper.cpp @@ -243,10 +243,11 @@ void fixBisectedAxis(float& full, float& negative, float& positive) { void UserInputMapper::update(float deltaTime) { Locker locker(_lock); - auto inputRecorder = InputRecorder::getInstance(); + InputRecorder* inputRecorder = InputRecorder::getInstance(); static uint64_t updateCount = 0; ++updateCount; + inputRecorder->resetFrame(); // Reset the axis state for next loop for (auto& channel : _actionStates) { channel = 0.0f; @@ -298,7 +299,7 @@ void UserInputMapper::update(float deltaTime) { emit inputEvent(input.id, value); } } - inputRecorder.frameTick(); + inputRecorder->frameTick(); } Input::NamedVector UserInputMapper::getAvailableInputs(uint16 deviceID) const { @@ -509,6 +510,7 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) { } // If the source hasn't been written yet, defer processing of this route + auto inputRecorder = InputRecorder::getInstance(); auto source = route->source; auto sourceInput = source->getInput(); if (sourceInput.device == STANDARD_DEVICE && !force && source->writeable()) { @@ -572,7 +574,6 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) { } } // no filters yet for pose - qDebug() << "--------------> applying destination <----------------"; destination->apply(value, source); } else { // Fetch the value, may have been overriden by previous loopback routes diff --git a/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.cpp index c3c3631118..6c14533f02 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.cpp +++ b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.cpp @@ -16,23 +16,25 @@ using namespace controller; void ActionEndpoint::apply(float newValue, const Pointer& source) { + InputRecorder* inputRecorder = InputRecorder::getInstance(); + if(inputRecorder->isPlayingback()) { + newValue = inputRecorder->getActionState(Action(_input.getChannel())); + } + _currentValue += newValue; if (_input != Input::INVALID_INPUT) { auto userInputMapper = DependencyManager::get(); userInputMapper->deltaActionState(Action(_input.getChannel()), newValue); } - auto inputRecorder = InputRecorder::getInstance(); - inputRecorder.setActionState(Action(_input.getChannel()), _currentValue); + inputRecorder->setActionState(Action(_input.getChannel()), newValue); } void ActionEndpoint::apply(const Pose& value, const Pointer& source) { _currentPose = value; - auto inputRecorder = InputRecorder::getInstance(); - inputRecorder.setActionState(Action(_input.getChannel()), _currentPose); - qDebug << "<--------------- destination"; - if (inputRecorder.isPlayingback()) { - qDebug() << "-------------> playing back <--------------"; - _currentPose = inputRecorder.getPoseState(Action(_input.getChannel())); + InputRecorder* inputRecorder = InputRecorder::getInstance(); + inputRecorder->setActionState(Action(_input.getChannel()), _currentPose); + if (inputRecorder->isPlayingback()) { + _currentPose = inputRecorder->getPoseState(Action(_input.getChannel())); } if (!_currentPose.isValid()) { From 1cf9485143f09910cb03446259b94ed956329d1d Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 19 Apr 2017 00:23:05 +0100 Subject: [PATCH 05/17] fixed compile issue --- .../src/controllers/InputRecorder.cpp | 51 ++++++++++++++++--- .../src/controllers/InputRecorder.h | 1 - 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/libraries/controllers/src/controllers/InputRecorder.cpp b/libraries/controllers/src/controllers/InputRecorder.cpp index 3ef6ef38ba..51480645fb 100644 --- a/libraries/controllers/src/controllers/InputRecorder.cpp +++ b/libraries/controllers/src/controllers/InputRecorder.cpp @@ -14,8 +14,41 @@ #include namespace controller { - void poseToJsonObject(const Pose pose) { - } + QJsonObject poseToJsonObject(const Pose pose) { + QJsonObject newPose; + + QJsonArray translation; + translation.append(pose.translation.x); + translation.append(pose.translation.y); + translation.append(pose.translation.z); + + QJsonArray rotation; + rotation.append(pose.rotation.x); + rotation.append(pose.rotation.y); + rotation.append(pose.rotation.z); + rotation.append(pose.rotation.w); + + QJsonArray velocity; + velocity.append(pose.velocity.x); + velocity.append(pose.velocity.y); + velocity.append(pose.velocity.z); + + QJsonArray angularVelocity; + angularVelocity.append(pose.angularVelocity.x); + angularVelocity.append(pose.angularVelocity.y); + angularVelocity.append(pose.angularVelocity.z); + + newPose["translation"] = translation; + newPose["rotation"] = rotation; + newPose["velocity"] = velocity; + newPose["angularVelocity"] = angularVelocity; + newPose["valid"] = pose.valid; + + return newPose; + } + + void exportFile(QJsonObject object) { + } InputRecorder::InputRecorder() {} @@ -40,22 +73,24 @@ namespace controller { QJsonArray actionArrayList; QJsonArray poseArrayList; - for(const ActionStates actionState _actionStateList) { + for(const ActionStates actionState: _actionStateList) { QJsonArray actionArray; - for (const float value, actionState) { + for (const float value: actionState) { actionArray.append(value); } actionArrayList.append(actionArray); } - for (const PoseStates poseState, _poseStateList) { + for (const PoseStates poseState: _poseStateList) { QJsonArray poseArray; - for (const Pose pose, poseState) { - + for (const Pose pose: poseState) { + poseArray.append(poseToJsonObject(pose)); } poseArrayList.append(poseArray); } - + + data["actionList"] = actionArrayList; + data["poseList"] = poseArrayList; } void InputRecorder::loadRecording() { diff --git a/libraries/controllers/src/controllers/InputRecorder.h b/libraries/controllers/src/controllers/InputRecorder.h index f9ec944ff7..5417cdc927 100644 --- a/libraries/controllers/src/controllers/InputRecorder.h +++ b/libraries/controllers/src/controllers/InputRecorder.h @@ -53,7 +53,6 @@ namespace controller { int _framesRecorded { 0 }; int _playCount { 0 }; - }; } #endif From 07f674eabea146a37c96fe6971ecfdb2bea8cc2e Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 19 Apr 2017 20:41:56 +0100 Subject: [PATCH 06/17] exprting compressed file --- interface/src/Application.cpp | 2 +- .../src/controllers/InputRecorder.cpp | 30 +++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8ccc587250..cf079ac2c8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2738,7 +2738,7 @@ void Application::keyPressEvent(QKeyEvent* event) { offscreenUi->load("Browser.qml"); } else if (isOption) { controller::InputRecorder* inputRecorder = controller::InputRecorder::getInstance(); - inputRecorder->togglePlayback(); + inputRecorder->saveRecording(); } break; diff --git a/libraries/controllers/src/controllers/InputRecorder.cpp b/libraries/controllers/src/controllers/InputRecorder.cpp index 51480645fb..e404048ffd 100644 --- a/libraries/controllers/src/controllers/InputRecorder.cpp +++ b/libraries/controllers/src/controllers/InputRecorder.cpp @@ -11,9 +11,19 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include -namespace controller { +QString SAVE_DIRECTORY = QDir::homePath()+"/hifi-input-recordings/"; +QString FILE_PREFIX_NAME = "input-recording-"; +QString COMPRESS_EXTENSION = ".tar.gz"; +namespace controller { + QJsonObject poseToJsonObject(const Pose pose) { QJsonObject newPose; @@ -47,7 +57,22 @@ namespace controller { return newPose; } - void exportFile(QJsonObject object) { + void exportToFile(QJsonObject& object) { + if (!QDir(SAVE_DIRECTORY).exists()) { + QDir().mkdir(SAVE_DIRECTORY); + } + + QString timeStamp = QDateTime::currentDateTime().toString(Qt::ISODate); + timeStamp.replace(":", "-"); + QString fileName = SAVE_DIRECTORY + FILE_PREFIX_NAME + timeStamp + COMPRESS_EXTENSION; + QFile saveFile (fileName); + if (!saveFile.open(QIODevice::WriteOnly)) { + qWarning() << "could not open file: " << fileName; + return; + } + QJsonDocument saveData(object); + QByteArray compressedData = qCompress(saveData.toJson(QJsonDocument::Compact)); + saveFile.write(compressedData); } InputRecorder::InputRecorder() {} @@ -91,6 +116,7 @@ namespace controller { data["actionList"] = actionArrayList; data["poseList"] = poseArrayList; + exportToFile(data); } void InputRecorder::loadRecording() { From cc34cb96e4b8b8c0f86b8a24efe2faeb85a8b1e6 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 21 Apr 2017 18:15:47 +0100 Subject: [PATCH 07/17] making ui for input recorder --- .../qml/hifi/tablet/InputRecorder.qml | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 interface/resources/qml/hifi/tablet/InputRecorder.qml diff --git a/interface/resources/qml/hifi/tablet/InputRecorder.qml b/interface/resources/qml/hifi/tablet/InputRecorder.qml new file mode 100644 index 0000000000..28804ee219 --- /dev/null +++ b/interface/resources/qml/hifi/tablet/InputRecorder.qml @@ -0,0 +1,103 @@ +// +// Created by Dante Ruiz 2017/04/17 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import Hifi 1.0 +import QtQuick.Controls 1.4 +import QtQuick.Dialogs 1.2 as OriginalDialogs + +import "../../styles-uit" +import "../../controls-uit" as HifiControls +import "../../windows" + +Rectangle { + id: inputRecorder + property var eventBridge; + HifiConstants { id: hifi } + signal sendToScript(var message); + color: hifi.colors.baseGray; + + + Row { + id: topButtons + width: parent.width + height: 40 + spacing: 40 + anchors { + left: parent.left + right: parent.right + top: parent.top + topMargin: 10 + } + HifiControls.Button { + id: start + text: "Start" + color: hifi.buttons.blue + enabled: true + } + + HifiControls.Button { + id: stop + text: "Stop" + color: hifi.buttons.blue + enabled: true + } + + HifiControls.Button { + id: save + text: "Save" + color: hifi.buttons.blue + enabled: true + } + + } + + HifiControls.VerticalSpacer {} + + HifiControls.TextField { + id: selectedFile + anchors.left: parent.left + anchors.right: parent.right + anchors.top: topButtons.top + anchors.topMargin: 40 + + colorScheme: hifi.colorSchemes.dark + readOnly: true + + } + + HifiControls.Button { + id: load + anchors.right: parent.right + anchors.top: selectedFile.bottom + anchors.topMargin: 10 + + text: "Load" + color: hifi.buttons.black + enabled: true + } + + HifiControls.Button { + id: browse + anchors.right: load.left + anchors.top: selectedFile.bottom + anchors.topMargin: 10 + + text: "Browse" + color: hifi.buttons.black + enabled: true + + Trigger { + id: browseTimer + interval: 5 + repeat: false + running: false + + } +} + From 64fcfd33a49c4207ae1c94ced5e523b959e1d451 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 21 Apr 2017 22:38:53 +0100 Subject: [PATCH 08/17] working on loading files --- .../qml/hifi/tablet/InputRecorder.qml | 32 +++++++++++++++---- .../src/controllers/InputRecorder.cpp | 23 ++++++++++++- .../src/controllers/InputRecorder.h | 4 ++- .../src/controllers/ScriptingInterface.cpp | 10 ++++++ .../src/controllers/ScriptingInterface.h | 2 ++ 5 files changed, 62 insertions(+), 9 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/InputRecorder.qml b/interface/resources/qml/hifi/tablet/InputRecorder.qml index 28804ee219..d726d16f9c 100644 --- a/interface/resources/qml/hifi/tablet/InputRecorder.qml +++ b/interface/resources/qml/hifi/tablet/InputRecorder.qml @@ -14,6 +14,7 @@ import QtQuick.Dialogs 1.2 as OriginalDialogs import "../../styles-uit" import "../../controls-uit" as HifiControls import "../../windows" +import "../../dialogs" Rectangle { id: inputRecorder @@ -21,8 +22,10 @@ Rectangle { HifiConstants { id: hifi } signal sendToScript(var message); color: hifi.colors.baseGray; + property string path: "" + property var dialog: null; - + Component { id: fileDialog; TabletFileDialog { } } Row { id: topButtons width: parent.width @@ -39,6 +42,9 @@ Rectangle { text: "Start" color: hifi.buttons.blue enabled: true + onClicked: { + sendToScript({method: "Start"}); + } } HifiControls.Button { @@ -46,6 +52,9 @@ Rectangle { text: "Stop" color: hifi.buttons.blue enabled: true + onClicked: { + sendToScript({method: "Stop"}); + } } HifiControls.Button { @@ -53,6 +62,9 @@ Rectangle { text: "Save" color: hifi.buttons.blue enabled: true + onClicked: { + sendToScript({method: "Save"}); + } } } @@ -80,6 +92,7 @@ Rectangle { text: "Load" color: hifi.buttons.black enabled: true + onClicked: sendToScript({method: "Load", params: {file: path }}); } HifiControls.Button { @@ -91,13 +104,18 @@ Rectangle { text: "Browse" color: hifi.buttons.black enabled: true + onClicked: { + dialog = fileDialog.createObject(inputRecorder); + dialog.selectedFile.connect(getFileSelected); + } + } - Trigger { - id: browseTimer - interval: 5 - repeat: false - running: false - + + function getFileSelected(file) { + console.log("------------> file selected <----------------"); + //sendToScript({ method: "Load", params: { file: file} }); + selectedFile.text = file; + inputRecorder.path = file; } } diff --git a/libraries/controllers/src/controllers/InputRecorder.cpp b/libraries/controllers/src/controllers/InputRecorder.cpp index e404048ffd..782f44d0ac 100644 --- a/libraries/controllers/src/controllers/InputRecorder.cpp +++ b/libraries/controllers/src/controllers/InputRecorder.cpp @@ -74,6 +74,18 @@ namespace controller { QByteArray compressedData = qCompress(saveData.toJson(QJsonDocument::Compact)); saveFile.write(compressedData); } + + bool openFile(const QString& file, QJsonObject& object) { + QFile openFile(file); + if (!openFile.open(QIODevice::ReadOnly)) { + qWarning() << "could not open file: " << file; + return false; + } + QByteArray compressedData = qUncompress(openFile.readAll()); + QJsonDocument jsonDoc = QJsonDocument::fromBinaryData(compressedData); + object = jsonDoc.object(); + return true; + } InputRecorder::InputRecorder() {} @@ -119,7 +131,16 @@ namespace controller { exportToFile(data); } - void InputRecorder::loadRecording() { + void InputRecorder::loadRecording(const QString& path) { + QFileInfo info(path); + QString extension = info.suffix(); + if (extension != "gz") { + qWarning() << "Could not open file of that type"; + return; + } + QJsonObject data; + bool success = openFile(path, data); + qDebug() << "-------------------> loading file -------------->"; } void InputRecorder::stopRecording() { diff --git a/libraries/controllers/src/controllers/InputRecorder.h b/libraries/controllers/src/controllers/InputRecorder.h index 5417cdc927..8656966962 100644 --- a/libraries/controllers/src/controllers/InputRecorder.h +++ b/libraries/controllers/src/controllers/InputRecorder.h @@ -13,6 +13,8 @@ #include #include +#include + #include "Pose.h" #include "Actions.h" @@ -28,7 +30,7 @@ namespace controller { static InputRecorder* getInstance(); void saveRecording(); - void loadRecording(); + void loadRecording(const QString& path); void startRecording(); void startPlayback(); void stopPlayback(); diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp index f09e366df8..9225579732 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.cpp +++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp @@ -175,6 +175,16 @@ namespace controller { inputRecorder->stopPlayback(); } + void ScriptingInterface::saveInputRecording() { + InputRecorder* inputRecorder = InputRecorder::getInstance(); + inputRecorder->saveRecording(); + } + + void ScriptingInterface::loadInputRecording(const QString& file) { + InputRecorder* inputRecorder = InputRecorder::getInstance(); + inputRecorder->loadRecording(file); + } + bool ScriptingInterface::triggerHapticPulseOnDevice(unsigned int device, float strength, float duration, controller::Hand hand) const { return DependencyManager::get()->triggerHapticPulseOnDevice(device, strength, duration, hand); } diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h index 961ed5ef72..9ed2c60790 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.h +++ b/libraries/controllers/src/controllers/ScriptingInterface.h @@ -103,6 +103,8 @@ namespace controller { Q_INVOKABLE void stopInputRecording(); Q_INVOKABLE void startInputPlayback(); Q_INVOKABLE void stopInputPlayback(); + Q_INVOKABLE void saveInputRecording(); + Q_INVOKABLE void loadInputRecording(const QString& file); bool isMouseCaptured() const { return _mouseCaptured; } bool isTouchCaptured() const { return _touchCaptured; } From d057dfebf0d2a9412f6ab397b101646d65c87ad7 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 24 Apr 2017 19:57:38 +0100 Subject: [PATCH 09/17] got input recording to work --- .../qml/hifi/tablet/InputRecorder.qml | 14 ++++ interface/src/Application.cpp | 5 +- .../src/controllers/InputRecorder.cpp | 81 ++++++++++++++++--- 3 files changed, 86 insertions(+), 14 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/InputRecorder.qml b/interface/resources/qml/hifi/tablet/InputRecorder.qml index d726d16f9c..e4c3526839 100644 --- a/interface/resources/qml/hifi/tablet/InputRecorder.qml +++ b/interface/resources/qml/hifi/tablet/InputRecorder.qml @@ -110,6 +110,20 @@ Rectangle { } } + HifiControls.Button { + id: playBack + anchors.right: browse.left + anchors.top: selectedFile.bottom + anchors.topMargin: 10 + + text: "Playback" + color: hifi.buttons.black + enabled: true + onClicked: { + sendToScript({method: "playback"}); + } + } + function getFileSelected(file) { console.log("------------> file selected <----------------"); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 633c41c609..35853ab34c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2740,7 +2740,7 @@ void Application::keyPressEvent(QKeyEvent* event) { offscreenUi->load("Browser.qml"); } else if (isOption) { controller::InputRecorder* inputRecorder = controller::InputRecorder::getInstance(); - inputRecorder->saveRecording(); + inputRecorder->stopPlayback(); } break; @@ -2939,9 +2939,6 @@ void Application::keyPressEvent(QKeyEvent* event) { Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, !isFirstPersonChecked); Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, isFirstPersonChecked); cameraMenuChanged(); - } else if (isOption) { - controller::InputRecorder* inputRecorder = controller::InputRecorder::getInstance(); - inputRecorder->toggleRecording(); } break; } diff --git a/libraries/controllers/src/controllers/InputRecorder.cpp b/libraries/controllers/src/controllers/InputRecorder.cpp index 782f44d0ac..486405767b 100644 --- a/libraries/controllers/src/controllers/InputRecorder.cpp +++ b/libraries/controllers/src/controllers/InputRecorder.cpp @@ -57,6 +57,36 @@ namespace controller { return newPose; } + Pose jsonObjectToPose(const QJsonObject object) { + Pose pose; + QJsonArray translation = object["translation"].toArray(); + QJsonArray rotation = object["rotation"].toArray(); + QJsonArray velocity = object["velocity"].toArray(); + QJsonArray angularVelocity = object["angularVelocity"].toArray(); + + pose.valid = object["valid"].toBool(); + + pose.translation.x = translation[0].toDouble(); + pose.translation.y = translation[1].toDouble(); + pose.translation.z = translation[2].toDouble(); + + pose.rotation.x = rotation[0].toDouble(); + pose.rotation.y = rotation[1].toDouble(); + pose.rotation.z = rotation[2].toDouble(); + pose.rotation.w = rotation[3].toDouble(); + + pose.velocity.x = velocity[0].toDouble(); + pose.velocity.y = velocity[1].toDouble(); + pose.velocity.z = velocity[2].toDouble(); + + pose.angularVelocity.x = angularVelocity[0].toDouble(); + pose.angularVelocity.y = angularVelocity[1].toDouble(); + pose.angularVelocity.z = angularVelocity[2].toDouble(); + + return pose; + } + + void exportToFile(QJsonObject& object) { if (!QDir(SAVE_DIRECTORY).exists()) { QDir().mkdir(SAVE_DIRECTORY); @@ -65,6 +95,7 @@ namespace controller { QString timeStamp = QDateTime::currentDateTime().toString(Qt::ISODate); timeStamp.replace(":", "-"); QString fileName = SAVE_DIRECTORY + FILE_PREFIX_NAME + timeStamp + COMPRESS_EXTENSION; + qDebug() << fileName; QFile saveFile (fileName); if (!saveFile.open(QIODevice::WriteOnly)) { qWarning() << "could not open file: " << fileName; @@ -75,16 +106,19 @@ namespace controller { saveFile.write(compressedData); } - bool openFile(const QString& file, QJsonObject& object) { + QJsonObject openFile(const QString& file, bool& status) { + QJsonObject object; QFile openFile(file); if (!openFile.open(QIODevice::ReadOnly)) { qWarning() << "could not open file: " << file; - return false; + status = false; + return object; } QByteArray compressedData = qUncompress(openFile.readAll()); - QJsonDocument jsonDoc = QJsonDocument::fromBinaryData(compressedData); + QJsonDocument jsonDoc = QJsonDocument::fromJson(compressedData); object = jsonDoc.object(); - return true; + status = true; + return object; } InputRecorder::InputRecorder() {} @@ -132,15 +166,42 @@ namespace controller { } void InputRecorder::loadRecording(const QString& path) { - QFileInfo info(path); - QString extension = info.suffix(); + resetFrame(); + _poseStateList.clear(); + _actionStateList.clear(); + QString filePath = path; + filePath.remove(0,8); + QFileInfo info(filePath); + QString extension = info.suffix(); if (extension != "gz") { - qWarning() << "Could not open file of that type"; + qWarning() << "Could not open file of type " << extension; return; } - QJsonObject data; - bool success = openFile(path, data); - qDebug() << "-------------------> loading file -------------->"; + bool success = false; + QJsonObject data = openFile(info.absoluteFilePath(), success); + int count = 0; + if (success) { + _framesRecorded = data["frameCount"].toInt(); + QJsonArray actionArrayList = data["actionList"].toArray(); + QJsonArray poseArrayList = data["poseList"].toArray(); + for (int actionIndex = 0; actionIndex < actionArrayList.size(); actionIndex++) { + QJsonArray actionState = actionArrayList[actionIndex].toArray(); + for (int index = 0; index < actionState.size(); index++) { + _currentFrameActions[index] = actionState[index].toInt(); + } + _actionStateList.push_back(_currentFrameActions); + _currentFrameActions = ActionStates(toInt(Action::NUM_ACTIONS)); + } + + for (int poseIndex = 0; poseIndex < poseArrayList.size(); poseIndex++) { + QJsonArray poseState = poseArrayList[poseIndex].toArray(); + for (int index = 0; index < poseState.size(); index++) { + _currentFramePoses[index] = jsonObjectToPose(poseState[index].toObject()); + } + _poseStateList.push_back(_currentFramePoses); + _currentFramePoses = PoseStates(toInt(Action::NUM_ACTIONS)); + } + } } void InputRecorder::stopRecording() { From 367a6ac03cc13aded3fb33d3fa23e12133ad3bf2 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 24 Apr 2017 22:09:01 +0100 Subject: [PATCH 10/17] first prototype --- .../qml/hifi/tablet/InputRecorder.qml | 76 +++++++++++-------- .../src/controllers/InputRecorder.cpp | 12 ++- .../src/controllers/InputRecorder.h | 3 +- 3 files changed, 58 insertions(+), 33 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/InputRecorder.qml b/interface/resources/qml/hifi/tablet/InputRecorder.qml index e4c3526839..b9b5406a72 100644 --- a/interface/resources/qml/hifi/tablet/InputRecorder.qml +++ b/interface/resources/qml/hifi/tablet/InputRecorder.qml @@ -24,6 +24,7 @@ Rectangle { color: hifi.colors.baseGray; property string path: "" property var dialog: null; + property bool recording: false; Component { id: fileDialog; TabletFileDialog { } } Row { @@ -37,36 +38,50 @@ Rectangle { top: parent.top topMargin: 10 } + HifiControls.Button { id: start - text: "Start" - color: hifi.buttons.blue + text: "Start Recoring" + color: hifi.buttons.black enabled: true onClicked: { - sendToScript({method: "Start"}); - } - } - - HifiControls.Button { - id: stop - text: "Stop" - color: hifi.buttons.blue - enabled: true - onClicked: { - sendToScript({method: "Stop"}); + if (inputRecorder.recording) { + sendToScript({method: "Stop"}); + inputRecorder.recording = false; + start.text = "Start Recording"; + } else { + sendToScript({method: "Start"}); + inputRecorder.recording = true; + start.text = "Stop Recording"; + } } } HifiControls.Button { id: save - text: "Save" - color: hifi.buttons.blue + text: "Save Recording" + color: hifi.buttons.black enabled: true onClicked: { sendToScript({method: "Save"}); } } + + HifiControls.Button { + id: playBack + anchors.right: browse.left + anchors.top: selectedFile.bottom + anchors.topMargin: 10 + text: "Play Recording" + color: hifi.buttons.black + enabled: true + onClicked: { + sendToScript({method: "playback"}); + HMD.closeTablet(); + } + } + } HifiControls.VerticalSpacer {} @@ -110,24 +125,25 @@ Rectangle { } } - HifiControls.Button { - id: playBack - anchors.right: browse.left - anchors.top: selectedFile.bottom - anchors.topMargin: 10 - - text: "Playback" - color: hifi.buttons.black - enabled: true - onClicked: { - sendToScript({method: "playback"}); + Column { + id: notes + anchors.centerIn: parent; + spacing: 20 + + Text { + text: "All files are saved under the folder 'hifi-input-recording' in your home directory"; + color: "white" + font.pointSize: 10 + } + + Text { + text: "To cancel a recording playback press Alt-B" + color: "white" + font.pointSize: 10 } } - - + function getFileSelected(file) { - console.log("------------> file selected <----------------"); - //sendToScript({ method: "Load", params: { file: file} }); selectedFile.text = file; inputRecorder.path = file; } diff --git a/libraries/controllers/src/controllers/InputRecorder.cpp b/libraries/controllers/src/controllers/InputRecorder.cpp index 486405767b..8deb89e062 100644 --- a/libraries/controllers/src/controllers/InputRecorder.cpp +++ b/libraries/controllers/src/controllers/InputRecorder.cpp @@ -166,6 +166,10 @@ namespace controller { } void InputRecorder::loadRecording(const QString& path) { + _recording = false; + _playback = false; + _loading = true; + _playCount = 0; resetFrame(); _poseStateList.clear(); _actionStateList.clear(); @@ -174,16 +178,16 @@ namespace controller { QFileInfo info(filePath); QString extension = info.suffix(); if (extension != "gz") { - qWarning() << "Could not open file of type " << extension; + qWarning() << "can not load file with exentsion of " << extension; return; } bool success = false; QJsonObject data = openFile(info.absoluteFilePath(), success); - int count = 0; if (success) { _framesRecorded = data["frameCount"].toInt(); QJsonArray actionArrayList = data["actionList"].toArray(); QJsonArray poseArrayList = data["poseList"].toArray(); + for (int actionIndex = 0; actionIndex < actionArrayList.size(); actionIndex++) { QJsonArray actionState = actionArrayList[actionIndex].toArray(); for (int index = 0; index < actionState.size(); index++) { @@ -202,6 +206,8 @@ namespace controller { _currentFramePoses = PoseStates(toInt(Action::NUM_ACTIONS)); } } + + _loading = false; } void InputRecorder::stopRecording() { @@ -211,10 +217,12 @@ namespace controller { void InputRecorder::startPlayback() { _playback = true; _recording = false; + _playCount = 0; } void InputRecorder::stopPlayback() { _playback = false; + _playCount = 0; } void InputRecorder::setActionState(controller::Action action, float value) { diff --git a/libraries/controllers/src/controllers/InputRecorder.h b/libraries/controllers/src/controllers/InputRecorder.h index 8656966962..20b30f4b6e 100644 --- a/libraries/controllers/src/controllers/InputRecorder.h +++ b/libraries/controllers/src/controllers/InputRecorder.h @@ -39,7 +39,7 @@ namespace controller { void togglePlayback() { _playback = !_playback; } void resetFrame(); bool isRecording() { return _recording; } - bool isPlayingback() { return _playback; } + bool isPlayingback() { return (_playback && !_loading); } void setActionState(controller::Action action, float value); void setActionState(controller::Action action, const controller::Pose pose); float getActionState(controller::Action action); @@ -48,6 +48,7 @@ namespace controller { private: bool _recording { false }; bool _playback { false }; + bool _loading { false }; std::vector _poseStateList = std::vector(); std::vector _actionStateList = std::vector(); PoseStates _currentFramePoses = PoseStates(toInt(Action::NUM_ACTIONS)); From 8705db07e542bb7f63d491b52d8e6c479f0ee64f Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 24 Apr 2017 22:22:49 +0100 Subject: [PATCH 11/17] removed dead code --- libraries/controllers/src/controllers/UserInputMapper.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp index be10c46538..71b052bfe4 100755 --- a/libraries/controllers/src/controllers/UserInputMapper.cpp +++ b/libraries/controllers/src/controllers/UserInputMapper.cpp @@ -510,7 +510,6 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) { } // If the source hasn't been written yet, defer processing of this route - auto inputRecorder = InputRecorder::getInstance(); auto source = route->source; auto sourceInput = source->getInput(); if (sourceInput.device == STANDARD_DEVICE && !force && source->writeable()) { From b023356fb78ad6a6aca7ed50f6cdbefb518597a8 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 24 Apr 2017 22:29:13 +0100 Subject: [PATCH 12/17] added javascript file --- scripts/developer/inputRecording.js | 73 +++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 scripts/developer/inputRecording.js diff --git a/scripts/developer/inputRecording.js b/scripts/developer/inputRecording.js new file mode 100644 index 0000000000..26abea72bb --- /dev/null +++ b/scripts/developer/inputRecording.js @@ -0,0 +1,73 @@ +// +// Created by Dante Ruiz 2017/04/17 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { + var onRecordingScreen = false; + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var button = tablet.addButton({ + text: "IRecord" + }); + function onClick() { + if (onRecordingScreen) { + tablet.gotoHomeScreen(); + } else { + tablet.loadQMLSource("InputRecorder.qml"); + } + } + + button.clicked.connect(onClick); + tablet.fromQml.connect(fromQml); + function fromQml(message) { + switch (message.method) { + case "Start": + startRecording(); + break; + case "Stop": + stopRecording(); + break; + case "Save": + saveRecording(); + break; + case "Load": + loadRecording(message.params.file); + break; + case "playback": + startPlayback(); + break; + } + + } + + function startRecording() { + Controller.startInputRecording(); + } + + function stopRecording() { + Controller.stopInputRecording(); + } + + function saveRecording() { + Controller.saveInputRecording(); + } + + function loadRecording(file) { + Controller.loadInputRecording(file); + } + + function startPlayback() { + Controller.startInputPlayback(); + } + + Script.scriptEnding.connect(function () { + button.clicked.disconnect(onClick); + if (tablet) { + tablet.removeButton(button); + } + }); + +}()); From 2a997f2a4d4ba5e1bcff7a8c257fe93b83cb5572 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 24 Apr 2017 23:08:02 +0100 Subject: [PATCH 13/17] fix for ubuntu build error --- libraries/controllers/src/controllers/InputRecorder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/controllers/src/controllers/InputRecorder.cpp b/libraries/controllers/src/controllers/InputRecorder.cpp index 8deb89e062..cd41c40804 100644 --- a/libraries/controllers/src/controllers/InputRecorder.cpp +++ b/libraries/controllers/src/controllers/InputRecorder.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include QString SAVE_DIRECTORY = QDir::homePath()+"/hifi-input-recordings/"; From 8c020a0ec2af180c40bdba8971d007de77aba3fe Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 25 Apr 2017 18:01:19 +0100 Subject: [PATCH 14/17] saving work --- .../qml/hifi/tablet/InputRecorder.qml | 37 ++++++++++++------- libraries/controllers/CMakeLists.txt | 2 +- .../src/controllers/InputRecorder.cpp | 9 ++++- libraries/ui/src/FileDialogHelper.cpp | 4 ++ libraries/ui/src/FileDialogHelper.h | 1 + scripts/developer/inputRecording.js | 22 +++++++++++ 6 files changed, 58 insertions(+), 17 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/InputRecorder.qml b/interface/resources/qml/hifi/tablet/InputRecorder.qml index b9b5406a72..77f21e338c 100644 --- a/interface/resources/qml/hifi/tablet/InputRecorder.qml +++ b/interface/resources/qml/hifi/tablet/InputRecorder.qml @@ -98,25 +98,15 @@ Rectangle { } + + HifiControls.Button { - id: load + id: browse anchors.right: parent.right anchors.top: selectedFile.bottom anchors.topMargin: 10 - text: "Load" - color: hifi.buttons.black - enabled: true - onClicked: sendToScript({method: "Load", params: {file: path }}); - } - - HifiControls.Button { - id: browse - anchors.right: load.left - anchors.top: selectedFile.bottom - anchors.topMargin: 10 - - text: "Browse" + text: "Load..." color: hifi.buttons.black enabled: true onClicked: { @@ -146,6 +136,25 @@ Rectangle { function getFileSelected(file) { selectedFile.text = file; inputRecorder.path = file; + sendToScript({method: "Load", params: {file: path }}); + } + + function fromScript(message) { + switch (message.method) { + case "update": + updateButtonStatus(message.params); + break; + } + } + + function updateButtonStatus(status) { + inputRecorder.recording = status; + + if (inputRecorder.recording) { + start.text = "Stop Recording"; + } else { + start.text = "Start Recording"; + } } } diff --git a/libraries/controllers/CMakeLists.txt b/libraries/controllers/CMakeLists.txt index 384218691a..bf226f2647 100644 --- a/libraries/controllers/CMakeLists.txt +++ b/libraries/controllers/CMakeLists.txt @@ -10,4 +10,4 @@ GroupSources("src/controllers") add_dependency_external_projects(glm) find_package(GLM REQUIRED) -target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) +target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS} "${CMAKE_BINARY_DIR}/includes") diff --git a/libraries/controllers/src/controllers/InputRecorder.cpp b/libraries/controllers/src/controllers/InputRecorder.cpp index cd41c40804..5a10cc1d4a 100644 --- a/libraries/controllers/src/controllers/InputRecorder.cpp +++ b/libraries/controllers/src/controllers/InputRecorder.cpp @@ -17,9 +17,14 @@ #include #include #include -#include +#include +#include -QString SAVE_DIRECTORY = QDir::homePath()+"/hifi-input-recordings/"; +#include +#include + +QString SAVE_DIRECTORY = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/" + BuildInfo::INTERFACE_NAME + + "/interface" + "/hifi-input-recordings/"; QString FILE_PREFIX_NAME = "input-recording-"; QString COMPRESS_EXTENSION = ".tar.gz"; namespace controller { diff --git a/libraries/ui/src/FileDialogHelper.cpp b/libraries/ui/src/FileDialogHelper.cpp index 2752de8592..6d14adf1db 100644 --- a/libraries/ui/src/FileDialogHelper.cpp +++ b/libraries/ui/src/FileDialogHelper.cpp @@ -26,6 +26,10 @@ QStringList FileDialogHelper::standardPath(StandardLocation location) { return QStandardPaths::standardLocations(static_cast(location)); } +QString FileDialogHelper::writableLocation(StandardLocation location) { + return QStandardPaths::writableLocation(static_cast(location)); +} + QString FileDialogHelper::urlToPath(const QUrl& url) { return url.toLocalFile(); } diff --git a/libraries/ui/src/FileDialogHelper.h b/libraries/ui/src/FileDialogHelper.h index 6c352ecdfc..12fd60daac 100644 --- a/libraries/ui/src/FileDialogHelper.h +++ b/libraries/ui/src/FileDialogHelper.h @@ -48,6 +48,7 @@ public: Q_INVOKABLE QUrl home(); Q_INVOKABLE QStringList standardPath(StandardLocation location); + Q_INVOKABLE QString writableLocation(StandardLocation location); Q_INVOKABLE QStringList drives(); Q_INVOKABLE QString urlToPath(const QUrl& url); Q_INVOKABLE bool urlIsDir(const QUrl& url); diff --git a/scripts/developer/inputRecording.js b/scripts/developer/inputRecording.js index 26abea72bb..7a3809c058 100644 --- a/scripts/developer/inputRecording.js +++ b/scripts/developer/inputRecording.js @@ -7,6 +7,7 @@ // (function() { + var recording = false; var onRecordingScreen = false; var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ @@ -15,13 +16,20 @@ function onClick() { if (onRecordingScreen) { tablet.gotoHomeScreen(); + onRecordingScreen = false; } else { tablet.loadQMLSource("InputRecorder.qml"); + onRecordingScreen = true; } } + function onScreenChanged(type, url) { + onRecordingScreen = false; + } + button.clicked.connect(onClick); tablet.fromQml.connect(fromQml); + tablet.screenChanged.connect(onScreenChanged); function fromQml(message) { switch (message.method) { case "Start": @@ -45,10 +53,12 @@ function startRecording() { Controller.startInputRecording(); + recording = true; } function stopRecording() { Controller.stopInputRecording(); + recording = false; } function saveRecording() { @@ -63,11 +73,23 @@ Controller.startInputPlayback(); } + function sendToQml(message) { + tablet.sendToQml(message); + } + + function update() { + sendToQml({method: "update", params: recording}); + } + + Script.setInterval(update, 60); + Script.scriptEnding.connect(function () { button.clicked.disconnect(onClick); if (tablet) { tablet.removeButton(button); } + + Controller.stopInputRecording(); }); }()); From 79d827c6becf9ad81865801fcb7304ae606b1b0a Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 26 Apr 2017 16:52:51 +0100 Subject: [PATCH 15/17] added requested features --- interface/resources/qml/hifi/tablet/InputRecorder.qml | 9 +++++++++ libraries/controllers/src/controllers/InputRecorder.cpp | 7 +++++-- libraries/controllers/src/controllers/InputRecorder.h | 1 + .../controllers/src/controllers/ScriptingInterface.cpp | 5 +++++ .../controllers/src/controllers/ScriptingInterface.h | 1 + scripts/developer/inputRecording.js | 8 ++++++++ 6 files changed, 29 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/InputRecorder.qml b/interface/resources/qml/hifi/tablet/InputRecorder.qml index 77f21e338c..6b307b2f79 100644 --- a/interface/resources/qml/hifi/tablet/InputRecorder.qml +++ b/interface/resources/qml/hifi/tablet/InputRecorder.qml @@ -23,6 +23,7 @@ Rectangle { signal sendToScript(var message); color: hifi.colors.baseGray; property string path: "" + property string dir: "" property var dialog: null; property bool recording: false; @@ -49,6 +50,7 @@ Rectangle { sendToScript({method: "Stop"}); inputRecorder.recording = false; start.text = "Start Recording"; + selectedFile.text = ""; } else { sendToScript({method: "Start"}); inputRecorder.recording = true; @@ -111,6 +113,9 @@ Rectangle { enabled: true onClicked: { dialog = fileDialog.createObject(inputRecorder); + dialog.caption = "InputRecorder"; + console.log(dialog.dir); + dialog.dir = "file:///" + inputRecorder.dir; dialog.selectedFile.connect(getFileSelected); } } @@ -144,6 +149,10 @@ Rectangle { case "update": updateButtonStatus(message.params); break; + case "path": + console.log(message.params); + inputRecorder.dir = message.params; + break; } } diff --git a/libraries/controllers/src/controllers/InputRecorder.cpp b/libraries/controllers/src/controllers/InputRecorder.cpp index 5a10cc1d4a..2d2cd40739 100644 --- a/libraries/controllers/src/controllers/InputRecorder.cpp +++ b/libraries/controllers/src/controllers/InputRecorder.cpp @@ -23,8 +23,7 @@ #include #include -QString SAVE_DIRECTORY = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/" + BuildInfo::INTERFACE_NAME + - "/interface" + "/hifi-input-recordings/"; +QString SAVE_DIRECTORY = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/" + BuildInfo::MODIFIED_ORGANIZATION + "/" + BuildInfo::INTERFACE_NAME + "/hifi-input-recordings/"; QString FILE_PREFIX_NAME = "input-recording-"; QString COMPRESS_EXTENSION = ".tar.gz"; namespace controller { @@ -135,6 +134,10 @@ namespace controller { return &inputRecorder; } + QString InputRecorder::getSaveDirectory() { + return SAVE_DIRECTORY; + } + void InputRecorder::startRecording() { _recording = true; _playback = false; diff --git a/libraries/controllers/src/controllers/InputRecorder.h b/libraries/controllers/src/controllers/InputRecorder.h index 20b30f4b6e..d1cc9a32eb 100644 --- a/libraries/controllers/src/controllers/InputRecorder.h +++ b/libraries/controllers/src/controllers/InputRecorder.h @@ -44,6 +44,7 @@ namespace controller { void setActionState(controller::Action action, const controller::Pose pose); float getActionState(controller::Action action); controller::Pose getPoseState(controller::Action action); + QString getSaveDirectory(); void frameTick(); private: bool _recording { false }; diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp index 9225579732..16db22401f 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.cpp +++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp @@ -185,6 +185,11 @@ namespace controller { inputRecorder->loadRecording(file); } + QString ScriptingInterface::getInputRecorderSaveDirectory() { + InputRecorder* inputRecorder = InputRecorder::getInstance(); + return inputRecorder->getSaveDirectory(); + } + bool ScriptingInterface::triggerHapticPulseOnDevice(unsigned int device, float strength, float duration, controller::Hand hand) const { return DependencyManager::get()->triggerHapticPulseOnDevice(device, strength, duration, hand); } diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h index 9ed2c60790..2c60ca25f5 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.h +++ b/libraries/controllers/src/controllers/ScriptingInterface.h @@ -105,6 +105,7 @@ namespace controller { Q_INVOKABLE void stopInputPlayback(); Q_INVOKABLE void saveInputRecording(); Q_INVOKABLE void loadInputRecording(const QString& file); + Q_INVOKABLE QString getInputRecorderSaveDirectory(); bool isMouseCaptured() const { return _mouseCaptured; } bool isTouchCaptured() const { return _touchCaptured; } diff --git a/scripts/developer/inputRecording.js b/scripts/developer/inputRecording.js index 7a3809c058..85bda623b3 100644 --- a/scripts/developer/inputRecording.js +++ b/scripts/developer/inputRecording.js @@ -9,6 +9,7 @@ (function() { var recording = false; var onRecordingScreen = false; + var passedSaveDirectory = false; var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ text: "IRecord" @@ -25,6 +26,7 @@ function onScreenChanged(type, url) { onRecordingScreen = false; + passedSaveDirectory = false; } button.clicked.connect(onClick); @@ -78,6 +80,12 @@ } function update() { + + if (!passedSaveDirectory) { + var directory = Controller.getInputRecorderSaveDirectory(); + sendToQml({method: "path", params: directory}); + passedSaveDirectory = true; + } sendToQml({method: "update", params: recording}); } From 4df953d5100891f215e8ec578153533644d07a5b Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 26 Apr 2017 19:14:14 +0100 Subject: [PATCH 16/17] fixed text issue --- interface/resources/qml/hifi/tablet/InputRecorder.qml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/InputRecorder.qml b/interface/resources/qml/hifi/tablet/InputRecorder.qml index 6b307b2f79..656034d5db 100644 --- a/interface/resources/qml/hifi/tablet/InputRecorder.qml +++ b/interface/resources/qml/hifi/tablet/InputRecorder.qml @@ -50,7 +50,7 @@ Rectangle { sendToScript({method: "Stop"}); inputRecorder.recording = false; start.text = "Start Recording"; - selectedFile.text = ""; + selectedFile.text = "Current recording is not saved"; } else { sendToScript({method: "Start"}); inputRecorder.recording = true; @@ -66,6 +66,7 @@ Rectangle { enabled: true onClicked: { sendToScript({method: "Save"}); + selectedFile.text = ""; } } @@ -126,7 +127,7 @@ Rectangle { spacing: 20 Text { - text: "All files are saved under the folder 'hifi-input-recording' in your home directory"; + text: "All files are saved under the folder 'hifi-input-recording' in interfaces AppData directory"; color: "white" font.pointSize: 10 } From 95d6a451c69f666ffacfebbc6938fed60808cb63 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 26 Apr 2017 22:14:53 +0100 Subject: [PATCH 17/17] fixed work mapping --- interface/resources/qml/hifi/tablet/InputRecorder.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/tablet/InputRecorder.qml b/interface/resources/qml/hifi/tablet/InputRecorder.qml index 656034d5db..76b122d07d 100644 --- a/interface/resources/qml/hifi/tablet/InputRecorder.qml +++ b/interface/resources/qml/hifi/tablet/InputRecorder.qml @@ -127,7 +127,7 @@ Rectangle { spacing: 20 Text { - text: "All files are saved under the folder 'hifi-input-recording' in interfaces AppData directory"; + text: "All files are saved under the folder 'hifi-input-recording' in AppData directory"; color: "white" font.pointSize: 10 }