mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 16:41:02 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into update-collision-hulls-of-avatar-children
This commit is contained in:
commit
8158d34b20
31 changed files with 691 additions and 92 deletions
|
@ -397,7 +397,7 @@ void Agent::processAgentAvatarAndAudio(float deltaTime) {
|
||||||
if (_numAvatarSoundSentBytes == soundByteArray.size()) {
|
if (_numAvatarSoundSentBytes == soundByteArray.size()) {
|
||||||
// we're done with this sound object - so set our pointer back to NULL
|
// we're done with this sound object - so set our pointer back to NULL
|
||||||
// and our sent bytes back to zero
|
// and our sent bytes back to zero
|
||||||
_avatarSound = NULL;
|
_avatarSound.clear();
|
||||||
_numAvatarSoundSentBytes = 0;
|
_numAvatarSoundSentBytes = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ public:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void run();
|
void run();
|
||||||
void playAvatarSound(Sound* avatarSound) { setAvatarSound(avatarSound); }
|
void playAvatarSound(SharedSoundPointer avatarSound) { setAvatarSound(avatarSound); }
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void requestScript();
|
void requestScript();
|
||||||
|
@ -77,7 +77,7 @@ private:
|
||||||
MixedAudioStream _receivedAudioStream;
|
MixedAudioStream _receivedAudioStream;
|
||||||
float _lastReceivedAudioLoudness;
|
float _lastReceivedAudioLoudness;
|
||||||
|
|
||||||
void setAvatarSound(Sound* avatarSound) { _avatarSound = avatarSound; }
|
void setAvatarSound(SharedSoundPointer avatarSound) { _avatarSound = avatarSound; }
|
||||||
|
|
||||||
void sendAvatarIdentityPacket();
|
void sendAvatarIdentityPacket();
|
||||||
void sendAvatarBillboardPacket();
|
void sendAvatarBillboardPacket();
|
||||||
|
@ -85,7 +85,7 @@ private:
|
||||||
QString _scriptContents;
|
QString _scriptContents;
|
||||||
QTimer* _scriptRequestTimeout { nullptr };
|
QTimer* _scriptRequestTimeout { nullptr };
|
||||||
bool _isListeningToAudioStream = false;
|
bool _isListeningToAudioStream = false;
|
||||||
Sound* _avatarSound = nullptr;
|
SharedSoundPointer _avatarSound;
|
||||||
int _numAvatarSoundSentBytes = 0;
|
int _numAvatarSoundSentBytes = 0;
|
||||||
bool _isAvatar = false;
|
bool _isAvatar = false;
|
||||||
QTimer* _avatarIdentityTimer = nullptr;
|
QTimer* _avatarIdentityTimer = nullptr;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": 1.1,
|
"version": 1.2,
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
{
|
||||||
"name": "metaverse",
|
"name": "metaverse",
|
||||||
|
@ -249,7 +249,7 @@
|
||||||
"label": "X end",
|
"label": "X end",
|
||||||
"can_set": true,
|
"can_set": true,
|
||||||
"placeholder": "16384.0"
|
"placeholder": "16384.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "y_min",
|
"name": "y_min",
|
||||||
"label": "Y start",
|
"label": "Y start",
|
||||||
|
|
|
@ -103,4 +103,5 @@
|
||||||
<script src='js/sweetalert.min.js'></script>
|
<script src='js/sweetalert.min.js'></script>
|
||||||
<script src='js/settings.js'></script>
|
<script src='js/settings.js'></script>
|
||||||
<script src='js/form2js.min.js'></script>
|
<script src='js/form2js.min.js'></script>
|
||||||
|
<script src='js/sha256.js'></script>
|
||||||
<!--#include virtual="page-end.html"-->
|
<!--#include virtual="page-end.html"-->
|
||||||
|
|
|
@ -867,6 +867,14 @@ function saveSettings() {
|
||||||
// grab a JSON representation of the form via form2js
|
// grab a JSON representation of the form via form2js
|
||||||
var formJSON = form2js('settings-form', ".", false, cleanupFormValues, true);
|
var formJSON = form2js('settings-form', ".", false, cleanupFormValues, true);
|
||||||
|
|
||||||
|
// check if we've set the basic http password - if so convert it to base64
|
||||||
|
if (formJSON["security"]) {
|
||||||
|
var password = formJSON["security"]["http_password"];
|
||||||
|
if (password.length > 0) {
|
||||||
|
formJSON["security"]["http_password"] = sha256_digest(password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.log(formJSON);
|
console.log(formJSON);
|
||||||
|
|
||||||
// re-enable all inputs
|
// re-enable all inputs
|
||||||
|
|
247
domain-server/resources/web/settings/js/sha256.js
Normal file
247
domain-server/resources/web/settings/js/sha256.js
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
/*
|
||||||
|
* A JavaScript implementation of the SHA256 hash function.
|
||||||
|
*
|
||||||
|
* FILE: sha256.js
|
||||||
|
* VERSION: 0.8
|
||||||
|
* AUTHOR: Christoph Bichlmeier <informatik@zombiearena.de>
|
||||||
|
*
|
||||||
|
* NOTE: This version is not tested thoroughly!
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003, Christoph Bichlmeier
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* ======================================================================
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
|
||||||
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||||
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||||
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* SHA256 logical functions */
|
||||||
|
function rotateRight(n,x) {
|
||||||
|
return ((x >>> n) | (x << (32 - n)));
|
||||||
|
}
|
||||||
|
function choice(x,y,z) {
|
||||||
|
return ((x & y) ^ (~x & z));
|
||||||
|
}
|
||||||
|
function majority(x,y,z) {
|
||||||
|
return ((x & y) ^ (x & z) ^ (y & z));
|
||||||
|
}
|
||||||
|
function sha256_Sigma0(x) {
|
||||||
|
return (rotateRight(2, x) ^ rotateRight(13, x) ^ rotateRight(22, x));
|
||||||
|
}
|
||||||
|
function sha256_Sigma1(x) {
|
||||||
|
return (rotateRight(6, x) ^ rotateRight(11, x) ^ rotateRight(25, x));
|
||||||
|
}
|
||||||
|
function sha256_sigma0(x) {
|
||||||
|
return (rotateRight(7, x) ^ rotateRight(18, x) ^ (x >>> 3));
|
||||||
|
}
|
||||||
|
function sha256_sigma1(x) {
|
||||||
|
return (rotateRight(17, x) ^ rotateRight(19, x) ^ (x >>> 10));
|
||||||
|
}
|
||||||
|
function sha256_expand(W, j) {
|
||||||
|
return (W[j&0x0f] += sha256_sigma1(W[(j+14)&0x0f]) + W[(j+9)&0x0f] +
|
||||||
|
sha256_sigma0(W[(j+1)&0x0f]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hash constant words K: */
|
||||||
|
var K256 = new Array(
|
||||||
|
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||||
|
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||||
|
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||||
|
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||||
|
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||||
|
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||||
|
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||||
|
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||||
|
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||||
|
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||||
|
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||||
|
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||||
|
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||||
|
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||||
|
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||||
|
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||||
|
);
|
||||||
|
|
||||||
|
/* global arrays */
|
||||||
|
var ihash, count, buffer;
|
||||||
|
var sha256_hex_digits = "0123456789abcdef";
|
||||||
|
|
||||||
|
/* Add 32-bit integers with 16-bit operations (bug in some JS-interpreters:
|
||||||
|
overflow) */
|
||||||
|
function safe_add(x, y)
|
||||||
|
{
|
||||||
|
var lsw = (x & 0xffff) + (y & 0xffff);
|
||||||
|
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
||||||
|
return (msw << 16) | (lsw & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialise the SHA256 computation */
|
||||||
|
function sha256_init() {
|
||||||
|
ihash = new Array(8);
|
||||||
|
count = new Array(2);
|
||||||
|
buffer = new Array(64);
|
||||||
|
count[0] = count[1] = 0;
|
||||||
|
ihash[0] = 0x6a09e667;
|
||||||
|
ihash[1] = 0xbb67ae85;
|
||||||
|
ihash[2] = 0x3c6ef372;
|
||||||
|
ihash[3] = 0xa54ff53a;
|
||||||
|
ihash[4] = 0x510e527f;
|
||||||
|
ihash[5] = 0x9b05688c;
|
||||||
|
ihash[6] = 0x1f83d9ab;
|
||||||
|
ihash[7] = 0x5be0cd19;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transform a 512-bit message block */
|
||||||
|
function sha256_transform() {
|
||||||
|
var a, b, c, d, e, f, g, h, T1, T2;
|
||||||
|
var W = new Array(16);
|
||||||
|
|
||||||
|
/* Initialize registers with the previous intermediate value */
|
||||||
|
a = ihash[0];
|
||||||
|
b = ihash[1];
|
||||||
|
c = ihash[2];
|
||||||
|
d = ihash[3];
|
||||||
|
e = ihash[4];
|
||||||
|
f = ihash[5];
|
||||||
|
g = ihash[6];
|
||||||
|
h = ihash[7];
|
||||||
|
|
||||||
|
/* make 32-bit words */
|
||||||
|
for(var i=0; i<16; i++)
|
||||||
|
W[i] = ((buffer[(i<<2)+3]) | (buffer[(i<<2)+2] << 8) | (buffer[(i<<2)+1]
|
||||||
|
<< 16) | (buffer[i<<2] << 24));
|
||||||
|
|
||||||
|
for(var j=0; j<64; j++) {
|
||||||
|
T1 = h + sha256_Sigma1(e) + choice(e, f, g) + K256[j];
|
||||||
|
if(j < 16) T1 += W[j];
|
||||||
|
else T1 += sha256_expand(W, j);
|
||||||
|
T2 = sha256_Sigma0(a) + majority(a, b, c);
|
||||||
|
h = g;
|
||||||
|
g = f;
|
||||||
|
f = e;
|
||||||
|
e = safe_add(d, T1);
|
||||||
|
d = c;
|
||||||
|
c = b;
|
||||||
|
b = a;
|
||||||
|
a = safe_add(T1, T2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute the current intermediate hash value */
|
||||||
|
ihash[0] += a;
|
||||||
|
ihash[1] += b;
|
||||||
|
ihash[2] += c;
|
||||||
|
ihash[3] += d;
|
||||||
|
ihash[4] += e;
|
||||||
|
ihash[5] += f;
|
||||||
|
ihash[6] += g;
|
||||||
|
ihash[7] += h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the next chunk of data and update the SHA256 computation */
|
||||||
|
function sha256_update(data, inputLen) {
|
||||||
|
var i, index, curpos = 0;
|
||||||
|
/* Compute number of bytes mod 64 */
|
||||||
|
index = ((count[0] >> 3) & 0x3f);
|
||||||
|
var remainder = (inputLen & 0x3f);
|
||||||
|
|
||||||
|
/* Update number of bits */
|
||||||
|
if ((count[0] += (inputLen << 3)) < (inputLen << 3)) count[1]++;
|
||||||
|
count[1] += (inputLen >> 29);
|
||||||
|
|
||||||
|
/* Transform as many times as possible */
|
||||||
|
for(i=0; i+63<inputLen; i+=64) {
|
||||||
|
for(var j=index; j<64; j++)
|
||||||
|
buffer[j] = data.charCodeAt(curpos++);
|
||||||
|
sha256_transform();
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Buffer remaining input */
|
||||||
|
for(var j=0; j<remainder; j++)
|
||||||
|
buffer[j] = data.charCodeAt(curpos++);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finish the computation by operations such as padding */
|
||||||
|
function sha256_final() {
|
||||||
|
var index = ((count[0] >> 3) & 0x3f);
|
||||||
|
buffer[index++] = 0x80;
|
||||||
|
if(index <= 56) {
|
||||||
|
for(var i=index; i<56; i++)
|
||||||
|
buffer[i] = 0;
|
||||||
|
} else {
|
||||||
|
for(var i=index; i<64; i++)
|
||||||
|
buffer[i] = 0;
|
||||||
|
sha256_transform();
|
||||||
|
for(var i=0; i<56; i++)
|
||||||
|
buffer[i] = 0;
|
||||||
|
}
|
||||||
|
buffer[56] = (count[1] >>> 24) & 0xff;
|
||||||
|
buffer[57] = (count[1] >>> 16) & 0xff;
|
||||||
|
buffer[58] = (count[1] >>> 8) & 0xff;
|
||||||
|
buffer[59] = count[1] & 0xff;
|
||||||
|
buffer[60] = (count[0] >>> 24) & 0xff;
|
||||||
|
buffer[61] = (count[0] >>> 16) & 0xff;
|
||||||
|
buffer[62] = (count[0] >>> 8) & 0xff;
|
||||||
|
buffer[63] = count[0] & 0xff;
|
||||||
|
sha256_transform();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Split the internal hash values into an array of bytes */
|
||||||
|
function sha256_encode_bytes() {
|
||||||
|
var j=0;
|
||||||
|
var output = new Array(32);
|
||||||
|
for(var i=0; i<8; i++) {
|
||||||
|
output[j++] = ((ihash[i] >>> 24) & 0xff);
|
||||||
|
output[j++] = ((ihash[i] >>> 16) & 0xff);
|
||||||
|
output[j++] = ((ihash[i] >>> 8) & 0xff);
|
||||||
|
output[j++] = (ihash[i] & 0xff);
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the internal hash as a hex string */
|
||||||
|
function sha256_encode_hex() {
|
||||||
|
var output = new String();
|
||||||
|
for(var i=0; i<8; i++) {
|
||||||
|
for(var j=28; j>=0; j-=4)
|
||||||
|
output += sha256_hex_digits.charAt((ihash[i] >>> j) & 0x0f);
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main function: returns a hex string representing the SHA256 value of the
|
||||||
|
given data */
|
||||||
|
function sha256_digest(data) {
|
||||||
|
sha256_init();
|
||||||
|
sha256_update(data, data.length);
|
||||||
|
sha256_final();
|
||||||
|
return sha256_encode_hex();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* test if the JS-interpreter is working properly */
|
||||||
|
function sha256_self_test() {
|
||||||
|
return sha256_digest("message digest") ==
|
||||||
|
"f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650";
|
||||||
|
}
|
|
@ -1679,8 +1679,9 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
|
||||||
QString settingsUsername = valueForKeyPath(settingsMap, BASIC_AUTH_USERNAME_KEY_PATH)->toString();
|
QString settingsUsername = valueForKeyPath(settingsMap, BASIC_AUTH_USERNAME_KEY_PATH)->toString();
|
||||||
const QVariant* settingsPasswordVariant = valueForKeyPath(settingsMap, BASIC_AUTH_PASSWORD_KEY_PATH);
|
const QVariant* settingsPasswordVariant = valueForKeyPath(settingsMap, BASIC_AUTH_PASSWORD_KEY_PATH);
|
||||||
QString settingsPassword = settingsPasswordVariant ? settingsPasswordVariant->toString() : "";
|
QString settingsPassword = settingsPasswordVariant ? settingsPasswordVariant->toString() : "";
|
||||||
|
QString hexHeaderPassword = QCryptographicHash::hash(headerPassword.toUtf8(), QCryptographicHash::Sha256).toHex();
|
||||||
|
|
||||||
if (settingsUsername == headerUsername && headerPassword == settingsPassword) {
|
if (settingsUsername == headerUsername && hexHeaderPassword == settingsPassword) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,7 +129,9 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList
|
||||||
// reload the master and user config so that the merged config is right
|
// reload the master and user config so that the merged config is right
|
||||||
_configMap.loadMasterAndUserConfig(argumentList);
|
_configMap.loadMasterAndUserConfig(argumentList);
|
||||||
}
|
}
|
||||||
} else if (oldVersion < 1.1) {
|
}
|
||||||
|
|
||||||
|
if (oldVersion < 1.1) {
|
||||||
static const QString ENTITY_SERVER_SETTINGS_KEY = "entity_server_settings";
|
static const QString ENTITY_SERVER_SETTINGS_KEY = "entity_server_settings";
|
||||||
static const QString ENTITY_FILE_NAME_KEY = "persistFilename";
|
static const QString ENTITY_FILE_NAME_KEY = "persistFilename";
|
||||||
static const QString ENTITY_FILE_PATH_KEYPATH = ENTITY_SERVER_SETTINGS_KEY + ".persistFilePath";
|
static const QString ENTITY_FILE_PATH_KEYPATH = ENTITY_SERVER_SETTINGS_KEY + ".persistFilePath";
|
||||||
|
@ -165,6 +167,28 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < 1.2) {
|
||||||
|
// This was prior to the base64 encoding of password for HTTP Basic Authentication.
|
||||||
|
// If we have a password in the previous settings file, make it base 64
|
||||||
|
static const QString BASIC_AUTH_PASSWORD_KEY_PATH { "security.http_password" };
|
||||||
|
|
||||||
|
QVariant* passwordVariant = valueForKeyPath(_configMap.getUserConfig(), BASIC_AUTH_PASSWORD_KEY_PATH);
|
||||||
|
|
||||||
|
if (passwordVariant && passwordVariant->canConvert(QMetaType::QString)) {
|
||||||
|
QString plaintextPassword = passwordVariant->toString();
|
||||||
|
|
||||||
|
qDebug() << "Migrating plaintext password to SHA256 hash in domain-server settings.";
|
||||||
|
|
||||||
|
*passwordVariant = QCryptographicHash::hash(plaintextPassword.toUtf8(), QCryptographicHash::Sha256).toHex();
|
||||||
|
|
||||||
|
// write the new settings to file
|
||||||
|
persistToFile();
|
||||||
|
|
||||||
|
// reload the master and user config so the merged config is correct
|
||||||
|
_configMap.loadMasterAndUserConfig(argumentList);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// write the current description version to our settings
|
// write the current description version to our settings
|
||||||
|
|
78
examples/example/audio/largeHall.js
Normal file
78
examples/example/audio/largeHall.js
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
//
|
||||||
|
// largeHall.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Freidrica on 4/1/16.
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This entity script invokes reverb upon entering an entity acting as a trigger zone
|
||||||
|
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
(function() {
|
||||||
|
var _this = this;
|
||||||
|
print("EBL PRELOADING NEW VERSION ")
|
||||||
|
var audioOptions = new AudioEffectOptions({
|
||||||
|
bandwidth: 7000,
|
||||||
|
preDelay: 80,
|
||||||
|
lateDelay: 0,
|
||||||
|
reverbTime: 3,
|
||||||
|
earlyDiffusion: 100,
|
||||||
|
lateDiffusion: 100,
|
||||||
|
roomSize: 50,
|
||||||
|
density: 100,
|
||||||
|
bassMult: 1.5,
|
||||||
|
bassFreq: 250,
|
||||||
|
highGain: -12,
|
||||||
|
highFreq: 3000,
|
||||||
|
modRate: 2.3,
|
||||||
|
modDepth: 50,
|
||||||
|
earlyGain: -12,
|
||||||
|
lateGain: -12,
|
||||||
|
earlyMixLeft: 20,
|
||||||
|
earlyMixRight: 20,
|
||||||
|
lateMixLeft: 90,
|
||||||
|
lateMixRight: 90,
|
||||||
|
wetDryMix: 90,
|
||||||
|
});
|
||||||
|
|
||||||
|
function setter(name) {
|
||||||
|
return function(value) {
|
||||||
|
audioOptions[name] = value;
|
||||||
|
AudioDevice.setReverbOptions(audioOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getter(name) {
|
||||||
|
return function() {
|
||||||
|
return audioOptions[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayer(units) {
|
||||||
|
return function(value) {
|
||||||
|
return (value).toFixed(1) + units;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scriptEnding() {
|
||||||
|
AudioDevice.setReverb(false);
|
||||||
|
print("Reverb is OFF.");
|
||||||
|
}
|
||||||
|
_this.enterEntity = function(entityID) {
|
||||||
|
print('EBL I am insiude');
|
||||||
|
|
||||||
|
AudioDevice.setReverbOptions(audioOptions);
|
||||||
|
AudioDevice.setReverb(true);
|
||||||
|
print("Reverb is ON.");
|
||||||
|
};
|
||||||
|
|
||||||
|
_this.leaveEntity = function(entityID) {
|
||||||
|
print('EBL I am outsidee');
|
||||||
|
AudioDevice.setReverb(false);
|
||||||
|
print("Reverb is OFF.");
|
||||||
|
// Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome');
|
||||||
|
};
|
||||||
|
});
|
78
examples/example/audio/smallRoom.js
Normal file
78
examples/example/audio/smallRoom.js
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
//
|
||||||
|
// smallRoom.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Freidrica on 4/1/16.
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This entity script invokes reverb upon entering an entity acting as a trigger zone
|
||||||
|
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var _this = this;
|
||||||
|
print("EBL PRELOADING NEW VERSION ")
|
||||||
|
var audioOptions = new AudioEffectOptions({
|
||||||
|
bandwidth: 7000,
|
||||||
|
preDelay: 20,
|
||||||
|
lateDelay: 0,
|
||||||
|
reverbTime: 1.5,
|
||||||
|
earlyDiffusion: 100,
|
||||||
|
lateDiffusion: 100,
|
||||||
|
roomSize: 50,
|
||||||
|
density: 100,
|
||||||
|
bassMult: 1.5,
|
||||||
|
bassFreq: 250,
|
||||||
|
highGain: -12,
|
||||||
|
highFreq: 3000,
|
||||||
|
modRate: 2.3,
|
||||||
|
modDepth: 50,
|
||||||
|
earlyGain: -24,
|
||||||
|
lateGain: -24,
|
||||||
|
earlyMixLeft: 20,
|
||||||
|
earlyMixRight: 20,
|
||||||
|
lateMixLeft: 90,
|
||||||
|
lateMixRight: 90,
|
||||||
|
wetDryMix: 70,
|
||||||
|
});
|
||||||
|
|
||||||
|
function setter(name) {
|
||||||
|
return function(value) {
|
||||||
|
audioOptions[name] = value;
|
||||||
|
AudioDevice.setReverbOptions(audioOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getter(name) {
|
||||||
|
return function() {
|
||||||
|
return audioOptions[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayer(units) {
|
||||||
|
return function(value) {
|
||||||
|
return (value).toFixed(1) + units;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scriptEnding() {
|
||||||
|
AudioDevice.setReverb(false);
|
||||||
|
print("Reverb is OFF.");
|
||||||
|
}
|
||||||
|
_this.enterEntity = function(entityID) {
|
||||||
|
print('EBL I am insiude');
|
||||||
|
// create a slider for each parameter
|
||||||
|
AudioDevice.setReverbOptions(audioOptions);
|
||||||
|
AudioDevice.setReverb(true);
|
||||||
|
print("Reverb is ON.");
|
||||||
|
};
|
||||||
|
|
||||||
|
_this.leaveEntity = function(entityID) {
|
||||||
|
print('EBL I am outside');
|
||||||
|
AudioDevice.setReverb(false);
|
||||||
|
print("Reverb is OFF.");
|
||||||
|
};
|
||||||
|
});
|
|
@ -452,6 +452,10 @@ input[type=checkbox]:checked + label:hover {
|
||||||
min-height: 29px;
|
min-height: 29px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.property.checkbox {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.property label {
|
.property label {
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|
|
@ -3462,11 +3462,9 @@ void Application::update(float deltaTime) {
|
||||||
const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND;
|
const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND;
|
||||||
bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY;
|
bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY;
|
||||||
bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum);
|
bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum);
|
||||||
|
|
||||||
// if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it
|
// if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it
|
||||||
if (queryIsDue || viewIsDifferentEnough) {
|
if (queryIsDue || viewIsDifferentEnough) {
|
||||||
_lastQueriedTime = now;
|
_lastQueriedTime = now;
|
||||||
|
|
||||||
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
|
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
|
||||||
queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions);
|
queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions);
|
||||||
}
|
}
|
||||||
|
@ -3561,7 +3559,7 @@ int Application::sendNackPackets() {
|
||||||
return packetsSent;
|
return packetsSent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions) {
|
void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions, bool forceResend) {
|
||||||
|
|
||||||
if (!_settingsLoaded) {
|
if (!_settingsLoaded) {
|
||||||
return; // bail early if settings are not loaded
|
return; // bail early if settings are not loaded
|
||||||
|
@ -3648,7 +3646,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
||||||
|
|
||||||
auto queryPacket = NLPacket::create(packetType);
|
auto queryPacket = NLPacket::create(packetType);
|
||||||
|
|
||||||
nodeList->eachNode([&](const SharedNodePointer& node){
|
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||||
// only send to the NodeTypes that are serverType
|
// only send to the NodeTypes that are serverType
|
||||||
if (node->getActiveSocket() && node->getType() == serverType) {
|
if (node->getActiveSocket() && node->getType() == serverType) {
|
||||||
|
|
||||||
|
@ -3717,6 +3715,16 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
||||||
_octreeQuery.setMaxQueryPacketsPerSecond(0);
|
_octreeQuery.setMaxQueryPacketsPerSecond(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if asked to forceResend, then set the query's position/orientation to be degenerate in a manner
|
||||||
|
// that will cause our next query to be guarenteed to be different and the server will resend to us
|
||||||
|
if (forceResend) {
|
||||||
|
_octreeQuery.setCameraPosition(glm::vec3(-0.1, -0.1, -0.1));
|
||||||
|
const glm::quat OFF_IN_NEGATIVE_SPACE = glm::quat(-0.5, 0, -0.5, 1.0);
|
||||||
|
_octreeQuery.setCameraOrientation(OFF_IN_NEGATIVE_SPACE);
|
||||||
|
_octreeQuery.setCameraNearClip(0.1f);
|
||||||
|
_octreeQuery.setCameraFarClip(0.1f);
|
||||||
|
}
|
||||||
|
|
||||||
// encode the query data
|
// encode the query data
|
||||||
int packetSize = _octreeQuery.getBroadcastData(reinterpret_cast<unsigned char*>(queryPacket->getPayload()));
|
int packetSize = _octreeQuery.getBroadcastData(reinterpret_cast<unsigned char*>(queryPacket->getPayload()));
|
||||||
queryPacket->setPayloadSize(packetSize);
|
queryPacket->setPayloadSize(packetSize);
|
||||||
|
@ -4133,6 +4141,7 @@ void Application::clearDomainOctreeDetails() {
|
||||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME);
|
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME);
|
||||||
|
|
||||||
|
_recentlyClearedDomain = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::domainChanged(const QString& domainHostname) {
|
void Application::domainChanged(const QString& domainHostname) {
|
||||||
|
@ -4154,7 +4163,7 @@ void Application::nodeAdded(SharedNodePointer node) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::nodeActivated(SharedNodePointer node) const {
|
void Application::nodeActivated(SharedNodePointer node) {
|
||||||
if (node->getType() == NodeType::AssetServer) {
|
if (node->getType() == NodeType::AssetServer) {
|
||||||
// asset server just connected - check if we have the asset browser showing
|
// asset server just connected - check if we have the asset browser showing
|
||||||
|
|
||||||
|
@ -4173,10 +4182,20 @@ void Application::nodeActivated(SharedNodePointer node) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we get a new EntityServer activated, do a "forceRedraw" query. This will send a degenerate
|
||||||
|
// query so that the server will think our next non-degenerate query is "different enough" to send
|
||||||
|
// us a full scene
|
||||||
|
if (_recentlyClearedDomain && node->getType() == NodeType::EntityServer) {
|
||||||
|
_recentlyClearedDomain = false;
|
||||||
|
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
|
||||||
|
queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::nodeKilled(SharedNodePointer node) {
|
void Application::nodeKilled(SharedNodePointer node) {
|
||||||
|
|
||||||
// These are here because connecting NodeList::nodeKilled to OctreePacketProcessor::nodeKilled doesn't work:
|
// These are here because connecting NodeList::nodeKilled to OctreePacketProcessor::nodeKilled doesn't work:
|
||||||
// OctreePacketProcessor::nodeKilled is not being called when NodeList::nodeKilled is emitted.
|
// OctreePacketProcessor::nodeKilled is not being called when NodeList::nodeKilled is emitted.
|
||||||
// This may have to do with GenericThread::threadRoutine() blocking the QThread event loop
|
// This may have to do with GenericThread::threadRoutine() blocking the QThread event loop
|
||||||
|
|
|
@ -312,7 +312,7 @@ private slots:
|
||||||
void domainChanged(const QString& domainHostname);
|
void domainChanged(const QString& domainHostname);
|
||||||
void updateWindowTitle() const;
|
void updateWindowTitle() const;
|
||||||
void nodeAdded(SharedNodePointer node) const;
|
void nodeAdded(SharedNodePointer node) const;
|
||||||
void nodeActivated(SharedNodePointer node) const;
|
void nodeActivated(SharedNodePointer node);
|
||||||
void nodeKilled(SharedNodePointer node);
|
void nodeKilled(SharedNodePointer node);
|
||||||
static void packetSent(quint64 length);
|
static void packetSent(quint64 length);
|
||||||
void updateDisplayMode();
|
void updateDisplayMode();
|
||||||
|
@ -331,7 +331,7 @@ private:
|
||||||
void updateThreads(float deltaTime);
|
void updateThreads(float deltaTime);
|
||||||
void updateDialogs(float deltaTime) const;
|
void updateDialogs(float deltaTime) const;
|
||||||
|
|
||||||
void queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions);
|
void queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions, bool forceResend = false);
|
||||||
static void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum);
|
static void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum);
|
||||||
|
|
||||||
glm::vec3 getSunDirection() const;
|
glm::vec3 getSunDirection() const;
|
||||||
|
@ -520,6 +520,8 @@ private:
|
||||||
std::atomic<uint32_t> _processOctreeStatsCounter { 0 };
|
std::atomic<uint32_t> _processOctreeStatsCounter { 0 };
|
||||||
|
|
||||||
bool _keyboardDeviceHasFocus { true };
|
bool _keyboardDeviceHasFocus { true };
|
||||||
|
|
||||||
|
bool _recentlyClearedDomain { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Application_h
|
#endif // hifi_Application_h
|
||||||
|
|
|
@ -219,12 +219,12 @@ Menu::Menu() {
|
||||||
// View > First Person
|
// View > First Person
|
||||||
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu,
|
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu,
|
||||||
MenuOption::FirstPerson, 0, // QML Qt:: Key_P
|
MenuOption::FirstPerson, 0, // QML Qt:: Key_P
|
||||||
false, qApp, SLOT(cameraMenuChanged())));
|
true, qApp, SLOT(cameraMenuChanged())));
|
||||||
|
|
||||||
// View > Third Person
|
// View > Third Person
|
||||||
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu,
|
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu,
|
||||||
MenuOption::ThirdPerson, 0,
|
MenuOption::ThirdPerson, 0,
|
||||||
true, qApp, SLOT(cameraMenuChanged())));
|
false, qApp, SLOT(cameraMenuChanged())));
|
||||||
|
|
||||||
// View > Mirror
|
// View > Mirror
|
||||||
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu,
|
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu,
|
||||||
|
|
|
@ -32,8 +32,8 @@ AudioInjector::AudioInjector(QObject* parent) :
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions) :
|
AudioInjector::AudioInjector(const Sound& sound, const AudioInjectorOptions& injectorOptions) :
|
||||||
_audioData(sound->getByteArray()),
|
_audioData(sound.getByteArray()),
|
||||||
_options(injectorOptions)
|
_options(injectorOptions)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
AudioInjector(QObject* parent);
|
AudioInjector(QObject* parent);
|
||||||
AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions);
|
AudioInjector(const Sound& sound, const AudioInjectorOptions& injectorOptions);
|
||||||
AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions);
|
AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions);
|
||||||
|
|
||||||
bool isFinished() const { return _state == State::Finished; }
|
bool isFinished() const { return _state == State::Finished; }
|
||||||
|
|
|
@ -23,13 +23,15 @@
|
||||||
|
|
||||||
#include "AudioRingBuffer.h"
|
#include "AudioRingBuffer.h"
|
||||||
|
|
||||||
|
static const QString RING_BUFFER_OVERFLOW_DEBUG { "AudioRingBuffer::writeData has overflown the buffer. Overwriting old data." };
|
||||||
|
|
||||||
AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode, int numFramesCapacity) :
|
AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode, int numFramesCapacity) :
|
||||||
_frameCapacity(numFramesCapacity),
|
_frameCapacity(numFramesCapacity),
|
||||||
_sampleCapacity(numFrameSamples * numFramesCapacity),
|
_sampleCapacity(numFrameSamples * numFramesCapacity),
|
||||||
_bufferLength(numFrameSamples * (numFramesCapacity + 1)),
|
_bufferLength(numFrameSamples * (numFramesCapacity + 1)),
|
||||||
_numFrameSamples(numFrameSamples),
|
_numFrameSamples(numFrameSamples),
|
||||||
_randomAccessMode(randomAccessMode),
|
_randomAccessMode(randomAccessMode),
|
||||||
_overflowCount(0)
|
_overflowCount(0)
|
||||||
{
|
{
|
||||||
if (numFrameSamples) {
|
if (numFrameSamples) {
|
||||||
_buffer = new int16_t[_bufferLength];
|
_buffer = new int16_t[_bufferLength];
|
||||||
|
@ -41,6 +43,8 @@ _overflowCount(0)
|
||||||
_nextOutput = NULL;
|
_nextOutput = NULL;
|
||||||
_endOfLastWrite = NULL;
|
_endOfLastWrite = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(RING_BUFFER_OVERFLOW_DEBUG);
|
||||||
};
|
};
|
||||||
|
|
||||||
AudioRingBuffer::~AudioRingBuffer() {
|
AudioRingBuffer::~AudioRingBuffer() {
|
||||||
|
@ -131,8 +135,6 @@ int AudioRingBuffer::writeData(const char* data, int maxSize) {
|
||||||
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete);
|
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete);
|
||||||
_overflowCount++;
|
_overflowCount++;
|
||||||
|
|
||||||
const QString RING_BUFFER_OVERFLOW_DEBUG { "AudioRingBuffer::writeData has overflown the buffer. Overwriting old data." };
|
|
||||||
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(RING_BUFFER_OVERFLOW_DEBUG);
|
|
||||||
qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG);
|
qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +181,12 @@ int AudioRingBuffer::addSilentSamples(int silentSamples) {
|
||||||
if (silentSamples > samplesRoomFor) {
|
if (silentSamples > samplesRoomFor) {
|
||||||
// there's not enough room for this write. write as many silent samples as we have room for
|
// there's not enough room for this write. write as many silent samples as we have room for
|
||||||
silentSamples = samplesRoomFor;
|
silentSamples = samplesRoomFor;
|
||||||
qCDebug(audio) << "Dropping some silent samples to prevent ring buffer overflow";
|
|
||||||
|
static const QString DROPPED_SILENT_DEBUG {
|
||||||
|
"AudioRingBuffer::addSilentSamples dropping silent samples to prevent overflow."
|
||||||
|
};
|
||||||
|
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(DROPPED_SILENT_DEBUG);
|
||||||
|
qCDebug(audio) << qPrintable(DROPPED_SILENT_DEBUG);
|
||||||
}
|
}
|
||||||
|
|
||||||
// memset zeroes into the buffer, accomodate a wrap around the end
|
// memset zeroes into the buffer, accomodate a wrap around the end
|
||||||
|
@ -243,7 +250,7 @@ int AudioRingBuffer::writeSamples(ConstIterator source, int maxSamples) {
|
||||||
int samplesToDelete = samplesToCopy - samplesRoomFor;
|
int samplesToDelete = samplesToCopy - samplesRoomFor;
|
||||||
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete);
|
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete);
|
||||||
_overflowCount++;
|
_overflowCount++;
|
||||||
qCDebug(audio) << "Overflowed ring buffer! Overwriting old data";
|
qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG);
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t* bufferLast = _buffer + _bufferLength - 1;
|
int16_t* bufferLast = _buffer + _bufferLength - 1;
|
||||||
|
@ -264,7 +271,7 @@ int AudioRingBuffer::writeSamplesWithFade(ConstIterator source, int maxSamples,
|
||||||
int samplesToDelete = samplesToCopy - samplesRoomFor;
|
int samplesToDelete = samplesToCopy - samplesRoomFor;
|
||||||
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete);
|
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete);
|
||||||
_overflowCount++;
|
_overflowCount++;
|
||||||
qCDebug(audio) << "Overflowed ring buffer! Overwriting old data";
|
qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG);
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t* bufferLast = _buffer + _bufferLength - 1;
|
int16_t* bufferLast = _buffer + _bufferLength - 1;
|
||||||
|
|
|
@ -27,22 +27,18 @@
|
||||||
#include "AudioLogging.h"
|
#include "AudioLogging.h"
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
|
|
||||||
static int soundMetaTypeId = qRegisterMetaType<Sound*>();
|
QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, const SharedSoundPointer& in) {
|
||||||
|
return engine->newQObject(new SoundScriptingInterface(in), QScriptEngine::ScriptOwnership);
|
||||||
QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, SharedSoundPointer const& in) {
|
|
||||||
return engine->newQObject(in.data());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundSharedPointerFromScriptValue(const QScriptValue& object, SharedSoundPointer &out) {
|
void soundSharedPointerFromScriptValue(const QScriptValue& object, SharedSoundPointer& out) {
|
||||||
out = SharedSoundPointer(qobject_cast<Sound*>(object.toQObject()));
|
if (auto soundInterface = qobject_cast<SoundScriptingInterface*>(object.toQObject())) {
|
||||||
|
out = soundInterface->getSound();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QScriptValue soundPointerToScriptValue(QScriptEngine* engine, Sound* const& in) {
|
SoundScriptingInterface::SoundScriptingInterface(SharedSoundPointer sound) : _sound(sound) {
|
||||||
return engine->newQObject(in);
|
QObject::connect(sound.data(), &Sound::ready, this, &SoundScriptingInterface::ready);
|
||||||
}
|
|
||||||
|
|
||||||
void soundPointerFromScriptValue(const QScriptValue &object, Sound* &out) {
|
|
||||||
out = qobject_cast<Sound*>(object.toQObject());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Sound::Sound(const QUrl& url, bool isStereo) :
|
Sound::Sound(const QUrl& url, bool isStereo) :
|
||||||
|
|
|
@ -20,18 +20,16 @@
|
||||||
|
|
||||||
class Sound : public Resource {
|
class Sound : public Resource {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(bool downloaded READ isReady)
|
|
||||||
Q_PROPERTY(float duration READ getDuration)
|
|
||||||
public:
|
public:
|
||||||
Sound(const QUrl& url, bool isStereo = false);
|
Sound(const QUrl& url, bool isStereo = false);
|
||||||
|
|
||||||
bool isStereo() const { return _isStereo; }
|
bool isStereo() const { return _isStereo; }
|
||||||
bool isReady() const { return _isReady; }
|
bool isReady() const { return _isReady; }
|
||||||
float getDuration() { return _duration; }
|
float getDuration() const { return _duration; }
|
||||||
|
|
||||||
|
|
||||||
const QByteArray& getByteArray() { return _byteArray; }
|
const QByteArray& getByteArray() const { return _byteArray; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void ready();
|
void ready();
|
||||||
|
@ -50,13 +48,28 @@ private:
|
||||||
|
|
||||||
typedef QSharedPointer<Sound> SharedSoundPointer;
|
typedef QSharedPointer<Sound> SharedSoundPointer;
|
||||||
|
|
||||||
|
class SoundScriptingInterface : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(bool downloaded READ isReady)
|
||||||
|
Q_PROPERTY(float duration READ getDuration)
|
||||||
|
|
||||||
|
public:
|
||||||
|
SoundScriptingInterface(SharedSoundPointer sound);
|
||||||
|
SharedSoundPointer getSound() { return _sound; }
|
||||||
|
|
||||||
|
bool isReady() const { return _sound->isReady(); }
|
||||||
|
float getDuration() { return _sound->getDuration(); }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void ready();
|
||||||
|
|
||||||
|
private:
|
||||||
|
SharedSoundPointer _sound;
|
||||||
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(SharedSoundPointer)
|
Q_DECLARE_METATYPE(SharedSoundPointer)
|
||||||
QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, SharedSoundPointer const& in);
|
QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, const SharedSoundPointer& in);
|
||||||
void soundSharedPointerFromScriptValue(const QScriptValue& object, SharedSoundPointer &out);
|
void soundSharedPointerFromScriptValue(const QScriptValue& object, SharedSoundPointer& out);
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(Sound*)
|
|
||||||
QScriptValue soundPointerToScriptValue(QScriptEngine* engine, Sound* const& in);
|
|
||||||
void soundPointerFromScriptValue(const QScriptValue& object, Sound* &out);
|
|
||||||
|
|
||||||
|
|
||||||
#endif // hifi_Sound_h
|
#endif // hifi_Sound_h
|
||||||
|
|
|
@ -1033,7 +1033,7 @@ Mapping::Pointer UserInputMapper::parseMapping(const QJsonValue& json) {
|
||||||
Route::Pointer route = parseRoute(channelIt);
|
Route::Pointer route = parseRoute(channelIt);
|
||||||
|
|
||||||
if (!route) {
|
if (!route) {
|
||||||
qWarning() << "Couldn't parse route";
|
qWarning() << "Couldn't parse route:" << mapping->name << channelIt;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,8 +71,8 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityTreeRenderer::~EntityTreeRenderer() {
|
EntityTreeRenderer::~EntityTreeRenderer() {
|
||||||
// NOTE: we don't need to delete _entitiesScriptEngine because it is registered with the application and has a
|
// NOTE: We don't need to delete _entitiesScriptEngine because
|
||||||
// signal tied to call it's deleteLater on doneRunning
|
// it is registered with ScriptEngines, which will call deleteLater for us.
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTreeRenderer::clear() {
|
void EntityTreeRenderer::clear() {
|
||||||
|
|
|
@ -77,6 +77,12 @@ void GLTextureTransferHelper::setup() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLTextureTransferHelper::shutdown() {
|
||||||
|
_canvas->doneCurrent();
|
||||||
|
_canvas->moveToThreadWithContext(qApp->thread());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
|
bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
|
||||||
for (auto package : messages) {
|
for (auto package : messages) {
|
||||||
glWaitSync(package.fence, 0, GL_TIMEOUT_IGNORED);
|
glWaitSync(package.fence, 0, GL_TIMEOUT_IGNORED);
|
||||||
|
|
|
@ -28,6 +28,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
|
void shutdown() override;
|
||||||
bool processQueueItems(const Queue& messages) override;
|
bool processQueueItems(const Queue& messages) override;
|
||||||
void transferTextureSynchronous(const gpu::Texture& texture);
|
void transferTextureSynchronous(const gpu::Texture& texture);
|
||||||
|
|
||||||
|
|
|
@ -380,7 +380,7 @@ void Resource::allReferencesCleared() {
|
||||||
_cache->addUnusedResource(self);
|
_cache->addUnusedResource(self);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
delete this;
|
deleteLater();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
52
libraries/render-utils/src/sdf_text3D_overlay.slf
Normal file
52
libraries/render-utils/src/sdf_text3D_overlay.slf
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<@include gpu/Config.slh@>
|
||||||
|
<$VERSION_HEADER$>
|
||||||
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
// sdf_text.frag
|
||||||
|
// fragment shader
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2015-02-04
|
||||||
|
// Based on fragment shader code from
|
||||||
|
// https://github.com/paulhoux/Cinder-Samples/blob/master/TextRendering/include/text/Text.cpp
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
|
uniform sampler2D Font;
|
||||||
|
uniform bool Outline;
|
||||||
|
uniform vec4 Color;
|
||||||
|
|
||||||
|
// the interpolated normal
|
||||||
|
in vec3 _normal;
|
||||||
|
in vec2 _texCoord0;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 _fragColor0;
|
||||||
|
|
||||||
|
const float gamma = 2.2;
|
||||||
|
const float smoothing = 32.0;
|
||||||
|
const float interiorCutoff = 0.8;
|
||||||
|
const float outlineExpansion = 0.2;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// retrieve signed distance
|
||||||
|
float sdf = texture(Font, _texCoord0).g;
|
||||||
|
if (Outline) {
|
||||||
|
if (sdf > interiorCutoff) {
|
||||||
|
sdf = 1.0 - sdf;
|
||||||
|
} else {
|
||||||
|
sdf += outlineExpansion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// perform adaptive anti-aliasing of the edges
|
||||||
|
// The larger we're rendering, the less anti-aliasing we need
|
||||||
|
float s = smoothing * length(fwidth(_texCoord0));
|
||||||
|
float w = clamp( s, 0.0, 0.5);
|
||||||
|
float a = smoothstep(0.5 - w, 0.5 + w, sdf);
|
||||||
|
|
||||||
|
// gamma correction for linear attenuation
|
||||||
|
a = pow(a, 1.0 / gamma);
|
||||||
|
|
||||||
|
// discard if unvisible
|
||||||
|
if (a < 0.01) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
_fragColor0 = vec4(Color.rgb, a);
|
||||||
|
}
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "sdf_text3D_vert.h"
|
#include "sdf_text3D_vert.h"
|
||||||
#include "sdf_text3D_frag.h"
|
#include "sdf_text3D_frag.h"
|
||||||
|
#include "sdf_text3D_overlay_frag.h"
|
||||||
|
|
||||||
#include "../RenderUtilsLogging.h"
|
#include "../RenderUtilsLogging.h"
|
||||||
#include "FontFamilies.h"
|
#include "FontFamilies.h"
|
||||||
|
@ -220,10 +221,13 @@ void Font::setupGPU() {
|
||||||
{
|
{
|
||||||
auto vertexShader = gpu::Shader::createVertex(std::string(sdf_text3D_vert));
|
auto vertexShader = gpu::Shader::createVertex(std::string(sdf_text3D_vert));
|
||||||
auto pixelShader = gpu::Shader::createPixel(std::string(sdf_text3D_frag));
|
auto pixelShader = gpu::Shader::createPixel(std::string(sdf_text3D_frag));
|
||||||
|
auto pixelShaderOverlay = gpu::Shader::createPixel(std::string(sdf_text3D_overlay_frag));
|
||||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader);
|
gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader);
|
||||||
|
gpu::ShaderPointer programOverlay = gpu::Shader::createProgram(vertexShader, pixelShaderOverlay);
|
||||||
|
|
||||||
gpu::Shader::BindingSet slotBindings;
|
gpu::Shader::BindingSet slotBindings;
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
gpu::Shader::makeProgram(*program, slotBindings);
|
||||||
|
gpu::Shader::makeProgram(*programOverlay, slotBindings);
|
||||||
|
|
||||||
_fontLoc = program->getTextures().findLocation("Font");
|
_fontLoc = program->getTextures().findLocation("Font");
|
||||||
_outlineLoc = program->getUniforms().findLocation("Outline");
|
_outlineLoc = program->getUniforms().findLocation("Outline");
|
||||||
|
@ -237,9 +241,10 @@ void Font::setupGPU() {
|
||||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||||
_pipeline = gpu::Pipeline::create(program, state);
|
_pipeline = gpu::Pipeline::create(program, state);
|
||||||
|
|
||||||
auto layeredState = std::make_shared<gpu::State>(state->getValues());
|
auto layeredState = std::make_shared<gpu::State>();
|
||||||
layeredState->setDepthTest(false);
|
layeredState->setCullMode(gpu::State::CULL_BACK);
|
||||||
_layeredPipeline = gpu::Pipeline::create(program, layeredState);
|
layeredState->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||||
|
_layeredPipeline = gpu::Pipeline::create(programOverlay, layeredState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanity checks
|
// Sanity checks
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
void registerAudioMetaTypes(QScriptEngine* engine) {
|
void registerAudioMetaTypes(QScriptEngine* engine) {
|
||||||
qScriptRegisterMetaType(engine, injectorOptionsToScriptValue, injectorOptionsFromScriptValue);
|
qScriptRegisterMetaType(engine, injectorOptionsToScriptValue, injectorOptionsFromScriptValue);
|
||||||
qScriptRegisterMetaType(engine, soundSharedPointerToScriptValue, soundSharedPointerFromScriptValue);
|
qScriptRegisterMetaType(engine, soundSharedPointerToScriptValue, soundSharedPointerFromScriptValue);
|
||||||
qScriptRegisterMetaType(engine, soundPointerToScriptValue, soundPointerFromScriptValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioScriptingInterface& AudioScriptingInterface::getInstance() {
|
AudioScriptingInterface& AudioScriptingInterface::getInstance() {
|
||||||
|
@ -31,13 +30,14 @@ AudioScriptingInterface::AudioScriptingInterface() :
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptAudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions& injectorOptions) {
|
ScriptAudioInjector* AudioScriptingInterface::playSound(SharedSoundPointer sound, const AudioInjectorOptions& injectorOptions) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
ScriptAudioInjector* injector = NULL;
|
ScriptAudioInjector* injector = NULL;
|
||||||
|
|
||||||
QMetaObject::invokeMethod(this, "playSound", Qt::BlockingQueuedConnection,
|
QMetaObject::invokeMethod(this, "playSound", Qt::BlockingQueuedConnection,
|
||||||
Q_RETURN_ARG(ScriptAudioInjector*, injector),
|
Q_RETURN_ARG(ScriptAudioInjector*, injector),
|
||||||
Q_ARG(Sound*, sound), Q_ARG(const AudioInjectorOptions&, injectorOptions));
|
Q_ARG(SharedSoundPointer, sound),
|
||||||
|
Q_ARG(const AudioInjectorOptions&, injectorOptions));
|
||||||
return injector;
|
return injector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// this method is protected to stop C++ callers from calling, but invokable from script
|
// this method is protected to stop C++ callers from calling, but invokable from script
|
||||||
Q_INVOKABLE ScriptAudioInjector* playSound(Sound* sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions());
|
Q_INVOKABLE ScriptAudioInjector* playSound(SharedSoundPointer sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions());
|
||||||
|
|
||||||
Q_INVOKABLE void setStereoInput(bool stereo);
|
Q_INVOKABLE void setStereoInput(bool stereo);
|
||||||
|
|
||||||
|
|
|
@ -154,7 +154,11 @@ ScriptEngine::~ScriptEngine() {
|
||||||
|
|
||||||
void ScriptEngine::disconnectNonEssentialSignals() {
|
void ScriptEngine::disconnectNonEssentialSignals() {
|
||||||
disconnect();
|
disconnect();
|
||||||
connect(this, &ScriptEngine::doneRunning, thread(), &QThread::quit);
|
QThread* receiver;
|
||||||
|
// Ensure the thread should be running, and does exist
|
||||||
|
if (_isRunning && _isThreaded && (receiver = thread())) {
|
||||||
|
connect(this, &ScriptEngine::doneRunning, receiver, &QThread::quit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::runInThread() {
|
void ScriptEngine::runInThread() {
|
||||||
|
@ -578,7 +582,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString&
|
||||||
_registeredHandlers[entityID] = RegisteredEventHandlers();
|
_registeredHandlers[entityID] = RegisteredEventHandlers();
|
||||||
}
|
}
|
||||||
CallbackList& handlersForEvent = _registeredHandlers[entityID][eventName];
|
CallbackList& handlersForEvent = _registeredHandlers[entityID][eventName];
|
||||||
CallbackData handlerData = {handler, currentEntityIdentifier};
|
CallbackData handlerData = {handler, currentEntityIdentifier, currentSandboxURL};
|
||||||
handlersForEvent << handlerData; // Note that the same handler can be added many times. See removeEntityEventHandler().
|
handlersForEvent << handlerData; // Note that the same handler can be added many times. See removeEntityEventHandler().
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -795,7 +799,7 @@ void ScriptEngine::timerFired() {
|
||||||
|
|
||||||
// call the associated JS function, if it exists
|
// call the associated JS function, if it exists
|
||||||
if (timerData.function.isValid()) {
|
if (timerData.function.isValid()) {
|
||||||
callWithEnvironment(timerData.definingEntityIdentifier, timerData.function, timerData.function, QScriptValueList());
|
callWithEnvironment(timerData.definingEntityIdentifier, timerData.definingSandboxURL, timerData.function, timerData.function, QScriptValueList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -810,7 +814,7 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int
|
||||||
// make sure the timer stops when the script does
|
// make sure the timer stops when the script does
|
||||||
connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop);
|
connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop);
|
||||||
|
|
||||||
CallbackData timerData = {function, currentEntityIdentifier};
|
CallbackData timerData = {function, currentEntityIdentifier, currentSandboxURL};
|
||||||
_timerFunctionMap.insert(newTimer, timerData);
|
_timerFunctionMap.insert(newTimer, timerData);
|
||||||
|
|
||||||
newTimer->start(intervalMS);
|
newTimer->start(intervalMS);
|
||||||
|
@ -885,19 +889,49 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac
|
||||||
return; // bail early
|
return; // bail early
|
||||||
}
|
}
|
||||||
QList<QUrl> urls;
|
QList<QUrl> urls;
|
||||||
|
bool knowsSensitivity = false;
|
||||||
|
Qt::CaseSensitivity sensitivity;
|
||||||
|
auto getSensitivity = [&]() {
|
||||||
|
if (!knowsSensitivity) {
|
||||||
|
QString path = currentSandboxURL.path();
|
||||||
|
QFileInfo upperFI(path.toUpper());
|
||||||
|
QFileInfo lowerFI(path.toLower());
|
||||||
|
sensitivity = (upperFI == lowerFI) ? Qt::CaseInsensitive : Qt::CaseSensitive;
|
||||||
|
knowsSensitivity = true;
|
||||||
|
}
|
||||||
|
return sensitivity;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Guard against meaningless query and fragment parts.
|
||||||
|
// Do NOT use PreferLocalFile as its behavior is unpredictable (e.g., on defaultScriptsLocation())
|
||||||
|
const auto strippingFlags = QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment;
|
||||||
for (QString file : includeFiles) {
|
for (QString file : includeFiles) {
|
||||||
QUrl thisURL { resolvePath(file) };
|
QUrl thisURL { resolvePath(file) };
|
||||||
if (!_includedURLs.contains(thisURL)) {
|
if (!_includedURLs.contains(thisURL)) {
|
||||||
urls.append(thisURL);
|
if (!currentSandboxURL.isEmpty() && (thisURL.scheme() == "file") &&
|
||||||
_includedURLs << thisURL;
|
(
|
||||||
}
|
(currentSandboxURL.scheme() != "file") ||
|
||||||
else {
|
(
|
||||||
|
!thisURL.toString(strippingFlags).startsWith(defaultScriptsLocation().toString(), getSensitivity()) &&
|
||||||
|
!thisURL.toString(strippingFlags).startsWith(currentSandboxURL.toString(strippingFlags), getSensitivity())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
qCWarning(scriptengine) << "Script.include() ignoring file path" << thisURL << "outside of original entity script" << currentSandboxURL;
|
||||||
|
} else {
|
||||||
|
// We could also check here for CORS, but we don't yet.
|
||||||
|
// It turns out that QUrl.resolve will not change hosts and copy authority, so we don't need to check that here.
|
||||||
|
urls.append(thisURL);
|
||||||
|
_includedURLs << thisURL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
qCDebug(scriptengine) << "Script.include() ignoring previously included url:" << thisURL;
|
qCDebug(scriptengine) << "Script.include() ignoring previously included url:" << thisURL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BatchLoader* loader = new BatchLoader(urls);
|
BatchLoader* loader = new BatchLoader(urls);
|
||||||
EntityItemID capturedEntityIdentifier = currentEntityIdentifier;
|
EntityItemID capturedEntityIdentifier = currentEntityIdentifier;
|
||||||
|
QUrl capturedSandboxURL = currentSandboxURL;
|
||||||
|
|
||||||
auto evaluateScripts = [=](const QMap<QUrl, QString>& data) {
|
auto evaluateScripts = [=](const QMap<QUrl, QString>& data) {
|
||||||
auto parentURL = _parentURL;
|
auto parentURL = _parentURL;
|
||||||
|
@ -912,13 +946,13 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac
|
||||||
auto operation = [&]() {
|
auto operation = [&]() {
|
||||||
evaluate(contents, url.toString());
|
evaluate(contents, url.toString());
|
||||||
};
|
};
|
||||||
doWithEnvironment(capturedEntityIdentifier, operation);
|
doWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, operation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_parentURL = parentURL;
|
_parentURL = parentURL;
|
||||||
|
|
||||||
if (callback.isFunction()) {
|
if (callback.isFunction()) {
|
||||||
callWithEnvironment(capturedEntityIdentifier, QScriptValue(callback), QScriptValue(), QScriptValueList());
|
callWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, QScriptValue(callback), QScriptValue(), QScriptValueList());
|
||||||
}
|
}
|
||||||
|
|
||||||
loader->deleteLater();
|
loader->deleteLater();
|
||||||
|
@ -996,10 +1030,11 @@ void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QStrin
|
||||||
CallbackList handlersForEvent = handlersOnEntity[eventName];
|
CallbackList handlersForEvent = handlersOnEntity[eventName];
|
||||||
if (!handlersForEvent.isEmpty()) {
|
if (!handlersForEvent.isEmpty()) {
|
||||||
for (int i = 0; i < handlersForEvent.count(); ++i) {
|
for (int i = 0; i < handlersForEvent.count(); ++i) {
|
||||||
// handlersForEvent[i] can tonain many handlers that may have each been added by different interface or entity scripts,
|
// handlersForEvent[i] can contain many handlers that may have each been added by different interface or entity scripts,
|
||||||
// and the entity scripts may be for entities other than the one this is a handler for.
|
// and the entity scripts may be for entities other than the one this is a handler for.
|
||||||
// Fortunately, the definingEntityIdentifier captured the entity script id (if any) when the handler was added.
|
// Fortunately, the definingEntityIdentifier captured the entity script id (if any) when the handler was added.
|
||||||
callWithEnvironment(handlersForEvent[i].definingEntityIdentifier, handlersForEvent[i].function, QScriptValue(), eventHandlerArgs);
|
CallbackData& handler = handlersForEvent[i];
|
||||||
|
callWithEnvironment(handler.definingEntityIdentifier, handler.definingSandboxURL, handler.function, QScriptValue(), eventHandlerArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1089,9 +1124,19 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!testConstructor.isFunction()) {
|
if (!testConstructor.isFunction()) {
|
||||||
qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID << "\n"
|
QString testConstructorType = QString(testConstructor.toVariant().typeName());
|
||||||
" NOT CONSTRUCTOR\n"
|
if (testConstructorType == "") {
|
||||||
" SCRIPT:" << scriptOrURL;
|
testConstructorType = "empty";
|
||||||
|
}
|
||||||
|
QString testConstructorValue = testConstructor.toString();
|
||||||
|
const int maxTestConstructorValueSize = 80;
|
||||||
|
if (testConstructorValue.size() > maxTestConstructorValueSize) {
|
||||||
|
testConstructorValue = testConstructorValue.mid(0, maxTestConstructorValueSize) + "...";
|
||||||
|
}
|
||||||
|
qCDebug(scriptengine) << "Error -- ScriptEngine::loadEntityScript() entity:" << entityID
|
||||||
|
<< "failed to load entity script -- expected a function, got " + testConstructorType
|
||||||
|
<< "," << testConstructorValue
|
||||||
|
<< "," << scriptOrURL;
|
||||||
|
|
||||||
if (!isFileUrl) {
|
if (!isFileUrl) {
|
||||||
scriptCache->addScriptToBadScriptList(scriptOrURL);
|
scriptCache->addScriptToBadScriptList(scriptOrURL);
|
||||||
|
@ -1106,13 +1151,14 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
|
||||||
lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch();
|
lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch();
|
||||||
}
|
}
|
||||||
QScriptValue entityScriptConstructor, entityScriptObject;
|
QScriptValue entityScriptConstructor, entityScriptObject;
|
||||||
|
QUrl sandboxURL = currentSandboxURL.isEmpty() ? scriptOrURL : currentSandboxURL;
|
||||||
auto initialization = [&]{
|
auto initialization = [&]{
|
||||||
entityScriptConstructor = evaluate(contents, fileName);
|
entityScriptConstructor = evaluate(contents, fileName);
|
||||||
entityScriptObject = entityScriptConstructor.construct();
|
entityScriptObject = entityScriptConstructor.construct();
|
||||||
};
|
};
|
||||||
doWithEnvironment(entityID, initialization);
|
doWithEnvironment(entityID, sandboxURL, initialization);
|
||||||
|
|
||||||
EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified };
|
EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified, sandboxURL };
|
||||||
_entityScripts[entityID] = newDetails;
|
_entityScripts[entityID] = newDetails;
|
||||||
if (isURL) {
|
if (isURL) {
|
||||||
setParentURL("");
|
setParentURL("");
|
||||||
|
@ -1201,9 +1247,11 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) {
|
||||||
// Even if entityID is supplied as currentEntityIdentifier, this still documents the source
|
// Even if entityID is supplied as currentEntityIdentifier, this still documents the source
|
||||||
// of the code being executed (e.g., if we ever sandbox different entity scripts, or provide different
|
// of the code being executed (e.g., if we ever sandbox different entity scripts, or provide different
|
||||||
// global values for different entity scripts).
|
// global values for different entity scripts).
|
||||||
void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, std::function<void()> operation) {
|
void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function<void()> operation) {
|
||||||
EntityItemID oldIdentifier = currentEntityIdentifier;
|
EntityItemID oldIdentifier = currentEntityIdentifier;
|
||||||
|
QUrl oldSandboxURL = currentSandboxURL;
|
||||||
currentEntityIdentifier = entityID;
|
currentEntityIdentifier = entityID;
|
||||||
|
currentSandboxURL = sandboxURL;
|
||||||
|
|
||||||
#if DEBUG_CURRENT_ENTITY
|
#if DEBUG_CURRENT_ENTITY
|
||||||
QScriptValue oldData = this->globalObject().property("debugEntityID");
|
QScriptValue oldData = this->globalObject().property("debugEntityID");
|
||||||
|
@ -1215,12 +1263,13 @@ void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, std::function
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
currentEntityIdentifier = oldIdentifier;
|
currentEntityIdentifier = oldIdentifier;
|
||||||
|
currentSandboxURL = oldSandboxURL;
|
||||||
}
|
}
|
||||||
void ScriptEngine::callWithEnvironment(const EntityItemID& entityID, QScriptValue function, QScriptValue thisObject, QScriptValueList args) {
|
void ScriptEngine::callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args) {
|
||||||
auto operation = [&]() {
|
auto operation = [&]() {
|
||||||
function.call(thisObject, args);
|
function.call(thisObject, args);
|
||||||
};
|
};
|
||||||
doWithEnvironment(entityID, operation);
|
doWithEnvironment(entityID, sandboxURL, operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params) {
|
void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params) {
|
||||||
|
@ -1249,7 +1298,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS
|
||||||
QScriptValueList args;
|
QScriptValueList args;
|
||||||
args << entityID.toScriptValue(this);
|
args << entityID.toScriptValue(this);
|
||||||
args << qScriptValueFromSequence(this, params);
|
args << qScriptValueFromSequence(this, params);
|
||||||
callWithEnvironment(entityID, entityScript.property(methodName), entityScript, args);
|
callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1281,7 +1330,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS
|
||||||
QScriptValueList args;
|
QScriptValueList args;
|
||||||
args << entityID.toScriptValue(this);
|
args << entityID.toScriptValue(this);
|
||||||
args << event.toScriptValue(this);
|
args << event.toScriptValue(this);
|
||||||
callWithEnvironment(entityID, entityScript.property(methodName), entityScript, args);
|
callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1315,7 +1364,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS
|
||||||
args << entityID.toScriptValue(this);
|
args << entityID.toScriptValue(this);
|
||||||
args << otherID.toScriptValue(this);
|
args << otherID.toScriptValue(this);
|
||||||
args << collisionToScriptValue(this, collision);
|
args << collisionToScriptValue(this, collision);
|
||||||
callWithEnvironment(entityID, entityScript.property(methodName), entityScript, args);
|
callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ class CallbackData {
|
||||||
public:
|
public:
|
||||||
QScriptValue function;
|
QScriptValue function;
|
||||||
EntityItemID definingEntityIdentifier;
|
EntityItemID definingEntityIdentifier;
|
||||||
|
QUrl definingSandboxURL;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef QList<CallbackData> CallbackList;
|
typedef QList<CallbackData> CallbackList;
|
||||||
|
@ -57,6 +58,7 @@ public:
|
||||||
QString scriptText;
|
QString scriptText;
|
||||||
QScriptValue scriptObject;
|
QScriptValue scriptObject;
|
||||||
int64_t lastModified;
|
int64_t lastModified;
|
||||||
|
QUrl definingSandboxURL;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScriptEngine : public QScriptEngine, public ScriptUser, public EntitiesScriptEngineProvider {
|
class ScriptEngine : public QScriptEngine, public ScriptUser, public EntitiesScriptEngineProvider {
|
||||||
|
@ -214,8 +216,9 @@ protected:
|
||||||
Q_INVOKABLE void entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success);
|
Q_INVOKABLE void entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success);
|
||||||
|
|
||||||
EntityItemID currentEntityIdentifier {}; // Contains the defining entity script entity id during execution, if any. Empty for interface script execution.
|
EntityItemID currentEntityIdentifier {}; // Contains the defining entity script entity id during execution, if any. Empty for interface script execution.
|
||||||
void doWithEnvironment(const EntityItemID& entityID, std::function<void()> operation);
|
QUrl currentSandboxURL {}; // The toplevel url string for the entity script that loaded the code being executed, else empty.
|
||||||
void callWithEnvironment(const EntityItemID& entityID, QScriptValue function, QScriptValue thisObject, QScriptValueList args);
|
void doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function<void()> operation);
|
||||||
|
void callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args);
|
||||||
|
|
||||||
friend class ScriptEngines;
|
friend class ScriptEngines;
|
||||||
static std::atomic<bool> _stoppingAllScripts;
|
static std::atomic<bool> _stoppingAllScripts;
|
||||||
|
|
|
@ -43,6 +43,11 @@ public:
|
||||||
auto result = static_cast<MenuUserData*>(object->userData(USER_DATA_ID));
|
auto result = static_cast<MenuUserData*>(object->userData(USER_DATA_ID));
|
||||||
if (!result) {
|
if (!result) {
|
||||||
qWarning() << "Unable to find MenuUserData for object " << object;
|
qWarning() << "Unable to find MenuUserData for object " << object;
|
||||||
|
if (auto action = dynamic_cast<QAction*>(object)) {
|
||||||
|
qWarning() << action->text();
|
||||||
|
} else if (auto menu = dynamic_cast<QMenu*>(object)) {
|
||||||
|
qWarning() << menu->title();
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
Loading…
Reference in a new issue