History

isolate calls to the QtScript libraries to an interface we control

Heather Anderson committed 5 years ago

Commit 1e018db1 parent 713b29e260 files · +6904 −5064Browse files

Showing the changes to libraries/script-engine/src/ScriptValueUtils.cpp (1 of 260 files). Show all

Unified · Split

libraries/script-engine/src/ScriptValueUtils.cpp+888−0
@@ -0,0 +1,888 @@
1+//
2+// ScriptValueUtils.cpp
3+// libraries/shared/src
4+//
5+// Created by Anthony Thibault on 4/15/16.
6+// Copyright 2016 High Fidelity, Inc.
7+//
8+// Utilities for working with QtScriptValues
9+//
10+// Distributed under the Apache License, Version 2.0.
11+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
12+//
13+
14+#include "ScriptValueUtils.h"
15+
16+#include <QtCore/QVariant>
17+#include <QtGui/QColor>
18+#include <QtCore/QRect>
19+#include <QtCore/QUrl>
20+#include <QtCore/QUuid>
21+
22+#include <AACube.h>
23+#include <shared/MiniPromises.h>
24+#include <RegisteredMetaTypes.h>
25+
26+#include "ScriptEngine.h"
27+#include "ScriptEngineCast.h"
28+#include "ScriptValueIterator.h"
29+
30+bool isListOfStrings(const ScriptValuePointer& arg) {
31+ if (!arg->isArray()) {
32+ return false;
33+ }
34+
35+ auto lengthProperty = arg->property("length");
36+ if (!lengthProperty->isNumber()) {
37+ return false;
38+ }
39+
40+ int length = lengthProperty->toInt32();
41+ for (int i = 0; i < length; i++) {
42+ if (!arg->property(i)->isString()) {
43+ return false;
44+ }
45+ }
46+
47+ return true;
48+}
49+
50+void registerMetaTypes(ScriptEngine* engine) {
51+ scriptRegisterMetaType(engine, vec2ToScriptValue, vec2FromScriptValue);
52+ scriptRegisterMetaType(engine, vec3ToScriptValue, vec3FromScriptValue);
53+ scriptRegisterMetaType(engine, u8vec3ToScriptValue, u8vec3FromScriptValue);
54+ scriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue);
55+ scriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue);
56+ scriptRegisterMetaType(engine, mat4toScriptValue, mat4FromScriptValue);
57+
58+ scriptRegisterMetaType(engine, qVectorVec3ToScriptValue, qVectorVec3FromScriptValue);
59+ scriptRegisterMetaType(engine, qVectorQuatToScriptValue, qVectorQuatFromScriptValue);
60+ scriptRegisterMetaType(engine, qVectorBoolToScriptValue, qVectorBoolFromScriptValue);
61+ scriptRegisterMetaType(engine, qVectorFloatToScriptValue, qVectorFloatFromScriptValue);
62+ scriptRegisterMetaType(engine, qVectorIntToScriptValue, qVectorIntFromScriptValue);
63+ scriptRegisterMetaType(engine, qVectorQUuidToScriptValue, qVectorQUuidFromScriptValue);
64+
65+ scriptRegisterMetaType(engine, qSizeFToScriptValue, qSizeFFromScriptValue);
66+ scriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue);
67+ scriptRegisterMetaType(engine, qURLToScriptValue, qURLFromScriptValue);
68+ scriptRegisterMetaType(engine, qColorToScriptValue, qColorFromScriptValue);
69+
70+ scriptRegisterMetaType(engine, pickRayToScriptValue, pickRayFromScriptValue);
71+ scriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue);
72+ scriptRegisterMetaType(engine, quuidToScriptValue, quuidFromScriptValue);
73+ scriptRegisterMetaType(engine, aaCubeToScriptValue, aaCubeFromScriptValue);
74+
75+ scriptRegisterMetaType(engine, stencilMaskModeToScriptValue, stencilMaskModeFromScriptValue);
76+
77+ scriptRegisterMetaType(engine, promiseToScriptValue, promiseFromScriptValue);
78+
79+ scriptRegisterSequenceMetaType<QVector<unsigned int>>(engine);
80+}
81+
82+ScriptValuePointer vec2ToScriptValue(ScriptEngine* engine, const glm::vec2& vec2) {
83+ auto prototype = engine->globalObject()->property("__hifi_vec2__");
84+ if (!prototype->property("defined")->toBool()) {
85+ prototype = engine->evaluate(
86+ "__hifi_vec2__ = Object.defineProperties({}, { "
87+ "defined: { value: true },"
88+ "0: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"
89+ "1: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"
90+ "u: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"
91+ "v: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }"
92+ "})");
93+ }
94+ ScriptValuePointer value = engine->newObject();
95+ value->setProperty("x", vec2.x);
96+ value->setProperty("y", vec2.y);
97+ value->setPrototype(prototype);
98+ return value;
99+}
100+
101+void vec2FromScriptValue(const ScriptValuePointer& object, glm::vec2& vec2) {
102+ if (object->isNumber()) {
103+ vec2 = glm::vec2(object->toVariant().toFloat());
104+ } else if (object->isArray()) {
105+ QVariantList list = object->toVariant().toList();
106+ if (list.length() == 2) {
107+ vec2.x = list[0].toFloat();
108+ vec2.y = list[1].toFloat();
109+ }
110+ } else {
111+ ScriptValuePointer x = object->property("x");
112+ if (!x->isValid()) {
113+ x = object->property("u");
114+ }
115+
116+ ScriptValuePointer y = object->property("y");
117+ if (!y->isValid()) {
118+ y = object->property("v");
119+ }
120+
121+ vec2.x = x->toVariant().toFloat();
122+ vec2.y = y->toVariant().toFloat();
123+ }
124+}
125+
126+ScriptValuePointer vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) {
127+ auto prototype = engine->globalObject()->property("__hifi_vec3__");
128+ if (!prototype->property("defined")->toBool()) {
129+ prototype = engine->evaluate(
130+ "__hifi_vec3__ = Object.defineProperties({}, { "
131+ "defined: { value: true },"
132+ "0: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"
133+ "1: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"
134+ "2: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } },"
135+ "r: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"
136+ "g: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"
137+ "b: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } },"
138+ "red: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"
139+ "green: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"
140+ "blue: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }"
141+ "})");
142+ }
143+ ScriptValuePointer value = engine->newObject();
144+ value->setProperty("x", vec3.x);
145+ value->setProperty("y", vec3.y);
146+ value->setProperty("z", vec3.z);
147+ value->setPrototype(prototype);
148+ return value;
149+}
150+
151+ScriptValuePointer vec3ColorToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) {
152+ auto prototype = engine->globalObject()->property("__hifi_vec3_color__");
153+ if (!prototype->property("defined")->toBool()) {
154+ prototype = engine->evaluate(
155+ "__hifi_vec3_color__ = Object.defineProperties({}, { "
156+ "defined: { value: true },"
157+ "0: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } },"
158+ "1: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } },"
159+ "2: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } },"
160+ "r: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } },"
161+ "g: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } },"
162+ "b: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } },"
163+ "x: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } },"
164+ "y: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } },"
165+ "z: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }"
166+ "})");
167+ }
168+ ScriptValuePointer value = engine->newObject();
169+ value->setProperty("red", vec3.x);
170+ value->setProperty("green", vec3.y);
171+ value->setProperty("blue", vec3.z);
172+ value->setPrototype(prototype);
173+ return value;
174+}
175+
176+void vec3FromScriptValue(const ScriptValuePointer& object, glm::vec3& vec3) {
177+ if (object->isNumber()) {
178+ vec3 = glm::vec3(object->toVariant().toFloat());
179+ } else if (object->isString()) {
180+ QColor qColor(object->toString());
181+ if (qColor.isValid()) {
182+ vec3.x = qColor.red();
183+ vec3.y = qColor.green();
184+ vec3.z = qColor.blue();
185+ }
186+ } else if (object->isArray()) {
187+ QVariantList list = object->toVariant().toList();
188+ if (list.length() == 3) {
189+ vec3.x = list[0].toFloat();
190+ vec3.y = list[1].toFloat();
191+ vec3.z = list[2].toFloat();
192+ }
193+ } else {
194+ ScriptValuePointer x = object->property("x");
195+ if (!x->isValid()) {
196+ x = object->property("r");
197+ }
198+ if (!x->isValid()) {
199+ x = object->property("red");
200+ }
201+
202+ ScriptValuePointer y = object->property("y");
203+ if (!y->isValid()) {
204+ y = object->property("g");
205+ }
206+ if (!y->isValid()) {
207+ y = object->property("green");
208+ }
209+
210+ ScriptValuePointer z = object->property("z");
211+ if (!z->isValid()) {
212+ z = object->property("b");
213+ }
214+ if (!z->isValid()) {
215+ z = object->property("blue");
216+ }
217+
218+ vec3.x = x->toVariant().toFloat();
219+ vec3.y = y->toVariant().toFloat();
220+ vec3.z = z->toVariant().toFloat();
221+ }
222+}
223+
224+ScriptValuePointer u8vec3ToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3) {
225+ auto prototype = engine->globalObject()->property("__hifi_u8vec3__");
226+ if (!prototype->property("defined")->toBool()) {
227+ prototype = engine->evaluate(
228+ "__hifi_u8vec3__ = Object.defineProperties({}, { "
229+ "defined: { value: true },"
230+ "0: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"
231+ "1: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"
232+ "2: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } },"
233+ "r: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"
234+ "g: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"
235+ "b: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } },"
236+ "red: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } },"
237+ "green: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } },"
238+ "blue: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }"
239+ "})");
240+ }
241+ ScriptValuePointer value = engine->newObject();
242+ value->setProperty("x", vec3.x);
243+ value->setProperty("y", vec3.y);
244+ value->setProperty("z", vec3.z);
245+ value->setPrototype(prototype);
246+ return value;
247+}
248+
249+ScriptValuePointer u8vec3ColorToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3) {
250+ auto prototype = engine->globalObject()->property("__hifi_u8vec3_color__");
251+ if (!prototype->property("defined")->toBool()) {
252+ prototype = engine->evaluate(
253+ "__hifi_u8vec3_color__ = Object.defineProperties({}, { "
254+ "defined: { value: true },"
255+ "0: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } },"
256+ "1: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } },"
257+ "2: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } },"
258+ "r: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } },"
259+ "g: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } },"
260+ "b: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } },"
261+ "x: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } },"
262+ "y: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } },"
263+ "z: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }"
264+ "})");
265+ }
266+ ScriptValuePointer value = engine->newObject();
267+ value->setProperty("red", vec3.x);
268+ value->setProperty("green", vec3.y);
269+ value->setProperty("blue", vec3.z);
270+ value->setPrototype(prototype);
271+ return value;
272+}
273+
274+void u8vec3FromScriptValue(const ScriptValuePointer& object, glm::u8vec3& vec3) {
275+ if (object->isNumber()) {
276+ vec3 = glm::vec3(object->toVariant().toUInt());
277+ } else if (object->isString()) {
278+ QColor qColor(object->toString());
279+ if (qColor.isValid()) {
280+ vec3.x = (uint8_t)qColor.red();
281+ vec3.y = (uint8_t)qColor.green();
282+ vec3.z = (uint8_t)qColor.blue();
283+ }
284+ } else if (object->isArray()) {
285+ QVariantList list = object->toVariant().toList();
286+ if (list.length() == 3) {
287+ vec3.x = list[0].toUInt();
288+ vec3.y = list[1].toUInt();
289+ vec3.z = list[2].toUInt();
290+ }
291+ } else {
292+ ScriptValuePointer x = object->property("x");
293+ if (!x->isValid()) {
294+ x = object->property("r");
295+ }
296+ if (!x->isValid()) {
297+ x = object->property("red");
298+ }
299+
300+ ScriptValuePointer y = object->property("y");
301+ if (!y->isValid()) {
302+ y = object->property("g");
303+ }
304+ if (!y->isValid()) {
305+ y = object->property("green");
306+ }
307+
308+ ScriptValuePointer z = object->property("z");
309+ if (!z->isValid()) {
310+ z = object->property("b");
311+ }
312+ if (!z->isValid()) {
313+ z = object->property("blue");
314+ }
315+
316+ vec3.x = x->toVariant().toUInt();
317+ vec3.y = y->toVariant().toUInt();
318+ vec3.z = z->toVariant().toUInt();
319+ }
320+}
321+
322+ScriptValuePointer vec4toScriptValue(ScriptEngine* engine, const glm::vec4& vec4) {
323+ ScriptValuePointer obj = engine->newObject();
324+ obj->setProperty("x", vec4.x);
325+ obj->setProperty("y", vec4.y);
326+ obj->setProperty("z", vec4.z);
327+ obj->setProperty("w", vec4.w);
328+ return obj;
329+}
330+
331+void vec4FromScriptValue(const ScriptValuePointer& object, glm::vec4& vec4) {
332+ vec4.x = object->property("x")->toVariant().toFloat();
333+ vec4.y = object->property("y")->toVariant().toFloat();
334+ vec4.z = object->property("z")->toVariant().toFloat();
335+ vec4.w = object->property("w")->toVariant().toFloat();
336+}
337+
338+ScriptValuePointer mat4toScriptValue(ScriptEngine* engine, const glm::mat4& mat4) {
339+ ScriptValuePointer obj = engine->newObject();
340+ obj->setProperty("r0c0", mat4[0][0]);
341+ obj->setProperty("r1c0", mat4[0][1]);
342+ obj->setProperty("r2c0", mat4[0][2]);
343+ obj->setProperty("r3c0", mat4[0][3]);
344+ obj->setProperty("r0c1", mat4[1][0]);
345+ obj->setProperty("r1c1", mat4[1][1]);
346+ obj->setProperty("r2c1", mat4[1][2]);
347+ obj->setProperty("r3c1", mat4[1][3]);
348+ obj->setProperty("r0c2", mat4[2][0]);
349+ obj->setProperty("r1c2", mat4[2][1]);
350+ obj->setProperty("r2c2", mat4[2][2]);
351+ obj->setProperty("r3c2", mat4[2][3]);
352+ obj->setProperty("r0c3", mat4[3][0]);
353+ obj->setProperty("r1c3", mat4[3][1]);
354+ obj->setProperty("r2c3", mat4[3][2]);
355+ obj->setProperty("r3c3", mat4[3][3]);
356+ return obj;
357+}
358+
359+void mat4FromScriptValue(const ScriptValuePointer& object, glm::mat4& mat4) {
360+ mat4[0][0] = object->property("r0c0")->toVariant().toFloat();
361+ mat4[0][1] = object->property("r1c0")->toVariant().toFloat();
362+ mat4[0][2] = object->property("r2c0")->toVariant().toFloat();
363+ mat4[0][3] = object->property("r3c0")->toVariant().toFloat();
364+ mat4[1][0] = object->property("r0c1")->toVariant().toFloat();
365+ mat4[1][1] = object->property("r1c1")->toVariant().toFloat();
366+ mat4[1][2] = object->property("r2c1")->toVariant().toFloat();
367+ mat4[1][3] = object->property("r3c1")->toVariant().toFloat();
368+ mat4[2][0] = object->property("r0c2")->toVariant().toFloat();
369+ mat4[2][1] = object->property("r1c2")->toVariant().toFloat();
370+ mat4[2][2] = object->property("r2c2")->toVariant().toFloat();
371+ mat4[2][3] = object->property("r3c2")->toVariant().toFloat();
372+ mat4[3][0] = object->property("r0c3")->toVariant().toFloat();
373+ mat4[3][1] = object->property("r1c3")->toVariant().toFloat();
374+ mat4[3][2] = object->property("r2c3")->toVariant().toFloat();
375+ mat4[3][3] = object->property("r3c3")->toVariant().toFloat();
376+}
377+
378+ScriptValuePointer qVectorVec3ColorToScriptValue(ScriptEngine* engine, const QVector<glm::vec3>& vector) {
379+ ScriptValuePointer array = engine->newArray();
380+ for (int i = 0; i < vector.size(); i++) {
381+ array->setProperty(i, vec3ColorToScriptValue(engine, vector.at(i)));
382+ }
383+ return array;
384+}
385+
386+ScriptValuePointer qVectorVec3ToScriptValue(ScriptEngine* engine, const QVector<glm::vec3>& vector) {
387+ ScriptValuePointer array = engine->newArray();
388+ for (int i = 0; i < vector.size(); i++) {
389+ array->setProperty(i, vec3ToScriptValue(engine, vector.at(i)));
390+ }
391+ return array;
392+}
393+
394+QVector<glm::vec3> qVectorVec3FromScriptValue(const ScriptValuePointer& array) {
395+ QVector<glm::vec3> newVector;
396+ int length = array->property("length")->toInteger();
397+
398+ for (int i = 0; i < length; i++) {
399+ glm::vec3 newVec3 = glm::vec3();
400+ vec3FromScriptValue(array->property(i), newVec3);
401+ newVector << newVec3;
402+ }
403+ return newVector;
404+}
405+
406+void qVectorVec3FromScriptValue(const ScriptValuePointer& array, QVector<glm::vec3>& vector) {
407+ int length = array->property("length")->toInteger();
408+
409+ for (int i = 0; i < length; i++) {
410+ glm::vec3 newVec3 = glm::vec3();
411+ vec3FromScriptValue(array->property(i), newVec3);
412+ vector << newVec3;
413+ }
414+}
415+
416+ScriptValuePointer quatToScriptValue(ScriptEngine* engine, const glm::quat& quat) {
417+ ScriptValuePointer obj = engine->newObject();
418+ if (quat.x != quat.x || quat.y != quat.y || quat.z != quat.z || quat.w != quat.w) {
419+ // if quat contains a NaN don't try to convert it
420+ return obj;
421+ }
422+ obj->setProperty("x", quat.x);
423+ obj->setProperty("y", quat.y);
424+ obj->setProperty("z", quat.z);
425+ obj->setProperty("w", quat.w);
426+ return obj;
427+}
428+
429+void quatFromScriptValue(const ScriptValuePointer& object, glm::quat& quat) {
430+ quat.x = object->property("x")->toVariant().toFloat();
431+ quat.y = object->property("y")->toVariant().toFloat();
432+ quat.z = object->property("z")->toVariant().toFloat();
433+ quat.w = object->property("w")->toVariant().toFloat();
434+
435+ // enforce normalized quaternion
436+ float length = glm::length(quat);
437+ if (length > FLT_EPSILON) {
438+ quat /= length;
439+ } else {
440+ quat = glm::quat();
441+ }
442+}
443+
444+ScriptValuePointer qVectorQuatToScriptValue(ScriptEngine* engine, const QVector<glm::quat>& vector) {
445+ ScriptValuePointer array = engine->newArray();
446+ for (int i = 0; i < vector.size(); i++) {
447+ array->setProperty(i, quatToScriptValue(engine, vector.at(i)));
448+ }
449+ return array;
450+}
451+
452+ScriptValuePointer qVectorBoolToScriptValue(ScriptEngine* engine, const QVector<bool>& vector) {
453+ ScriptValuePointer array = engine->newArray();
454+ for (int i = 0; i < vector.size(); i++) {
455+ array->setProperty(i, vector.at(i));
456+ }
457+ return array;
458+}
459+
460+QVector<float> qVectorFloatFromScriptValue(const ScriptValuePointer& array) {
461+ if (!array->isArray()) {
462+ return QVector<float>();
463+ }
464+ QVector<float> newVector;
465+ int length = array->property("length")->toInteger();
466+ newVector.reserve(length);
467+ for (int i = 0; i < length; i++) {
468+ if (array->property(i)->isNumber()) {
469+ newVector << array->property(i)->toNumber();
470+ }
471+ }
472+
473+ return newVector;
474+}
475+
476+ScriptValuePointer qVectorQUuidToScriptValue(ScriptEngine* engine, const QVector<QUuid>& vector) {
477+ ScriptValuePointer array = engine->newArray();
478+ for (int i = 0; i < vector.size(); i++) {
479+ array->setProperty(i, quuidToScriptValue(engine, vector.at(i)));
480+ }
481+ return array;
482+}
483+
484+void qVectorQUuidFromScriptValue(const ScriptValuePointer& array, QVector<QUuid>& vector) {
485+ int length = array->property("length")->toInteger();
486+
487+ for (int i = 0; i < length; i++) {
488+ vector << array->property(i)->toVariant().toUuid();
489+ }
490+}
491+
492+QVector<QUuid> qVectorQUuidFromScriptValue(const ScriptValuePointer& array) {
493+ if (!array->isArray()) {
494+ return QVector<QUuid>();
495+ }
496+ QVector<QUuid> newVector;
497+ int length = array->property("length")->toInteger();
498+ newVector.reserve(length);
499+ for (int i = 0; i < length; i++) {
500+ QString uuidAsString = array->property(i)->toString();
501+ QUuid fromString(uuidAsString);
502+ newVector << fromString;
503+ }
504+ return newVector;
505+}
506+
507+ScriptValuePointer qVectorFloatToScriptValue(ScriptEngine* engine, const QVector<float>& vector) {
508+ ScriptValuePointer array = engine->newArray();
509+ for (int i = 0; i < vector.size(); i++) {
510+ float num = vector.at(i);
511+ array->setProperty(i, engine->newValue(num));
512+ }
513+ return array;
514+}
515+
516+ScriptValuePointer qVectorIntToScriptValue(ScriptEngine* engine, const QVector<uint32_t>& vector) {
517+ ScriptValuePointer array = engine->newArray();
518+ for (int i = 0; i < vector.size(); i++) {
519+ int num = vector.at(i);
520+ array->setProperty(i, engine->newValue(num));
521+ }
522+ return array;
523+}
524+
525+void qVectorFloatFromScriptValue(const ScriptValuePointer& array, QVector<float>& vector) {
526+ int length = array->property("length")->toInteger();
527+
528+ for (int i = 0; i < length; i++) {
529+ vector << array->property(i)->toVariant().toFloat();
530+ }
531+}
532+
533+void qVectorIntFromScriptValue(const ScriptValuePointer& array, QVector<uint32_t>& vector) {
534+ int length = array->property("length")->toInteger();
535+
536+ for (int i = 0; i < length; i++) {
537+ vector << array->property(i)->toVariant().toInt();
538+ }
539+}
540+
541+QVector<glm::quat> qVectorQuatFromScriptValue(const ScriptValuePointer& array) {
542+ QVector<glm::quat> newVector;
543+ int length = array->property("length")->toInteger();
544+
545+ for (int i = 0; i < length; i++) {
546+ glm::quat newQuat = glm::quat();
547+ quatFromScriptValue(array->property(i), newQuat);
548+ newVector << newQuat;
549+ }
550+ return newVector;
551+}
552+
553+void qVectorQuatFromScriptValue(const ScriptValuePointer& array, QVector<glm::quat>& vector) {
554+ int length = array->property("length")->toInteger();
555+
556+ for (int i = 0; i < length; i++) {
557+ glm::quat newQuat = glm::quat();
558+ quatFromScriptValue(array->property(i), newQuat);
559+ vector << newQuat;
560+ }
561+}
562+
563+QVector<bool> qVectorBoolFromScriptValue(const ScriptValuePointer& array) {
564+ QVector<bool> newVector;
565+ int length = array->property("length")->toInteger();
566+
567+ for (int i = 0; i < length; i++) {
568+ newVector << array->property(i)->toBool();
569+ }
570+ return newVector;
571+}
572+
573+void qVectorBoolFromScriptValue(const ScriptValuePointer& array, QVector<bool>& vector) {
574+ int length = array->property("length")->toInteger();
575+
576+ for (int i = 0; i < length; i++) {
577+ vector << array->property(i)->toBool();
578+ }
579+}
580+
581+ScriptValuePointer qRectToScriptValue(ScriptEngine* engine, const QRect& rect) {
582+ ScriptValuePointer obj = engine->newObject();
583+ obj->setProperty("x", rect.x());
584+ obj->setProperty("y", rect.y());
585+ obj->setProperty("width", rect.width());
586+ obj->setProperty("height", rect.height());
587+ return obj;
588+}
589+
590+void qRectFromScriptValue(const ScriptValuePointer& object, QRect& rect) {
591+ rect.setX(object->property("x")->toVariant().toInt());
592+ rect.setY(object->property("y")->toVariant().toInt());
593+ rect.setWidth(object->property("width")->toVariant().toInt());
594+ rect.setHeight(object->property("height")->toVariant().toInt());
595+}
596+
597+ScriptValuePointer qRectFToScriptValue(ScriptEngine* engine, const QRectF& rect) {
598+ ScriptValuePointer obj = engine->newObject();
599+ obj->setProperty("x", rect.x());
600+ obj->setProperty("y", rect.y());
601+ obj->setProperty("width", rect.width());
602+ obj->setProperty("height", rect.height());
603+ return obj;
604+}
605+
606+void qRectFFromScriptValue(const ScriptValuePointer& object, QRectF& rect) {
607+ rect.setX(object->property("x")->toVariant().toFloat());
608+ rect.setY(object->property("y")->toVariant().toFloat());
609+ rect.setWidth(object->property("width")->toVariant().toFloat());
610+ rect.setHeight(object->property("height")->toVariant().toFloat());
611+}
612+
613+ScriptValuePointer qColorToScriptValue(ScriptEngine* engine, const QColor& color) {
614+ ScriptValuePointer object = engine->newObject();
615+ object->setProperty("red", color.red());
616+ object->setProperty("green", color.green());
617+ object->setProperty("blue", color.blue());
618+ object->setProperty("alpha", color.alpha());
619+ return object;
620+}
621+
622+/**jsdoc
623+ * An axis-aligned cube, defined as the bottom right near (minimum axes values) corner of the cube plus the dimension of its
624+ * sides.
625+ * @typedef {object} AACube
626+ * @property {number} x - X coordinate of the brn corner of the cube.
627+ * @property {number} y - Y coordinate of the brn corner of the cube.
628+ * @property {number} z - Z coordinate of the brn corner of the cube.
629+ * @property {number} scale - The dimensions of each side of the cube.
630+ */
631+ScriptValuePointer aaCubeToScriptValue(ScriptEngine* engine, const AACube& aaCube) {
632+ ScriptValuePointer obj = engine->newObject();
633+ const glm::vec3& corner = aaCube.getCorner();
634+ obj->setProperty("x", corner.x);
635+ obj->setProperty("y", corner.y);
636+ obj->setProperty("z", corner.z);
637+ obj->setProperty("scale", aaCube.getScale());
638+ return obj;
639+}
640+
641+void aaCubeFromScriptValue(const ScriptValuePointer& object, AACube& aaCube) {
642+ glm::vec3 corner;
643+ corner.x = object->property("x")->toVariant().toFloat();
644+ corner.y = object->property("y")->toVariant().toFloat();
645+ corner.z = object->property("z")->toVariant().toFloat();
646+ float scale = object->property("scale")->toVariant().toFloat();
647+
648+ aaCube.setBox(corner, scale);
649+}
650+
651+void qColorFromScriptValue(const ScriptValuePointer& object, QColor& color) {
652+ if (object->isNumber()) {
653+ color.setRgb(object->toUInt32());
654+
655+ } else if (object->isString()) {
656+ color.setNamedColor(object->toString());
657+
658+ } else {
659+ ScriptValuePointer alphaValue = object->property("alpha");
660+ color.setRgb(object->property("red")->toInt32(), object->property("green")->toInt32(), object->property("blue")->toInt32(),
661+ alphaValue->isNumber() ? alphaValue->toInt32() : 255);
662+ }
663+}
664+
665+ScriptValuePointer qURLToScriptValue(ScriptEngine* engine, const QUrl& url) {
666+ return engine->newValue(url.toString());
667+}
668+
669+void qURLFromScriptValue(const ScriptValuePointer& object, QUrl& url) {
670+ url = object->toString();
671+}
672+
673+ScriptValuePointer pickRayToScriptValue(ScriptEngine* engine, const PickRay& pickRay) {
674+ ScriptValuePointer obj = engine->newObject();
675+ ScriptValuePointer origin = vec3ToScriptValue(engine, pickRay.origin);
676+ obj->setProperty("origin", origin);
677+ ScriptValuePointer direction = vec3ToScriptValue(engine, pickRay.direction);
678+ obj->setProperty("direction", direction);
679+ return obj;
680+}
681+
682+void pickRayFromScriptValue(const ScriptValuePointer& object, PickRay& pickRay) {
683+ ScriptValuePointer originValue = object->property("origin");
684+ if (originValue->isValid()) {
685+ auto x = originValue->property("x");
686+ auto y = originValue->property("y");
687+ auto z = originValue->property("z");
688+ if (x->isValid() && y->isValid() && z->isValid()) {
689+ pickRay.origin.x = x->toVariant().toFloat();
690+ pickRay.origin.y = y->toVariant().toFloat();
691+ pickRay.origin.z = z->toVariant().toFloat();
692+ }
693+ }
694+ ScriptValuePointer directionValue = object->property("direction");
695+ if (directionValue->isValid()) {
696+ auto x = directionValue->property("x");
697+ auto y = directionValue->property("y");
698+ auto z = directionValue->property("z");
699+ if (x->isValid() && y->isValid() && z->isValid()) {
700+ pickRay.direction.x = x->toVariant().toFloat();
701+ pickRay.direction.y = y->toVariant().toFloat();
702+ pickRay.direction.z = z->toVariant().toFloat();
703+ }
704+ }
705+}
706+
707+/**jsdoc
708+ * Details of a collision between avatars and entities.
709+ * @typedef {object} Collision
710+ * @property {ContactEventType} type - The contact type of the collision event.
711+ * @property {Uuid} idA - The ID of one of the avatars or entities in the collision.
712+ * @property {Uuid} idB - The ID of the other of the avatars or entities in the collision.
713+ * @property {Vec3} penetration - The amount of penetration between the two items.
714+ * @property {Vec3} contactPoint - The point of contact.
715+ * @property {Vec3} velocityChange - The change in relative velocity of the two items, in m/s.
716+ */
717+ScriptValuePointer collisionToScriptValue(ScriptEngine* engine, const Collision& collision) {
718+ ScriptValuePointer obj = engine->newObject();
719+ obj->setProperty("type", collision.type);
720+ obj->setProperty("idA", quuidToScriptValue(engine, collision.idA));
721+ obj->setProperty("idB", quuidToScriptValue(engine, collision.idB));
722+ obj->setProperty("penetration", vec3ToScriptValue(engine, collision.penetration));
723+ obj->setProperty("contactPoint", vec3ToScriptValue(engine, collision.contactPoint));
724+ obj->setProperty("velocityChange", vec3ToScriptValue(engine, collision.velocityChange));
725+ return obj;
726+}
727+
728+void collisionFromScriptValue(const ScriptValuePointer& object, Collision& collision) {
729+ // TODO: implement this when we know what it means to accept collision events from JS
730+}
731+
732+ScriptValuePointer quuidToScriptValue(ScriptEngine* engine, const QUuid& uuid) {
733+ if (uuid.isNull()) {
734+ return engine->nullValue();
735+ }
736+ ScriptValuePointer obj(engine->newValue(uuid.toString()));
737+ return obj;
738+}
739+
740+void quuidFromScriptValue(const ScriptValuePointer& object, QUuid& uuid) {
741+ if (object.isNull()) {
742+ uuid = QUuid();
743+ return;
744+ }
745+ QString uuidAsString = object->toVariant().toString();
746+ QUuid fromString(uuidAsString);
747+ uuid = fromString;
748+}
749+
750+/**jsdoc
751+ * A 2D size value.
752+ * @typedef {object} Size
753+ * @property {number} height - The height value.
754+ * @property {number} width - The width value.
755+ */
756+ScriptValuePointer qSizeFToScriptValue(ScriptEngine* engine, const QSizeF& qSizeF) {
757+ ScriptValuePointer obj = engine->newObject();
758+ obj->setProperty("width", qSizeF.width());
759+ obj->setProperty("height", qSizeF.height());
760+ return obj;
761+}
762+
763+void qSizeFFromScriptValue(const ScriptValuePointer& object, QSizeF& qSizeF) {
764+ qSizeF.setWidth(object->property("width")->toVariant().toFloat());
765+ qSizeF.setHeight(object->property("height")->toVariant().toFloat());
766+}
767+
768+/**jsdoc
769+ * The details of an animation that is playing.
770+ * @typedef {object} Avatar.AnimationDetails
771+ * @property {string} role - <em>Not used.</em>
772+ * @property {string} url - The URL to the animation file. Animation files need to be in glTF or FBX format but only need to
773+ * contain the avatar skeleton and animation data. glTF models may be in JSON or binary format (".gltf" or ".glb" URLs
774+ * respectively).
775+ * <p><strong>Warning:</strong> glTF animations currently do not always animate correctly.</p>
776+ * @property {number} fps - The frames per second(FPS) rate for the animation playback. 30 FPS is normal speed.
777+ * @property {number} priority - <em>Not used.</em>
778+ * @property {boolean} loop - <code>true</code> if the animation should loop, <code>false</code> if it shouldn't.
779+ * @property {boolean} hold - <em>Not used.</em>
780+ * @property {number} firstFrame - The frame the animation should start at.
781+ * @property {number} lastFrame - The frame the animation should stop at.
782+ * @property {boolean} running - <em>Not used.</em>
783+ * @property {number} currentFrame - The current frame being played.
784+ * @property {boolean} startAutomatically - <em>Not used.</em>
785+ * @property {boolean} allowTranslation - <em>Not used.</em>
786+ */
787+ScriptValuePointer animationDetailsToScriptValue(ScriptEngine* engine, const AnimationDetails& details) {
788+ ScriptValuePointer obj = engine->newObject();
789+ obj->setProperty("role", details.role);
790+ obj->setProperty("url", details.url.toString());
791+ obj->setProperty("fps", details.fps);
792+ obj->setProperty("priority", details.priority);
793+ obj->setProperty("loop", details.loop);
794+ obj->setProperty("hold", details.hold);
795+ obj->setProperty("startAutomatically", details.startAutomatically);
796+ obj->setProperty("firstFrame", details.firstFrame);
797+ obj->setProperty("lastFrame", details.lastFrame);
798+ obj->setProperty("running", details.running);
799+ obj->setProperty("currentFrame", details.currentFrame);
800+ obj->setProperty("allowTranslation", details.allowTranslation);
801+ return obj;
802+}
803+
804+void animationDetailsFromScriptValue(const ScriptValuePointer& object, AnimationDetails& details) {
805+ // nothing for now...
806+}
807+
808+ScriptValuePointer meshToScriptValue(ScriptEngine* engine, MeshProxy* const& in) {
809+ return engine->newQObject(in, ScriptEngine::QtOwnership,
810+ ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeChildObjects);
811+}
812+
813+void meshFromScriptValue(const ScriptValuePointer& value, MeshProxy*& out) {
814+ out = qobject_cast<MeshProxy*>(value->toQObject());
815+}
816+
817+ScriptValuePointer meshesToScriptValue(ScriptEngine* engine, const MeshProxyList& in) {
818+ // ScriptValueList result;
819+ ScriptValuePointer result = engine->newArray();
820+ int i = 0;
821+ foreach (MeshProxy* const meshProxy, in) { result->setProperty(i++, meshToScriptValue(engine, meshProxy)); }
822+ return result;
823+}
824+
825+void meshesFromScriptValue(const ScriptValuePointer& value, MeshProxyList& out) {
826+ ScriptValueIteratorPointer itr(value->newIterator());
827+
828+ qDebug() << "in meshesFromScriptValue, value.length =" << value->property("length")->toInt32();
829+
830+ while (itr->hasNext()) {
831+ itr->next();
832+ MeshProxy* meshProxy = scriptvalue_cast<MeshProxyList::value_type>(itr->value());
833+ if (meshProxy) {
834+ out.append(meshProxy);
835+ } else {
836+ qDebug() << "null meshProxy";
837+ }
838+ }
839+}
840+
841+/**jsdoc
842+ * A triangle in a mesh.
843+ * @typedef {object} MeshFace
844+ * @property {number[]} vertices - The indexes of the three vertices that make up the face.
845+ */
846+ScriptValuePointer meshFaceToScriptValue(ScriptEngine* engine, const MeshFace& meshFace) {
847+ ScriptValuePointer obj = engine->newObject();
848+ obj->setProperty("vertices", qVectorIntToScriptValue(engine, meshFace.vertexIndices));
849+ return obj;
850+}
851+
852+void meshFaceFromScriptValue(const ScriptValuePointer& object, MeshFace& meshFaceResult) {
853+ qVectorIntFromScriptValue(object->property("vertices"), meshFaceResult.vertexIndices);
854+}
855+
856+ScriptValuePointer qVectorMeshFaceToScriptValue(ScriptEngine* engine, const QVector<MeshFace>& vector) {
857+ ScriptValuePointer array = engine->newArray();
858+ for (int i = 0; i < vector.size(); i++) {
859+ array->setProperty(i, meshFaceToScriptValue(engine, vector.at(i)));
860+ }
861+ return array;
862+}
863+
864+void qVectorMeshFaceFromScriptValue(const ScriptValuePointer& array, QVector<MeshFace>& result) {
865+ int length = array->property("length")->toInteger();
866+ result.clear();
867+
868+ for (int i = 0; i < length; i++) {
869+ MeshFace meshFace = MeshFace();
870+ meshFaceFromScriptValue(array->property(i), meshFace);
871+ result << meshFace;
872+ }
873+}
874+
875+ScriptValuePointer stencilMaskModeToScriptValue(ScriptEngine* engine, const StencilMaskMode& stencilMode) {
876+ return engine->newValue((int)stencilMode);
877+}
878+
879+void stencilMaskModeFromScriptValue(const ScriptValuePointer& object, StencilMaskMode& stencilMode) {
880+ stencilMode = StencilMaskMode(object->toVariant().toInt());
881+}
882+
883+void promiseFromScriptValue(const ScriptValuePointer& object, std::shared_ptr<MiniPromise>& promise) {
884+ Q_ASSERT(false);
885+}
886+ScriptValuePointer promiseToScriptValue(ScriptEngine* engine, const std::shared_ptr<MiniPromise>& promise) {
887+ return engine->newQObject(promise.get());
888+}