141 lines · 4.7 KB · C++
RawDownload
////  KasenAPIExample.cpp//  plugins/KasenAPIExample/src////  Created by Kasen IO on 2019.07.14 | realities.dev | kasenvr@gmail.com//  Copyright 2019 Kasen IO////  Authored by: Humbletim (humbletim@gmail.com)////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html////  Example of prototyping new JS APIs by leveraging the existing plugin system. #include "ExampleScriptPlugin.h" #include <QCoreApplication>#include <QtCore/QJsonObject>#include <QtCore/QLoggingCategory>#include <QtCore/QThread>#include <QtCore/QTimer> #include <SharedUtil.h>#include <AvatarHashMap.h> namespace custom_api_example { QLoggingCategory logger{ "custom_api_example" }; class KasenAPIExample : public example::ScriptPlugin {    Q_OBJECT    Q_PLUGIN_METADATA(IID "KasenAPIExample" FILE "plugin.json")public:    KasenAPIExample() : example::ScriptPlugin("KasenAPIExample", "0.0.1") {        qCInfo(logger) << "plugin loaded" << qApp << toString() << QThread::currentThread();     } public slots:    /**jsdoc     * Returns current microseconds (usecs) since Epoch. note: 1000usecs == 1ms     * @example <caption>Measure current setTimeout accuracy.</caption>     * var expected = 1000;     * var start = KasenAPIExample.now();     * Script.setTimeout(function () {     *     var elapsed = (KasenAPIExample.now() - start)/1000;     *     print("expected (ms):", expected, "actual (ms):", elapsed);     * }, expected);     */    QVariant now() const {        return usecTimestampNow();    }     /**jsdoc     * Returns the available blendshape names for an avatar.     * @example <caption>Get blendshape names</caption>     * print(JSON.stringify(KasenAPIExample.getBlendshapeNames(MyAvatar.sessionUUID)));     */    QStringList getBlendshapeNames(const QUuid& avatarID) const {        QVector<QString> out;        if (auto head = getAvatarHead(avatarID)) {            for (const auto& kv : head->getBlendshapeMap().toStdMap()) {                if (kv.second >= out.size()) out.resize(kv.second+1);                out[kv.second] = kv.first;            }        }        return out.toList();    }     /**jsdoc     * Returns a key-value object with active (non-zero) blendshapes.     * eg: { JawOpen: 1.0, ... }     * @example <caption>Get active blendshape map</caption>     * print(JSON.stringify(KasenAPIExample.getActiveBlendshapes(MyAvatar.sessionUUID)));     */    QVariant getActiveBlendshapes(const QUuid& avatarID) const {        if (auto head = getAvatarHead(avatarID)) {            return head->toJson()["blendShapes"].toVariant();        }        return {};    }     QVariant getBlendshapeMapping(const QUuid& avatarID) const {        QVariantMap out;        if (auto head = getAvatarHead(avatarID)) {            for (const auto& kv : head->getBlendshapeMap().toStdMap()) {                out[kv.first] = kv.second;            }        }        return out;    }     QVariant getBlendshapes(const QUuid& avatarID) const {        QVariantMap result;        if (auto head = getAvatarHead(avatarID)) {            QStringList names = getBlendshapeNames(avatarID);            auto states = head->getBlendshapeStates();            result = {                { "base", zipNonZeroValues(names, states.base) },                { "summed", zipNonZeroValues(names, states.summed) },                { "transient", zipNonZeroValues(names, states.transient) },            };        }        return result;    } private:    static QVariantMap zipNonZeroValues(const QStringList& keys, const QVector<float>& values) {        QVariantMap out;        for (int i=1; i < values.size(); i++) {            if (fabs(values[i]) > 1.0e-6f) {                out[keys.value(i)] = values[i];            }        }        return out;    }    struct _HeadHelper : public HeadData {        QMap<QString,int> getBlendshapeMap() const {            return BLENDSHAPE_LOOKUP_MAP;        }        struct States { QVector<float> base, summed, transient; };        States getBlendshapeStates() const {            return {                _blendshapeCoefficients,                _summedBlendshapeCoefficients,                _transientBlendshapeCoefficients            };        }    };    static const _HeadHelper* getAvatarHead(const QUuid& avatarID) {        auto avatars = DependencyManager::get<AvatarHashMap>();        auto avatar = avatars ? avatars->getAvatarBySessionID(avatarID) : nullptr;        auto head = avatar ? avatar->getHeadData() : nullptr;        return reinterpret_cast<const _HeadHelper*>(head);    }}; } const QLoggingCategory& example::logger{ custom_api_example::logger }; #include "KasenAPIExample.moc"