mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-15 06:36:44 +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,
|
||||
RIGHT_HAND,
|
||||
LEFT_ARM,
|
||||
RIGHT_ARM,
|
||||
LEFT_FOOT,
|
||||
RIGHT_FOOT,
|
||||
HIPS,
|
||||
|
@ -103,6 +101,8 @@ enum class Action {
|
|||
// Bisected aliases for TRANSLATE_CAMERA_Z
|
||||
BOOM_IN,
|
||||
BOOM_OUT,
|
||||
LEFT_ARM,
|
||||
RIGHT_ARM,
|
||||
|
||||
|
||||
NUM_ACTIONS,
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "InputRecorder.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
|
@ -19,9 +18,12 @@
|
|||
#include <QByteArray>
|
||||
#include <QStandardPaths>
|
||||
#include <PathUtils.h>
|
||||
#include <QUrl>
|
||||
|
||||
#include <BuildInfo.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 FILE_PREFIX_NAME = "input-recording-";
|
||||
|
@ -108,6 +110,7 @@ namespace controller {
|
|||
QJsonDocument saveData(object);
|
||||
QByteArray compressedData = qCompress(saveData.toJson(QJsonDocument::Compact));
|
||||
saveFile.write(compressedData);
|
||||
saveFile.close();
|
||||
}
|
||||
|
||||
QJsonObject openFile(const QString& file, bool& status) {
|
||||
|
@ -122,6 +125,7 @@ namespace controller {
|
|||
QJsonDocument jsonDoc = QJsonDocument::fromJson(compressedData);
|
||||
object = jsonDoc.object();
|
||||
status = true;
|
||||
openFile.close();
|
||||
return object;
|
||||
}
|
||||
|
||||
|
@ -146,31 +150,43 @@ namespace controller {
|
|||
_actionStateList.clear();
|
||||
}
|
||||
|
||||
void InputRecorder::saveRecording() {
|
||||
QJsonObject InputRecorder::recordDataToJson() {
|
||||
QJsonObject data;
|
||||
data["frameCount"] = _framesRecorded;
|
||||
|
||||
data["version"] = "1.0";
|
||||
|
||||
QJsonArray actionArrayList;
|
||||
QJsonArray poseArrayList;
|
||||
for(const ActionStates actionState: _actionStateList) {
|
||||
QJsonArray actionArray;
|
||||
for (const float value: actionState) {
|
||||
actionArray.append(value);
|
||||
for (const auto action: actionState) {
|
||||
QJsonObject actionJson;
|
||||
actionJson["name"] = action.first;
|
||||
actionJson["value"] = action.second;
|
||||
actionArray.append(actionJson);
|
||||
}
|
||||
actionArrayList.append(actionArray);
|
||||
}
|
||||
|
||||
for (const PoseStates poseState: _poseStateList) {
|
||||
QJsonArray poseArray;
|
||||
for (const Pose pose: poseState) {
|
||||
poseArray.append(poseToJsonObject(pose));
|
||||
for (const auto pose: poseState) {
|
||||
QJsonObject poseJson;
|
||||
poseJson["name"] = pose.first;
|
||||
poseJson["pose"] = poseToJsonObject(pose.second);
|
||||
poseArray.append(poseJson);
|
||||
}
|
||||
poseArrayList.append(poseArray);
|
||||
}
|
||||
|
||||
data["actionList"] = actionArrayList;
|
||||
data["poseList"] = poseArrayList;
|
||||
exportToFile(data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void InputRecorder::saveRecording() {
|
||||
exportToFile(recordDataToJson());
|
||||
}
|
||||
|
||||
void InputRecorder::loadRecording(const QString& path) {
|
||||
|
@ -181,8 +197,8 @@ namespace controller {
|
|||
resetFrame();
|
||||
_poseStateList.clear();
|
||||
_actionStateList.clear();
|
||||
QString filePath = path;
|
||||
filePath.remove(0,8);
|
||||
QUrl urlPath(path);
|
||||
QString filePath = urlPath.toLocalFile();
|
||||
QFileInfo info(filePath);
|
||||
QString extension = info.suffix();
|
||||
if (extension != "gz") {
|
||||
|
@ -190,8 +206,9 @@ namespace controller {
|
|||
return;
|
||||
}
|
||||
bool success = false;
|
||||
QJsonObject data = openFile(info.absoluteFilePath(), success);
|
||||
if (success) {
|
||||
QJsonObject data = openFile(filePath, success);
|
||||
auto keyValue = data.find("version");
|
||||
if (success && keyValue != data.end()) {
|
||||
_framesRecorded = data["frameCount"].toInt();
|
||||
QJsonArray actionArrayList = data["actionList"].toArray();
|
||||
QJsonArray poseArrayList = data["poseList"].toArray();
|
||||
|
@ -199,25 +216,71 @@ namespace controller {
|
|||
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].toDouble();
|
||||
QJsonObject actionObject = actionState[index].toObject();;
|
||||
_currentFrameActions[actionObject["name"].toString()] = actionObject["value"].toDouble();
|
||||
}
|
||||
_actionStateList.push_back(_currentFrameActions);
|
||||
_currentFrameActions = ActionStates(toInt(Action::NUM_ACTIONS));
|
||||
_currentFrameActions.clear();
|
||||
}
|
||||
|
||||
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());
|
||||
QJsonObject poseObject = poseState[index].toObject();
|
||||
_currentFramePoses[poseObject["name"].toString()] = jsonObjectToPose(poseObject["pose"].toObject());
|
||||
}
|
||||
_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;
|
||||
}
|
||||
|
||||
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() {
|
||||
_recording = false;
|
||||
_framesRecorded = (int)_actionStateList.size();
|
||||
|
@ -234,41 +297,36 @@ namespace controller {
|
|||
_playCount = 0;
|
||||
}
|
||||
|
||||
void InputRecorder::setActionState(controller::Action action, float value) {
|
||||
void InputRecorder::setActionState(const QString& action, float value) {
|
||||
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) {
|
||||
_currentFramePoses[toInt(action)] = pose;
|
||||
_currentFramePoses[action] = pose;
|
||||
}
|
||||
}
|
||||
|
||||
void InputRecorder::resetFrame() {
|
||||
if (_recording) {
|
||||
for(auto& channel : _currentFramePoses) {
|
||||
channel = Pose();
|
||||
}
|
||||
|
||||
for(auto& channel : _currentFrameActions) {
|
||||
channel = 0.0f;
|
||||
}
|
||||
_currentFramePoses.clear();
|
||||
_currentFrameActions.clear();
|
||||
}
|
||||
}
|
||||
|
||||
float InputRecorder::getActionState(controller::Action action) {
|
||||
float InputRecorder::getActionState(const QString& action) {
|
||||
if (_actionStateList.size() > 0 ) {
|
||||
return _actionStateList[_playCount][toInt(action)];
|
||||
return _actionStateList[_playCount][action];
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
controller::Pose InputRecorder::getPoseState(controller::Action action) {
|
||||
controller::Pose InputRecorder::getPoseState(const QString& action) {
|
||||
if (_poseStateList.size() > 0) {
|
||||
return _poseStateList[_playCount][toInt(action)];
|
||||
return _poseStateList[_playCount][action];
|
||||
}
|
||||
|
||||
return Pose();
|
||||
|
|
|
@ -12,8 +12,10 @@
|
|||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <QString>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "Pose.h"
|
||||
#include "Actions.h"
|
||||
|
@ -21,8 +23,8 @@
|
|||
namespace controller {
|
||||
class InputRecorder {
|
||||
public:
|
||||
using PoseStates = std::vector<Pose>;
|
||||
using ActionStates = std::vector<float>;
|
||||
using PoseStates = std::map<QString, Pose>;
|
||||
using ActionStates = std::map<QString, float>;
|
||||
|
||||
InputRecorder();
|
||||
~InputRecorder();
|
||||
|
@ -31,6 +33,7 @@ namespace controller {
|
|||
|
||||
void saveRecording();
|
||||
void loadRecording(const QString& path);
|
||||
void convertFile(const QString& path);
|
||||
void startRecording();
|
||||
void startPlayback();
|
||||
void stopPlayback();
|
||||
|
@ -40,20 +43,21 @@ namespace controller {
|
|||
void resetFrame();
|
||||
bool isRecording() { return _recording; }
|
||||
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);
|
||||
controller::Pose getPoseState(controller::Action action);
|
||||
void setActionState(const QString& action, float value);
|
||||
void setActionState(const QString& action, const controller::Pose& pose);
|
||||
float getActionState(const QString& action);
|
||||
controller::Pose getPoseState(const QString& action);
|
||||
QString getSaveDirectory();
|
||||
void frameTick();
|
||||
private:
|
||||
QJsonObject recordDataToJson();
|
||||
bool _recording { false };
|
||||
bool _playback { false };
|
||||
bool _loading { false };
|
||||
std::vector<PoseStates> _poseStateList = std::vector<PoseStates>();
|
||||
std::vector<ActionStates> _actionStateList = std::vector<ActionStates>();
|
||||
PoseStates _currentFramePoses = PoseStates(toInt(Action::NUM_ACTIONS));
|
||||
ActionStates _currentFrameActions = ActionStates(toInt(Action::NUM_ACTIONS));
|
||||
PoseStates _currentFramePoses;
|
||||
ActionStates _currentFrameActions;
|
||||
|
||||
int _framesRecorded { 0 };
|
||||
int _playCount { 0 };
|
||||
|
|
|
@ -17,31 +17,33 @@ using namespace controller;
|
|||
|
||||
void ActionEndpoint::apply(float newValue, const Pointer& source) {
|
||||
InputRecorder* inputRecorder = InputRecorder::getInstance();
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
QString actionName = userInputMapper->getActionName(Action(_input.getChannel()));
|
||||
if(inputRecorder->isPlayingback()) {
|
||||
newValue = inputRecorder->getActionState(Action(_input.getChannel()));
|
||||
newValue = inputRecorder->getActionState(actionName);
|
||||
}
|
||||
|
||||
_currentValue += newValue;
|
||||
if (_input != Input::INVALID_INPUT) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
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) {
|
||||
_currentPose = value;
|
||||
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()) {
|
||||
_currentPose = inputRecorder->getPoseState(Action(_input.getChannel()));
|
||||
_currentPose = inputRecorder->getPoseState(actionName);
|
||||
}
|
||||
|
||||
if (!_currentPose.isValid()) {
|
||||
return;
|
||||
}
|
||||
if (_input != Input::INVALID_INPUT) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->setActionState(Action(_input.getChannel()), _currentPose);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue