From 82166f494738a6338d53750a92f79dd1ce1fabe0 Mon Sep 17 00:00:00 2001
From: ZappoMan <brad@highfidelity.io>
Date: Tue, 11 Apr 2017 14:06:36 -0700
Subject: [PATCH] add rotate and transform filters for poses

---
 .../src/controllers/impl/Filter.cpp           | 65 +++++++++++++++++++
 .../controllers/src/controllers/impl/Filter.h |  2 +
 .../controllers/impl/RouteBuilderProxy.cpp    | 13 +++-
 .../src/controllers/impl/RouteBuilderProxy.h  |  2 +
 .../controllers/impl/filters/RotateFilter.cpp | 21 ++++++
 .../controllers/impl/filters/RotateFilter.h   | 40 ++++++++++++
 .../impl/filters/TransformFilter.cpp          | 21 ++++++
 .../impl/filters/TransformFilter.h            | 41 ++++++++++++
 .../impl/filters/TranslateFilter.cpp          |  4 +-
 .../impl/filters/TranslateFilter.h            | 10 +--
 script-archive/controllers/puppetFeet3.js     | 12 +++-
 11 files changed, 218 insertions(+), 13 deletions(-)
 create mode 100644 libraries/controllers/src/controllers/impl/filters/RotateFilter.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/filters/RotateFilter.h
 create mode 100644 libraries/controllers/src/controllers/impl/filters/TransformFilter.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/filters/TransformFilter.h

diff --git a/libraries/controllers/src/controllers/impl/Filter.cpp b/libraries/controllers/src/controllers/impl/Filter.cpp
index a75c43463e..12e666825b 100644
--- a/libraries/controllers/src/controllers/impl/Filter.cpp
+++ b/libraries/controllers/src/controllers/impl/Filter.cpp
@@ -25,6 +25,7 @@
 #include "filters/PulseFilter.h"
 #include "filters/ScaleFilter.h"
 #include "filters/TranslateFilter.h"
+#include "filters/TransformFilter.h"
 
 using namespace controller;
 
@@ -39,6 +40,7 @@ REGISTER_FILTER_CLASS_INSTANCE(InvertFilter, "invert")
 REGISTER_FILTER_CLASS_INSTANCE(ScaleFilter, "scale")
 REGISTER_FILTER_CLASS_INSTANCE(PulseFilter, "pulse")
 REGISTER_FILTER_CLASS_INSTANCE(TranslateFilter, "translate")
+REGISTER_FILTER_CLASS_INSTANCE(TransformFilter, "transform")
 
 const QString JSON_FILTER_TYPE = QStringLiteral("type");
 const QString JSON_FILTER_PARAMS = QStringLiteral("params");
@@ -112,6 +114,69 @@ bool Filter::parseVec3Parameter(const QJsonValue& parameters, const QString& nam
     return false;
 }
 
+bool Filter::parseMat4Parameter(const QJsonValue& parameters, const QString& name, glm::mat4& output) {
+    if (parameters.isObject()) {
+        auto objectParameters = parameters.toObject();
+
+
+        if (objectParameters.contains("r0c0") && 
+            objectParameters.contains("r1c0") &&
+            objectParameters.contains("r2c0") &&
+            objectParameters.contains("r3c0") &&
+            objectParameters.contains("r0c1") &&
+            objectParameters.contains("r1c1") &&
+            objectParameters.contains("r2c1") &&
+            objectParameters.contains("r3c1") &&
+            objectParameters.contains("r0c2") &&
+            objectParameters.contains("r1c2") &&
+            objectParameters.contains("r2c2") &&
+            objectParameters.contains("r3c2") &&
+            objectParameters.contains("r0c3") &&
+            objectParameters.contains("r1c3") &&
+            objectParameters.contains("r2c3") &&
+            objectParameters.contains("r3c3")) {
+
+            output[0][0] = objectParameters["r0c0"].toDouble();
+            output[0][1] = objectParameters["r1c0"].toDouble();
+            output[0][2] = objectParameters["r2c0"].toDouble();
+            output[0][3] = objectParameters["r3c0"].toDouble();
+            output[1][0] = objectParameters["r0c1"].toDouble();
+            output[1][1] = objectParameters["r1c1"].toDouble();
+            output[1][2] = objectParameters["r2c1"].toDouble();
+            output[1][3] = objectParameters["r3c1"].toDouble();
+            output[2][0] = objectParameters["r0c2"].toDouble();
+            output[2][1] = objectParameters["r1c2"].toDouble();
+            output[2][2] = objectParameters["r2c2"].toDouble();
+            output[2][3] = objectParameters["r3c2"].toDouble();
+            output[3][0] = objectParameters["r0c3"].toDouble();
+            output[3][1] = objectParameters["r1c3"].toDouble();
+            output[3][2] = objectParameters["r2c3"].toDouble();
+            output[3][3] = objectParameters["r3c3"].toDouble();
+
+            return true;
+        }
+    }
+    return false;
+}
+
+bool Filter::parseQuatParameter(const QJsonValue& parameters, const QString& name, glm::quat& output) {
+    if (parameters.isObject()) {
+        auto objectParameters = parameters.toObject();
+        if (objectParameters.contains("w") && 
+            objectParameters.contains("x") && 
+            objectParameters.contains("y") && 
+            objectParameters.contains("z")) {
+
+            output = glm::quat(objectParameters["w"].toDouble(),
+                               objectParameters["x"].toDouble(),
+                               objectParameters["y"].toDouble(),
+                               objectParameters["z"].toDouble());
+            return true;
+        }
+    }
+    return false;
+}
+
 
 #if 0
 
diff --git a/libraries/controllers/src/controllers/impl/Filter.h b/libraries/controllers/src/controllers/impl/Filter.h
index c268a227d7..d20a3d08e3 100644
--- a/libraries/controllers/src/controllers/impl/Filter.h
+++ b/libraries/controllers/src/controllers/impl/Filter.h
@@ -47,6 +47,8 @@ namespace controller {
 
         static bool parseSingleFloatParameter(const QJsonValue& parameters, const QString& name, float& output);
         static bool parseVec3Parameter(const QJsonValue& parameters, const QString& name, glm::vec3& output);
+        static bool parseMat4Parameter(const QJsonValue& parameters, const QString& name, glm::mat4& output);
+        static bool parseQuatParameter(const QJsonValue& parameters, const QString& name, glm::quat& output);
     protected:
         static Factory _factory;
     };
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
index 93ec8d4acd..fa662dcc13 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
@@ -27,6 +27,8 @@
 #include "filters/PulseFilter.h"
 #include "filters/ScaleFilter.h"
 #include "filters/TranslateFilter.h"
+#include "filters/TransformFilter.h"
+#include "filters/RotateFilter.h"
 #include "conditionals/AndConditional.h"
 
 using namespace controller;
@@ -105,11 +107,20 @@ QObject* RouteBuilderProxy::deadZone(float min) {
 }
 
 QObject* RouteBuilderProxy::translate(glm::vec3 translate) {
-    qDebug() << __FUNCTION__ << "translate:" << translate;
     addFilter(std::make_shared<TranslateFilter>(translate));
     return this;
 }
 
+QObject* RouteBuilderProxy::transform(glm::mat4 transform) {
+    addFilter(std::make_shared<TransformFilter>(transform));
+    return this;
+}
+
+QObject* RouteBuilderProxy::rotate(glm::quat rotation) {
+    addFilter(std::make_shared<RotateFilter>(rotation));
+    return this;
+}
+
 QObject* RouteBuilderProxy::constrainToInteger() {
     addFilter(std::make_shared<ConstrainToIntegerFilter>());
     return this;
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
index 0d3ddd55fb..7696eefebe 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
@@ -49,6 +49,8 @@ class RouteBuilderProxy : public QObject {
         Q_INVOKABLE QObject* constrainToInteger();
         Q_INVOKABLE QObject* constrainToPositiveInteger();
         Q_INVOKABLE QObject* translate(glm::vec3 translate);
+        Q_INVOKABLE QObject* transform(glm::mat4 transform);
+        Q_INVOKABLE QObject* rotate(glm::quat rotation);
 
     private:
         void to(const Endpoint::Pointer& destination);
diff --git a/libraries/controllers/src/controllers/impl/filters/RotateFilter.cpp b/libraries/controllers/src/controllers/impl/filters/RotateFilter.cpp
new file mode 100644
index 0000000000..b5a94ba492
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/RotateFilter.cpp
@@ -0,0 +1,21 @@
+//
+//  Created by Brad Hefta-Gaub 2017/04/11
+//  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 "RotateFilter.h"
+
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+
+#include <StreamUtils.h>
+
+using namespace controller;
+
+bool RotateFilter::parseParameters(const QJsonValue& parameters) {
+    static const QString JSON_ROTATION = QStringLiteral("rotation");
+    return parseQuatParameter(parameters, JSON_ROTATION, _rotation);
+}
diff --git a/libraries/controllers/src/controllers/impl/filters/RotateFilter.h b/libraries/controllers/src/controllers/impl/filters/RotateFilter.h
new file mode 100644
index 0000000000..a5c3b10655
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/RotateFilter.h
@@ -0,0 +1,40 @@
+//
+//  Created by Brad Hefta-Gaub 2017/04/11
+//  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
+//
+
+#pragma once
+#ifndef hifi_Controllers_Filters_Rotate_h
+#define hifi_Controllers_Filters_Rotate_h
+
+#include <glm/gtx/transform.hpp>
+
+#include "../Filter.h"
+
+namespace controller {
+
+class RotateFilter : public Filter {
+    REGISTER_FILTER_CLASS(RotateFilter);
+public:
+    RotateFilter() { }
+    RotateFilter(glm::quat rotation) : _rotation(rotation) {}
+
+    virtual float apply(float value) const override { return value; }
+
+    virtual Pose apply(Pose value) const override {
+        glm::quat temp = _rotation;
+        return value.transform(glm::mat4(temp));
+    }
+
+    virtual bool parseParameters(const QJsonValue& parameters) override;
+
+private:
+    glm::quat _rotation;
+};
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/filters/TransformFilter.cpp b/libraries/controllers/src/controllers/impl/filters/TransformFilter.cpp
new file mode 100644
index 0000000000..71568b4c29
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/TransformFilter.cpp
@@ -0,0 +1,21 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 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 "TransformFilter.h"
+
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+
+#include <StreamUtils.h>
+
+using namespace controller;
+
+bool TransformFilter::parseParameters(const QJsonValue& parameters) {
+    static const QString JSON_TRANSFORM = QStringLiteral("transform");
+    return parseMat4Parameter(parameters, JSON_TRANSFORM, _transform);
+}
diff --git a/libraries/controllers/src/controllers/impl/filters/TransformFilter.h b/libraries/controllers/src/controllers/impl/filters/TransformFilter.h
new file mode 100644
index 0000000000..9999fd03c7
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/TransformFilter.h
@@ -0,0 +1,41 @@
+//
+//  Created by Brad Hefta-Gaub 2017/04/11
+//  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
+//
+
+#pragma once
+#ifndef hifi_Controllers_Filters_Transform_h
+#define hifi_Controllers_Filters_Transform_h
+
+#include <glm/gtx/transform.hpp>
+
+#include "../Filter.h"
+
+namespace controller {
+
+class TransformFilter : public Filter {
+    REGISTER_FILTER_CLASS(TransformFilter);
+public:
+    TransformFilter() { }
+    TransformFilter(glm::mat4 transform) : _transform(transform) {}
+
+    virtual float apply(float value) const override {
+        return value;
+    }
+
+    virtual Pose apply(Pose value) const override {
+        return value.transform(_transform);
+    }
+
+    virtual bool parseParameters(const QJsonValue& parameters) override;
+
+private:
+    glm::mat4 _transform;
+};
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/filters/TranslateFilter.cpp b/libraries/controllers/src/controllers/impl/filters/TranslateFilter.cpp
index 6f7e1e6a45..e63afcdd9e 100644
--- a/libraries/controllers/src/controllers/impl/filters/TranslateFilter.cpp
+++ b/libraries/controllers/src/controllers/impl/filters/TranslateFilter.cpp
@@ -17,7 +17,5 @@ using namespace controller;
 
 bool TranslateFilter::parseParameters(const QJsonValue& parameters) {
     static const QString JSON_TRANSLATE = QStringLiteral("translate");
-    bool result = parseVec3Parameter(parameters, JSON_TRANSLATE, _translate);
-    qDebug() << __FUNCTION__ << "_translate:" << _translate;
-    return result;
+    return parseVec3Parameter(parameters, JSON_TRANSLATE, _translate);
 }
diff --git a/libraries/controllers/src/controllers/impl/filters/TranslateFilter.h b/libraries/controllers/src/controllers/impl/filters/TranslateFilter.h
index 504e4c3151..d5ac417b98 100644
--- a/libraries/controllers/src/controllers/impl/filters/TranslateFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/TranslateFilter.h
@@ -12,8 +12,6 @@
 
 #include <glm/gtx/transform.hpp>
 
-#include <StreamUtils.h>
-
 #include "../Filter.h"
 
 namespace controller {
@@ -21,12 +19,8 @@ namespace controller {
 class TranslateFilter : public Filter {
     REGISTER_FILTER_CLASS(TranslateFilter);
 public:
-    TranslateFilter() {
-        qDebug() << __FUNCTION__;
-    }
-    TranslateFilter(glm::vec3 translate) : _translate(translate) {
-        qDebug() << __FUNCTION__ << "translate:" << translate;
-    }
+    TranslateFilter() { }
+    TranslateFilter(glm::vec3 translate) : _translate(translate) {}
 
     virtual float apply(float value) const override {
         return value;
diff --git a/script-archive/controllers/puppetFeet3.js b/script-archive/controllers/puppetFeet3.js
index 8fa7d5c632..3c9618edd9 100644
--- a/script-archive/controllers/puppetFeet3.js
+++ b/script-archive/controllers/puppetFeet3.js
@@ -14,7 +14,17 @@ var MAPPING_NAME = "com.highfidelity.examples.puppetFeet3";
 var mapping = Controller.newMapping(MAPPING_NAME);
 var puppetOffset = { x: 0, y: -1, z: 0 };
 
-mapping.from(Controller.Standard.LeftHand).peek().translate(puppetOffset).to(Controller.Standard.LeftFoot);
+var rotation = Quat.fromPitchYawRollDegrees(0, 0, -90); 
+var noTranslation = { x: 0, y: 0, z: 0 };
+var transformMatrix = Mat4.createFromRotAndTrans(rotation, noTranslation);
+var rotateAndTranslate = Mat4.createFromRotAndTrans(rotation, puppetOffset);
+
+
+mapping.from(Controller.Standard.LeftHand).peek().rotate(rotation).translate(puppetOffset).to(Controller.Standard.LeftFoot);
+
+//mapping.from(Controller.Standard.LeftHand).peek().translate(puppetOffset).to(Controller.Standard.LeftFoot);
+//mapping.from(Controller.Standard.LeftHand).peek().transform(transformMatrix).translate(puppetOffset).to(Controller.Standard.LeftFoot);
+//mapping.from(Controller.Standard.LeftHand).peek().transform(rotateAndTranslate).to(Controller.Standard.LeftFoot);
 
 Controller.enableMapping(MAPPING_NAME);