1193 lines · 46.6 KB · C++
RawDownload
////  ScriptValueUtils.cpp//  libraries/shared/src////  Created by Anthony Thibault on 4/15/16.//  Copyright 2016 High Fidelity, Inc.//  Copyright 2022-2023 Overte e.V.////  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//  SPDX-License-Identifier: Apache-2.0// #include "ScriptValueUtils.h" #include <QtCore/QVariant>#include <QtGui/QColor>#include <QtGui/QVector2D>#include <QtGui/QVector3D>#include <QtCore/QRect>#include <QtCore/QUrl>#include <QtCore/QUuid>#include <QtCore/QTimer> #include <AACube.h>#include <shared/MiniPromises.h>#include <RegisteredMetaTypes.h>#include <EntityItemID.h> #include "ScriptEngine.h"#include "ScriptEngineCast.h"#include "ScriptValueIterator.h"#include "ScriptEngineLogging.h"#include "v8/FastScriptValueUtils.h"#include "AddressManager.h"#include "Sampler.h" bool isListOfStrings(const ScriptValue& 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<QVector2D, qVector2DToScriptValue, qVector2DFromScriptValue>(engine);    scriptRegisterMetaType<QVector3D, qVector3DToScriptValue, qVector3DFromScriptValue>(engine);     scriptRegisterMetaType<glm::vec2, vec2ToScriptValue, vec2FromScriptValue>(engine);    scriptRegisterMetaType<glm::vec3, vec3ToScriptValue, vec3FromScriptValue>(engine);    scriptRegisterMetaType<glm::u8vec3, u8vec3ToScriptValue, u8vec3FromScriptValue>(engine);    scriptRegisterMetaType<glm::vec4, vec4toScriptValue, vec4FromScriptValue>(engine);    scriptRegisterMetaType<glm::quat, quatToScriptValue, quatFromScriptValue>(engine);    scriptRegisterMetaType<glm::mat4, mat4toScriptValue, mat4FromScriptValue>(engine);     scriptRegisterMetaType<QVector< glm::vec3 >, qVectorVec3ToScriptValue, qVectorVec3FromScriptValue>(engine);    scriptRegisterMetaType<QVector< glm::quat >, qVectorQuatToScriptValue, qVectorQuatFromScriptValue>(engine);    scriptRegisterMetaType<QVector< bool >, qVectorBoolToScriptValue, qVectorBoolFromScriptValue>(engine);    scriptRegisterMetaType<QVector< float >, qVectorFloatToScriptValue, qVectorFloatFromScriptValue>(engine);    scriptRegisterMetaType<QVector< uint32_t >, qVectorIntToScriptValue, qVectorIntFromScriptValue>(engine);    scriptRegisterMetaType<QVector< QUuid >, qVectorQUuidToScriptValue, qVectorQUuidFromScriptValue>(engine);     scriptRegisterMetaType<QSizeF, qSizeFToScriptValue, qSizeFFromScriptValue>(engine);    scriptRegisterMetaType<QRect, qRectToScriptValue, qRectFromScriptValue>(engine);    scriptRegisterMetaType<QUrl, qURLToScriptValue, qURLFromScriptValue>(engine);    scriptRegisterMetaType<QColor, qColorToScriptValue, qColorFromScriptValue>(engine);    scriptRegisterMetaType<QTimer*, qTimerToScriptValue, qTimerFromScriptValue>(engine, "QTimer*");    scriptRegisterMetaType<QByteArray, qBytearrayToScriptValue, qBytearrayFromScriptValue>(engine, "QByteArray");     scriptRegisterMetaType<PickRay, pickRayToScriptValue, pickRayFromScriptValue>(engine);    scriptRegisterMetaType<Collision, collisionToScriptValue, collisionFromScriptValue>(engine);    scriptRegisterMetaType<QUuid, quuidToScriptValue, quuidFromScriptValue>(engine);    scriptRegisterMetaType<AACube, aaCubeToScriptValue, aaCubeFromScriptValue>(engine);     scriptRegisterMetaType<StencilMaskMode, stencilMaskModeToScriptValue, stencilMaskModeFromScriptValue>(engine);     scriptRegisterMetaType<AnimationDetails, animationDetailsToScriptValue, animationDetailsFromScriptValue>(engine);     scriptRegisterMetaType<MeshProxy*, meshToScriptValue, meshFromScriptValue>(engine);    scriptRegisterMetaType<MeshProxyList, meshesToScriptValue, meshesFromScriptValue>(engine);     scriptRegisterSequenceMetaType<QVector<unsigned int> >(engine);    scriptRegisterSequenceMetaType<QVector<QUuid>>(engine);    scriptRegisterSequenceMetaType<QVector<EntityItemID>>(engine);     scriptRegisterSequenceMetaType<QVector<glm::vec2>>(engine);    scriptRegisterSequenceMetaType<QVector<glm::quat>>(engine);    scriptRegisterSequenceMetaType<QVector<QString>>(engine);     scriptRegisterMetaType<AddressManager::LookupTrigger, scriptValueFromEnumClass<AddressManager::LookupTrigger>, scriptValueToEnumClass<AddressManager::LookupTrigger>>(engine, "LookupTrigger");} ScriptValue qVector2DToScriptValue(ScriptEngine* engine, const QVector2D& qVector2D) {    glm::vec2 vec2(qVector2D.x(), qVector2D.y());    return vec2ToScriptValue(engine, vec2);} bool qVector2DFromScriptValue(const ScriptValue& object, QVector2D& qVector2D) {    glm::vec2 vec2;    if (vec2FromScriptValue(object, vec2)) {        qVector2D.setX(vec2.x);        qVector2D.setY(vec2.y);        return true;    } else {        return false;    }} ScriptValue qVector3DToScriptValue(ScriptEngine* engine, const QVector3D& qVector3D) {    glm::vec3 vec3(qVector3D.x(), qVector3D.y(), qVector3D.z());    return vec3ToScriptValue(engine, vec3);} bool qVector3DFromScriptValue(const ScriptValue& object, QVector3D& qVector3D) {    glm::vec3 vec3;    if (vec3FromScriptValue(object, vec3)) {        qVector3D.setX(vec3.x);        qVector3D.setY(vec3.y);        qVector3D.setZ(vec3.z);        return true;    } else {        return false;    }} ScriptValue 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; } }"            "})");    }    ScriptValue value = engine->newObject();    value.setProperty("x", vec2.x);    value.setProperty("y", vec2.y);    value.setPrototype(prototype);    return value;} bool vec2FromScriptValue(const ScriptValue& 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 {        ScriptValue x = object.property("x");        if (!x.isValid()) {            x = object.property("u");        }         ScriptValue y = object.property("y");        if (!y.isValid()) {            y = object.property("v");        }         vec2.x = x.toVariant().toFloat();        vec2.y = y.toVariant().toFloat();    }    return true;} #ifndef CONVERSIONS_OPTIMIZED_FOR_V8ScriptValue vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) {    auto prototype = engine->globalObject().property("__hifi_vec3__");    if (!prototype.hasProperty("defined") || !prototype.property("defined").toBool()) {        prototype = engine->evaluate(            "globalThis.__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; } }"            "})");    }    ScriptValue value = engine->newObject();    value.setProperty("x", vec3.x);    value.setProperty("y", vec3.y);    value.setProperty("z", vec3.z);    value.setPrototype(prototype);    return value;}#endif ScriptValue vec3ColorToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) {    auto prototype = engine->globalObject().property("__hifi_vec3_color__");    if (!prototype.property("defined").toBool()) {        prototype = engine->evaluate(            "globalThis.__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; } }"            "})");    }    ScriptValue value = engine->newObject();    value.setProperty("red", vec3.x);    value.setProperty("green", vec3.y);    value.setProperty("blue", vec3.z);    value.setPrototype(prototype);    return value;} // V8TODO: add similar checks to rest of the conversions#ifndef CONVERSIONS_OPTIMIZED_FOR_V8bool vec3FromScriptValue(const ScriptValue& 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 {            return false;        }    } 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 {            return false;        }    } else if (object.isObject()) {        ScriptValue x = object.property("x");        if (!x.isValid()) {            x = object.property("r");        }        if (!x.isValid()) {            x = object.property("red");        }         ScriptValue y = object.property("y");        if (!y.isValid()) {            y = object.property("g");        }        if (!y.isValid()) {            y = object.property("green");        }         ScriptValue z = object.property("z");        if (!z.isValid()) {            z = object.property("b");        }        if (!z.isValid()) {            z = object.property("blue");        }         if (!x.isValid() || !y.isValid() || !z.isValid()) {            // V8TODO: This breaks the sit script because in our API valid Vec3 can be created from just 2 values            //return false;        }         vec3.x = x.toVariant().toFloat();        vec3.y = y.toVariant().toFloat();        vec3.z = z.toVariant().toFloat();    } else {        return false;    }    return true;}#endif ScriptValue 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; } }"            "})");    }    ScriptValue value = engine->newObject();    value.setProperty("x", vec3.x);    value.setProperty("y", vec3.y);    value.setProperty("z", vec3.z);    value.setPrototype(prototype);    return value;} ScriptValue 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; } }"            "})");    }    ScriptValue value = engine->newObject();    value.setProperty("red", vec3.x);    value.setProperty("green", vec3.y);    value.setProperty("blue", vec3.z);    value.setPrototype(prototype);    return value;} bool u8vec3FromScriptValue(const ScriptValue& 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 {        ScriptValue x = object.property("x");        if (!x.isValid()) {            x = object.property("r");        }        if (!x.isValid()) {            x = object.property("red");        }         ScriptValue y = object.property("y");        if (!y.isValid()) {            y = object.property("g");        }        if (!y.isValid()) {            y = object.property("green");        }         ScriptValue 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();    }    return true;} ScriptValue vec4toScriptValue(ScriptEngine* engine, const glm::vec4& vec4) {    ScriptValue 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;} ScriptValue vec4ColorToScriptValue(ScriptEngine* engine, const glm::vec4& vec4) {    auto prototype = engine->globalObject().property("__hifi_vec4_color__");    if (!prototype.property("defined").toBool()) {        prototype = engine->evaluate(            "globalThis.__hifi_vec4_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; } },"            "3: { set: function(nv) { return this.alpha = nv; }, get: function() { return this.alpha; } },"            "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; } },"            "a: { set: function(nv) { return this.alpha = nv; }, get: function() { return this.alpha; } },"            "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; } },"            "a: { set: function(nv) { return this.alpha = nv; }, get: function() { return this.alpha; } }"            "})");    }    ScriptValue value = engine->newObject();    value.setProperty("red", vec4.x);    value.setProperty("green", vec4.y);    value.setProperty("blue", vec4.z);    value.setProperty("alpha", vec4.w);    value.setPrototype(prototype);    return value;} bool vec4FromScriptValue(const ScriptValue& 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();    return true;} ScriptValue mat4toScriptValue(ScriptEngine* engine, const glm::mat4& mat4) {    ScriptValue 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;} bool mat4FromScriptValue(const ScriptValue& 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();    return true;} ScriptValue qVectorVec3ColorToScriptValue(ScriptEngine* engine, const QVector<glm::vec3>& vector) {    ScriptValue array = engine->newArray();    for (int i = 0; i < vector.size(); i++) {        array.setProperty(i, vec3ColorToScriptValue(engine, vector.at(i)));    }    return array;} ScriptValue qVectorVec3ToScriptValue(ScriptEngine* engine, const QVector<glm::vec3>& vector) {    ScriptValue array = engine->newArray();    for (int i = 0; i < vector.size(); i++) {        array.setProperty(i, vec3ToScriptValue(engine, vector.at(i)));    }    return array;

Lines 1–500 of 1193.