mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 15:53:28 +02:00
fixed some input recorder design issue
This commit is contained in:
parent
4a52f4090d
commit
cca0fa6600
4 changed files with 111 additions and 47 deletions
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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 };
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue