887 lines · 35.0 KB · C++
RawDownload
////  ScriptValueUtils.cpp//  libraries/shared/src////  Created by Anthony Thibault on 4/15/16.//  Copyright 2016 High Fidelity, Inc.////  Utilities for working with QtScriptValues////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "ScriptValueUtils.h" #include <QtCore/QVariant>#include <QtGui/QColor>#include <QtCore/QRect>#include <QtCore/QUrl>#include <QtCore/QUuid> #include <AACube.h>#include <shared/MiniPromises.h>#include <RegisteredMetaTypes.h> #include "ScriptEngine.h"#include "ScriptEngineCast.h"#include "ScriptValueIterator.h" bool isListOfStrings(const ScriptValuePointer& arg) {    if (!arg->isArray()) {        return false;    }     auto lengthProperty = arg->property("length");    if (!lengthProperty->isNumber()) {        return false;    }     int length = lengthProperty->toInt32();    for (int i = 0; i < length; i++) {        if (!arg->property(i)->isString()) {            return false;        }    }     return true;} void registerMetaTypes(ScriptEngine* engine) {    scriptRegisterMetaType(engine, vec2ToScriptValue, vec2FromScriptValue);    scriptRegisterMetaType(engine, vec3ToScriptValue, vec3FromScriptValue);    scriptRegisterMetaType(engine, u8vec3ToScriptValue, u8vec3FromScriptValue);    scriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue);    scriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue);    scriptRegisterMetaType(engine, mat4toScriptValue, mat4FromScriptValue);     scriptRegisterMetaType(engine, qVectorVec3ToScriptValue, qVectorVec3FromScriptValue);    scriptRegisterMetaType(engine, qVectorQuatToScriptValue, qVectorQuatFromScriptValue);    scriptRegisterMetaType(engine, qVectorBoolToScriptValue, qVectorBoolFromScriptValue);    scriptRegisterMetaType(engine, qVectorFloatToScriptValue, qVectorFloatFromScriptValue);    scriptRegisterMetaType(engine, qVectorIntToScriptValue, qVectorIntFromScriptValue);    scriptRegisterMetaType(engine, qVectorQUuidToScriptValue, qVectorQUuidFromScriptValue);     scriptRegisterMetaType(engine, qSizeFToScriptValue, qSizeFFromScriptValue);    scriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue);    scriptRegisterMetaType(engine, qURLToScriptValue, qURLFromScriptValue);    scriptRegisterMetaType(engine, qColorToScriptValue, qColorFromScriptValue);     scriptRegisterMetaType(engine, pickRayToScriptValue, pickRayFromScriptValue);    scriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue);    scriptRegisterMetaType(engine, quuidToScriptValue, quuidFromScriptValue);    scriptRegisterMetaType(engine, aaCubeToScriptValue, aaCubeFromScriptValue);     scriptRegisterMetaType(engine, stencilMaskModeToScriptValue, stencilMaskModeFromScriptValue);     scriptRegisterMetaType(engine, promiseToScriptValue, promiseFromScriptValue);     scriptRegisterSequenceMetaType<QVector<unsigned int>>(engine);} ScriptValuePointer vec2ToScriptValue(ScriptEngine* engine, const glm::vec2& vec2) {    auto prototype = engine->globalObject()->property("__hifi_vec2__");    if (!prototype->property("defined")->toBool()) {        prototype = engine->evaluate(            "__hifi_vec2__ = Object.defineProperties({}, { "            "defined: { value: true },"            "0: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"            "1: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"            "u: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"            "v: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }"            "})");    }    ScriptValuePointer value = engine->newObject();    value->setProperty("x", vec2.x);    value->setProperty("y", vec2.y);    value->setPrototype(prototype);    return value;} void vec2FromScriptValue(const ScriptValuePointer& object, glm::vec2& vec2) {    if (object->isNumber()) {        vec2 = glm::vec2(object->toVariant().toFloat());    } else if (object->isArray()) {        QVariantList list = object->toVariant().toList();        if (list.length() == 2) {            vec2.x = list[0].toFloat();            vec2.y = list[1].toFloat();        }    } else {        ScriptValuePointer x = object->property("x");        if (!x->isValid()) {            x = object->property("u");        }         ScriptValuePointer y = object->property("y");        if (!y->isValid()) {            y = object->property("v");        }         vec2.x = x->toVariant().toFloat();        vec2.y = y->toVariant().toFloat();    }} ScriptValuePointer vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) {    auto prototype = engine->globalObject()->property("__hifi_vec3__");    if (!prototype->property("defined")->toBool()) {        prototype = engine->evaluate(            "__hifi_vec3__ = Object.defineProperties({}, { "            "defined: { value: true },"            "0: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"            "1: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"            "2: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } },"            "r: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"            "g: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"            "b: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } },"            "red: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"            "green: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"            "blue: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }"            "})");    }    ScriptValuePointer value = engine->newObject();    value->setProperty("x", vec3.x);    value->setProperty("y", vec3.y);    value->setProperty("z", vec3.z);    value->setPrototype(prototype);    return value;} ScriptValuePointer vec3ColorToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) {    auto prototype = engine->globalObject()->property("__hifi_vec3_color__");    if (!prototype->property("defined")->toBool()) {        prototype = engine->evaluate(            "__hifi_vec3_color__ = Object.defineProperties({}, { "            "defined: { value: true },"            "0: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } },"            "1: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } },"            "2: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } },"            "r: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } },"            "g: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } },"            "b: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } },"            "x: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } },"            "y: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } },"            "z: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }"            "})");    }    ScriptValuePointer value = engine->newObject();    value->setProperty("red", vec3.x);    value->setProperty("green", vec3.y);    value->setProperty("blue", vec3.z);    value->setPrototype(prototype);    return value;} void vec3FromScriptValue(const ScriptValuePointer& object, glm::vec3& vec3) {    if (object->isNumber()) {        vec3 = glm::vec3(object->toVariant().toFloat());    } else if (object->isString()) {        QColor qColor(object->toString());        if (qColor.isValid()) {            vec3.x = qColor.red();            vec3.y = qColor.green();            vec3.z = qColor.blue();        }    } else if (object->isArray()) {        QVariantList list = object->toVariant().toList();        if (list.length() == 3) {            vec3.x = list[0].toFloat();            vec3.y = list[1].toFloat();            vec3.z = list[2].toFloat();        }    } else {        ScriptValuePointer x = object->property("x");        if (!x->isValid()) {            x = object->property("r");        }        if (!x->isValid()) {            x = object->property("red");        }         ScriptValuePointer y = object->property("y");        if (!y->isValid()) {            y = object->property("g");        }        if (!y->isValid()) {            y = object->property("green");        }         ScriptValuePointer z = object->property("z");        if (!z->isValid()) {            z = object->property("b");        }        if (!z->isValid()) {            z = object->property("blue");        }         vec3.x = x->toVariant().toFloat();        vec3.y = y->toVariant().toFloat();        vec3.z = z->toVariant().toFloat();    }} ScriptValuePointer u8vec3ToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3) {    auto prototype = engine->globalObject()->property("__hifi_u8vec3__");    if (!prototype->property("defined")->toBool()) {        prototype = engine->evaluate(            "__hifi_u8vec3__ = Object.defineProperties({}, { "            "defined: { value: true },"            "0: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"            "1: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"            "2: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } },"            "r: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"            "g: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"            "b: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } },"            "red: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"            "green: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"            "blue: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }"            "})");    }    ScriptValuePointer value = engine->newObject();    value->setProperty("x", vec3.x);    value->setProperty("y", vec3.y);    value->setProperty("z", vec3.z);    value->setPrototype(prototype);    return value;} ScriptValuePointer u8vec3ColorToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3) {    auto prototype = engine->globalObject()->property("__hifi_u8vec3_color__");    if (!prototype->property("defined")->toBool()) {        prototype = engine->evaluate(            "__hifi_u8vec3_color__ = Object.defineProperties({}, { "            "defined: { value: true },"            "0: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } },"            "1: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } },"            "2: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } },"            "r: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } },"            "g: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } },"            "b: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } },"            "x: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } },"            "y: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } },"            "z: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }"            "})");    }    ScriptValuePointer value = engine->newObject();    value->setProperty("red", vec3.x);    value->setProperty("green", vec3.y);    value->setProperty("blue", vec3.z);    value->setPrototype(prototype);    return value;} void u8vec3FromScriptValue(const ScriptValuePointer& object, glm::u8vec3& vec3) {    if (object->isNumber()) {        vec3 = glm::vec3(object->toVariant().toUInt());    } else if (object->isString()) {        QColor qColor(object->toString());        if (qColor.isValid()) {            vec3.x = (uint8_t)qColor.red();            vec3.y = (uint8_t)qColor.green();            vec3.z = (uint8_t)qColor.blue();        }    } else if (object->isArray()) {        QVariantList list = object->toVariant().toList();        if (list.length() == 3) {            vec3.x = list[0].toUInt();            vec3.y = list[1].toUInt();            vec3.z = list[2].toUInt();        }    } else {        ScriptValuePointer x = object->property("x");        if (!x->isValid()) {            x = object->property("r");        }        if (!x->isValid()) {            x = object->property("red");        }         ScriptValuePointer y = object->property("y");        if (!y->isValid()) {            y = object->property("g");        }        if (!y->isValid()) {            y = object->property("green");        }         ScriptValuePointer z = object->property("z");        if (!z->isValid()) {            z = object->property("b");        }        if (!z->isValid()) {            z = object->property("blue");        }         vec3.x = x->toVariant().toUInt();        vec3.y = y->toVariant().toUInt();        vec3.z = z->toVariant().toUInt();    }} ScriptValuePointer vec4toScriptValue(ScriptEngine* engine, const glm::vec4& vec4) {    ScriptValuePointer obj = engine->newObject();    obj->setProperty("x", vec4.x);    obj->setProperty("y", vec4.y);    obj->setProperty("z", vec4.z);    obj->setProperty("w", vec4.w);    return obj;} void vec4FromScriptValue(const ScriptValuePointer& object, glm::vec4& vec4) {    vec4.x = object->property("x")->toVariant().toFloat();    vec4.y = object->property("y")->toVariant().toFloat();    vec4.z = object->property("z")->toVariant().toFloat();    vec4.w = object->property("w")->toVariant().toFloat();} ScriptValuePointer mat4toScriptValue(ScriptEngine* engine, const glm::mat4& mat4) {    ScriptValuePointer obj = engine->newObject();    obj->setProperty("r0c0", mat4[0][0]);    obj->setProperty("r1c0", mat4[0][1]);    obj->setProperty("r2c0", mat4[0][2]);    obj->setProperty("r3c0", mat4[0][3]);    obj->setProperty("r0c1", mat4[1][0]);    obj->setProperty("r1c1", mat4[1][1]);    obj->setProperty("r2c1", mat4[1][2]);    obj->setProperty("r3c1", mat4[1][3]);    obj->setProperty("r0c2", mat4[2][0]);    obj->setProperty("r1c2", mat4[2][1]);    obj->setProperty("r2c2", mat4[2][2]);    obj->setProperty("r3c2", mat4[2][3]);    obj->setProperty("r0c3", mat4[3][0]);    obj->setProperty("r1c3", mat4[3][1]);    obj->setProperty("r2c3", mat4[3][2]);    obj->setProperty("r3c3", mat4[3][3]);    return obj;} void mat4FromScriptValue(const ScriptValuePointer& object, glm::mat4& mat4) {    mat4[0][0] = object->property("r0c0")->toVariant().toFloat();    mat4[0][1] = object->property("r1c0")->toVariant().toFloat();    mat4[0][2] = object->property("r2c0")->toVariant().toFloat();    mat4[0][3] = object->property("r3c0")->toVariant().toFloat();    mat4[1][0] = object->property("r0c1")->toVariant().toFloat();    mat4[1][1] = object->property("r1c1")->toVariant().toFloat();    mat4[1][2] = object->property("r2c1")->toVariant().toFloat();    mat4[1][3] = object->property("r3c1")->toVariant().toFloat();    mat4[2][0] = object->property("r0c2")->toVariant().toFloat();    mat4[2][1] = object->property("r1c2")->toVariant().toFloat();    mat4[2][2] = object->property("r2c2")->toVariant().toFloat();    mat4[2][3] = object->property("r3c2")->toVariant().toFloat();    mat4[3][0] = object->property("r0c3")->toVariant().toFloat();    mat4[3][1] = object->property("r1c3")->toVariant().toFloat();    mat4[3][2] = object->property("r2c3")->toVariant().toFloat();    mat4[3][3] = object->property("r3c3")->toVariant().toFloat();} ScriptValuePointer qVectorVec3ColorToScriptValue(ScriptEngine* engine, const QVector<glm::vec3>& vector) {    ScriptValuePointer array = engine->newArray();    for (int i = 0; i < vector.size(); i++) {        array->setProperty(i, vec3ColorToScriptValue(engine, vector.at(i)));    }    return array;} ScriptValuePointer qVectorVec3ToScriptValue(ScriptEngine* engine, const QVector<glm::vec3>& vector) {    ScriptValuePointer array = engine->newArray();    for (int i = 0; i < vector.size(); i++) {        array->setProperty(i, vec3ToScriptValue(engine, vector.at(i)));    }    return array;} QVector<glm::vec3> qVectorVec3FromScriptValue(const ScriptValuePointer& array) {    QVector<glm::vec3> newVector;    int length = array->property("length")->toInteger();     for (int i = 0; i < length; i++) {        glm::vec3 newVec3 = glm::vec3();        vec3FromScriptValue(array->property(i), newVec3);        newVector << newVec3;    }    return newVector;} void qVectorVec3FromScriptValue(const ScriptValuePointer& array, QVector<glm::vec3>& vector) {    int length = array->property("length")->toInteger();     for (int i = 0; i < length; i++) {        glm::vec3 newVec3 = glm::vec3();        vec3FromScriptValue(array->property(i), newVec3);        vector << newVec3;    }} ScriptValuePointer quatToScriptValue(ScriptEngine* engine, const glm::quat& quat) {    ScriptValuePointer obj = engine->newObject();    if (quat.x != quat.x || quat.y != quat.y || quat.z != quat.z || quat.w != quat.w) {        // if quat contains a NaN don't try to convert it        return obj;    }    obj->setProperty("x", quat.x);    obj->setProperty("y", quat.y);    obj->setProperty("z", quat.z);    obj->setProperty("w", quat.w);    return obj;} void quatFromScriptValue(const ScriptValuePointer& object, glm::quat& quat) {    quat.x = object->property("x")->toVariant().toFloat();    quat.y = object->property("y")->toVariant().toFloat();    quat.z = object->property("z")->toVariant().toFloat();    quat.w = object->property("w")->toVariant().toFloat();     // enforce normalized quaternion    float length = glm::length(quat);    if (length > FLT_EPSILON) {        quat /= length;    } else {        quat = glm::quat();    }} ScriptValuePointer qVectorQuatToScriptValue(ScriptEngine* engine, const QVector<glm::quat>& vector) {    ScriptValuePointer array = engine->newArray();    for (int i = 0; i < vector.size(); i++) {        array->setProperty(i, quatToScriptValue(engine, vector.at(i)));    }    return array;} ScriptValuePointer qVectorBoolToScriptValue(ScriptEngine* engine, const QVector<bool>& vector) {    ScriptValuePointer array = engine->newArray();    for (int i = 0; i < vector.size(); i++) {        array->setProperty(i, vector.at(i));    }    return array;} QVector<float> qVectorFloatFromScriptValue(const ScriptValuePointer& array) {    if (!array->isArray()) {        return QVector<float>();    }    QVector<float> newVector;    int length = array->property("length")->toInteger();    newVector.reserve(length);    for (int i = 0; i < length; i++) {        if (array->property(i)->isNumber()) {            newVector << array->property(i)->toNumber();        }    }     return newVector;} ScriptValuePointer qVectorQUuidToScriptValue(ScriptEngine* engine, const QVector<QUuid>& vector) {    ScriptValuePointer array = engine->newArray();    for (int i = 0; i < vector.size(); i++) {        array->setProperty(i, quuidToScriptValue(engine, vector.at(i)));    }    return array;} void qVectorQUuidFromScriptValue(const ScriptValuePointer& array, QVector<QUuid>& vector) {    int length = array->property("length")->toInteger();     for (int i = 0; i < length; i++) {        vector << array->property(i)->toVariant().toUuid();    }} QVector<QUuid> qVectorQUuidFromScriptValue(const ScriptValuePointer& array) {    if (!array->isArray()) {        return QVector<QUuid>();    }    QVector<QUuid> newVector;    int length = array->property("length")->toInteger();    newVector.reserve(length);    for (int i = 0; i < length; i++) {        QString uuidAsString = array->property(i)->toString();

Lines 1–500 of 887.