fixed some input recorder design issue

This commit is contained in:
Dante Ruiz 2017-06-01 00:23:37 +01:00
parent 4a52f4090d
commit cca0fa6600
4 changed files with 111 additions and 47 deletions

View file

@ -42,8 +42,6 @@ enum class Action {
LEFT_HAND = NUM_COMBINED_AXES, LEFT_HAND = NUM_COMBINED_AXES,
RIGHT_HAND, RIGHT_HAND,
LEFT_ARM,
RIGHT_ARM,
LEFT_FOOT, LEFT_FOOT,
RIGHT_FOOT, RIGHT_FOOT,
HIPS, HIPS,
@ -103,6 +101,8 @@ enum class Action {
// Bisected aliases for TRANSLATE_CAMERA_Z // Bisected aliases for TRANSLATE_CAMERA_Z
BOOM_IN, BOOM_IN,
BOOM_OUT, BOOM_OUT,
LEFT_ARM,
RIGHT_ARM,
NUM_ACTIONS, NUM_ACTIONS,

View file

@ -9,7 +9,6 @@
#include "InputRecorder.h" #include "InputRecorder.h"
#include <QJsonArray> #include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument> #include <QJsonDocument>
#include <QFile> #include <QFile>
#include <QDir> #include <QDir>
@ -19,9 +18,12 @@
#include <QByteArray> #include <QByteArray>
#include <QStandardPaths> #include <QStandardPaths>
#include <PathUtils.h> #include <PathUtils.h>
#include <QUrl>
#include <BuildInfo.h> #include <BuildInfo.h>
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include <DependencyManager.h>
#include "UserInputMapper.h"
QString SAVE_DIRECTORY = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/" + BuildInfo::MODIFIED_ORGANIZATION + "/" + BuildInfo::INTERFACE_NAME + "/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 FILE_PREFIX_NAME = "input-recording-";
@ -108,6 +110,7 @@ namespace controller {
QJsonDocument saveData(object); QJsonDocument saveData(object);
QByteArray compressedData = qCompress(saveData.toJson(QJsonDocument::Compact)); QByteArray compressedData = qCompress(saveData.toJson(QJsonDocument::Compact));
saveFile.write(compressedData); saveFile.write(compressedData);
saveFile.close();
} }
QJsonObject openFile(const QString& file, bool& status) { QJsonObject openFile(const QString& file, bool& status) {
@ -122,6 +125,7 @@ namespace controller {
QJsonDocument jsonDoc = QJsonDocument::fromJson(compressedData); QJsonDocument jsonDoc = QJsonDocument::fromJson(compressedData);
object = jsonDoc.object(); object = jsonDoc.object();
status = true; status = true;
openFile.close();
return object; return object;
} }
@ -146,31 +150,43 @@ namespace controller {
_actionStateList.clear(); _actionStateList.clear();
} }
void InputRecorder::saveRecording() { QJsonObject InputRecorder::recordDataToJson() {
QJsonObject data; QJsonObject data;
data["frameCount"] = _framesRecorded; data["frameCount"] = _framesRecorded;
data["version"] = "1.0";
QJsonArray actionArrayList; QJsonArray actionArrayList;
QJsonArray poseArrayList; QJsonArray poseArrayList;
for(const ActionStates actionState: _actionStateList) { for(const ActionStates actionState: _actionStateList) {
QJsonArray actionArray; QJsonArray actionArray;
for (const float value: actionState) { for (const auto action: actionState) {
actionArray.append(value); QJsonObject actionJson;
actionJson["name"] = action.first;
actionJson["value"] = action.second;
actionArray.append(actionJson);
} }
actionArrayList.append(actionArray); actionArrayList.append(actionArray);
} }
for (const PoseStates poseState: _poseStateList) { for (const PoseStates poseState: _poseStateList) {
QJsonArray poseArray; QJsonArray poseArray;
for (const Pose pose: poseState) { for (const auto pose: poseState) {
poseArray.append(poseToJsonObject(pose)); QJsonObject poseJson;
poseJson["name"] = pose.first;
poseJson["pose"] = poseToJsonObject(pose.second);
poseArray.append(poseJson);
} }
poseArrayList.append(poseArray); poseArrayList.append(poseArray);
} }
data["actionList"] = actionArrayList; data["actionList"] = actionArrayList;
data["poseList"] = poseArrayList; data["poseList"] = poseArrayList;
exportToFile(data);
return data;
}
void InputRecorder::saveRecording() {
exportToFile(recordDataToJson());
} }
void InputRecorder::loadRecording(const QString& path) { void InputRecorder::loadRecording(const QString& path) {
@ -181,8 +197,8 @@ namespace controller {
resetFrame(); resetFrame();
_poseStateList.clear(); _poseStateList.clear();
_actionStateList.clear(); _actionStateList.clear();
QString filePath = path; QUrl urlPath(path);
filePath.remove(0,8); QString filePath = urlPath.toLocalFile();
QFileInfo info(filePath); QFileInfo info(filePath);
QString extension = info.suffix(); QString extension = info.suffix();
if (extension != "gz") { if (extension != "gz") {
@ -190,8 +206,9 @@ namespace controller {
return; return;
} }
bool success = false; bool success = false;
QJsonObject data = openFile(info.absoluteFilePath(), success); QJsonObject data = openFile(filePath, success);
if (success) { auto keyValue = data.find("version");
if (success && keyValue != data.end()) {
_framesRecorded = data["frameCount"].toInt(); _framesRecorded = data["frameCount"].toInt();
QJsonArray actionArrayList = data["actionList"].toArray(); QJsonArray actionArrayList = data["actionList"].toArray();
QJsonArray poseArrayList = data["poseList"].toArray(); QJsonArray poseArrayList = data["poseList"].toArray();
@ -199,25 +216,71 @@ namespace controller {
for (int actionIndex = 0; actionIndex < actionArrayList.size(); actionIndex++) { for (int actionIndex = 0; actionIndex < actionArrayList.size(); actionIndex++) {
QJsonArray actionState = actionArrayList[actionIndex].toArray(); QJsonArray actionState = actionArrayList[actionIndex].toArray();
for (int index = 0; index < actionState.size(); index++) { for (int index = 0; index < actionState.size(); index++) {
_currentFrameActions[index] = actionState[index].toDouble(); QJsonObject actionObject = actionState[index].toObject();;
_currentFrameActions[actionObject["name"].toString()] = actionObject["value"].toDouble();
} }
_actionStateList.push_back(_currentFrameActions); _actionStateList.push_back(_currentFrameActions);
_currentFrameActions = ActionStates(toInt(Action::NUM_ACTIONS)); _currentFrameActions.clear();
} }
for (int poseIndex = 0; poseIndex < poseArrayList.size(); poseIndex++) { for (int poseIndex = 0; poseIndex < poseArrayList.size(); poseIndex++) {
QJsonArray poseState = poseArrayList[poseIndex].toArray(); QJsonArray poseState = poseArrayList[poseIndex].toArray();
for (int index = 0; index < poseState.size(); index++) { for (int index = 0; index < poseState.size(); index++) {
_currentFramePoses[index] = jsonObjectToPose(poseState[index].toObject()); QJsonObject poseObject = poseState[index].toObject();
_currentFramePoses[poseObject["name"].toString()] = jsonObjectToPose(poseObject["pose"].toObject());
} }
_poseStateList.push_back(_currentFramePoses); _poseStateList.push_back(_currentFramePoses);
_currentFramePoses = PoseStates(toInt(Action::NUM_ACTIONS)); _currentFramePoses.clear();
} }
} else if (success) {
//convert recording to new reacording standard and rewrite file
auto userInputMapper = DependencyManager::get<UserInputMapper>();
_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++) {
QString actionName = userInputMapper->getActionName(Action(index));
_currentFrameActions[actionName] = actionState[index].toDouble();
}
_actionStateList.push_back(_currentFrameActions);
_currentFrameActions.clear();
}
for (int poseIndex = 0; poseIndex < poseArrayList.size(); poseIndex++) {
QJsonArray poseState = poseArrayList[poseIndex].toArray();
for (int index = 0; index < poseState.size(); index++) {
QString actionName = userInputMapper->getActionName(Action(index));
_currentFramePoses[actionName] = jsonObjectToPose(poseState[index].toObject());
}
_poseStateList.push_back(_currentFramePoses);
_currentFramePoses.clear();
}
convertFile(filePath);
} }
_loading = false; _loading = false;
} }
void InputRecorder::convertFile(const QString& path) {
if (!QDir(SAVE_DIRECTORY).exists()) {
QDir().mkdir(SAVE_DIRECTORY);
}
QJsonObject data = recordDataToJson();
QFile saveFile (path);
if (!saveFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
qWarning() << "could not open file: " << path;
return;
}
QJsonDocument saveData(data);
QByteArray compressedData = qCompress(saveData.toJson(QJsonDocument::Compact));
saveFile.write(compressedData);
}
void InputRecorder::stopRecording() { void InputRecorder::stopRecording() {
_recording = false; _recording = false;
_framesRecorded = (int)_actionStateList.size(); _framesRecorded = (int)_actionStateList.size();
@ -234,41 +297,36 @@ namespace controller {
_playCount = 0; _playCount = 0;
} }
void InputRecorder::setActionState(controller::Action action, float value) { void InputRecorder::setActionState(const QString& action, float value) {
if (_recording) { if (_recording) {
_currentFrameActions[toInt(action)] += value; _currentFrameActions[action] += value;
} }
} }
void InputRecorder::setActionState(controller::Action action, const controller::Pose pose) { void InputRecorder::setActionState(const QString& action, const controller::Pose& pose) {
if (_recording) { if (_recording) {
_currentFramePoses[toInt(action)] = pose; _currentFramePoses[action] = pose;
} }
} }
void InputRecorder::resetFrame() { void InputRecorder::resetFrame() {
if (_recording) { if (_recording) {
for(auto& channel : _currentFramePoses) { _currentFramePoses.clear();
channel = Pose(); _currentFrameActions.clear();
}
for(auto& channel : _currentFrameActions) {
channel = 0.0f;
}
} }
} }
float InputRecorder::getActionState(controller::Action action) { float InputRecorder::getActionState(const QString& action) {
if (_actionStateList.size() > 0 ) { if (_actionStateList.size() > 0 ) {
return _actionStateList[_playCount][toInt(action)]; return _actionStateList[_playCount][action];
} }
return 0.0f; return 0.0f;
} }
controller::Pose InputRecorder::getPoseState(controller::Action action) { controller::Pose InputRecorder::getPoseState(const QString& action) {
if (_poseStateList.size() > 0) { if (_poseStateList.size() > 0) {
return _poseStateList[_playCount][toInt(action)]; return _poseStateList[_playCount][action];
} }
return Pose(); return Pose();

View file

@ -12,8 +12,10 @@
#include <mutex> #include <mutex>
#include <atomic> #include <atomic>
#include <vector> #include <vector>
#include <map>
#include <QString> #include <QString>
#include <QJsonObject>
#include "Pose.h" #include "Pose.h"
#include "Actions.h" #include "Actions.h"
@ -21,8 +23,8 @@
namespace controller { namespace controller {
class InputRecorder { class InputRecorder {
public: public:
using PoseStates = std::vector<Pose>; using PoseStates = std::map<QString, Pose>;
using ActionStates = std::vector<float>; using ActionStates = std::map<QString, float>;
InputRecorder(); InputRecorder();
~InputRecorder(); ~InputRecorder();
@ -31,6 +33,7 @@ namespace controller {
void saveRecording(); void saveRecording();
void loadRecording(const QString& path); void loadRecording(const QString& path);
void convertFile(const QString& path);
void startRecording(); void startRecording();
void startPlayback(); void startPlayback();
void stopPlayback(); void stopPlayback();
@ -40,20 +43,21 @@ namespace controller {
void resetFrame(); void resetFrame();
bool isRecording() { return _recording; } bool isRecording() { return _recording; }
bool isPlayingback() { return (_playback && !_loading); } bool isPlayingback() { return (_playback && !_loading); }
void setActionState(controller::Action action, float value); void setActionState(const QString& action, float value);
void setActionState(controller::Action action, const controller::Pose pose); void setActionState(const QString& action, const controller::Pose& pose);
float getActionState(controller::Action action); float getActionState(const QString& action);
controller::Pose getPoseState(controller::Action action); controller::Pose getPoseState(const QString& action);
QString getSaveDirectory(); QString getSaveDirectory();
void frameTick(); void frameTick();
private: private:
QJsonObject recordDataToJson();
bool _recording { false }; bool _recording { false };
bool _playback { false }; bool _playback { false };
bool _loading { false }; bool _loading { false };
std::vector<PoseStates> _poseStateList = std::vector<PoseStates>(); std::vector<PoseStates> _poseStateList = std::vector<PoseStates>();
std::vector<ActionStates> _actionStateList = std::vector<ActionStates>(); std::vector<ActionStates> _actionStateList = std::vector<ActionStates>();
PoseStates _currentFramePoses = PoseStates(toInt(Action::NUM_ACTIONS)); PoseStates _currentFramePoses;
ActionStates _currentFrameActions = ActionStates(toInt(Action::NUM_ACTIONS)); ActionStates _currentFrameActions;
int _framesRecorded { 0 }; int _framesRecorded { 0 };
int _playCount { 0 }; int _playCount { 0 };

View file

@ -17,31 +17,33 @@ using namespace controller;
void ActionEndpoint::apply(float newValue, const Pointer& source) { void ActionEndpoint::apply(float newValue, const Pointer& source) {
InputRecorder* inputRecorder = InputRecorder::getInstance(); InputRecorder* inputRecorder = InputRecorder::getInstance();
auto userInputMapper = DependencyManager::get<UserInputMapper>();
QString actionName = userInputMapper->getActionName(Action(_input.getChannel()));
if(inputRecorder->isPlayingback()) { if(inputRecorder->isPlayingback()) {
newValue = inputRecorder->getActionState(Action(_input.getChannel())); newValue = inputRecorder->getActionState(actionName);
} }
_currentValue += newValue; _currentValue += newValue;
if (_input != Input::INVALID_INPUT) { if (_input != Input::INVALID_INPUT) {
auto userInputMapper = DependencyManager::get<UserInputMapper>();
userInputMapper->deltaActionState(Action(_input.getChannel()), newValue); userInputMapper->deltaActionState(Action(_input.getChannel()), newValue);
} }
inputRecorder->setActionState(Action(_input.getChannel()), newValue); inputRecorder->setActionState(actionName, newValue);
} }
void ActionEndpoint::apply(const Pose& value, const Pointer& source) { void ActionEndpoint::apply(const Pose& value, const Pointer& source) {
_currentPose = value; _currentPose = value;
InputRecorder* inputRecorder = InputRecorder::getInstance(); InputRecorder* inputRecorder = InputRecorder::getInstance();
inputRecorder->setActionState(Action(_input.getChannel()), _currentPose); auto userInputMapper = DependencyManager::get<UserInputMapper>();
QString actionName = userInputMapper->getActionName(Action(_input.getChannel()));
inputRecorder->setActionState(actionName, _currentPose);
if (inputRecorder->isPlayingback()) { if (inputRecorder->isPlayingback()) {
_currentPose = inputRecorder->getPoseState(Action(_input.getChannel())); _currentPose = inputRecorder->getPoseState(actionName);
} }
if (!_currentPose.isValid()) { if (!_currentPose.isValid()) {
return; return;
} }
if (_input != Input::INVALID_INPUT) { if (_input != Input::INVALID_INPUT) {
auto userInputMapper = DependencyManager::get<UserInputMapper>();
userInputMapper->setActionState(Action(_input.getChannel()), _currentPose); userInputMapper->setActionState(Action(_input.getChannel()), _currentPose);
} }
} }