mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-08-08 10:47:10 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into editHandleToggleFix
This commit is contained in:
commit
7b9341954f
225 changed files with 6205 additions and 2219 deletions
|
@ -28,7 +28,7 @@ android {
|
|||
'-DSTABLE_BUILD=' + STABLE_BUILD,
|
||||
'-DDISABLE_QML=OFF',
|
||||
'-DDISABLE_KTX_CACHE=OFF',
|
||||
'-DUSE_BREAKPAD=' + (project.hasProperty("BACKTRACE_URL") && project.hasProperty("BACKTRACE_TOKEN") ? 'ON' : 'OFF');
|
||||
'-DUSE_BREAKPAD=' + (System.getenv("CMAKE_BACKTRACE_URL") && System.getenv("CMAKE_BACKTRACE_TOKEN") ? 'ON' : 'OFF');
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
|
@ -48,8 +48,8 @@ android {
|
|||
|
||||
buildTypes {
|
||||
debug {
|
||||
buildConfigField "String", "BACKTRACE_URL", "\"" + (project.hasProperty("BACKTRACE_URL") ? BACKTRACE_URL : '') + "\""
|
||||
buildConfigField "String", "BACKTRACE_TOKEN", "\"" + (project.hasProperty("BACKTRACE_TOKEN") ? BACKTRACE_TOKEN : '') + "\""
|
||||
buildConfigField "String", "BACKTRACE_URL", "\"" + (System.getenv("CMAKE_BACKTRACE_URL") ? System.getenv("CMAKE_BACKTRACE_URL") : '') + "\""
|
||||
buildConfigField "String", "BACKTRACE_TOKEN", "\"" + (System.getenv("CMAKE_BACKTRACE_TOKEN") ? System.getenv("CMAKE_BACKTRACE_TOKEN") : '') + "\""
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
|
@ -58,8 +58,8 @@ android {
|
|||
project.hasProperty("HIFI_ANDROID_KEYSTORE_PASSWORD") &&
|
||||
project.hasProperty("HIFI_ANDROID_KEY_ALIAS") &&
|
||||
project.hasProperty("HIFI_ANDROID_KEY_PASSWORD")? signingConfigs.release : null
|
||||
buildConfigField "String", "BACKTRACE_URL", "\"" + (project.hasProperty("BACKTRACE_URL") ? BACKTRACE_URL : '') + "\""
|
||||
buildConfigField "String", "BACKTRACE_TOKEN", "\"" + (project.hasProperty("BACKTRACE_TOKEN") ? BACKTRACE_TOKEN : '') + "\""
|
||||
buildConfigField "String", "BACKTRACE_URL", "\"" + (System.getenv("CMAKE_BACKTRACE_URL") ? System.getenv("CMAKE_BACKTRACE_URL") : '') + "\""
|
||||
buildConfigField "String", "BACKTRACE_TOKEN", "\"" + (System.getenv("CMAKE_BACKTRACE_TOKEN") ? System.getenv("CMAKE_BACKTRACE_TOKEN") : '') + "\""
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,10 @@ android {
|
|||
// so our merge has to depend on the external native build
|
||||
variant.externalNativeBuildTasks.each { task ->
|
||||
variant.mergeResources.dependsOn(task)
|
||||
def uploadDumpSymsTask = rootProject.getTasksByName("uploadBreakpadDumpSyms${variant.name.capitalize()}", false).first()
|
||||
def runDumpSymsTask = rootProject.getTasksByName("runBreakpadDumpSyms${variant.name.capitalize()}", false).first()
|
||||
runDumpSymsTask.dependsOn(task)
|
||||
variant.assemble.dependsOn(uploadDumpSymsTask)
|
||||
}
|
||||
|
||||
variant.mergeAssets.doLast {
|
||||
|
|
|
@ -228,7 +228,7 @@ Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeLogin(JNIEnv *en
|
|||
env->ReleaseStringUTFChars(username_, c_username);
|
||||
env->ReleaseStringUTFChars(password_, c_password);
|
||||
|
||||
auto accountManager = AndroidHelper::instance().getAccountManager();
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
||||
__loginCompletedListener = QAndroidJniObject(instance);
|
||||
__usernameChangedListener = QAndroidJniObject(usernameChangedListener);
|
||||
|
@ -270,18 +270,18 @@ Java_io_highfidelity_hifiinterface_SplashActivity_registerLoadCompleteListener(J
|
|||
}
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_io_highfidelity_hifiinterface_MainActivity_nativeIsLoggedIn(JNIEnv *env, jobject instance) {
|
||||
return AndroidHelper::instance().getAccountManager()->isLoggedIn();
|
||||
return DependencyManager::get<AccountManager>()->isLoggedIn();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_io_highfidelity_hifiinterface_MainActivity_nativeLogout(JNIEnv *env, jobject instance) {
|
||||
AndroidHelper::instance().getAccountManager()->logout();
|
||||
DependencyManager::get<AccountManager>()->logout();
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_io_highfidelity_hifiinterface_MainActivity_nativeGetDisplayName(JNIEnv *env,
|
||||
jobject instance) {
|
||||
QString username = AndroidHelper::instance().getAccountManager()->getAccountInfo().getUsername();
|
||||
QString username = DependencyManager::get<AccountManager>()->getAccountInfo().getUsername();
|
||||
return env->NewStringUTF(username.toLatin1().data());
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ buildscript {
|
|||
plugins {
|
||||
id 'de.undercouch.download' version '3.3.0'
|
||||
id "cz.malohlava" version "1.0.3"
|
||||
id "io.github.http-builder-ng.http-plugin" version "0.1.1"
|
||||
}
|
||||
|
||||
allprojects {
|
||||
|
@ -67,6 +68,7 @@ def baseFolder = new File(HIFI_ANDROID_PRECOMPILED)
|
|||
def appDir = new File(projectDir, 'app')
|
||||
def jniFolder = new File(appDir, 'src/main/jniLibs/arm64-v8a')
|
||||
def baseUrl = 'https://hifi-public.s3.amazonaws.com/dependencies/android/'
|
||||
def breakpadDumpSymsDir = new File("${appDir}/build/tmp/breakpadDumpSyms")
|
||||
|
||||
def qtFile='qt-5.9.3_linux_armv8-libcpp_openssl.tgz'
|
||||
def qtChecksum='04599670ccca84bd2b15f6915568eb2d'
|
||||
|
@ -151,11 +153,11 @@ def packages = [
|
|||
checksum: '14b02795d774457a33bbc60e00a786bc'
|
||||
],
|
||||
breakpad: [
|
||||
file: 'breakpad.zip',
|
||||
versionId: '2OwvCCZrF171wnte5T44AnjTYFhhJsGJ',
|
||||
checksum: 'a46062a3167dfedd4fb4916136e204d2',
|
||||
file: 'breakpad.tgz',
|
||||
versionId: '8VrYXz7oyc.QBxNia0BVJOUBvrFO61jI',
|
||||
checksum: 'ddcb23df336b08017042ba4786db1d9e',
|
||||
sharedLibFolder: 'lib',
|
||||
includeLibs: ['libbreakpad_client.a','libbreakpad.a']
|
||||
includeLibs: ['libbreakpad_client.a']
|
||||
]
|
||||
]
|
||||
|
||||
|
@ -549,7 +551,93 @@ task cleanDependencies(type: Delete) {
|
|||
delete 'app/src/main/res/values/libs.xml'
|
||||
}
|
||||
|
||||
def runBreakpadDumpSyms = { buildType ->
|
||||
gradle.startParameter.showStacktrace = ShowStacktrace.ALWAYS
|
||||
|
||||
def objDir = new File("${appDir}/build/intermediates/cmake/${buildType}/obj/arm64-v8a")
|
||||
def stripDebugSymbol = "${appDir}/build/intermediates/transforms/stripDebugSymbol/${buildType}/0/lib/arm64-v8a/"
|
||||
def outputDir = new File(breakpadDumpSymsDir, buildType)
|
||||
if (!outputDir.exists()) {
|
||||
outputDir.mkdirs()
|
||||
}
|
||||
|
||||
objDir.eachFileRecurse (FileType.FILES) { file ->
|
||||
if (file.name.endsWith('.so')) {
|
||||
def output = file.name + ".sym"
|
||||
def cmdArgs = [
|
||||
file.toString(),
|
||||
stripDebugSymbol
|
||||
]
|
||||
def result = exec {
|
||||
workingDir HIFI_ANDROID_PRECOMPILED + '/breakpad/bin'
|
||||
commandLine './dump_syms'
|
||||
args cmdArgs
|
||||
ignoreExitValue true
|
||||
standardOutput = new BufferedOutputStream(new FileOutputStream(new File(outputDir, output)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task runBreakpadDumpSymsDebug() {
|
||||
doLast {
|
||||
runBreakpadDumpSyms("debug");
|
||||
}
|
||||
}
|
||||
|
||||
task runBreakpadDumpSymsRelease() {
|
||||
doLast {
|
||||
runBreakpadDumpSyms("release");
|
||||
}
|
||||
}
|
||||
|
||||
task zipDumpSymsDebug(type: Zip, dependsOn: runBreakpadDumpSymsDebug) {
|
||||
from (new File(breakpadDumpSymsDir, "debug").absolutePath)
|
||||
archiveName "symbols-${RELEASE_NUMBER}-debug.zip"
|
||||
destinationDir(new File("${appDir}/build/tmp/"))
|
||||
}
|
||||
|
||||
task zipDumpSymsRelease(type: Zip, dependsOn: runBreakpadDumpSymsRelease) {
|
||||
from (new File(breakpadDumpSymsDir, "release").absolutePath)
|
||||
archiveName "symbols-${RELEASE_NUMBER}-release.zip"
|
||||
destinationDir(new File("${appDir}/build/tmp/"))
|
||||
}
|
||||
|
||||
task uploadBreakpadDumpSymsDebug(type:io.github.httpbuilderng.http.HttpTask, dependsOn: zipDumpSymsDebug) {
|
||||
onlyIf {
|
||||
System.getenv("CMAKE_BACKTRACE_URL") && System.getenv("CMAKE_BACKTRACE_SYMBOLS_TOKEN")
|
||||
}
|
||||
config {
|
||||
request.uri = System.getenv("CMAKE_BACKTRACE_URL")
|
||||
}
|
||||
post {
|
||||
request.uri.path = '/post'
|
||||
request.uri.query = [format: 'symbols', token: System.getenv("CMAKE_BACKTRACE_SYMBOLS_TOKEN")]
|
||||
request.body = new File("${appDir}/build/tmp/", "symbols-${RELEASE_NUMBER}-debug.zip").bytes
|
||||
request.contentType = 'application/octet-stream'
|
||||
response.success {
|
||||
println ("${appDir}/build/tmp/symbols-${RELEASE_NUMBER}-debug.zip uploaded")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task uploadBreakpadDumpSymsRelease(type:io.github.httpbuilderng.http.HttpTask, dependsOn: zipDumpSymsRelease) {
|
||||
onlyIf {
|
||||
System.getenv("CMAKE_BACKTRACE_URL") && System.getenv("CMAKE_BACKTRACE_SYMBOLS_TOKEN")
|
||||
}
|
||||
config {
|
||||
request.uri = System.getenv("CMAKE_BACKTRACE_URL")
|
||||
}
|
||||
post {
|
||||
request.uri.path = '/post'
|
||||
request.uri.query = [format: 'symbols', token: System.getenv("CMAKE_BACKTRACE_SYMBOLS_TOKEN")]
|
||||
request.body = new File("${appDir}/build/tmp/", "symbols-${RELEASE_NUMBER}-release.zip").bytes
|
||||
request.contentType = 'application/octet-stream'
|
||||
response.success {
|
||||
println ("${appDir}/build/tmp/symbols-${RELEASE_NUMBER}-release.zip uploaded")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME this code is prototyping the desired functionality for doing build time binary dependency resolution.
|
||||
// See the comment on the qtBundle task above
|
||||
|
|
|
@ -504,6 +504,11 @@ void EntityServer::startDynamicDomainVerification() {
|
|||
QString thisDomainID = DependencyManager::get<AddressManager>()->getDomainID().remove(QRegExp("\\{|\\}"));
|
||||
if (jsonObject["domain_id"].toString() != thisDomainID) {
|
||||
EntityItemPointer entity = tree->findEntityByEntityItemID(entityID);
|
||||
if (!entity) {
|
||||
qCDebug(entities) << "Entity undergoing dynamic domain verification is no longer available:" << entityID;
|
||||
networkReply->deleteLater();
|
||||
return;
|
||||
}
|
||||
if (entity->getAge() > (_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS/MSECS_PER_SECOND)) {
|
||||
qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString()
|
||||
<< "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << entityID;
|
||||
|
|
21
cmake/externals/etc2comp/CMakeLists.txt
vendored
21
cmake/externals/etc2comp/CMakeLists.txt
vendored
|
@ -33,23 +33,20 @@ ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
|||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
if (WIN32)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/build/EtcLib/Debug/EtcLib.lib CACHE FILEPATH "Path to Etc2Comp debug library")
|
||||
if (WIN32 OR APPLE)
|
||||
if (WIN32)
|
||||
set(_LIB_FILE "EtcLib.lib")
|
||||
else ()
|
||||
set(_LIB_FILE "libEtcLib.a")
|
||||
endif ()
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/build/EtcLib/Debug/${_LIB_FILE} CACHE FILEPATH "Path to Etc2Comp debug library")
|
||||
|
||||
# use generator expression to ensure the correct library is found when building different configurations in VS
|
||||
set(_LIB_FOLDER "$<$<CONFIG:RelWithDebInfo>:build/EtcLib/RelWithDebInfo>")
|
||||
set(_LIB_FOLDER "${_LIB_FOLDER}$<$<CONFIG:MinSizeRel>:build/EtcLib/MinSizeRel>")
|
||||
set(_LIB_FOLDER "${_LIB_FOLDER}$<$<OR:$<CONFIG:Release>,$<CONFIG:Debug>>:build/EtcLib/Release>")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/${_LIB_FOLDER}/EtcLib.lib CACHE FILEPATH "Path to Etc2Comp release library")
|
||||
|
||||
elseif (APPLE)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/build/EtcLib/Debug/libEtcLib.a CACHE FILEPATH "Path to EtcLib debug library")
|
||||
|
||||
set(_LIB_FOLDER "$<$<CONFIG:RelWithDebInfo>:build/EtcLib/RelWithDebInfo>")
|
||||
set(_LIB_FOLDER "${_LIB_FOLDER}$<$<CONFIG:MinSizeRel>:build/EtcLib/MinSizeRel>")
|
||||
set(_LIB_FOLDER "${_LIB_FOLDER}$<$<OR:$<CONFIG:Release>,$<CONFIG:Debug>>:build/EtcLib/Release>")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/${_LIB_FOLDER}/libEtcLib.a CACHE FILEPATH "Path to Etc2Comp release library")
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/${_LIB_FOLDER}/${_LIB_FILE} CACHE FILEPATH "Path to Etc2Comp release library")
|
||||
else ()
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Path to EtcLib debug library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/build/EtcLib/libEtcLib.a CACHE FILEPATH "Path to EtcLib release library")
|
||||
|
|
|
@ -660,9 +660,8 @@ void DomainGatekeeper::requestUserPublicKey(const QString& username, bool isOpti
|
|||
|
||||
// even if we have a public key for them right now, request a new one in case it has just changed
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.jsonCallbackReceiver = this;
|
||||
callbackParams.callbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "publicKeyJSONCallback";
|
||||
callbackParams.errorCallbackReceiver = this;
|
||||
callbackParams.errorCallbackMethod = "publicKeyJSONErrorCallback";
|
||||
|
||||
|
||||
|
@ -675,19 +674,19 @@ void DomainGatekeeper::requestUserPublicKey(const QString& username, bool isOpti
|
|||
QNetworkAccessManager::GetOperation, callbackParams);
|
||||
}
|
||||
|
||||
QString extractUsernameFromPublicKeyRequest(QNetworkReply& requestReply) {
|
||||
QString extractUsernameFromPublicKeyRequest(QNetworkReply* requestReply) {
|
||||
// extract the username from the request url
|
||||
QString username;
|
||||
const QString PUBLIC_KEY_URL_REGEX_STRING = "api\\/v1\\/users\\/([A-Za-z0-9_\\.]+)\\/public_key";
|
||||
QRegExp usernameRegex(PUBLIC_KEY_URL_REGEX_STRING);
|
||||
if (usernameRegex.indexIn(requestReply.url().toString()) != -1) {
|
||||
if (usernameRegex.indexIn(requestReply->url().toString()) != -1) {
|
||||
username = usernameRegex.cap(1);
|
||||
}
|
||||
return username.toLower();
|
||||
}
|
||||
|
||||
void DomainGatekeeper::publicKeyJSONCallback(QNetworkReply& requestReply) {
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object();
|
||||
void DomainGatekeeper::publicKeyJSONCallback(QNetworkReply* requestReply) {
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply->readAll()).object();
|
||||
QString username = extractUsernameFromPublicKeyRequest(requestReply);
|
||||
|
||||
bool isOptimisticKey = _inFlightPublicKeyRequests.take(username);
|
||||
|
@ -707,8 +706,8 @@ void DomainGatekeeper::publicKeyJSONCallback(QNetworkReply& requestReply) {
|
|||
}
|
||||
}
|
||||
|
||||
void DomainGatekeeper::publicKeyJSONErrorCallback(QNetworkReply& requestReply) {
|
||||
qDebug() << "publicKey api call failed:" << requestReply.error();
|
||||
void DomainGatekeeper::publicKeyJSONErrorCallback(QNetworkReply* requestReply) {
|
||||
qDebug() << "publicKey api call failed:" << requestReply->error();
|
||||
QString username = extractUsernameFromPublicKeyRequest(requestReply);
|
||||
_inFlightPublicKeyRequests.remove(username);
|
||||
}
|
||||
|
@ -893,9 +892,8 @@ void DomainGatekeeper::getGroupMemberships(const QString& username) {
|
|||
|
||||
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.jsonCallbackReceiver = this;
|
||||
callbackParams.callbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "getIsGroupMemberJSONCallback";
|
||||
callbackParams.errorCallbackReceiver = this;
|
||||
callbackParams.errorCallbackMethod = "getIsGroupMemberErrorCallback";
|
||||
|
||||
const QString GET_IS_GROUP_MEMBER_PATH = "api/v1/groups/members/%2";
|
||||
|
@ -906,18 +904,18 @@ void DomainGatekeeper::getGroupMemberships(const QString& username) {
|
|||
|
||||
}
|
||||
|
||||
QString extractUsernameFromGroupMembershipsReply(QNetworkReply& requestReply) {
|
||||
QString extractUsernameFromGroupMembershipsReply(QNetworkReply* requestReply) {
|
||||
// extract the username from the request url
|
||||
QString username;
|
||||
const QString GROUP_MEMBERSHIPS_URL_REGEX_STRING = "api\\/v1\\/groups\\/members\\/([A-Za-z0-9_\\.]+)";
|
||||
QRegExp usernameRegex(GROUP_MEMBERSHIPS_URL_REGEX_STRING);
|
||||
if (usernameRegex.indexIn(requestReply.url().toString()) != -1) {
|
||||
if (usernameRegex.indexIn(requestReply->url().toString()) != -1) {
|
||||
username = usernameRegex.cap(1);
|
||||
}
|
||||
return username.toLower();
|
||||
}
|
||||
|
||||
void DomainGatekeeper::getIsGroupMemberJSONCallback(QNetworkReply& requestReply) {
|
||||
void DomainGatekeeper::getIsGroupMemberJSONCallback(QNetworkReply* requestReply) {
|
||||
// {
|
||||
// "data":{
|
||||
// "username":"sethalves",
|
||||
|
@ -934,7 +932,7 @@ void DomainGatekeeper::getIsGroupMemberJSONCallback(QNetworkReply& requestReply)
|
|||
// "status":"success"
|
||||
// }
|
||||
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object();
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply->readAll()).object();
|
||||
if (jsonObject["status"].toString() == "success") {
|
||||
QJsonObject data = jsonObject["data"].toObject();
|
||||
QJsonObject groups = data["groups"].toObject();
|
||||
|
@ -953,16 +951,15 @@ void DomainGatekeeper::getIsGroupMemberJSONCallback(QNetworkReply& requestReply)
|
|||
_inFlightGroupMembershipsRequests.remove(extractUsernameFromGroupMembershipsReply(requestReply));
|
||||
}
|
||||
|
||||
void DomainGatekeeper::getIsGroupMemberErrorCallback(QNetworkReply& requestReply) {
|
||||
qDebug() << "getIsGroupMember api call failed:" << requestReply.error();
|
||||
void DomainGatekeeper::getIsGroupMemberErrorCallback(QNetworkReply* requestReply) {
|
||||
qDebug() << "getIsGroupMember api call failed:" << requestReply->error();
|
||||
_inFlightGroupMembershipsRequests.remove(extractUsernameFromGroupMembershipsReply(requestReply));
|
||||
}
|
||||
|
||||
void DomainGatekeeper::getDomainOwnerFriendsList() {
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.jsonCallbackReceiver = this;
|
||||
callbackParams.callbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "getDomainOwnerFriendsListJSONCallback";
|
||||
callbackParams.errorCallbackReceiver = this;
|
||||
callbackParams.errorCallbackMethod = "getDomainOwnerFriendsListErrorCallback";
|
||||
|
||||
const QString GET_FRIENDS_LIST_PATH = "api/v1/user/friends";
|
||||
|
@ -974,7 +971,7 @@ void DomainGatekeeper::getDomainOwnerFriendsList() {
|
|||
|
||||
}
|
||||
|
||||
void DomainGatekeeper::getDomainOwnerFriendsListJSONCallback(QNetworkReply& requestReply) {
|
||||
void DomainGatekeeper::getDomainOwnerFriendsListJSONCallback(QNetworkReply* requestReply) {
|
||||
// {
|
||||
// status: "success",
|
||||
// data: {
|
||||
|
@ -991,7 +988,7 @@ void DomainGatekeeper::getDomainOwnerFriendsListJSONCallback(QNetworkReply& requ
|
|||
// ]
|
||||
// }
|
||||
// }
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object();
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply->readAll()).object();
|
||||
if (jsonObject["status"].toString() == "success") {
|
||||
_domainOwnerFriends.clear();
|
||||
QJsonArray friends = jsonObject["data"].toObject()["friends"].toArray();
|
||||
|
@ -1003,8 +1000,8 @@ void DomainGatekeeper::getDomainOwnerFriendsListJSONCallback(QNetworkReply& requ
|
|||
}
|
||||
}
|
||||
|
||||
void DomainGatekeeper::getDomainOwnerFriendsListErrorCallback(QNetworkReply& requestReply) {
|
||||
qDebug() << "getDomainOwnerFriendsList api call failed:" << requestReply.error();
|
||||
void DomainGatekeeper::getDomainOwnerFriendsListErrorCallback(QNetworkReply* requestReply) {
|
||||
qDebug() << "getDomainOwnerFriendsList api call failed:" << requestReply->error();
|
||||
}
|
||||
|
||||
void DomainGatekeeper::refreshGroupsCache() {
|
||||
|
|
|
@ -51,14 +51,14 @@ public slots:
|
|||
void processICEPingReplyPacket(QSharedPointer<ReceivedMessage> message);
|
||||
void processICEPeerInformationPacket(QSharedPointer<ReceivedMessage> message);
|
||||
|
||||
void publicKeyJSONCallback(QNetworkReply& requestReply);
|
||||
void publicKeyJSONErrorCallback(QNetworkReply& requestReply);
|
||||
void publicKeyJSONCallback(QNetworkReply* requestReply);
|
||||
void publicKeyJSONErrorCallback(QNetworkReply* requestReply);
|
||||
|
||||
void getIsGroupMemberJSONCallback(QNetworkReply& requestReply);
|
||||
void getIsGroupMemberErrorCallback(QNetworkReply& requestReply);
|
||||
void getIsGroupMemberJSONCallback(QNetworkReply* requestReply);
|
||||
void getIsGroupMemberErrorCallback(QNetworkReply* requestReply);
|
||||
|
||||
void getDomainOwnerFriendsListJSONCallback(QNetworkReply& requestReply);
|
||||
void getDomainOwnerFriendsListErrorCallback(QNetworkReply& requestReply);
|
||||
void getDomainOwnerFriendsListJSONCallback(QNetworkReply* requestReply);
|
||||
void getDomainOwnerFriendsListErrorCallback(QNetworkReply* requestReply);
|
||||
|
||||
void refreshGroupsCache();
|
||||
|
||||
|
|
|
@ -514,13 +514,13 @@ void DomainServer::getTemporaryName(bool force) {
|
|||
|
||||
// request a temporary name from the metaverse
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
JSONCallbackParameters callbackParameters { this, "handleTempDomainSuccess", this, "handleTempDomainError" };
|
||||
JSONCallbackParameters callbackParameters { this, "handleTempDomainSuccess", "handleTempDomainError" };
|
||||
accountManager->sendRequest("/api/v1/domains/temporary", AccountManagerAuth::None,
|
||||
QNetworkAccessManager::PostOperation, callbackParameters);
|
||||
}
|
||||
|
||||
void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) {
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object();
|
||||
void DomainServer::handleTempDomainSuccess(QNetworkReply* requestReply) {
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply->readAll()).object();
|
||||
|
||||
// grab the information for the new domain
|
||||
static const QString DATA_KEY = "data";
|
||||
|
@ -565,7 +565,7 @@ void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) {
|
|||
}
|
||||
}
|
||||
|
||||
void DomainServer::handleTempDomainError(QNetworkReply& requestReply) {
|
||||
void DomainServer::handleTempDomainError(QNetworkReply* requestReply) {
|
||||
qWarning() << "A temporary name was requested but there was an error creating one. Please try again via domain-server relaunch"
|
||||
<< "or from the domain-server settings.";
|
||||
}
|
||||
|
@ -1345,7 +1345,7 @@ void DomainServer::sendPendingTransactionsToServer() {
|
|||
|
||||
JSONCallbackParameters transactionCallbackParams;
|
||||
|
||||
transactionCallbackParams.jsonCallbackReceiver = this;
|
||||
transactionCallbackParams.callbackReceiver = this;
|
||||
transactionCallbackParams.jsonCallbackMethod = "transactionJSONCallback";
|
||||
|
||||
while (i != _pendingAssignmentCredits.end()) {
|
||||
|
@ -1449,11 +1449,11 @@ void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) {
|
|||
DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(getID())),
|
||||
AccountManagerAuth::Optional,
|
||||
QNetworkAccessManager::PutOperation,
|
||||
JSONCallbackParameters(nullptr, QString(), this, "handleMetaverseHeartbeatError"),
|
||||
JSONCallbackParameters(this, QString(), "handleMetaverseHeartbeatError"),
|
||||
domainUpdateJSON.toUtf8());
|
||||
}
|
||||
|
||||
void DomainServer::handleMetaverseHeartbeatError(QNetworkReply& requestReply) {
|
||||
void DomainServer::handleMetaverseHeartbeatError(QNetworkReply* requestReply) {
|
||||
if (!_metaverseHeartbeatTimer) {
|
||||
// avoid rehandling errors from the same issue
|
||||
return;
|
||||
|
@ -1462,13 +1462,13 @@ void DomainServer::handleMetaverseHeartbeatError(QNetworkReply& requestReply) {
|
|||
// only attempt to grab a new temporary name if we're already a temporary domain server
|
||||
if (_type == MetaverseTemporaryDomain) {
|
||||
// check if we need to force a new temporary domain name
|
||||
switch (requestReply.error()) {
|
||||
switch (requestReply->error()) {
|
||||
// if we have a temporary domain with a bad token, we get a 401
|
||||
case QNetworkReply::NetworkError::AuthenticationRequiredError: {
|
||||
static const QString DATA_KEY = "data";
|
||||
static const QString TOKEN_KEY = "api_key";
|
||||
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object();
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply->readAll()).object();
|
||||
auto tokenFailure = jsonObject[DATA_KEY].toObject()[TOKEN_KEY];
|
||||
|
||||
if (!tokenFailure.isNull()) {
|
||||
|
@ -1531,9 +1531,8 @@ void DomainServer::sendICEServerAddressToMetaverseAPI() {
|
|||
|
||||
// make sure we hear about failure so we can retry
|
||||
JSONCallbackParameters callbackParameters;
|
||||
callbackParameters.errorCallbackReceiver = this;
|
||||
callbackParameters.callbackReceiver = this;
|
||||
callbackParameters.errorCallbackMethod = "handleFailedICEServerAddressUpdate";
|
||||
callbackParameters.jsonCallbackReceiver = this;
|
||||
callbackParameters.jsonCallbackMethod = "handleSuccessfulICEServerAddressUpdate";
|
||||
|
||||
static bool printedIceServerMessage = false;
|
||||
|
@ -1552,7 +1551,7 @@ void DomainServer::sendICEServerAddressToMetaverseAPI() {
|
|||
domainUpdateJSON.toUtf8());
|
||||
}
|
||||
|
||||
void DomainServer::handleSuccessfulICEServerAddressUpdate(QNetworkReply& requestReply) {
|
||||
void DomainServer::handleSuccessfulICEServerAddressUpdate(QNetworkReply* requestReply) {
|
||||
_sendICEServerAddressToMetaverseAPIInProgress = false;
|
||||
if (_sendICEServerAddressToMetaverseAPIRedo) {
|
||||
qDebug() << "ice-server address updated with metaverse, but has since changed. redoing update...";
|
||||
|
@ -1563,7 +1562,7 @@ void DomainServer::handleSuccessfulICEServerAddressUpdate(QNetworkReply& request
|
|||
}
|
||||
}
|
||||
|
||||
void DomainServer::handleFailedICEServerAddressUpdate(QNetworkReply& requestReply) {
|
||||
void DomainServer::handleFailedICEServerAddressUpdate(QNetworkReply* requestReply) {
|
||||
_sendICEServerAddressToMetaverseAPIInProgress = false;
|
||||
if (_sendICEServerAddressToMetaverseAPIRedo) {
|
||||
// if we have new data, retry right away, even though the previous attempt didn't go well.
|
||||
|
@ -1573,7 +1572,7 @@ void DomainServer::handleFailedICEServerAddressUpdate(QNetworkReply& requestRepl
|
|||
const int ICE_SERVER_UPDATE_RETRY_MS = 2 * 1000;
|
||||
|
||||
qWarning() << "Failed to update ice-server address with High Fidelity Metaverse - error was"
|
||||
<< requestReply.errorString();
|
||||
<< requestReply->errorString();
|
||||
qWarning() << "\tRe-attempting in" << ICE_SERVER_UPDATE_RETRY_MS / 1000 << "seconds";
|
||||
|
||||
QTimer::singleShot(ICE_SERVER_UPDATE_RETRY_MS, this, SLOT(sendICEServerAddressToMetaverseAPI()));
|
||||
|
|
|
@ -108,10 +108,10 @@ private slots:
|
|||
void sendHeartbeatToIceServer();
|
||||
|
||||
void handleConnectedNode(SharedNodePointer newNode);
|
||||
void handleTempDomainSuccess(QNetworkReply& requestReply);
|
||||
void handleTempDomainError(QNetworkReply& requestReply);
|
||||
void handleTempDomainSuccess(QNetworkReply* requestReply);
|
||||
void handleTempDomainError(QNetworkReply* requestReply);
|
||||
|
||||
void handleMetaverseHeartbeatError(QNetworkReply& requestReply);
|
||||
void handleMetaverseHeartbeatError(QNetworkReply* requestReply);
|
||||
|
||||
void queuedQuit(QString quitMessage, int exitCode);
|
||||
|
||||
|
@ -121,8 +121,8 @@ private slots:
|
|||
void handleICEHostInfo(const QHostInfo& hostInfo);
|
||||
|
||||
void sendICEServerAddressToMetaverseAPI();
|
||||
void handleSuccessfulICEServerAddressUpdate(QNetworkReply& requestReply);
|
||||
void handleFailedICEServerAddressUpdate(QNetworkReply& requestReply);
|
||||
void handleSuccessfulICEServerAddressUpdate(QNetworkReply* requestReply);
|
||||
void handleFailedICEServerAddressUpdate(QNetworkReply* requestReply);
|
||||
|
||||
void updateReplicatedNodes();
|
||||
void updateDownstreamNodes();
|
||||
|
|
|
@ -1815,9 +1815,8 @@ void DomainServerSettingsManager::apiRefreshGroupInformation() {
|
|||
|
||||
void DomainServerSettingsManager::apiGetGroupID(const QString& groupName) {
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.jsonCallbackReceiver = this;
|
||||
callbackParams.callbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "apiGetGroupIDJSONCallback";
|
||||
callbackParams.errorCallbackReceiver = this;
|
||||
callbackParams.errorCallbackMethod = "apiGetGroupIDErrorCallback";
|
||||
|
||||
const QString GET_GROUP_ID_PATH = "api/v1/groups/names/%1";
|
||||
|
@ -1826,7 +1825,7 @@ void DomainServerSettingsManager::apiGetGroupID(const QString& groupName) {
|
|||
QNetworkAccessManager::GetOperation, callbackParams);
|
||||
}
|
||||
|
||||
void DomainServerSettingsManager::apiGetGroupIDJSONCallback(QNetworkReply& requestReply) {
|
||||
void DomainServerSettingsManager::apiGetGroupIDJSONCallback(QNetworkReply* requestReply) {
|
||||
// {
|
||||
// "data":{
|
||||
// "groups":[{
|
||||
|
@ -1857,7 +1856,7 @@ void DomainServerSettingsManager::apiGetGroupIDJSONCallback(QNetworkReply& reque
|
|||
// },
|
||||
// "status":"success"
|
||||
// }
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object();
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply->readAll()).object();
|
||||
if (jsonObject["status"].toString() == "success") {
|
||||
QJsonArray groups = jsonObject["data"].toObject()["groups"].toArray();
|
||||
for (int i = 0; i < groups.size(); i++) {
|
||||
|
@ -1876,15 +1875,14 @@ void DomainServerSettingsManager::apiGetGroupIDJSONCallback(QNetworkReply& reque
|
|||
}
|
||||
}
|
||||
|
||||
void DomainServerSettingsManager::apiGetGroupIDErrorCallback(QNetworkReply& requestReply) {
|
||||
qDebug() << "******************** getGroupID api call failed:" << requestReply.error();
|
||||
void DomainServerSettingsManager::apiGetGroupIDErrorCallback(QNetworkReply* requestReply) {
|
||||
qDebug() << "******************** getGroupID api call failed:" << requestReply->error();
|
||||
}
|
||||
|
||||
void DomainServerSettingsManager::apiGetGroupRanks(const QUuid& groupID) {
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.jsonCallbackReceiver = this;
|
||||
callbackParams.callbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "apiGetGroupRanksJSONCallback";
|
||||
callbackParams.errorCallbackReceiver = this;
|
||||
callbackParams.errorCallbackMethod = "apiGetGroupRanksErrorCallback";
|
||||
|
||||
const QString GET_GROUP_RANKS_PATH = "api/v1/groups/%1/ranks";
|
||||
|
@ -1893,7 +1891,7 @@ void DomainServerSettingsManager::apiGetGroupRanks(const QUuid& groupID) {
|
|||
QNetworkAccessManager::GetOperation, callbackParams);
|
||||
}
|
||||
|
||||
void DomainServerSettingsManager::apiGetGroupRanksJSONCallback(QNetworkReply& requestReply) {
|
||||
void DomainServerSettingsManager::apiGetGroupRanksJSONCallback(QNetworkReply* requestReply) {
|
||||
// {
|
||||
// "data":{
|
||||
// "groups":{
|
||||
|
@ -1926,7 +1924,7 @@ void DomainServerSettingsManager::apiGetGroupRanksJSONCallback(QNetworkReply& re
|
|||
// }
|
||||
|
||||
bool changed = false;
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object();
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply->readAll()).object();
|
||||
|
||||
if (jsonObject["status"].toString() == "success") {
|
||||
QJsonObject groups = jsonObject["data"].toObject()["groups"].toObject();
|
||||
|
@ -1972,8 +1970,8 @@ void DomainServerSettingsManager::apiGetGroupRanksJSONCallback(QNetworkReply& re
|
|||
}
|
||||
}
|
||||
|
||||
void DomainServerSettingsManager::apiGetGroupRanksErrorCallback(QNetworkReply& requestReply) {
|
||||
qDebug() << "******************** getGroupRanks api call failed:" << requestReply.error();
|
||||
void DomainServerSettingsManager::apiGetGroupRanksErrorCallback(QNetworkReply* requestReply) {
|
||||
qDebug() << "******************** getGroupRanks api call failed:" << requestReply->error();
|
||||
}
|
||||
|
||||
void DomainServerSettingsManager::recordGroupMembership(const QString& name, const QUuid groupID, QUuid rankID) {
|
||||
|
|
|
@ -133,10 +133,10 @@ signals:
|
|||
void settingsUpdated();
|
||||
|
||||
public slots:
|
||||
void apiGetGroupIDJSONCallback(QNetworkReply& requestReply);
|
||||
void apiGetGroupIDErrorCallback(QNetworkReply& requestReply);
|
||||
void apiGetGroupRanksJSONCallback(QNetworkReply& requestReply);
|
||||
void apiGetGroupRanksErrorCallback(QNetworkReply& requestReply);
|
||||
void apiGetGroupIDJSONCallback(QNetworkReply* requestReply);
|
||||
void apiGetGroupIDErrorCallback(QNetworkReply* requestReply);
|
||||
void apiGetGroupRanksJSONCallback(QNetworkReply* requestReply);
|
||||
void apiGetGroupRanksErrorCallback(QNetworkReply* requestReply);
|
||||
|
||||
private slots:
|
||||
void processSettingsRequestPacket(QSharedPointer<ReceivedMessage> message);
|
||||
|
|
|
@ -206,14 +206,13 @@ endif()
|
|||
|
||||
# link required hifi libraries
|
||||
link_hifi_libraries(
|
||||
shared task octree ktx gpu gl procedural graphics graphics-scripting render
|
||||
shared workload task octree ktx gpu gl procedural graphics graphics-scripting render
|
||||
pointers
|
||||
recording fbx networking model-networking entities avatars trackers
|
||||
audio audio-client animation script-engine physics
|
||||
render-utils entities-renderer avatars-renderer ui qml auto-updater midi
|
||||
controllers plugins image trackers
|
||||
ui-plugins display-plugins input-plugins
|
||||
workload
|
||||
${PLATFORM_GL_BACKEND}
|
||||
)
|
||||
|
||||
|
|
|
@ -126,10 +126,12 @@ Item {
|
|||
activeFocusOnPress: true
|
||||
|
||||
ShortcutText {
|
||||
z: 10
|
||||
anchors {
|
||||
verticalCenter: usernameField.textFieldLabel.verticalCenter
|
||||
left: usernameField.textFieldLabel.right
|
||||
leftMargin: 10
|
||||
left: usernameField.left
|
||||
top: usernameField.top
|
||||
leftMargin: usernameField.textFieldLabel.contentWidth + 10
|
||||
topMargin: -19
|
||||
}
|
||||
|
||||
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Username?</a>"
|
||||
|
@ -154,10 +156,12 @@ Item {
|
|||
activeFocusOnPress: true
|
||||
|
||||
ShortcutText {
|
||||
z: 10
|
||||
anchors {
|
||||
verticalCenter: passwordField.textFieldLabel.verticalCenter
|
||||
left: passwordField.textFieldLabel.right
|
||||
leftMargin: 10
|
||||
left: passwordField.left
|
||||
top: passwordField.top
|
||||
leftMargin: passwordField.textFieldLabel.contentWidth + 10
|
||||
topMargin: -19
|
||||
}
|
||||
|
||||
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Password?</a>"
|
||||
|
@ -168,6 +172,7 @@ Item {
|
|||
|
||||
onLinkActivated: loginDialog.openUrl(link)
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
root.text = "";
|
||||
root.isPassword = true;
|
||||
|
|
|
@ -62,8 +62,6 @@ Original.Button {
|
|||
hifi.buttons.pressedColor[control.color]
|
||||
} else if (control.hovered) {
|
||||
hifi.buttons.hoveredColor[control.color]
|
||||
} else if (!control.hovered && control.focus) {
|
||||
hifi.buttons.focusedColor[control.color]
|
||||
} else {
|
||||
hifi.buttons.colorStart[control.color]
|
||||
}
|
||||
|
@ -78,8 +76,6 @@ Original.Button {
|
|||
hifi.buttons.pressedColor[control.color]
|
||||
} else if (control.hovered) {
|
||||
hifi.buttons.hoveredColor[control.color]
|
||||
} else if (!control.hovered && control.focus) {
|
||||
hifi.buttons.focusedColor[control.color]
|
||||
} else {
|
||||
hifi.buttons.colorFinish[control.color]
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ Item {
|
|||
height: parent !== null ? parent.height : undefined
|
||||
property var parentStackItem: null
|
||||
property int headerHeight: 70
|
||||
property string url
|
||||
property string scriptURL
|
||||
property bool keyboardEnabled: false
|
||||
property bool keyboardRaised: false
|
||||
|
@ -23,6 +22,7 @@ Item {
|
|||
property bool punctuationMode: false
|
||||
property bool passwordField: false
|
||||
property bool isDesktop: false
|
||||
property alias url: web.url
|
||||
property alias webView: web.webViewCore
|
||||
property alias profile: web.webViewCoreProfile
|
||||
property bool remove: false
|
||||
|
@ -81,7 +81,7 @@ Item {
|
|||
color: hifi.colors.baseGray
|
||||
font.pixelSize: 12
|
||||
verticalAlignment: Text.AlignLeft
|
||||
text: root.url
|
||||
text: web.url
|
||||
anchors {
|
||||
top: nav.bottom
|
||||
horizontalCenter: parent.horizontalCenter;
|
||||
|
@ -131,11 +131,11 @@ Item {
|
|||
|
||||
function loadUrl(url) {
|
||||
web.webViewCore.url = url
|
||||
root.url = web.webViewCore.url;
|
||||
}
|
||||
|
||||
onUrlChanged: {
|
||||
loadUrl(url);
|
||||
Rectangle {
|
||||
anchors.fill: web;
|
||||
color: hifi.colors.white;
|
||||
}
|
||||
|
||||
FlickableWebViewCore {
|
||||
|
|
|
@ -129,12 +129,10 @@ Rectangle {
|
|||
id: stereoMic
|
||||
spacing: muteMic.spacing;
|
||||
text: qsTr("Enable stereo input");
|
||||
checked: AudioScriptingInterface.isStereoInput();
|
||||
checked: AudioScriptingInterface.isStereoInput;
|
||||
onClicked: {
|
||||
var success = AudioScriptingInterface.setStereoInput(checked);
|
||||
if (!success) {
|
||||
checked = !checked;
|
||||
}
|
||||
AudioScriptingInterface.isStereoInput = checked;
|
||||
checked = Qt.binding(function() { return AudioScriptingInterface.isStereoInput; }); // restore binding
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -646,6 +646,7 @@ Item {
|
|||
height: 40;
|
||||
enabled: root.hasPermissionToRezThis &&
|
||||
MyAvatar.skeletonModelURL !== root.itemHref &&
|
||||
!root.wornEntityID &&
|
||||
root.valid;
|
||||
|
||||
onHoveredChanged: {
|
||||
|
|
|
@ -957,7 +957,7 @@ Rectangle {
|
|||
function updateCurrentlyWornWearables(wearables) {
|
||||
for (var i = 0; i < purchasesModel.count; i++) {
|
||||
for (var j = 0; j < wearables.length; j++) {
|
||||
if (purchasesModel.get(i).itemType === "wearable" &&
|
||||
if (purchasesModel.get(i).item_type === "wearable" &&
|
||||
wearables[j].entityCertID === purchasesModel.get(i).certificate_id &&
|
||||
wearables[j].entityEdition.toString() === purchasesModel.get(i).edition_number) {
|
||||
purchasesModel.setProperty(i, 'wornEntityID', wearables[j].entityID);
|
||||
|
|
|
@ -253,7 +253,11 @@ At the moment, there is currently no way to convert HFC to other currencies. Sta
|
|||
} else if (link === "#blockchain") {
|
||||
Qt.openUrlExternally("https://docs.highfidelity.com/high-fidelity-commerce");
|
||||
} else if (link === "#bank") {
|
||||
Qt.openUrlExternally("hifi://BankOfHighFidelity");
|
||||
if ((Account.metaverseServerURL).toString().indexOf("staging") >= 0) {
|
||||
Qt.openUrlExternally("hifi://hifiqa-master-metaverse-staging"); // So that we can test in staging.
|
||||
} else {
|
||||
Qt.openUrlExternally("hifi://BankOfHighFidelity");
|
||||
}
|
||||
} else if (link === "#support") {
|
||||
Qt.openUrlExternally("mailto:support@highfidelity.com");
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ Item {
|
|||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 20;
|
||||
width: parent.width/2;
|
||||
width: parent.width/2 - anchors.leftMargin;
|
||||
height: 80;
|
||||
}
|
||||
|
||||
|
@ -252,60 +252,6 @@ Item {
|
|||
anchors.bottom: parent.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
|
||||
Item { // On empty history. We don't want to flash and then replace, so don't show until we know we're zero.
|
||||
visible: transactionHistoryModel.count === 0 && transactionHistoryModel.currentPageToRetrieve < 0;
|
||||
anchors.centerIn: parent;
|
||||
width: parent.width - 12;
|
||||
height: parent.height;
|
||||
|
||||
HifiControlsUit.Separator {
|
||||
colorScheme: 1;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.top: parent.top;
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: noActivityText;
|
||||
text: "Congrats! Your wallet is all set!<br><br>" +
|
||||
"<b>Where's my HFC?</b><br>" +
|
||||
"High Fidelity commerce is in open beta right now. Want more HFC? Get it by meeting with a banker at " +
|
||||
"<a href='#goToBank'>BankOfHighFidelity</a>!"
|
||||
// Text size
|
||||
size: 22;
|
||||
// Style
|
||||
color: hifi.colors.blueAccent;
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 36;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 12;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 12;
|
||||
height: paintedHeight;
|
||||
wrapMode: Text.WordWrap;
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
|
||||
onLinkActivated: {
|
||||
sendSignalToWallet({ method: "transactionHistory_goToBank" });
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Button {
|
||||
id: bankButton;
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.top: noActivityText.bottom;
|
||||
anchors.topMargin: 30;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
width: parent.width/2;
|
||||
height: 50;
|
||||
text: "VISIT BANK OF HIGH FIDELITY";
|
||||
onClicked: {
|
||||
sendSignalToWallet({ method: "transactionHistory_goToBank" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: transactionHistory;
|
||||
|
@ -407,6 +353,64 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
// On empty history. We don't want to flash and then replace, so don't show until we know we should.
|
||||
// The history is empty when it contains 1 item (the pending item count) AND there are no pending items.
|
||||
visible: transactionHistoryModel.count === 1 &&
|
||||
transactionHistoryModel.retrievedAtLeastOnePage &&
|
||||
transactionHistoryModel.get(0).count === 0;
|
||||
anchors.centerIn: parent;
|
||||
width: parent.width - 12;
|
||||
height: parent.height;
|
||||
|
||||
HifiControlsUit.Separator {
|
||||
colorScheme: 1;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.top: parent.top;
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: noActivityText;
|
||||
text: "Congrats! Your wallet is all set!<br><br>" +
|
||||
"<b>Where's my HFC?</b><br>" +
|
||||
"High Fidelity commerce is in open beta right now. Want more HFC? Get it by meeting with a banker at " +
|
||||
"<a href='#goToBank'>BankOfHighFidelity</a>!"
|
||||
// Text size
|
||||
size: 22;
|
||||
// Style
|
||||
color: hifi.colors.blueAccent;
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 36;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 12;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 12;
|
||||
height: paintedHeight;
|
||||
wrapMode: Text.WordWrap;
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
|
||||
onLinkActivated: {
|
||||
sendSignalToWallet({ method: "transactionHistory_goToBank" });
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Button {
|
||||
id: bankButton;
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.top: noActivityText.bottom;
|
||||
anchors.topMargin: 30;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
width: parent.width/2;
|
||||
height: 50;
|
||||
text: "VISIT BANK OF HIGH FIDELITY";
|
||||
onClicked: {
|
||||
sendSignalToWallet({ method: "transactionHistory_goToBank" });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ PreferencesDialog {
|
|||
id: root
|
||||
objectName: "GeneralPreferencesDialog"
|
||||
title: "General Settings"
|
||||
showCategories: ["User Interface", "HMD", "Snapshots", "Privacy"]
|
||||
showCategories: ["User Interface", "Mouse Sensitivity", "HMD", "Snapshots", "Privacy"]
|
||||
property var settings: Settings {
|
||||
category: root.objectName
|
||||
property alias x: root.x
|
||||
|
|
|
@ -32,6 +32,6 @@ StackView {
|
|||
TabletPreferencesDialog {
|
||||
id: root
|
||||
objectName: "TabletGeneralPreferences"
|
||||
showCategories: ["User Interface", "HMD", "Snapshots", "Privacy"]
|
||||
showCategories: ["User Interface", "Mouse Sensitivity", "HMD", "Snapshots", "Privacy"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,31 +10,11 @@
|
|||
//
|
||||
#include "AndroidHelper.h"
|
||||
#include <QDebug>
|
||||
#include <AccountManager.h>
|
||||
|
||||
AndroidHelper::AndroidHelper() {
|
||||
}
|
||||
|
||||
AndroidHelper::~AndroidHelper() {
|
||||
workerThread.quit();
|
||||
workerThread.wait();
|
||||
}
|
||||
|
||||
void AndroidHelper::init() {
|
||||
workerThread.start();
|
||||
_accountManager = QSharedPointer<AccountManager>(new AccountManager, &QObject::deleteLater);
|
||||
_accountManager->setIsAgent(true);
|
||||
_accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL());
|
||||
_accountManager->setSessionID(DependencyManager::get<AccountManager>()->getSessionID());
|
||||
connect(_accountManager.data(), &AccountManager::loginComplete, [](const QUrl& authURL) {
|
||||
DependencyManager::get<AccountManager>()->setAccountInfo(AndroidHelper::instance().getAccountManager()->getAccountInfo());
|
||||
DependencyManager::get<AccountManager>()->setAuthURL(authURL);
|
||||
});
|
||||
|
||||
connect(_accountManager.data(), &AccountManager::logoutComplete, [] () {
|
||||
DependencyManager::get<AccountManager>()->logout();
|
||||
});
|
||||
_accountManager->moveToThread(&workerThread);
|
||||
}
|
||||
|
||||
void AndroidHelper::requestActivity(const QString &activityName, const bool backToScene) {
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
#define hifi_Android_Helper_h
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <AccountManager.h>
|
||||
|
||||
class AndroidHelper : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -23,7 +21,6 @@ public:
|
|||
static AndroidHelper instance;
|
||||
return instance;
|
||||
}
|
||||
void init();
|
||||
void requestActivity(const QString &activityName, const bool backToScene);
|
||||
void notifyLoadComplete();
|
||||
void notifyEnterForeground();
|
||||
|
@ -31,7 +28,6 @@ public:
|
|||
|
||||
void performHapticFeedback(int duration);
|
||||
|
||||
QSharedPointer<AccountManager> getAccountManager() { return _accountManager; }
|
||||
AndroidHelper(AndroidHelper const&) = delete;
|
||||
void operator=(AndroidHelper const&) = delete;
|
||||
|
||||
|
@ -49,8 +45,6 @@ signals:
|
|||
private:
|
||||
AndroidHelper();
|
||||
~AndroidHelper();
|
||||
QSharedPointer<AccountManager> _accountManager;
|
||||
QThread workerThread;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1081,6 +1081,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->startThread();
|
||||
|
||||
// move the AddressManager to the NodeList thread so that domain resets due to domain changes always occur
|
||||
// before we tell MyAvatar to go to a new location in the new domain
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
addressManager->moveToThread(nodeList->thread());
|
||||
|
||||
const char** constArgv = const_cast<const char**>(argv);
|
||||
if (cmdOptionExists(argc, constArgv, "--disableWatchdog")) {
|
||||
DISABLE_WATCHDOG = true;
|
||||
|
@ -1163,24 +1168,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
});
|
||||
audioIO->startThread();
|
||||
|
||||
auto audioScriptingInterface = DependencyManager::set<AudioScriptingInterface, scripting::Audio>();
|
||||
connect(audioIO.data(), &AudioClient::mutedByMixer, audioScriptingInterface.data(), &AudioScriptingInterface::mutedByMixer);
|
||||
connect(audioIO.data(), &AudioClient::receivedFirstPacket, audioScriptingInterface.data(), &AudioScriptingInterface::receivedFirstPacket);
|
||||
connect(audioIO.data(), &AudioClient::disconnected, audioScriptingInterface.data(), &AudioScriptingInterface::disconnected);
|
||||
connect(audioIO.data(), &AudioClient::muteEnvironmentRequested, [](glm::vec3 position, float radius) {
|
||||
auto audioClient = DependencyManager::get<AudioClient>();
|
||||
auto audioScriptingInterface = DependencyManager::get<AudioScriptingInterface>();
|
||||
auto myAvatarPosition = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldPosition();
|
||||
float distance = glm::distance(myAvatarPosition, position);
|
||||
|
||||
if (distance < radius) {
|
||||
audioClient->setMuted(true);
|
||||
audioScriptingInterface->environmentMuted();
|
||||
}
|
||||
});
|
||||
connect(this, &Application::activeDisplayPluginChanged,
|
||||
reinterpret_cast<scripting::Audio*>(audioScriptingInterface.data()), &scripting::Audio::onContextChanged);
|
||||
|
||||
// Make sure we don't time out during slow operations at startup
|
||||
updateHeartbeat();
|
||||
|
||||
|
@ -1249,8 +1236,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
accountManager->setIsAgent(true);
|
||||
accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL());
|
||||
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
|
||||
// use our MyAvatar position and quat for address manager path
|
||||
addressManager->setPositionGetter([this]{ return getMyAvatar()->getWorldPosition(); });
|
||||
addressManager->setOrientationGetter([this]{ return getMyAvatar()->getWorldOrientation(); });
|
||||
|
@ -1366,6 +1351,28 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
initializeDisplayPlugins();
|
||||
qCDebug(interfaceapp, "Initialized Display");
|
||||
|
||||
// An audio device changed signal received before the display plugins are set up will cause a crash,
|
||||
// so we defer the setup of the `scripting::Audio` class until this point
|
||||
{
|
||||
auto audioScriptingInterface = DependencyManager::set<AudioScriptingInterface, scripting::Audio>();
|
||||
connect(audioIO.data(), &AudioClient::mutedByMixer, audioScriptingInterface.data(), &AudioScriptingInterface::mutedByMixer);
|
||||
connect(audioIO.data(), &AudioClient::receivedFirstPacket, audioScriptingInterface.data(), &AudioScriptingInterface::receivedFirstPacket);
|
||||
connect(audioIO.data(), &AudioClient::disconnected, audioScriptingInterface.data(), &AudioScriptingInterface::disconnected);
|
||||
connect(audioIO.data(), &AudioClient::muteEnvironmentRequested, [](glm::vec3 position, float radius) {
|
||||
auto audioClient = DependencyManager::get<AudioClient>();
|
||||
auto audioScriptingInterface = DependencyManager::get<AudioScriptingInterface>();
|
||||
auto myAvatarPosition = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldPosition();
|
||||
float distance = glm::distance(myAvatarPosition, position);
|
||||
|
||||
if (distance < radius) {
|
||||
audioClient->setMuted(true);
|
||||
audioScriptingInterface->environmentMuted();
|
||||
}
|
||||
});
|
||||
connect(this, &Application::activeDisplayPluginChanged,
|
||||
reinterpret_cast<scripting::Audio*>(audioScriptingInterface.data()), &scripting::Audio::onContextChanged);
|
||||
}
|
||||
|
||||
// Create the rendering engine. This can be slow on some machines due to lots of
|
||||
// GPU pipeline creation.
|
||||
initializeRenderEngine();
|
||||
|
@ -1751,6 +1758,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
|
||||
// set the local loopback interface for local sounds
|
||||
AudioInjector::setLocalAudioInterface(audioIO.data());
|
||||
auto audioScriptingInterface = DependencyManager::get<AudioScriptingInterface>();
|
||||
audioScriptingInterface->setLocalAudioInterface(audioIO.data());
|
||||
connect(audioIO.data(), &AudioClient::noiseGateOpened, audioScriptingInterface.data(), &AudioScriptingInterface::noiseGateOpened);
|
||||
connect(audioIO.data(), &AudioClient::noiseGateClosed, audioScriptingInterface.data(), &AudioScriptingInterface::noiseGateClosed);
|
||||
|
@ -2251,7 +2259,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
qCDebug(interfaceapp) << "Metaverse session ID is" << uuidStringWithoutCurlyBraces(accountManager->getSessionID());
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
AndroidHelper::instance().init();
|
||||
connect(&AndroidHelper::instance(), &AndroidHelper::enterBackground, this, &Application::enterBackground);
|
||||
connect(&AndroidHelper::instance(), &AndroidHelper::enterForeground, this, &Application::enterForeground);
|
||||
AndroidHelper::instance().notifyLoadComplete();
|
||||
|
@ -2289,6 +2296,7 @@ void Application::domainConnectionRefused(const QString& reasonMessage, int reas
|
|||
QString message = "Unable to connect to the location you are visiting.\n";
|
||||
message += reasonMessage;
|
||||
OffscreenUi::asyncWarning("", message);
|
||||
getMyAvatar()->setWorldVelocity(glm::vec3(0.0f));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -2534,6 +2542,8 @@ Application::~Application() {
|
|||
_main3DScene = nullptr;
|
||||
_renderEngine = nullptr;
|
||||
|
||||
_gameWorkload.shutdown();
|
||||
|
||||
DependencyManager::destroy<Preferences>();
|
||||
|
||||
_entityClipboard->eraseAllOctreeElements();
|
||||
|
@ -2990,6 +3000,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
|
|||
surfaceContext->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("Scene", DependencyManager::get<SceneScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("Render", _renderEngine->getConfiguration().get());
|
||||
surfaceContext->setContextProperty("Workload", _gameWorkload._engine->getConfiguration().get());
|
||||
surfaceContext->setContextProperty("Reticle", getApplicationCompositor().getReticleInterface());
|
||||
surfaceContext->setContextProperty("Snapshot", DependencyManager::get<Snapshot>().data());
|
||||
|
||||
|
@ -4529,6 +4540,10 @@ void Application::idle() {
|
|||
qFatal("Unable to make main thread context current");
|
||||
}
|
||||
|
||||
{
|
||||
_gameWorkload.updateViews(_viewFrustum, getMyAvatar()->getHeadPosition());
|
||||
_gameWorkload._engine->run();
|
||||
}
|
||||
{
|
||||
PerformanceTimer perfTimer("update");
|
||||
PerformanceWarning warn(showWarnings, "Application::idle()... update()");
|
||||
|
@ -4924,6 +4939,9 @@ void Application::init() {
|
|||
avatar->setCollisionSound(sound);
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
_gameWorkload.startup(getEntities()->getWorkloadSpace(), _main3DScene, _entitySimulation);
|
||||
_entitySimulation->setWorkloadSpace(getEntities()->getWorkloadSpace());
|
||||
}
|
||||
|
||||
void Application::loadAvatarScripts(const QVector<QString>& urls) {
|
||||
|
@ -5275,14 +5293,16 @@ void Application::setKeyboardFocusEntity(const EntityItemID& entityItemID) {
|
|||
auto entityId = _keyboardFocusedEntity.get();
|
||||
if (entities->wantsKeyboardFocus(entityId)) {
|
||||
entities->setProxyWindow(entityId, _window->windowHandle());
|
||||
auto entity = getEntities()->getEntity(entityId);
|
||||
if (_keyboardMouseDevice->isActive()) {
|
||||
_keyboardMouseDevice->pluginFocusOutEvent();
|
||||
}
|
||||
_lastAcceptedKeyPress = usecTimestampNow();
|
||||
|
||||
setKeyboardFocusHighlight(entity->getWorldPosition(), entity->getWorldOrientation(),
|
||||
entity->getScaledDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR);
|
||||
auto entity = getEntities()->getEntity(entityId);
|
||||
if (entity) {
|
||||
setKeyboardFocusHighlight(entity->getWorldPosition(), entity->getWorldOrientation(),
|
||||
entity->getScaledDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5610,7 +5630,10 @@ void Application::update(float deltaTime) {
|
|||
{
|
||||
PROFILE_RANGE(simulation_physics, "Simulation");
|
||||
PerformanceTimer perfTimer("simulation");
|
||||
|
||||
if (_physicsEnabled) {
|
||||
auto t0 = std::chrono::high_resolution_clock::now();
|
||||
auto t1 = t0;
|
||||
{
|
||||
PROFILE_RANGE(simulation_physics, "PrePhysics");
|
||||
PerformanceTimer perfTimer("prePhysics)");
|
||||
|
@ -5634,6 +5657,8 @@ void Application::update(float deltaTime) {
|
|||
|
||||
_entitySimulation->applyDynamicChanges();
|
||||
|
||||
t1 = std::chrono::high_resolution_clock::now();
|
||||
|
||||
avatarManager->getObjectsToRemoveFromPhysics(motionStates);
|
||||
_physicsEngine->removeObjects(motionStates);
|
||||
avatarManager->getObjectsToAddToPhysics(motionStates);
|
||||
|
@ -5646,6 +5671,7 @@ void Application::update(float deltaTime) {
|
|||
dynamic->prepareForPhysicsSimulation();
|
||||
});
|
||||
}
|
||||
auto t2 = std::chrono::high_resolution_clock::now();
|
||||
{
|
||||
PROFILE_RANGE(simulation_physics, "StepPhysics");
|
||||
PerformanceTimer perfTimer("stepPhysics");
|
||||
|
@ -5653,6 +5679,7 @@ void Application::update(float deltaTime) {
|
|||
_physicsEngine->stepSimulation();
|
||||
});
|
||||
}
|
||||
auto t3 = std::chrono::high_resolution_clock::now();
|
||||
{
|
||||
if (_physicsEngine->hasOutgoingChanges()) {
|
||||
{
|
||||
|
@ -5698,12 +5725,26 @@ void Application::update(float deltaTime) {
|
|||
// NOTE: the PhysicsEngine stats are written to stdout NOT to Qt log framework
|
||||
_physicsEngine->dumpStatsIfNecessary();
|
||||
}
|
||||
auto t4 = std::chrono::high_resolution_clock::now();
|
||||
|
||||
if (!_aboutToQuit) {
|
||||
// NOTE: the getEntities()->update() call below will wait for lock
|
||||
// and will provide non-physical entity motion
|
||||
getEntities()->update(true); // update the models...
|
||||
}
|
||||
|
||||
auto t5 = std::chrono::high_resolution_clock::now();
|
||||
|
||||
workload::Timings timings(6);
|
||||
timings[0] = (t4 - t0);
|
||||
timings[1] = (t5 - t4);
|
||||
timings[2] = (t4 - t3);
|
||||
timings[3] = (t3 - t2);
|
||||
timings[4] = (t2 - t1);
|
||||
timings[5] = (t1 - t0);
|
||||
|
||||
_gameWorkload.updateSimulationTimings(timings);
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -6557,6 +6598,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
|
|||
|
||||
scriptEngine->registerGlobalObject("Scene", DependencyManager::get<SceneScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("Render", _renderEngine->getConfiguration().get());
|
||||
scriptEngine->registerGlobalObject("Workload", _gameWorkload._engine->getConfiguration().get());
|
||||
|
||||
GraphicsScriptingInterface::registerMetaTypes(scriptEngine.data());
|
||||
scriptEngine->registerGlobalObject("Graphics", DependencyManager::get<GraphicsScriptingInterface>().data());
|
||||
|
|
|
@ -72,6 +72,8 @@
|
|||
#include "ui/overlays/Overlays.h"
|
||||
#include "UndoStackScriptingInterface.h"
|
||||
|
||||
#include "workload/GameWorkload.h"
|
||||
|
||||
#include <procedural/ProceduralSkybox.h>
|
||||
#include <graphics/Skybox.h>
|
||||
#include <ModelScriptingInterface.h>
|
||||
|
@ -274,6 +276,8 @@ public:
|
|||
render::EnginePointer getRenderEngine() override { return _renderEngine; }
|
||||
gpu::ContextPointer getGPUContext() const { return _gpuContext; }
|
||||
|
||||
const GameWorkload& getGameWorkload() const { return _gameWorkload; }
|
||||
|
||||
virtual void pushPostUpdateLambda(void* key, const std::function<void()>& func) override;
|
||||
|
||||
void updateMyAvatarLookAtPosition();
|
||||
|
@ -657,6 +661,8 @@ private:
|
|||
render::EnginePointer _renderEngine{ new render::RenderEngine() };
|
||||
gpu::ContextPointer _gpuContext; // initialized during window creation
|
||||
|
||||
GameWorkload _gameWorkload;
|
||||
|
||||
mutable QMutex _renderArgsMutex{ QMutex::Recursive };
|
||||
struct AppRenderArgs {
|
||||
render::Args _renderArgs;
|
||||
|
|
|
@ -77,7 +77,7 @@ void addAvatarEntities(const QVariantList& avatarEntities) {
|
|||
|
||||
entity->setLastBroadcast(usecTimestampNow());
|
||||
// since we're creating this object we will immediately volunteer to own its simulation
|
||||
entity->flagForOwnershipBid(VOLUNTEER_SIMULATION_PRIORITY);
|
||||
entity->setScriptSimulationPriority(VOLUNTEER_SIMULATION_PRIORITY);
|
||||
entityProperties.setLastEdited(entity->getLastEdited());
|
||||
} else {
|
||||
qCDebug(entities) << "AvatarEntitiesBookmark failed to add new Entity to local Octree";
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <QtAndroidExtras/QAndroidJniObject>
|
||||
|
||||
#include <SettingHelpers.h>
|
||||
#include <BuildInfo.h>
|
||||
|
||||
google_breakpad::ExceptionHandler* gBreakpadHandler;
|
||||
|
||||
|
@ -43,7 +44,23 @@ QString obbDir() {
|
|||
return dataAbsPath;
|
||||
}
|
||||
|
||||
void flushAnnotations() {
|
||||
QSettings settings(obbDir() + "/annotations.json", JSON_FORMAT);
|
||||
settings.clear();
|
||||
settings.beginGroup("Annotations");
|
||||
for (auto k : annotations.keys()) {
|
||||
settings.setValue(k, annotations.value(k));
|
||||
}
|
||||
settings.endGroup();
|
||||
settings.sync();
|
||||
}
|
||||
|
||||
bool startCrashHandler() {
|
||||
annotations["version"] = BuildInfo::VERSION;
|
||||
annotations["build_number"] = BuildInfo::BUILD_NUMBER;
|
||||
annotations["build_type"] = BuildInfo::BUILD_TYPE_STRING;
|
||||
|
||||
flushAnnotations();
|
||||
|
||||
gBreakpadHandler = new google_breakpad::ExceptionHandler(
|
||||
google_breakpad::MinidumpDescriptor(obbDir().toStdString()),
|
||||
|
@ -56,15 +73,7 @@ void setCrashAnnotation(std::string name, std::string value) {
|
|||
QString qName = QString::fromStdString(name);
|
||||
QString qValue = QString::fromStdString(value);
|
||||
annotations[qName] = qValue;
|
||||
|
||||
QSettings settings(obbDir() + "/annotations.json", JSON_FORMAT);
|
||||
settings.clear();
|
||||
settings.beginGroup("Annotations");
|
||||
for (auto k : annotations.keys()) {
|
||||
settings.setValue(k, annotations.value(k));
|
||||
}
|
||||
settings.endGroup();
|
||||
settings.sync();
|
||||
flushAnnotations();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -97,7 +97,7 @@ void DiscoverabilityManager::updateLocation() {
|
|||
locationObject.insert(AVAILABILITY_KEY_IN_LOCATION, findableByString(static_cast<Discoverability::Mode>(_mode.get())));
|
||||
|
||||
JSONCallbackParameters callbackParameters;
|
||||
callbackParameters.jsonCallbackReceiver = this;
|
||||
callbackParameters.callbackReceiver = this;
|
||||
callbackParameters.jsonCallbackMethod = "handleHeartbeatResponse";
|
||||
|
||||
// figure out if we'll send a fresh location or just a simple heartbeat
|
||||
|
@ -121,7 +121,7 @@ void DiscoverabilityManager::updateLocation() {
|
|||
// we still send a heartbeat to the metaverse server for stats collection
|
||||
|
||||
JSONCallbackParameters callbackParameters;
|
||||
callbackParameters.jsonCallbackReceiver = this;
|
||||
callbackParameters.callbackReceiver = this;
|
||||
callbackParameters.jsonCallbackMethod = "handleHeartbeatResponse";
|
||||
|
||||
accountManager->sendRequest(API_USER_HEARTBEAT_PATH, AccountManagerAuth::Optional,
|
||||
|
@ -136,7 +136,7 @@ void DiscoverabilityManager::updateLocation() {
|
|||
setCrashAnnotation("address", currentAddress.toString().toStdString());
|
||||
}
|
||||
|
||||
void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply& requestReply) {
|
||||
void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply* requestReply) {
|
||||
auto dataObject = AccountManager::dataObjectFromResponse(requestReply);
|
||||
|
||||
if (!dataObject.isEmpty()) {
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
static QString findableByString(Discoverability::Mode discoverabilityMode);
|
||||
|
||||
private slots:
|
||||
void handleHeartbeatResponse(QNetworkReply& requestReply);
|
||||
void handleHeartbeatResponse(QNetworkReply* requestReply);
|
||||
|
||||
private:
|
||||
DiscoverabilityManager();
|
||||
|
|
|
@ -283,7 +283,7 @@ Menu::Menu() {
|
|||
MenuWrapper* settingsMenu = addMenu("Settings");
|
||||
|
||||
// Settings > General...
|
||||
action = addActionToQMenuAndActionHash(settingsMenu, MenuOption::Preferences, Qt::CTRL | Qt::Key_G, nullptr, nullptr, QAction::PreferencesRole);
|
||||
action = addActionToQMenuAndActionHash(settingsMenu, MenuOption::Preferences, Qt::CTRL | Qt::Key_G, nullptr, nullptr);
|
||||
connect(action, &QAction::triggered, [] {
|
||||
qApp->showDialog(QString("hifi/dialogs/GeneralPreferencesDialog.qml"),
|
||||
QString("hifi/tablet/TabletGeneralPreferences.qml"), "GeneralPreferencesDialog");
|
||||
|
|
|
@ -11,25 +11,16 @@
|
|||
|
||||
#include "SecondaryCamera.h"
|
||||
|
||||
#include <RenderDeferredTask.h>
|
||||
#include <RenderForwardTask.h>
|
||||
|
||||
#include <glm/gtx/transform.hpp>
|
||||
#include <gpu/Context.h>
|
||||
#include <TextureCache.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
using RenderArgsPointer = std::shared_ptr<RenderArgs>;
|
||||
|
||||
void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
|
||||
task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
|
||||
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
|
||||
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
||||
if (!isDeferred) {
|
||||
task.addJob<RenderForwardTask>("Forward", items);
|
||||
} else {
|
||||
task.addJob<RenderDeferredTask>("RenderDeferredTask", items);
|
||||
}
|
||||
}
|
||||
|
||||
class SecondaryCameraJob { // Changes renderContext for our framebuffer and view.
|
||||
public:
|
||||
using Config = SecondaryCameraJobConfig;
|
||||
|
@ -213,10 +204,10 @@ void SecondaryCameraRenderTask::build(JobModel& task, const render::Varying& inp
|
|||
const auto cachedArg = task.addJob<SecondaryCameraJob>("SecondaryCamera");
|
||||
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
|
||||
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
||||
if (!isDeferred) {
|
||||
task.addJob<RenderForwardTask>("Forward", items);
|
||||
if (isDeferred) {
|
||||
task.addJob<RenderDeferredTask>("RenderDeferredTask", items, false);
|
||||
} else {
|
||||
task.addJob<RenderDeferredTask>("RenderDeferredTask", items);
|
||||
task.addJob<RenderForwardTask>("Forward", items);
|
||||
}
|
||||
task.addJob<EndSecondaryCameraFrame>("EndSecondaryCamera", cachedArg);
|
||||
}
|
|
@ -12,23 +12,11 @@
|
|||
#pragma once
|
||||
#ifndef hifi_SecondaryCamera_h
|
||||
#define hifi_SecondaryCamera_h
|
||||
|
||||
#include <RenderShadowTask.h>
|
||||
|
||||
#include <render/RenderFetchCullSortTask.h>
|
||||
#include <RenderDeferredTask.h>
|
||||
#include <RenderForwardTask.h>
|
||||
#include <TextureCache.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
class MainRenderTask {
|
||||
public:
|
||||
using JobModel = render::Task::Model<MainRenderTask>;
|
||||
|
||||
MainRenderTask() {}
|
||||
|
||||
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred = true);
|
||||
};
|
||||
|
||||
class SecondaryCameraJobConfig : public render::Task::Config { // Exposes secondary camera parameters to JavaScript.
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QUuid attachedEntityId MEMBER attachedEntityId NOTIFY dirty) // entity whose properties define camera position and orientation
|
||||
|
|
|
@ -440,8 +440,8 @@ QVariantMap AvatarActionHold::getArguments() {
|
|||
QVariantMap arguments = ObjectDynamic::getArguments();
|
||||
withReadLock([&]{
|
||||
arguments["holderID"] = _holderID;
|
||||
arguments["relativePosition"] = glmToQMap(_relativePosition);
|
||||
arguments["relativeRotation"] = glmToQMap(_relativeRotation);
|
||||
arguments["relativePosition"] = vec3ToQMap(_relativePosition);
|
||||
arguments["relativeRotation"] = quatToQMap(_relativeRotation);
|
||||
arguments["timeScale"] = _linearTimeScale;
|
||||
arguments["hand"] = _hand;
|
||||
arguments["kinematic"] = _kinematic;
|
||||
|
|
|
@ -186,6 +186,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
uint64_t updateExpiry = startTime + UPDATE_BUDGET;
|
||||
int numAvatarsUpdated = 0;
|
||||
int numAVatarsNotUpdated = 0;
|
||||
bool physicsEnabled = qApp->isPhysicsEnabled();
|
||||
|
||||
render::Transaction transaction;
|
||||
while (!sortedAvatars.empty()) {
|
||||
|
@ -202,7 +203,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
if (_shouldRender) {
|
||||
avatar->ensureInScene(avatar, qApp->getMain3DScene());
|
||||
}
|
||||
if (!avatar->isInPhysicsSimulation()) {
|
||||
if (physicsEnabled && !avatar->isInPhysicsSimulation()) {
|
||||
ShapeInfo shapeInfo;
|
||||
avatar->computeShapeInfo(shapeInfo);
|
||||
btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
|
||||
|
|
|
@ -154,6 +154,10 @@ const QUuid AvatarMotionState::getObjectID() const {
|
|||
return _avatar->getSessionUUID();
|
||||
}
|
||||
|
||||
QString AvatarMotionState::getName() const {
|
||||
return _avatar->getName();
|
||||
}
|
||||
|
||||
// virtual
|
||||
QUuid AvatarMotionState::getSimulatorID() const {
|
||||
return _avatar->getSessionUUID();
|
||||
|
|
|
@ -59,6 +59,7 @@ public:
|
|||
|
||||
virtual const QUuid getObjectID() const override;
|
||||
|
||||
virtual QString getName() const override;
|
||||
virtual QUuid getSimulatorID() const override;
|
||||
|
||||
void setBoundingBox(const glm::vec3& corner, const glm::vec3& diagonal);
|
||||
|
|
|
@ -121,6 +121,7 @@ MyAvatar::MyAvatar(QThread* thread) :
|
|||
_headData = new MyHead(this);
|
||||
|
||||
_skeletonModel = std::make_shared<MySkeletonModel>(this, nullptr);
|
||||
_skeletonModel->setLoadingPriority(MYAVATAR_LOADING_PRIORITY);
|
||||
connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished);
|
||||
connect(_skeletonModel.get(), &Model::setURLFinished, this, [this](bool success) {
|
||||
if (success) {
|
||||
|
@ -531,10 +532,14 @@ void MyAvatar::forgetChild(SpatiallyNestablePointer newChild) const {
|
|||
SpatiallyNestable::forgetChild(newChild);
|
||||
}
|
||||
|
||||
void MyAvatar::updateChildCauterization(SpatiallyNestablePointer object) {
|
||||
void MyAvatar::recalculateChildCauterization() const {
|
||||
_cauterizationNeedsUpdate = true;
|
||||
}
|
||||
|
||||
void MyAvatar::updateChildCauterization(SpatiallyNestablePointer object, bool cauterize) {
|
||||
if (object->getNestableType() == NestableType::Entity) {
|
||||
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
|
||||
entity->setCauterized(!_prevShouldDrawHead);
|
||||
entity->setCauterized(cauterize);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -544,17 +549,42 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
animateScaleChanges(deltaTime);
|
||||
|
||||
if (_cauterizationNeedsUpdate) {
|
||||
const std::unordered_set<int>& headBoneSet = _skeletonModel->getCauterizeBoneSet();
|
||||
_cauterizationNeedsUpdate = false;
|
||||
|
||||
// Redisplay cauterized entities that are no longer children of the avatar.
|
||||
auto cauterizedChild = _cauterizedChildrenOfHead.begin();
|
||||
if (cauterizedChild != _cauterizedChildrenOfHead.end()) {
|
||||
auto children = getChildren();
|
||||
while (cauterizedChild != _cauterizedChildrenOfHead.end()) {
|
||||
if (!children.contains(*cauterizedChild)) {
|
||||
updateChildCauterization(*cauterizedChild, false);
|
||||
cauterizedChild = _cauterizedChildrenOfHead.erase(cauterizedChild);
|
||||
} else {
|
||||
++cauterizedChild;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update cauterization of entities that are children of the avatar.
|
||||
auto headBoneSet = _skeletonModel->getCauterizeBoneSet();
|
||||
forEachChild([&](SpatiallyNestablePointer object) {
|
||||
bool isChildOfHead = headBoneSet.find(object->getParentJointIndex()) != headBoneSet.end();
|
||||
if (isChildOfHead) {
|
||||
updateChildCauterization(object);
|
||||
// Cauterize or display children of head per head drawing state.
|
||||
updateChildCauterization(object, !_prevShouldDrawHead);
|
||||
object->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
||||
updateChildCauterization(descendant);
|
||||
updateChildCauterization(descendant, !_prevShouldDrawHead);
|
||||
});
|
||||
_cauterizedChildrenOfHead.insert(object);
|
||||
} else if (_cauterizedChildrenOfHead.find(object) != _cauterizedChildrenOfHead.end()) {
|
||||
// Redisplay cauterized children that are not longer children of the head.
|
||||
updateChildCauterization(object, false);
|
||||
object->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
||||
updateChildCauterization(descendant, false);
|
||||
});
|
||||
_cauterizedChildrenOfHead.erase(object);
|
||||
}
|
||||
});
|
||||
_cauterizationNeedsUpdate = false;
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -684,7 +714,8 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
entityTree->recurseTreeWithOperator(&moveOperator);
|
||||
}
|
||||
});
|
||||
_characterController.setFlyingAllowed(zoneAllowsFlying && _enableFlying);
|
||||
bool isPhysicsEnabled = qApp->isPhysicsEnabled();
|
||||
_characterController.setFlyingAllowed(zoneAllowsFlying && (_enableFlying || !isPhysicsEnabled));
|
||||
_characterController.setCollisionlessAllowed(collisionlessAllowed);
|
||||
}
|
||||
|
||||
|
@ -1067,8 +1098,8 @@ void MyAvatar::saveData() {
|
|||
settings.setValue("displayName", _displayName);
|
||||
settings.setValue("collisionSoundURL", _collisionSoundURL);
|
||||
settings.setValue("useSnapTurn", _useSnapTurn);
|
||||
settings.setValue("clearOverlayWhenMoving", _clearOverlayWhenMoving);
|
||||
settings.setValue("userHeight", getUserHeight());
|
||||
settings.setValue("enabledFlying", getFlyingEnabled());
|
||||
|
||||
settings.endGroup();
|
||||
}
|
||||
|
@ -1218,11 +1249,10 @@ void MyAvatar::loadData() {
|
|||
settings.remove("avatarEntityData");
|
||||
}
|
||||
setAvatarEntityDataChanged(true);
|
||||
|
||||
setFlyingEnabled(settings.value("enabledFlying").toBool());
|
||||
setDisplayName(settings.value("displayName").toString());
|
||||
setCollisionSoundURL(settings.value("collisionSoundURL", DEFAULT_AVATAR_COLLISION_SOUND_URL).toString());
|
||||
setSnapTurn(settings.value("useSnapTurn", _useSnapTurn).toBool());
|
||||
setClearOverlayWhenMoving(settings.value("clearOverlayWhenMoving", _clearOverlayWhenMoving).toBool());
|
||||
setDominantHand(settings.value("dominantHand", _dominantHand).toString().toLower());
|
||||
setUserHeight(settings.value("userHeight", DEFAULT_AVATAR_HEIGHT).toDouble());
|
||||
settings.endGroup();
|
||||
|
|
|
@ -469,16 +469,6 @@ public:
|
|||
* @param {boolean} on
|
||||
*/
|
||||
Q_INVOKABLE void setSnapTurn(bool on) { _useSnapTurn = on; }
|
||||
/**jsdoc
|
||||
* @function MyAvatar.getClearOverlayWhenMoving
|
||||
* @returns {boolean}
|
||||
*/
|
||||
Q_INVOKABLE bool getClearOverlayWhenMoving() const { return _clearOverlayWhenMoving; }
|
||||
/**jsdoc
|
||||
* @function MyAvatar.setClearOverlayWhenMoving
|
||||
* @param {boolean} on
|
||||
*/
|
||||
Q_INVOKABLE void setClearOverlayWhenMoving(bool on) { _clearOverlayWhenMoving = on; }
|
||||
|
||||
|
||||
/**jsdoc
|
||||
|
@ -1374,6 +1364,7 @@ private slots:
|
|||
protected:
|
||||
virtual void beParentOfChild(SpatiallyNestablePointer newChild) const override;
|
||||
virtual void forgetChild(SpatiallyNestablePointer newChild) const override;
|
||||
virtual void recalculateChildCauterization() const override;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -1433,7 +1424,7 @@ private:
|
|||
std::array<float, MAX_DRIVE_KEYS> _driveKeys;
|
||||
std::bitset<MAX_DRIVE_KEYS> _disabledDriveKeys;
|
||||
|
||||
bool _enableFlying { true };
|
||||
bool _enableFlying { false };
|
||||
bool _wasPushing { false };
|
||||
bool _isPushing { false };
|
||||
bool _isBeingPushed { false };
|
||||
|
@ -1495,7 +1486,6 @@ private:
|
|||
ThreadSafeValueCache<QUrl> _prefOverrideAnimGraphUrl;
|
||||
QUrl _fstAnimGraphOverrideUrl;
|
||||
bool _useSnapTurn { true };
|
||||
bool _clearOverlayWhenMoving { true };
|
||||
QString _dominantHand { DOMINANT_RIGHT_HAND };
|
||||
|
||||
const float ROLL_CONTROL_DEAD_ZONE_DEFAULT = 8.0f; // degrees
|
||||
|
@ -1566,6 +1556,7 @@ private:
|
|||
glm::quat _goToOrientation;
|
||||
|
||||
std::unordered_set<int> _headBoneSet;
|
||||
std::unordered_set<SpatiallyNestablePointer> _cauterizedChildrenOfHead;
|
||||
bool _prevShouldDrawHead;
|
||||
bool _rigEnabled { true };
|
||||
|
||||
|
@ -1621,7 +1612,7 @@ private:
|
|||
// height of user in sensor space, when standing erect.
|
||||
ThreadSafeValueCache<float> _userHeight { DEFAULT_AVATAR_HEIGHT };
|
||||
|
||||
void updateChildCauterization(SpatiallyNestablePointer object);
|
||||
void updateChildCauterization(SpatiallyNestablePointer object, bool cauterize);
|
||||
|
||||
// max unscaled forward movement speed
|
||||
ThreadSafeValueCache<float> _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED };
|
||||
|
|
|
@ -108,12 +108,15 @@ bool MyCharacterController::testRayShotgun(const glm::vec3& position, const glm:
|
|||
btScalar lengthAxis = axis.length();
|
||||
if (lengthAxis > FLT_EPSILON) {
|
||||
// we're walking sideways
|
||||
btScalar angle = acosf(lengthAxis / adjustedDirection.length());
|
||||
if (rayDirection.dot(forward) < 0.0f) {
|
||||
angle = PI - angle;
|
||||
btScalar cosAngle = lengthAxis / adjustedDirection.length();
|
||||
if (cosAngle < 1.0f) {
|
||||
btScalar angle = acosf(cosAngle);
|
||||
if (rayDirection.dot(forward) < 0.0f) {
|
||||
angle = PI - angle;
|
||||
}
|
||||
axis /= lengthAxis;
|
||||
rotation = btMatrix3x3(btQuaternion(axis, angle)) * rotation;
|
||||
}
|
||||
axis /= lengthAxis;
|
||||
rotation = btMatrix3x3(btQuaternion(axis, angle)) * rotation;
|
||||
} else if (rayDirection.dot(forward) < 0.0f) {
|
||||
// we're walking backwards
|
||||
rotation = btMatrix3x3(btQuaternion(_currentUp, PI)) * rotation;
|
||||
|
|
|
@ -28,15 +28,15 @@
|
|||
// account synthesizes a result {status: 'success', data: {keyStatus: "preexisting"|"conflicting"|"ok"}}
|
||||
|
||||
|
||||
QJsonObject Ledger::apiResponse(const QString& label, QNetworkReply& reply) {
|
||||
QByteArray response = reply.readAll();
|
||||
QJsonObject Ledger::apiResponse(const QString& label, QNetworkReply* reply) {
|
||||
QByteArray response = reply->readAll();
|
||||
QJsonObject data = QJsonDocument::fromJson(response).object();
|
||||
qInfo(commerce) << label << "response" << QJsonDocument(data).toJson(QJsonDocument::Compact);
|
||||
return data;
|
||||
}
|
||||
// Non-200 responses are not json:
|
||||
QJsonObject Ledger::failResponse(const QString& label, QNetworkReply& reply) {
|
||||
QString response = reply.readAll();
|
||||
QJsonObject Ledger::failResponse(const QString& label, QNetworkReply* reply) {
|
||||
QString response = reply->readAll();
|
||||
qWarning(commerce) << "FAILED" << label << response;
|
||||
|
||||
// tempResult will be NULL if the response isn't valid JSON.
|
||||
|
@ -52,8 +52,8 @@ QJsonObject Ledger::failResponse(const QString& label, QNetworkReply& reply) {
|
|||
return tempResult.object();
|
||||
}
|
||||
}
|
||||
#define ApiHandler(NAME) void Ledger::NAME##Success(QNetworkReply& reply) { emit NAME##Result(apiResponse(#NAME, reply)); }
|
||||
#define FailHandler(NAME) void Ledger::NAME##Failure(QNetworkReply& reply) { emit NAME##Result(failResponse(#NAME, reply)); }
|
||||
#define ApiHandler(NAME) void Ledger::NAME##Success(QNetworkReply* reply) { emit NAME##Result(apiResponse(#NAME, reply)); }
|
||||
#define FailHandler(NAME) void Ledger::NAME##Failure(QNetworkReply* reply) { emit NAME##Result(failResponse(#NAME, reply)); }
|
||||
#define Handler(NAME) ApiHandler(NAME) FailHandler(NAME)
|
||||
Handler(buy)
|
||||
Handler(receiveAt)
|
||||
|
@ -68,7 +68,7 @@ Handler(updateItem)
|
|||
void Ledger::send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, AccountManagerAuth::Type authType, QJsonObject request) {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
const QString URL = "/api/v1/commerce/";
|
||||
JSONCallbackParameters callbackParams(this, success, this, fail);
|
||||
JSONCallbackParameters callbackParams(this, success, fail);
|
||||
qCInfo(commerce) << "Sending" << endpoint << QJsonDocument(request).toJson(QJsonDocument::Compact);
|
||||
accountManager->sendRequest(URL + endpoint,
|
||||
authType,
|
||||
|
@ -223,12 +223,12 @@ QString transactionString(const QJsonObject& valueObject) {
|
|||
}
|
||||
|
||||
static const QString MARKETPLACE_ITEMS_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/marketplace/items/";
|
||||
void Ledger::historySuccess(QNetworkReply& reply) {
|
||||
void Ledger::historySuccess(QNetworkReply* reply) {
|
||||
// here we send a historyResult with some extra stuff in it
|
||||
// Namely, the styled text we'd like to show. The issue is the
|
||||
// QML cannot do that easily since it doesn't know what the wallet
|
||||
// public key(s) are. Let's keep it that way
|
||||
QByteArray response = reply.readAll();
|
||||
QByteArray response = reply->readAll();
|
||||
QJsonObject data = QJsonDocument::fromJson(response).object();
|
||||
qInfo(commerce) << "history" << "response" << QJsonDocument(data).toJson(QJsonDocument::Compact);
|
||||
|
||||
|
@ -262,7 +262,7 @@ void Ledger::historySuccess(QNetworkReply& reply) {
|
|||
emit historyResult(newData);
|
||||
}
|
||||
|
||||
void Ledger::historyFailure(QNetworkReply& reply) {
|
||||
void Ledger::historyFailure(QNetworkReply* reply) {
|
||||
failResponse("history", reply);
|
||||
}
|
||||
|
||||
|
@ -273,10 +273,10 @@ void Ledger::history(const QStringList& keys, const int& pageNumber, const int&
|
|||
keysQuery("history", "historySuccess", "historyFailure", params);
|
||||
}
|
||||
|
||||
void Ledger::accountSuccess(QNetworkReply& reply) {
|
||||
void Ledger::accountSuccess(QNetworkReply* reply) {
|
||||
// lets set the appropriate stuff in the wallet now
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
QByteArray response = reply.readAll();
|
||||
QByteArray response = reply->readAll();
|
||||
QJsonObject data = QJsonDocument::fromJson(response).object()["data"].toObject();
|
||||
|
||||
auto salt = QByteArray::fromBase64(data["salt"].toString().toUtf8());
|
||||
|
@ -312,7 +312,7 @@ void Ledger::accountSuccess(QNetworkReply& reply) {
|
|||
emit accountResult(responseData);
|
||||
}
|
||||
|
||||
void Ledger::accountFailure(QNetworkReply& reply) {
|
||||
void Ledger::accountFailure(QNetworkReply* reply) {
|
||||
failResponse("account", reply);
|
||||
}
|
||||
void Ledger::account() {
|
||||
|
@ -320,8 +320,8 @@ void Ledger::account() {
|
|||
}
|
||||
|
||||
// The api/failResponse is called just for the side effect of logging.
|
||||
void Ledger::updateLocationSuccess(QNetworkReply& reply) { apiResponse("updateLocation", reply); }
|
||||
void Ledger::updateLocationFailure(QNetworkReply& reply) { failResponse("updateLocation", reply); }
|
||||
void Ledger::updateLocationSuccess(QNetworkReply* reply) { apiResponse("updateLocation", reply); }
|
||||
void Ledger::updateLocationFailure(QNetworkReply* reply) { failResponse("updateLocation", reply); }
|
||||
void Ledger::updateLocation(const QString& asset_id, const QString& location, const bool& alsoUpdateSiblings, const bool controlledFailure) {
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
auto walletScriptingInterface = DependencyManager::get<WalletScriptingInterface>();
|
||||
|
@ -349,11 +349,11 @@ void Ledger::updateLocation(const QString& asset_id, const QString& location, co
|
|||
}
|
||||
}
|
||||
|
||||
void Ledger::certificateInfoSuccess(QNetworkReply& reply) {
|
||||
void Ledger::certificateInfoSuccess(QNetworkReply* reply) {
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
||||
QByteArray response = reply.readAll();
|
||||
QByteArray response = reply->readAll();
|
||||
QJsonObject replyObject = QJsonDocument::fromJson(response).object();
|
||||
|
||||
QStringList keys = wallet->listPublicKeys();
|
||||
|
@ -366,7 +366,7 @@ void Ledger::certificateInfoSuccess(QNetworkReply& reply) {
|
|||
qInfo(commerce) << "certificateInfo" << "response" << QJsonDocument(replyObject).toJson(QJsonDocument::Compact);
|
||||
emit certificateInfoResult(replyObject);
|
||||
}
|
||||
void Ledger::certificateInfoFailure(QNetworkReply& reply) {
|
||||
void Ledger::certificateInfoFailure(QNetworkReply* reply) {
|
||||
emit certificateInfoResult(failResponse("certificateInfo", reply));
|
||||
}
|
||||
void Ledger::certificateInfo(const QString& certificateId) {
|
||||
|
|
|
@ -65,36 +65,36 @@ signals:
|
|||
void updateCertificateStatus(const QString& certID, uint certStatus);
|
||||
|
||||
public slots:
|
||||
void buySuccess(QNetworkReply& reply);
|
||||
void buyFailure(QNetworkReply& reply);
|
||||
void receiveAtSuccess(QNetworkReply& reply);
|
||||
void receiveAtFailure(QNetworkReply& reply);
|
||||
void balanceSuccess(QNetworkReply& reply);
|
||||
void balanceFailure(QNetworkReply& reply);
|
||||
void inventorySuccess(QNetworkReply& reply);
|
||||
void inventoryFailure(QNetworkReply& reply);
|
||||
void historySuccess(QNetworkReply& reply);
|
||||
void historyFailure(QNetworkReply& reply);
|
||||
void accountSuccess(QNetworkReply& reply);
|
||||
void accountFailure(QNetworkReply& reply);
|
||||
void updateLocationSuccess(QNetworkReply& reply);
|
||||
void updateLocationFailure(QNetworkReply& reply);
|
||||
void certificateInfoSuccess(QNetworkReply& reply);
|
||||
void certificateInfoFailure(QNetworkReply& reply);
|
||||
void transferAssetToNodeSuccess(QNetworkReply& reply);
|
||||
void transferAssetToNodeFailure(QNetworkReply& reply);
|
||||
void transferAssetToUsernameSuccess(QNetworkReply& reply);
|
||||
void transferAssetToUsernameFailure(QNetworkReply& reply);
|
||||
void alreadyOwnedSuccess(QNetworkReply& reply);
|
||||
void alreadyOwnedFailure(QNetworkReply& reply);
|
||||
void availableUpdatesSuccess(QNetworkReply& reply);
|
||||
void availableUpdatesFailure(QNetworkReply& reply);
|
||||
void updateItemSuccess(QNetworkReply& reply);
|
||||
void updateItemFailure(QNetworkReply& reply);
|
||||
void buySuccess(QNetworkReply* reply);
|
||||
void buyFailure(QNetworkReply* reply);
|
||||
void receiveAtSuccess(QNetworkReply* reply);
|
||||
void receiveAtFailure(QNetworkReply* reply);
|
||||
void balanceSuccess(QNetworkReply* reply);
|
||||
void balanceFailure(QNetworkReply* reply);
|
||||
void inventorySuccess(QNetworkReply* reply);
|
||||
void inventoryFailure(QNetworkReply* reply);
|
||||
void historySuccess(QNetworkReply* reply);
|
||||
void historyFailure(QNetworkReply* reply);
|
||||
void accountSuccess(QNetworkReply* reply);
|
||||
void accountFailure(QNetworkReply* reply);
|
||||
void updateLocationSuccess(QNetworkReply* reply);
|
||||
void updateLocationFailure(QNetworkReply* reply);
|
||||
void certificateInfoSuccess(QNetworkReply* reply);
|
||||
void certificateInfoFailure(QNetworkReply* reply);
|
||||
void transferAssetToNodeSuccess(QNetworkReply* reply);
|
||||
void transferAssetToNodeFailure(QNetworkReply* reply);
|
||||
void transferAssetToUsernameSuccess(QNetworkReply* reply);
|
||||
void transferAssetToUsernameFailure(QNetworkReply* reply);
|
||||
void alreadyOwnedSuccess(QNetworkReply* reply);
|
||||
void alreadyOwnedFailure(QNetworkReply* reply);
|
||||
void availableUpdatesSuccess(QNetworkReply* reply);
|
||||
void availableUpdatesFailure(QNetworkReply* reply);
|
||||
void updateItemSuccess(QNetworkReply* reply);
|
||||
void updateItemFailure(QNetworkReply* reply);
|
||||
|
||||
private:
|
||||
QJsonObject apiResponse(const QString& label, QNetworkReply& reply);
|
||||
QJsonObject failResponse(const QString& label, QNetworkReply& reply);
|
||||
QJsonObject apiResponse(const QString& label, QNetworkReply* reply);
|
||||
QJsonObject failResponse(const QString& label, QNetworkReply* reply);
|
||||
void send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, AccountManagerAuth::Type authType, QJsonObject request);
|
||||
void keysQuery(const QString& endpoint, const QString& success, const QString& fail, QJsonObject& extraRequestParams);
|
||||
void keysQuery(const QString& endpoint, const QString& success, const QString& fail);
|
||||
|
|
|
@ -127,31 +127,40 @@ EC_KEY* readKeys(const char* filename) {
|
|||
bool Wallet::writeBackupInstructions() {
|
||||
QString inputFilename(PathUtils::resourcesPath() + "html/commerce/backup_instructions.html");
|
||||
QString outputFilename = PathUtils::getAppDataFilePath(INSTRUCTIONS_FILE);
|
||||
QFile inputFile(inputFilename);
|
||||
QFile outputFile(outputFilename);
|
||||
bool retval = false;
|
||||
|
||||
if (QFile::exists(outputFilename) || getKeyFilePath() == "")
|
||||
if (getKeyFilePath() == "")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
QFile::copy(inputFilename, outputFilename);
|
||||
|
||||
if (QFile::exists(outputFilename) && outputFile.open(QIODevice::ReadWrite)) {
|
||||
if (QFile::exists(inputFilename) && inputFile.open(QIODevice::ReadOnly)) {
|
||||
if (outputFile.open(QIODevice::ReadWrite)) {
|
||||
// Read the data from the original file, then close it
|
||||
QByteArray fileData = inputFile.readAll();
|
||||
inputFile.close();
|
||||
|
||||
QByteArray fileData = outputFile.readAll();
|
||||
QString text(fileData);
|
||||
// Translate the data from the original file into a QString
|
||||
QString text(fileData);
|
||||
|
||||
text.replace(QString("HIFIKEY_PATH_REPLACEME"), keyFilePath());
|
||||
// Replace the necessary string
|
||||
text.replace(QString("HIFIKEY_PATH_REPLACEME"), keyFilePath());
|
||||
|
||||
outputFile.seek(0); // go to the beginning of the file
|
||||
outputFile.write(text.toUtf8()); // write the new text back to the file
|
||||
// Write the new text back to the file
|
||||
outputFile.write(text.toUtf8());
|
||||
|
||||
outputFile.close(); // close the file handle.
|
||||
// Close the output file
|
||||
outputFile.close();
|
||||
|
||||
retval = true;
|
||||
qCDebug(commerce) << "wrote html file successfully";
|
||||
retval = true;
|
||||
qCDebug(commerce) << "wrote html file successfully";
|
||||
} else {
|
||||
qCDebug(commerce) << "failed to open output html file" << outputFilename;
|
||||
}
|
||||
} else {
|
||||
qCDebug(commerce) << "failed to open output html file" << outputFilename;
|
||||
qCDebug(commerce) << "failed to open input html file" << inputFilename;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -35,5 +35,8 @@ QVariant SettingsScriptingInterface::getValue(const QString& setting, const QVar
|
|||
}
|
||||
|
||||
void SettingsScriptingInterface::setValue(const QString& setting, const QVariant& value) {
|
||||
Setting::Handle<QVariant>(setting).set(value);
|
||||
// Make a deep-copy of the string.
|
||||
// Dangling pointers can occur with QStrings that are implicitly shared from a QScriptEngine.
|
||||
QString deepCopy = QString::fromUtf16(setting.utf16());
|
||||
Setting::Handle<QVariant>(deepCopy).set(value);
|
||||
}
|
||||
|
|
|
@ -113,9 +113,8 @@ void LoginDialog::linkSteam() {
|
|||
}
|
||||
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.jsonCallbackReceiver = this;
|
||||
callbackParams.callbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "linkCompleted";
|
||||
callbackParams.errorCallbackReceiver = this;
|
||||
callbackParams.errorCallbackMethod = "linkFailed";
|
||||
|
||||
const QString LINK_STEAM_PATH = "api/v1/user/steam/link";
|
||||
|
@ -141,9 +140,8 @@ void LoginDialog::createAccountFromStream(QString username) {
|
|||
}
|
||||
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.jsonCallbackReceiver = this;
|
||||
callbackParams.callbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "createCompleted";
|
||||
callbackParams.errorCallbackReceiver = this;
|
||||
callbackParams.errorCallbackMethod = "createFailed";
|
||||
|
||||
const QString CREATE_ACCOUNT_FROM_STEAM_PATH = "api/v1/user/steam/create";
|
||||
|
@ -185,28 +183,27 @@ void LoginDialog::openUrl(const QString& url) const {
|
|||
}
|
||||
}
|
||||
|
||||
void LoginDialog::linkCompleted(QNetworkReply& reply) {
|
||||
void LoginDialog::linkCompleted(QNetworkReply* reply) {
|
||||
emit handleLinkCompleted();
|
||||
}
|
||||
|
||||
void LoginDialog::linkFailed(QNetworkReply& reply) {
|
||||
emit handleLinkFailed(reply.errorString());
|
||||
void LoginDialog::linkFailed(QNetworkReply* reply) {
|
||||
emit handleLinkFailed(reply->errorString());
|
||||
}
|
||||
|
||||
void LoginDialog::createCompleted(QNetworkReply& reply) {
|
||||
void LoginDialog::createCompleted(QNetworkReply* reply) {
|
||||
emit handleCreateCompleted();
|
||||
}
|
||||
|
||||
void LoginDialog::createFailed(QNetworkReply& reply) {
|
||||
emit handleCreateFailed(reply.errorString());
|
||||
void LoginDialog::createFailed(QNetworkReply* reply) {
|
||||
emit handleCreateFailed(reply->errorString());
|
||||
}
|
||||
|
||||
void LoginDialog::signup(const QString& email, const QString& username, const QString& password) {
|
||||
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.jsonCallbackReceiver = this;
|
||||
callbackParams.callbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "signupCompleted";
|
||||
callbackParams.errorCallbackReceiver = this;
|
||||
callbackParams.errorCallbackMethod = "signupFailed";
|
||||
|
||||
QJsonObject payload;
|
||||
|
@ -228,7 +225,7 @@ void LoginDialog::signup(const QString& email, const QString& username, const QS
|
|||
QJsonDocument(payload).toJson());
|
||||
}
|
||||
|
||||
void LoginDialog::signupCompleted(QNetworkReply& reply) {
|
||||
void LoginDialog::signupCompleted(QNetworkReply* reply) {
|
||||
emit handleSignupCompleted();
|
||||
}
|
||||
|
||||
|
@ -242,10 +239,10 @@ QString errorStringFromAPIObject(const QJsonValue& apiObject) {
|
|||
}
|
||||
}
|
||||
|
||||
void LoginDialog::signupFailed(QNetworkReply& reply) {
|
||||
void LoginDialog::signupFailed(QNetworkReply* reply) {
|
||||
|
||||
// parse the returned JSON to see what the problem was
|
||||
auto jsonResponse = QJsonDocument::fromJson(reply.readAll());
|
||||
auto jsonResponse = QJsonDocument::fromJson(reply->readAll());
|
||||
|
||||
static const QString RESPONSE_DATA_KEY = "data";
|
||||
|
||||
|
|
|
@ -42,14 +42,14 @@ signals:
|
|||
void handleSignupFailed(QString errorString);
|
||||
|
||||
public slots:
|
||||
void linkCompleted(QNetworkReply& reply);
|
||||
void linkFailed(QNetworkReply& reply);
|
||||
void linkCompleted(QNetworkReply* reply);
|
||||
void linkFailed(QNetworkReply* reply);
|
||||
|
||||
void createCompleted(QNetworkReply& reply);
|
||||
void createFailed(QNetworkReply& reply);
|
||||
void createCompleted(QNetworkReply* reply);
|
||||
void createFailed(QNetworkReply* reply);
|
||||
|
||||
void signupCompleted(QNetworkReply& reply);
|
||||
void signupFailed(QNetworkReply& reply);
|
||||
void signupCompleted(QNetworkReply* reply);
|
||||
void signupFailed(QNetworkReply* reply);
|
||||
|
||||
protected slots:
|
||||
Q_INVOKABLE bool isSteamRunning() const;
|
||||
|
|
|
@ -88,38 +88,24 @@ void OverlayConductor::update(float dt) {
|
|||
_hmdMode = false;
|
||||
}
|
||||
|
||||
bool isAtRest = updateAvatarIsAtRest();
|
||||
bool isMoving = !isAtRest;
|
||||
|
||||
bool shouldRecenter = false;
|
||||
|
||||
if (_flags & SuppressedByMove) {
|
||||
if (!isMoving) {
|
||||
_flags &= ~SuppressedByMove;
|
||||
shouldRecenter = true;
|
||||
}
|
||||
} else {
|
||||
if (myAvatar->getClearOverlayWhenMoving() && isMoving) {
|
||||
_flags |= SuppressedByMove;
|
||||
}
|
||||
}
|
||||
|
||||
if (_flags & SuppressedByHead) {
|
||||
if (isAtRest) {
|
||||
_flags &= ~SuppressedByHead;
|
||||
if (_suppressedByHead) {
|
||||
if (updateAvatarIsAtRest()) {
|
||||
_suppressedByHead = false;
|
||||
shouldRecenter = true;
|
||||
}
|
||||
} else {
|
||||
if (_hmdMode && headOutsideOverlay()) {
|
||||
_flags |= SuppressedByHead;
|
||||
_suppressedByHead = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool targetVisible = Menu::getInstance()->isOptionChecked(MenuOption::Overlays) && (0 == (_flags & SuppressMask));
|
||||
bool targetVisible = Menu::getInstance()->isOptionChecked(MenuOption::Overlays) && !_suppressedByHead;
|
||||
if (targetVisible != currentVisible) {
|
||||
offscreenUi->setPinned(!targetVisible);
|
||||
}
|
||||
if (shouldRecenter && !_flags) {
|
||||
if (shouldRecenter && !_suppressedByHead) {
|
||||
centerUI();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,13 +25,7 @@ private:
|
|||
bool headOutsideOverlay() const;
|
||||
bool updateAvatarIsAtRest();
|
||||
|
||||
enum SupressionFlags {
|
||||
SuppressedByMove = 0x01,
|
||||
SuppressedByHead = 0x02,
|
||||
SuppressMask = 0x03,
|
||||
};
|
||||
|
||||
uint8_t _flags { SuppressedByMove };
|
||||
bool _suppressedByHead { false };
|
||||
bool _hmdMode { false };
|
||||
|
||||
// used by updateAvatarIsAtRest
|
||||
|
|
|
@ -161,12 +161,6 @@ void setupPreferences() {
|
|||
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Use reticle cursor instead of arrow", getter, setter));
|
||||
}
|
||||
|
||||
{
|
||||
auto getter = [=]()->bool { return myAvatar->getClearOverlayWhenMoving(); };
|
||||
auto setter = [=](bool value) { myAvatar->setClearOverlayWhenMoving(value); };
|
||||
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Clear overlays when moving", getter, setter));
|
||||
}
|
||||
|
||||
static const QString VIEW_CATEGORY{ "View" };
|
||||
{
|
||||
auto getter = [=]()->float { return myAvatar->getRealWorldFieldOfView(); };
|
||||
|
|
|
@ -365,15 +365,23 @@ QFile* Snapshot::savedFileForSnapshot(QImage& shot,
|
|||
// DON'T append ".jpg" to the filename. QT will save the image in the format associated with the
|
||||
// filename's suffix.
|
||||
// If you want lossless Snapshots, supply a `.png` filename. Otherwise, use `.jpeg` or `.jpg`.
|
||||
// For PNGs, we use a "quality" of "50". The output image quality is the same as "100"
|
||||
// is the same as "0" -- the difference lies in the amount of compression applied to the PNG,
|
||||
// which slightly affects the time it takes to save the image.
|
||||
// Otherwise, ".jpg" is appended to the user's requested filename so that the image is saved in JPG format.
|
||||
// If the user hasn't supplied a specific filename for the snapshot:
|
||||
// Save the snapshot in JPG format according to FILENAME_PATH_FORMAT
|
||||
// Save the snapshot in JPG format at "100" quality according to FILENAME_PATH_FORMAT
|
||||
int imageQuality = 100;
|
||||
QString filename;
|
||||
if (!userSelectedFilename.isNull()) {
|
||||
QFileInfo snapshotFileInfo(userSelectedFilename);
|
||||
QString userSelectedFilenameSuffix = snapshotFileInfo.suffix();
|
||||
userSelectedFilenameSuffix = userSelectedFilenameSuffix.toLower();
|
||||
if (SUPPORTED_IMAGE_FORMATS.contains(userSelectedFilenameSuffix)) {
|
||||
filename = userSelectedFilename;
|
||||
if (userSelectedFilenameSuffix == "png") {
|
||||
imageQuality = 50;
|
||||
}
|
||||
} else {
|
||||
filename = userSelectedFilename + ".jpg";
|
||||
}
|
||||
|
@ -381,8 +389,6 @@ QFile* Snapshot::savedFileForSnapshot(QImage& shot,
|
|||
filename = FILENAME_PATH_FORMAT.arg(username, now.toString(DATETIME_FORMAT));
|
||||
}
|
||||
|
||||
const int IMAGE_QUALITY = 100;
|
||||
|
||||
if (!isTemporary) {
|
||||
// If user has requested specific path then use it, else use the application value
|
||||
QString snapshotFullPath;
|
||||
|
@ -432,7 +438,7 @@ QFile* Snapshot::savedFileForSnapshot(QImage& shot,
|
|||
imageFile = new QFile(snapshotFullPath);
|
||||
}
|
||||
|
||||
shot.save(imageFile, 0, IMAGE_QUALITY);
|
||||
shot.save(imageFile, 0, imageQuality);
|
||||
imageFile->close();
|
||||
|
||||
return imageFile;
|
||||
|
@ -447,7 +453,7 @@ QFile* Snapshot::savedFileForSnapshot(QImage& shot,
|
|||
}
|
||||
imageTempFile->setAutoRemove(isTemporary);
|
||||
|
||||
shot.save(imageTempFile, 0, IMAGE_QUALITY);
|
||||
shot.save(imageTempFile, 0, imageQuality);
|
||||
imageTempFile->close();
|
||||
|
||||
return imageTempFile;
|
||||
|
@ -487,7 +493,7 @@ void Snapshot::uploadSnapshot(const QString& filename, const QUrl& href) {
|
|||
multiPart->append(imagePart);
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
JSONCallbackParameters callbackParams(uploader, "uploadSuccess", uploader, "uploadFailure");
|
||||
JSONCallbackParameters callbackParams(uploader, "uploadSuccess", "uploadFailure");
|
||||
|
||||
accountManager->sendRequest(SNAPSHOT_UPLOAD_URL, AccountManagerAuth::Required, QNetworkAccessManager::PostOperation,
|
||||
callbackParams, nullptr, multiPart);
|
||||
|
|
|
@ -23,11 +23,11 @@ SnapshotUploader::SnapshotUploader(QUrl inWorldLocation, QString pathname) :
|
|||
_pathname(pathname) {
|
||||
}
|
||||
|
||||
void SnapshotUploader::uploadSuccess(QNetworkReply& reply) {
|
||||
void SnapshotUploader::uploadSuccess(QNetworkReply* reply) {
|
||||
const QString STORY_UPLOAD_URL = "/api/v1/user_stories";
|
||||
|
||||
// parse the reply for the thumbnail_url
|
||||
QByteArray contents = reply.readAll();
|
||||
QByteArray contents = reply->readAll();
|
||||
QJsonParseError jsonError;
|
||||
auto doc = QJsonDocument::fromJson(contents, &jsonError);
|
||||
if (jsonError.error == QJsonParseError::NoError) {
|
||||
|
@ -60,7 +60,7 @@ void SnapshotUploader::uploadSuccess(QNetworkReply& reply) {
|
|||
rootObject.insert("user_story", userStoryObject);
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
JSONCallbackParameters callbackParams(this, "createStorySuccess", this, "createStoryFailure");
|
||||
JSONCallbackParameters callbackParams(this, "createStorySuccess", "createStoryFailure");
|
||||
|
||||
accountManager->sendRequest(STORY_UPLOAD_URL,
|
||||
AccountManagerAuth::Required,
|
||||
|
@ -74,11 +74,11 @@ void SnapshotUploader::uploadSuccess(QNetworkReply& reply) {
|
|||
}
|
||||
}
|
||||
|
||||
void SnapshotUploader::uploadFailure(QNetworkReply& reply) {
|
||||
QString replyString = reply.readAll();
|
||||
qDebug() << "Error " << reply.errorString() << " uploading snapshot " << _pathname << " from " << _inWorldLocation;
|
||||
void SnapshotUploader::uploadFailure(QNetworkReply* reply) {
|
||||
QString replyString = reply->readAll();
|
||||
qDebug() << "Error " << reply->errorString() << " uploading snapshot " << _pathname << " from " << _inWorldLocation;
|
||||
if (replyString.size() == 0) {
|
||||
replyString = reply.errorString();
|
||||
replyString = reply->errorString();
|
||||
}
|
||||
replyString = replyString.left(1000); // Only print first 1000 characters of error
|
||||
qDebug() << "Snapshot upload reply error (truncated):" << replyString;
|
||||
|
@ -86,17 +86,17 @@ void SnapshotUploader::uploadFailure(QNetworkReply& reply) {
|
|||
this->deleteLater();
|
||||
}
|
||||
|
||||
void SnapshotUploader::createStorySuccess(QNetworkReply& reply) {
|
||||
QString replyString = reply.readAll();
|
||||
void SnapshotUploader::createStorySuccess(QNetworkReply* reply) {
|
||||
QString replyString = reply->readAll();
|
||||
emit DependencyManager::get<WindowScriptingInterface>()->snapshotShared(false, replyString);
|
||||
this->deleteLater();
|
||||
}
|
||||
|
||||
void SnapshotUploader::createStoryFailure(QNetworkReply& reply) {
|
||||
QString replyString = reply.readAll();
|
||||
qDebug() << "Error " << reply.errorString() << " uploading snapshot story " << _pathname << " from " << _inWorldLocation;
|
||||
void SnapshotUploader::createStoryFailure(QNetworkReply* reply) {
|
||||
QString replyString = reply->readAll();
|
||||
qDebug() << "Error " << reply->errorString() << " uploading snapshot story " << _pathname << " from " << _inWorldLocation;
|
||||
if (replyString.size() == 0) {
|
||||
replyString = reply.errorString();
|
||||
replyString = reply->errorString();
|
||||
}
|
||||
replyString = replyString.left(1000); // Only print first 1000 characters of error
|
||||
qDebug() << "Snapshot story upload reply error (truncated):" << replyString;
|
||||
|
|
|
@ -21,12 +21,12 @@ class SnapshotUploader : public QObject {
|
|||
public:
|
||||
SnapshotUploader(QUrl inWorldLocation, QString pathname);
|
||||
public slots:
|
||||
void uploadSuccess(QNetworkReply& reply);
|
||||
void uploadFailure(QNetworkReply& reply);
|
||||
void createStorySuccess(QNetworkReply& reply);
|
||||
void createStoryFailure(QNetworkReply& reply);
|
||||
void uploadSuccess(QNetworkReply* reply);
|
||||
void uploadFailure(QNetworkReply* reply);
|
||||
void createStorySuccess(QNetworkReply* reply);
|
||||
void createStoryFailure(QNetworkReply* reply);
|
||||
private:
|
||||
QUrl _inWorldLocation;
|
||||
QString _pathname;
|
||||
};
|
||||
#endif // hifi_SnapshotUploader_h
|
||||
#endif // hifi_SnapshotUploader_h
|
||||
|
|
|
@ -490,9 +490,9 @@ void Stats::updateStats(bool force) {
|
|||
};
|
||||
for (int32_t j = 0; j < categories.size(); ++j) {
|
||||
QString recordKey = "/idle/update/" + categories[j];
|
||||
itr = allRecords.find(recordKey);
|
||||
if (itr != allRecords.end()) {
|
||||
float dt = (float)itr.value().getMovingAverage() / (float)USECS_PER_MSEC;
|
||||
auto record = PerformanceTimer::getTimerRecord(recordKey);
|
||||
if (record.getCount()) {
|
||||
float dt = (float) record.getMovingAverage() / (float)USECS_PER_MSEC;
|
||||
QString message = QString("\n %1 = %2").arg(categories[j]).arg(dt);
|
||||
idleUpdateStats.push(SortableStat(message, dt));
|
||||
}
|
||||
|
|
|
@ -41,12 +41,16 @@ bool Billboardable::pointTransformAtCamera(Transform& transform, glm::quat offse
|
|||
glm::vec3 cameraPos = qApp->getCamera().getPosition();
|
||||
// use the referencial from the avatar, y isn't always up
|
||||
glm::vec3 avatarUP = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldOrientation()*Vectors::UP;
|
||||
|
||||
glm::quat rotation(conjugate(toQuat(glm::lookAt(cameraPos, billboardPos, avatarUP))));
|
||||
|
||||
transform.setRotation(rotation);
|
||||
transform.postRotate(offsetRotation);
|
||||
return true;
|
||||
// check to see if glm::lookAt will work / using glm::lookAt variable name
|
||||
glm::highp_vec3 s(glm::cross(billboardPos - cameraPos, avatarUP));
|
||||
|
||||
// make sure s is not NaN for any component
|
||||
if(glm::length2(s) > 0.0f) {
|
||||
glm::quat rotation(conjugate(toQuat(glm::lookAt(cameraPos, billboardPos, avatarUP))));
|
||||
transform.setRotation(rotation);
|
||||
transform.postRotate(offsetRotation);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -254,6 +254,7 @@ void Web3DOverlay::setupQmlSurface() {
|
|||
_webSurface->getSurfaceContext()->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Render", AbstractViewStateInterface::instance()->getRenderEngine()->getConfiguration().get());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Workload", qApp->getGameWorkload()._engine->getConfiguration().get());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Pointers", DependencyManager::get<PointerScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Web3DOverlay", this);
|
||||
|
|
82
interface/src/workload/GameWorkload.cpp
Normal file
82
interface/src/workload/GameWorkload.cpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
//
|
||||
// GameWorkload.cpp
|
||||
//
|
||||
// Created by Sam Gateau on 2/16/2018.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GameWorkload.h"
|
||||
#include "GameWorkloadRenderer.h"
|
||||
#include <ViewFrustum.h>
|
||||
#include <workload/RegionTracker.h>
|
||||
#include <workload/SpaceClassifier.h>
|
||||
|
||||
#include "PhysicsBoundary.h"
|
||||
|
||||
class WorkloadEngineBuilder {
|
||||
public:
|
||||
using Inputs = workload::VaryingSet2<workload::Views, workload::Timings>;
|
||||
using Outputs = workload::RegionTracker::Outputs;
|
||||
using JobModel = workload::Task::ModelIO<WorkloadEngineBuilder, Inputs, Outputs>;
|
||||
void build(JobModel& model, const workload::Varying& in, workload::Varying& out) {
|
||||
|
||||
const auto& inViews = in.getN<Inputs>(0);
|
||||
const auto& inTimings = in.getN<Inputs>(1);
|
||||
|
||||
const auto usedViews = model.addJob<workload::SetupViews>("setupViews", inViews);
|
||||
|
||||
const auto controlViewsIn = workload::ControlViews::Input(usedViews, inTimings).asVarying();
|
||||
const auto fixedViews = model.addJob<workload::ControlViews>("controlViews", controlViewsIn);
|
||||
|
||||
const auto regionTrackerOut = model.addJob<workload::SpaceClassifierTask>("spaceClassifier", fixedViews);
|
||||
|
||||
model.addJob<PhysicsBoundary>("PhysicsBoundary", regionTrackerOut);
|
||||
|
||||
model.addJob<GameSpaceToRender>("SpaceToRender");
|
||||
|
||||
out = regionTrackerOut;
|
||||
}
|
||||
};
|
||||
|
||||
GameWorkloadContext::GameWorkloadContext(const workload::SpacePointer& space,
|
||||
const render::ScenePointer& scene,
|
||||
const PhysicalEntitySimulationPointer& simulation): WorkloadContext(space),
|
||||
_scene(scene), _simulation(simulation)
|
||||
{
|
||||
}
|
||||
|
||||
GameWorkloadContext::~GameWorkloadContext() {
|
||||
}
|
||||
|
||||
|
||||
GameWorkload::GameWorkload() :
|
||||
_engine(std::make_shared<workload::Engine>(WorkloadEngineBuilder::JobModel::create("Workload"), std::shared_ptr<GameWorkloadContext>()))
|
||||
{
|
||||
}
|
||||
|
||||
GameWorkload::~GameWorkload() {
|
||||
shutdown();
|
||||
}
|
||||
|
||||
void GameWorkload::startup(const workload::SpacePointer& space,
|
||||
const render::ScenePointer& scene,
|
||||
const PhysicalEntitySimulationPointer& simulation) {
|
||||
_engine->reset(std::make_shared<GameWorkloadContext>(space, scene, simulation));
|
||||
}
|
||||
|
||||
void GameWorkload::shutdown() {
|
||||
_engine.reset();
|
||||
}
|
||||
|
||||
void GameWorkload::updateViews(const ViewFrustum& frustum, const glm::vec3& headPosition) {
|
||||
workload::Views views;
|
||||
views.emplace_back(workload::View::evalFromFrustum(frustum, headPosition - frustum.getPosition()));
|
||||
views.emplace_back(workload::View::evalFromFrustum(frustum));
|
||||
_engine->feedInput<WorkloadEngineBuilder::Inputs>(0, views);
|
||||
}
|
||||
|
||||
void GameWorkload::updateSimulationTimings(const workload::Timings& timings) {
|
||||
_engine->feedInput<WorkloadEngineBuilder::Inputs>(1, timings);
|
||||
}
|
45
interface/src/workload/GameWorkload.h
Normal file
45
interface/src/workload/GameWorkload.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// GameWorkload.h
|
||||
//
|
||||
// Created by Sam Gateau on 2/16/2018.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#ifndef hifi_GameWorkload_h
|
||||
#define hifi_GameWorkload_h
|
||||
|
||||
#include <workload/Space.h>
|
||||
#include <workload/Engine.h>
|
||||
|
||||
#include <render/Scene.h>
|
||||
#include "PhysicalEntitySimulation.h"
|
||||
|
||||
class GameWorkloadContext : public workload::WorkloadContext {
|
||||
public:
|
||||
GameWorkloadContext(const workload::SpacePointer& space,
|
||||
const render::ScenePointer& scene,
|
||||
const PhysicalEntitySimulationPointer& simulation);
|
||||
virtual ~GameWorkloadContext();
|
||||
|
||||
render::ScenePointer _scene;
|
||||
PhysicalEntitySimulationPointer _simulation;
|
||||
};
|
||||
|
||||
class GameWorkload {
|
||||
public:
|
||||
GameWorkload();
|
||||
~GameWorkload();
|
||||
|
||||
void startup(const workload::SpacePointer& space,
|
||||
const render::ScenePointer& scene,
|
||||
const PhysicalEntitySimulationPointer& simulation);
|
||||
void shutdown();
|
||||
|
||||
void updateViews(const ViewFrustum& frustum, const glm::vec3& headPosition);
|
||||
void updateSimulationTimings(const workload::Timings& timings);
|
||||
|
||||
workload::EnginePointer _engine;
|
||||
};
|
||||
#endif // hifi_GameWorkload_h
|
257
interface/src/workload/GameWorkloadRenderer.cpp
Normal file
257
interface/src/workload/GameWorkloadRenderer.cpp
Normal file
|
@ -0,0 +1,257 @@
|
|||
//
|
||||
// GameWorkloadRender.cpp
|
||||
//
|
||||
// Created by Sam Gateau on 2/20/2018.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GameWorkloadRenderer.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <gpu/Context.h>
|
||||
|
||||
#include <StencilMaskPass.h>
|
||||
#include <GeometryCache.h>
|
||||
|
||||
#include "render-utils/drawWorkloadProxy_vert.h"
|
||||
#include "render-utils/drawWorkloadView_vert.h"
|
||||
#include "render-utils/drawWorkloadProxy_frag.h"
|
||||
#include "render-utils/drawWorkloadView_frag.h"
|
||||
|
||||
|
||||
void GameSpaceToRender::configure(const Config& config) {
|
||||
_freezeViews = config.freezeViews;
|
||||
_showAllProxies = config.showProxies;
|
||||
_showAllViews = config.showViews;
|
||||
}
|
||||
|
||||
void GameSpaceToRender::run(const workload::WorkloadContextPointer& runContext, Outputs& outputs) {
|
||||
auto gameWorkloadContext = std::dynamic_pointer_cast<GameWorkloadContext>(runContext);
|
||||
if (!gameWorkloadContext) {
|
||||
return;
|
||||
}
|
||||
auto space = gameWorkloadContext->_space;
|
||||
if (!space) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto visible = _showAllProxies || _showAllViews;
|
||||
auto showProxies = _showAllProxies;
|
||||
auto showViews = _showAllViews;
|
||||
auto freezeViews = _freezeViews;
|
||||
|
||||
render::Transaction transaction;
|
||||
auto scene = gameWorkloadContext->_scene;
|
||||
|
||||
// Nothing really needed, early exit
|
||||
if (!visible) {
|
||||
if (render::Item::isValidID(_spaceRenderItemID)) {
|
||||
transaction.updateItem<GameWorkloadRenderItem>(_spaceRenderItemID, [](GameWorkloadRenderItem& item) {
|
||||
item.setVisible(false);
|
||||
});
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
workload::Proxy::Vector proxies(space->getNumAllocatedProxies());
|
||||
space->copyProxyValues(proxies.data(), (uint32_t)proxies.size());
|
||||
|
||||
workload::Views views(space->getNumViews());
|
||||
space->copyViews(views);
|
||||
|
||||
// Valid space, let's display its content
|
||||
if (!render::Item::isValidID(_spaceRenderItemID)) {
|
||||
_spaceRenderItemID = scene->allocateID();
|
||||
auto renderItem = std::make_shared<GameWorkloadRenderItem>();
|
||||
renderItem->editBound().setBox(glm::vec3(-16000.0f), 32000.0f);
|
||||
renderItem->setAllProxies(proxies);
|
||||
transaction.resetItem(_spaceRenderItemID, std::make_shared<GameWorkloadRenderItem::Payload>(renderItem));
|
||||
}
|
||||
|
||||
transaction.updateItem<GameWorkloadRenderItem>(_spaceRenderItemID, [visible, showProxies, proxies, freezeViews, showViews, views](GameWorkloadRenderItem& item) {
|
||||
item.setVisible(visible);
|
||||
item.showProxies(showProxies);
|
||||
item.setAllProxies(proxies);
|
||||
item.showViews(showViews);
|
||||
item.setAllViews(views);
|
||||
});
|
||||
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const GameWorkloadRenderItem::Pointer& payload) {
|
||||
return payload->getKey();
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const GameWorkloadRenderItem::Pointer& payload) {
|
||||
if (payload) {
|
||||
return payload->getBound();
|
||||
}
|
||||
return Item::Bound();
|
||||
}
|
||||
template <> void payloadRender(const GameWorkloadRenderItem::Pointer& payload, RenderArgs* args) {
|
||||
if (payload) {
|
||||
payload->render(args);
|
||||
}
|
||||
}
|
||||
template <> const ShapeKey shapeGetShapeKey(const GameWorkloadRenderItem::Pointer& payload) {
|
||||
return ShapeKey::Builder::ownPipeline();
|
||||
}
|
||||
}
|
||||
|
||||
GameWorkloadRenderItem::GameWorkloadRenderItem() : _key(render::ItemKey::Builder::opaqueShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1)) {
|
||||
}
|
||||
|
||||
render::ItemKey GameWorkloadRenderItem::getKey() const {
|
||||
return _key;
|
||||
}
|
||||
|
||||
void GameWorkloadRenderItem::setVisible(bool isVisible) {
|
||||
if (isVisible) {
|
||||
_key = render::ItemKey::Builder(_key).withVisible();
|
||||
} else {
|
||||
_key = render::ItemKey::Builder(_key).withInvisible();
|
||||
}
|
||||
}
|
||||
|
||||
void GameWorkloadRenderItem::showProxies(bool show) {
|
||||
_showProxies = show;
|
||||
}
|
||||
|
||||
void GameWorkloadRenderItem::showViews(bool show) {
|
||||
_showViews = show;
|
||||
}
|
||||
|
||||
|
||||
void GameWorkloadRenderItem::setAllProxies(const workload::Proxy::Vector& proxies) {
|
||||
_myOwnProxies = proxies;
|
||||
static const uint32_t sizeOfProxy = sizeof(workload::Proxy);
|
||||
if (!_allProxiesBuffer) {
|
||||
_allProxiesBuffer = std::make_shared<gpu::Buffer>(sizeOfProxy);
|
||||
}
|
||||
|
||||
_allProxiesBuffer->setData(proxies.size() * sizeOfProxy, (const gpu::Byte*) proxies.data());
|
||||
_numAllProxies = (uint32_t) proxies.size();
|
||||
}
|
||||
|
||||
void GameWorkloadRenderItem::setAllViews(const workload::Views& views) {
|
||||
_myOwnViews = views;
|
||||
static const uint32_t sizeOfView = sizeof(workload::View);
|
||||
if (!_allViewsBuffer) {
|
||||
_allViewsBuffer = std::make_shared<gpu::Buffer>(sizeOfView);
|
||||
}
|
||||
|
||||
_allViewsBuffer->setData(views.size() * sizeOfView, (const gpu::Byte*) views.data());
|
||||
_numAllViews = (uint32_t)views.size();
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer GameWorkloadRenderItem::getProxiesPipeline() {
|
||||
if (!_drawAllProxiesPipeline) {
|
||||
auto vs = drawWorkloadProxy_vert::getShader();
|
||||
auto ps = drawWorkloadProxy_frag::getShader();
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding("workloadProxiesBuffer", 0));
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
/* state->setBlendFunction(true,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO);*/
|
||||
|
||||
PrepareStencil::testMaskDrawShape(*state);
|
||||
state->setCullMode(gpu::State::CULL_NONE);
|
||||
_drawAllProxiesPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
return _drawAllProxiesPipeline;
|
||||
}
|
||||
|
||||
|
||||
const gpu::PipelinePointer GameWorkloadRenderItem::getViewsPipeline() {
|
||||
if (!_drawAllViewsPipeline) {
|
||||
auto vs = drawWorkloadView_vert::getShader();
|
||||
auto ps = drawWorkloadView_frag::getShader();
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding("workloadViewsBuffer", 1));
|
||||
slotBindings.insert(gpu::Shader::Binding("drawMeshBuffer", 0));
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
/* state->setBlendFunction(true,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO);*/
|
||||
|
||||
PrepareStencil::testMaskDrawShape(*state);
|
||||
state->setCullMode(gpu::State::CULL_NONE);
|
||||
_drawAllViewsPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
return _drawAllViewsPipeline;
|
||||
}
|
||||
|
||||
const gpu::BufferPointer GameWorkloadRenderItem::getDrawViewBuffer() {
|
||||
if (!_drawViewBuffer) {
|
||||
int numSegments = 64;
|
||||
float angleStep = (float)M_PI * 2.0f / (float)numSegments;
|
||||
|
||||
struct Vert {
|
||||
glm::vec4 p;
|
||||
};
|
||||
std::vector<Vert> verts(numSegments + 1);
|
||||
for (int i = 0; i < numSegments; i++) {
|
||||
float angle = (float)i * angleStep;
|
||||
verts[i].p.x = cos(angle);
|
||||
verts[i].p.y = sin(angle);
|
||||
verts[i].p.z = angle;
|
||||
verts[i].p.w = 1.0f;
|
||||
}
|
||||
verts[numSegments] = verts[0];
|
||||
verts[numSegments].p.w = 0.0f;
|
||||
|
||||
_drawViewBuffer = std::make_shared<gpu::Buffer>(verts.size() * sizeof(Vert), (const gpu::Byte*) verts.data());
|
||||
_numDrawViewVerts = numSegments + 1;
|
||||
}
|
||||
return _drawViewBuffer;
|
||||
}
|
||||
|
||||
void GameWorkloadRenderItem::render(RenderArgs* args) {
|
||||
gpu::Batch& batch = *(args->_batch);
|
||||
|
||||
batch.setModelTransform(Transform());
|
||||
|
||||
batch.setResourceBuffer(0, _allProxiesBuffer);
|
||||
batch.setResourceBuffer(1, _allViewsBuffer);
|
||||
|
||||
// Show Proxies
|
||||
if (_showProxies) {
|
||||
batch.setPipeline(getProxiesPipeline());
|
||||
|
||||
static const int NUM_VERTICES_PER_PROXY = 3;
|
||||
batch.draw(gpu::TRIANGLES, NUM_VERTICES_PER_PROXY * _numAllProxies, 0);
|
||||
}
|
||||
|
||||
// Show Views
|
||||
if (_showViews) {
|
||||
batch.setPipeline(getViewsPipeline());
|
||||
|
||||
batch.setUniformBuffer(0, getDrawViewBuffer());
|
||||
static const int NUM_VERTICES_PER_DRAWVIEWVERT = 2;
|
||||
static const int NUM_REGIONS = 3;
|
||||
batch.draw(gpu::TRIANGLE_STRIP, NUM_REGIONS * NUM_VERTICES_PER_DRAWVIEWVERT * _numDrawViewVerts * _numAllViews, 0);
|
||||
|
||||
}
|
||||
|
||||
batch.setResourceBuffer(0, nullptr);
|
||||
batch.setResourceBuffer(1, nullptr);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
104
interface/src/workload/GameWorkloadRenderer.h
Normal file
104
interface/src/workload/GameWorkloadRenderer.h
Normal file
|
@ -0,0 +1,104 @@
|
|||
//
|
||||
// GameWorkloadRender.h
|
||||
//
|
||||
// Created by Sam Gateau on 2/20/2018.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#ifndef hifi_GameWorkloadRenderer_h
|
||||
#define hifi_GameWorkloadRenderer_h
|
||||
|
||||
#include "GameWorkload.h"
|
||||
|
||||
class GameSpaceToRenderConfig : public workload::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool freezeViews MEMBER freezeViews NOTIFY dirty)
|
||||
Q_PROPERTY(bool showProxies MEMBER showProxies NOTIFY dirty)
|
||||
Q_PROPERTY(bool showViews MEMBER showViews NOTIFY dirty)
|
||||
public:
|
||||
|
||||
bool freezeViews{ false };
|
||||
bool showProxies{ false };
|
||||
bool showViews{ false };
|
||||
signals:
|
||||
void dirty();
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
class GameSpaceToRender {
|
||||
public:
|
||||
using Config = GameSpaceToRenderConfig;
|
||||
using Outputs = render::Transaction;
|
||||
using JobModel = workload::Job::ModelO<GameSpaceToRender, Outputs, Config>;
|
||||
|
||||
GameSpaceToRender() {}
|
||||
|
||||
void configure(const Config& config);
|
||||
void run(const workload::WorkloadContextPointer& renderContext, Outputs& outputs);
|
||||
|
||||
protected:
|
||||
render::ItemID _spaceRenderItemID{ render::Item::INVALID_ITEM_ID };
|
||||
bool _freezeViews{ false };
|
||||
bool _showAllProxies{ false };
|
||||
bool _showAllViews{ false };
|
||||
};
|
||||
|
||||
|
||||
class GameWorkloadRenderItem {
|
||||
public:
|
||||
using Payload = render::Payload<GameWorkloadRenderItem>;
|
||||
using Pointer = Payload::DataPointer;
|
||||
|
||||
GameWorkloadRenderItem();
|
||||
~GameWorkloadRenderItem() {}
|
||||
void render(RenderArgs* args);
|
||||
|
||||
render::Item::Bound& editBound() { return _bound; }
|
||||
const render::Item::Bound& getBound() { return _bound; }
|
||||
|
||||
void setVisible(bool visible);
|
||||
void showProxies(bool show);
|
||||
void showViews(bool show);
|
||||
|
||||
void setAllProxies(const workload::Proxy::Vector& proxies);
|
||||
void setAllViews(const workload::Views& views);
|
||||
|
||||
render::ItemKey getKey() const;
|
||||
|
||||
protected:
|
||||
render::Item::Bound _bound;
|
||||
|
||||
workload::Proxy::Vector _myOwnProxies;
|
||||
gpu::BufferPointer _allProxiesBuffer;
|
||||
uint32_t _numAllProxies{ 0 };
|
||||
|
||||
workload::Views _myOwnViews;
|
||||
gpu::BufferPointer _allViewsBuffer;
|
||||
uint32_t _numAllViews{ 0 };
|
||||
|
||||
gpu::PipelinePointer _drawAllProxiesPipeline;
|
||||
const gpu::PipelinePointer getProxiesPipeline();
|
||||
|
||||
gpu::PipelinePointer _drawAllViewsPipeline;
|
||||
const gpu::PipelinePointer getViewsPipeline();
|
||||
|
||||
uint32_t _numDrawViewVerts{ 0 };
|
||||
gpu::BufferPointer _drawViewBuffer;
|
||||
const gpu::BufferPointer getDrawViewBuffer();
|
||||
|
||||
render::ItemKey _key;
|
||||
bool _showProxies{ true };
|
||||
bool _showViews{ true };
|
||||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const GameWorkloadRenderItem::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const GameWorkloadRenderItem::Pointer& payload);
|
||||
template <> void payloadRender(const GameWorkloadRenderItem::Pointer& payload, RenderArgs* args);
|
||||
template <> const ShapeKey shapeGetShapeKey(const GameWorkloadRenderItem::Pointer& payload);
|
||||
}
|
||||
|
||||
#endif
|
33
interface/src/workload/PhysicsBoundary.cpp
Normal file
33
interface/src/workload/PhysicsBoundary.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// PhysicsBoundary.h
|
||||
//
|
||||
// Created by Andrew Meadows 2018.04.05
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "PhysicsBoundary.h"
|
||||
|
||||
#include <PhysicsLogging.h>
|
||||
#include <workload/Space.h>
|
||||
|
||||
#include "workload/GameWorkload.h"
|
||||
|
||||
void PhysicsBoundary::run(const workload::WorkloadContextPointer& context, const Inputs& inputs) {
|
||||
auto space = context->_space;
|
||||
if (!space) {
|
||||
return;
|
||||
}
|
||||
GameWorkloadContext* gameContext = static_cast<GameWorkloadContext*>(context.get());
|
||||
PhysicalEntitySimulationPointer simulation = gameContext->_simulation;
|
||||
const auto& regionChanges = inputs.get0();
|
||||
for (uint32_t i = 0; i < (uint32_t)regionChanges.size(); ++i) {
|
||||
const workload::Space::Change& change = regionChanges[i];
|
||||
auto entity = space->getOwner(change.proxyId).get<EntityItemPointer>();
|
||||
if (entity) {
|
||||
simulation->changeEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
31
interface/src/workload/PhysicsBoundary.h
Normal file
31
interface/src/workload/PhysicsBoundary.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// PhysicsBoundary.h
|
||||
//
|
||||
// Created by Andrew Meadows 2018.04.05
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#ifndef hifi_PhysicsGatekeeper_h
|
||||
#define hifi_PhysicsGatekeeper_h
|
||||
|
||||
#include <EntityItem.h>
|
||||
#include <workload/Engine.h>
|
||||
#include <workload/RegionTracker.h>
|
||||
|
||||
#include "PhysicalEntitySimulation.h"
|
||||
|
||||
class PhysicsBoundary {
|
||||
public:
|
||||
using Config = workload::Job::Config;
|
||||
using Inputs = workload::RegionTracker::Outputs;
|
||||
using Outputs = bool;
|
||||
using JobModel = workload::Job::ModelI<PhysicsBoundary, Inputs, Config>; // this doesn't work
|
||||
|
||||
PhysicsBoundary() {}
|
||||
void configure(const Config& config) { }
|
||||
void run(const workload::WorkloadContextPointer& context, const Inputs& inputs);
|
||||
};
|
||||
|
||||
#endif // hifi_PhysicsGatekeeper_h
|
|
@ -1426,6 +1426,8 @@ bool AudioClient::setIsStereoInput(bool isStereoInput) {
|
|||
|
||||
// restart the input device
|
||||
switchInputToAudioDevice(_inputDeviceInfo);
|
||||
|
||||
emit isStereoInputChanged(_isStereoInput);
|
||||
}
|
||||
|
||||
return stereoInputChanged;
|
||||
|
@ -1463,6 +1465,8 @@ void AudioClient::outputFormatChanged() {
|
|||
}
|
||||
|
||||
bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo inputDeviceInfo, bool isShutdownRequest) {
|
||||
Q_ASSERT_X(QThread::currentThread() == thread(), Q_FUNC_INFO, "Function invoked on wrong thread");
|
||||
|
||||
qCDebug(audioclient) << __FUNCTION__ << "inputDeviceInfo: [" << inputDeviceInfo.deviceName() << "]";
|
||||
bool supportedFormat = false;
|
||||
|
||||
|
@ -1663,6 +1667,8 @@ void AudioClient::outputNotify() {
|
|||
}
|
||||
|
||||
bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceInfo, bool isShutdownRequest) {
|
||||
Q_ASSERT_X(QThread::currentThread() == thread(), Q_FUNC_INFO, "Function invoked on wrong thread");
|
||||
|
||||
qCDebug(audioclient) << "AudioClient::switchOutputToAudioDevice() outputDeviceInfo: [" << outputDeviceInfo.deviceName() << "]";
|
||||
bool supportedFormat = false;
|
||||
|
||||
|
@ -2021,7 +2027,7 @@ void AudioClient::setAvatarBoundingBoxParameters(glm::vec3 corner, glm::vec3 sca
|
|||
|
||||
|
||||
void AudioClient::startThread() {
|
||||
moveToNewNamedThread(this, "Audio Thread", [this] { start(); });
|
||||
moveToNewNamedThread(this, "Audio Thread", [this] { start(); }, QThread::TimeCriticalPriority);
|
||||
}
|
||||
|
||||
void AudioClient::setInputVolume(float volume, bool emitSignal) {
|
||||
|
|
|
@ -44,6 +44,9 @@ public slots:
|
|||
virtual bool setIsStereoInput(bool stereo) = 0;
|
||||
|
||||
virtual bool isStereoInput() = 0;
|
||||
|
||||
signals:
|
||||
void isStereoInputChanged(bool isStereo);
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(AbstractAudioInterface*)
|
||||
|
|
|
@ -14,6 +14,7 @@ include_hifi_library_headers(audio)
|
|||
include_hifi_library_headers(entities)
|
||||
include_hifi_library_headers(octree)
|
||||
include_hifi_library_headers(task)
|
||||
include_hifi_library_headers(workload)
|
||||
include_hifi_library_headers(graphics-scripting) # for ScriptableModel.h
|
||||
|
||||
target_bullet()
|
||||
|
|
|
@ -49,6 +49,9 @@ const float DISPLAYNAME_FADE_FACTOR = pow(0.01f, 1.0f / DISPLAYNAME_FADE_TIME);
|
|||
const float DISPLAYNAME_ALPHA = 1.0f;
|
||||
const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f;
|
||||
const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
|
||||
const float Avatar::MYAVATAR_LOADING_PRIORITY = (float)M_PI; // Entity priority is computed as atan2(maxDim, distance) which is <= PI / 2
|
||||
const float Avatar::OTHERAVATAR_LOADING_PRIORITY = MYAVATAR_LOADING_PRIORITY - EPSILON;
|
||||
const float Avatar::ATTACHMENT_LOADING_PRIORITY = OTHERAVATAR_LOADING_PRIORITY - EPSILON;
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
|
||||
|
@ -304,7 +307,6 @@ void Avatar::updateAvatarEntities() {
|
|||
// NOTE: if this avatar entity is not attached to us, strip its entity script completely...
|
||||
auto attachedScript = properties.getScript();
|
||||
if (!isMyAvatar() && !attachedScript.isEmpty()) {
|
||||
qCDebug(avatars_renderer) << "removing entity script from avatar attached entity:" << entityID << "old script:" << attachedScript;
|
||||
QString noScript;
|
||||
properties.setScript(noScript);
|
||||
}
|
||||
|
@ -551,10 +553,17 @@ void Avatar::measureMotionDerivatives(float deltaTime) {
|
|||
|
||||
// angular
|
||||
glm::quat orientation = getWorldOrientation();
|
||||
glm::quat delta = glm::inverse(_lastOrientation) * orientation;
|
||||
glm::vec3 angularVelocity = glm::axis(delta) * glm::angle(delta) * invDeltaTime;
|
||||
setWorldAngularVelocity(angularVelocity);
|
||||
_lastOrientation = getWorldOrientation();
|
||||
float changeDot = glm::abs(glm::dot(orientation, _lastOrientation));
|
||||
float CHANGE_DOT_THRESHOLD = 0.9999f;
|
||||
if (changeDot < CHANGE_DOT_THRESHOLD) {
|
||||
float angle = 2.0f * acosf(changeDot);
|
||||
glm::quat delta = glm::inverse(_lastOrientation) * orientation;
|
||||
glm::vec3 angularVelocity = (angle * invDeltaTime) * glm::axis(delta);
|
||||
setWorldAngularVelocity(angularVelocity);
|
||||
_lastOrientation = orientation;
|
||||
} else {
|
||||
setWorldAngularVelocity(glm::vec3(0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
enum TextRendererType {
|
||||
|
@ -1418,6 +1427,7 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
|||
if (_attachmentModels[i]->getURL() != attachmentData[i].modelURL) {
|
||||
_attachmentModelsTexturesLoaded[i] = false;
|
||||
}
|
||||
_attachmentModels[i]->setLoadingPriority(ATTACHMENT_LOADING_PRIORITY);
|
||||
_attachmentModels[i]->setURL(attachmentData[i].modelURL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -540,6 +540,10 @@ protected:
|
|||
AABox _renderBound;
|
||||
bool _isMeshVisible{ true };
|
||||
bool _needMeshVisibleSwitch{ true };
|
||||
|
||||
static const float MYAVATAR_LOADING_PRIORITY;
|
||||
static const float OTHERAVATAR_LOADING_PRIORITY;
|
||||
static const float ATTACHMENT_LOADING_PRIORITY;
|
||||
};
|
||||
|
||||
#endif // hifi_Avatar_h
|
||||
|
|
|
@ -12,6 +12,7 @@ OtherAvatar::OtherAvatar(QThread* thread) : Avatar(thread) {
|
|||
// give the pointer to our head to inherited _headData variable from AvatarData
|
||||
_headData = new Head(this);
|
||||
_skeletonModel = std::make_shared<SkeletonModel>(this, nullptr);
|
||||
_skeletonModel->setLoadingPriority(OTHERAVATAR_LOADING_PRIORITY);
|
||||
connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished);
|
||||
connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady);
|
||||
connect(_skeletonModel.get(), &Model::rigReset, this, &Avatar::rigReset);
|
||||
|
|
|
@ -2400,8 +2400,8 @@ QVariant AttachmentData::toVariant() const {
|
|||
QVariantMap result;
|
||||
result["modelUrl"] = modelURL;
|
||||
result["jointName"] = jointName;
|
||||
result["translation"] = glmToQMap(translation);
|
||||
result["rotation"] = glmToQMap(glm::degrees(safeEulerAngles(rotation)));
|
||||
result["translation"] = vec3ToQMap(translation);
|
||||
result["rotation"] = vec3ToQMap(glm::degrees(safeEulerAngles(rotation)));
|
||||
result["scale"] = scale;
|
||||
result["soft"] = isSoft;
|
||||
return result;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
set(TARGET_NAME entities-renderer)
|
||||
AUTOSCRIBE_SHADER_LIB(gpu graphics procedural render render-utils)
|
||||
setup_hifi_library(Network Script)
|
||||
link_hifi_libraries(shared gpu procedural graphics model-networking script-engine render render-utils image qml ui pointers)
|
||||
link_hifi_libraries(shared workload gpu procedural graphics model-networking script-engine render render-utils image qml ui pointers)
|
||||
include_hifi_library_headers(networking)
|
||||
include_hifi_library_headers(gl)
|
||||
include_hifi_library_headers(ktx)
|
||||
|
|
|
@ -206,6 +206,7 @@ void EntityTreeRenderer::clear() {
|
|||
}
|
||||
|
||||
// remove all entities from the scene
|
||||
_space->clear();
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
if (scene) {
|
||||
render::Transaction transaction;
|
||||
|
@ -290,6 +291,16 @@ void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, r
|
|||
if (!entity->isParentPathComplete()) {
|
||||
continue;
|
||||
}
|
||||
if (entity->getSpaceIndex() == -1) {
|
||||
std::unique_lock<std::mutex> lock(_spaceLock);
|
||||
auto spaceIndex = _space->allocateID();
|
||||
workload::Sphere sphere(entity->getWorldPosition(), entity->getBoundingRadius());
|
||||
workload::Transaction transaction;
|
||||
transaction.reset(spaceIndex, sphere, workload::Owner(entity));
|
||||
_space->enqueueTransaction(transaction);
|
||||
entity->setSpaceIndex(spaceIndex);
|
||||
connect(entity.get(), &EntityItem::spaceUpdate, this, &EntityTreeRenderer::handleSpaceUpdate, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
auto entityID = entity->getEntityItemID();
|
||||
processedIds.insert(entityID);
|
||||
|
@ -299,7 +310,6 @@ void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, r
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (!processedIds.empty()) {
|
||||
for (const auto& processedId : processedIds) {
|
||||
_entitiesToAdd.erase(processedId);
|
||||
|
@ -394,7 +404,6 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
|
|||
uint64_t expiry = updateStart + timeBudget;
|
||||
|
||||
// process the sorted renderables
|
||||
std::unordered_map<EntityItemID, EntityRendererPointer>::iterator itr;
|
||||
size_t numSorted = sortedRenderables.size();
|
||||
while (!sortedRenderables.empty() && usecTimestampNow() < expiry) {
|
||||
const auto renderable = sortedRenderables.top().getRenderer();
|
||||
|
@ -419,10 +428,12 @@ void EntityTreeRenderer::update(bool simulate) {
|
|||
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
|
||||
|
||||
// here we update _currentFrame and _lastAnimated and sync with the server properties.
|
||||
tree->update(simulate);
|
||||
|
||||
// Update the rendereable entities as needed
|
||||
{
|
||||
PerformanceTimer perfTimer("tree::update");
|
||||
tree->update(simulate);
|
||||
}
|
||||
|
||||
{ // Update the rendereable entities as needed
|
||||
PROFILE_RANGE(simulation_physics, "Scene");
|
||||
PerformanceTimer sceneTimer("scene");
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
|
@ -434,6 +445,24 @@ void EntityTreeRenderer::update(bool simulate) {
|
|||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
}
|
||||
{
|
||||
PerformanceTimer perfTimer("workload::transaction");
|
||||
workload::Transaction spaceTransaction;
|
||||
{ // update proxies in the workload::Space
|
||||
std::unique_lock<std::mutex> lock(_spaceLock);
|
||||
spaceTransaction.update(_spaceUpdates);
|
||||
_spaceUpdates.clear();
|
||||
}
|
||||
{
|
||||
std::vector<int32_t> staleProxies;
|
||||
tree->swapStaleProxies(staleProxies);
|
||||
spaceTransaction.remove(staleProxies);
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_spaceLock);
|
||||
_space->enqueueTransaction(spaceTransaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (simulate) {
|
||||
// Handle enter/leave entity logic
|
||||
|
@ -450,6 +479,11 @@ void EntityTreeRenderer::update(bool simulate) {
|
|||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::handleSpaceUpdate(std::pair<int32_t, glm::vec4> proxyUpdate) {
|
||||
std::unique_lock<std::mutex> lock(_spaceLock);
|
||||
_spaceUpdates.emplace_back(proxyUpdate.first, proxyUpdate.second);
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar) {
|
||||
bool didUpdate = false;
|
||||
float radius = 0.01f; // for now, assume 0.01 meter radius, because we actually check the point inside later
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <TextureCache.h>
|
||||
#include <OctreeProcessor.h>
|
||||
#include <render/Forward.h>
|
||||
#include <workload/Space.h>
|
||||
|
||||
class AbstractScriptingServicesInterface;
|
||||
class AbstractViewStateInterface;
|
||||
|
@ -116,6 +117,9 @@ public:
|
|||
EntityItemPointer getEntity(const EntityItemID& id);
|
||||
void onEntityChanged(const EntityItemID& id);
|
||||
|
||||
// Access the workload Space
|
||||
workload::SpacePointer getWorkloadSpace() const { return _space; }
|
||||
|
||||
signals:
|
||||
void enterEntity(const EntityItemID& entityItemID);
|
||||
void leaveEntity(const EntityItemID& entityItemID);
|
||||
|
@ -135,6 +139,8 @@ public slots:
|
|||
EntityRendererPointer renderableForEntityId(const EntityItemID& id) const;
|
||||
render::ItemID renderableIdForEntityId(const EntityItemID& id) const;
|
||||
|
||||
void handleSpaceUpdate(std::pair<int32_t, glm::vec4> proxyUpdate);
|
||||
|
||||
protected:
|
||||
virtual OctreePointer createTree() override {
|
||||
EntityTreePointer newTree = EntityTreePointer(new EntityTree(true));
|
||||
|
@ -255,6 +261,10 @@ private:
|
|||
static int _entitiesScriptEngineCount;
|
||||
static CalculateEntityLoadingPriority _calculateEntityLoadingPriorityFunc;
|
||||
static std::function<bool()> _entitiesShouldFadeFunction;
|
||||
|
||||
mutable std::mutex _spaceLock;
|
||||
workload::SpacePointer _space{ new workload::Space() };
|
||||
workload::Transaction::Updates _spaceUpdates;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -284,8 +284,8 @@ bool EntityRenderer::addToScene(const ScenePointer& scene, Transaction& transact
|
|||
makeStatusGetters(_entity, statusGetters);
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
transaction.resetItem(_renderItemID, renderPayload);
|
||||
updateInScene(scene, transaction);
|
||||
onAddToScene(_entity);
|
||||
updateInScene(scene, transaction);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -363,6 +363,14 @@ bool EntityRenderer::needsRenderUpdateFromEntity(const EntityItemPointer& entity
|
|||
return false;
|
||||
}
|
||||
|
||||
void EntityRenderer::updateModelTransform() {
|
||||
bool success = false;
|
||||
auto newModelTransform = _entity->getTransformToCenter(success);
|
||||
if (success) {
|
||||
_modelTransform = newModelTransform;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) {
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
|
||||
withWriteLock([&] {
|
||||
|
@ -419,4 +427,4 @@ void EntityRenderer::addMaterial(graphics::MaterialLayer material, const std::st
|
|||
void EntityRenderer::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||
_materials[parentMaterialName].remove(material);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,6 +97,7 @@ protected:
|
|||
virtual void doRender(RenderArgs* args) = 0;
|
||||
|
||||
bool isFading() const { return _isFading; }
|
||||
void updateModelTransform();
|
||||
virtual bool isTransparent() const { return _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) < 1.0f : false; }
|
||||
inline bool isValidRenderItem() const { return _renderItemID != Item::INVALID_ITEM_ID; }
|
||||
|
||||
|
@ -140,6 +141,7 @@ protected:
|
|||
bool _needsRenderUpdate { false };
|
||||
// Only touched on the rendering thread
|
||||
bool _renderUpdateQueued{ false };
|
||||
Transform _renderTransform;
|
||||
|
||||
std::unordered_map<std::string, graphics::MultiMaterial> _materials;
|
||||
std::mutex _materialsLock;
|
||||
|
|
|
@ -35,7 +35,6 @@ private:
|
|||
glm::vec2 _materialMappingPos;
|
||||
glm::vec2 _materialMappingScale;
|
||||
float _materialMappingRot;
|
||||
Transform _renderTransform;
|
||||
|
||||
std::shared_ptr<NetworkMaterial> _drawMaterial;
|
||||
};
|
||||
|
|
|
@ -188,7 +188,7 @@ bool RenderableModelEntityItem::needsUpdateModelBounds() const {
|
|||
}
|
||||
}
|
||||
|
||||
return model->needsReload();
|
||||
return false;
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::updateModelBounds() {
|
||||
|
@ -279,18 +279,16 @@ EntityItemProperties RenderableModelEntityItem::getProperties(EntityPropertyFlag
|
|||
}
|
||||
|
||||
bool RenderableModelEntityItem::supportsDetailedRayIntersection() const {
|
||||
return isModelLoaded();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
auto model = getModel();
|
||||
if (!model) {
|
||||
return true;
|
||||
if (!model || !isModelLoaded()) {
|
||||
return false;
|
||||
}
|
||||
// qCDebug(entitiesrenderer) << "RenderableModelEntityItem::findDetailedRayIntersection() precisionPicking:"
|
||||
// << precisionPicking;
|
||||
|
||||
return model->findRayIntersectionAgainstSubMeshes(origin, direction, distance,
|
||||
face, surfaceNormal, extraInfo, precisionPicking, false);
|
||||
|
@ -1176,19 +1174,8 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
|||
}
|
||||
|
||||
bool ModelEntityRenderer::needsRenderUpdate() const {
|
||||
ModelPointer model;
|
||||
withReadLock([&] {
|
||||
model = _model;
|
||||
});
|
||||
|
||||
if (model) {
|
||||
if (_needsJointSimulation || _moving || _animating) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// When the individual mesh parts of a model finish fading, they will mark their Model as needing updating
|
||||
// we will watch for that and ask the model to update it's render items
|
||||
if (_parsedModelURL != model->getURL()) {
|
||||
if (resultWithReadLock<bool>([&] {
|
||||
if (_moving || _animating) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1196,16 +1183,37 @@ bool ModelEntityRenderer::needsRenderUpdate() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!_prevModelLoaded) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
})) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ModelPointer model;
|
||||
QUrl parsedModelURL;
|
||||
withReadLock([&] {
|
||||
model = _model;
|
||||
parsedModelURL = _parsedModelURL;
|
||||
});
|
||||
|
||||
if (model) {
|
||||
// When the individual mesh parts of a model finish fading, they will mark their Model as needing updating
|
||||
// we will watch for that and ask the model to update it's render items
|
||||
if (parsedModelURL != model->getURL()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (model->needsReload()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME what is the difference between these two?
|
||||
if (model->needsFixupInScene()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME what is the difference between these two? ^^^^
|
||||
if (model->getRenderItemsNeedUpdate()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1219,7 +1227,7 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
|
|||
return true;
|
||||
}
|
||||
|
||||
if (_lastModelURL != entity->getModelURL()) {
|
||||
if (_parsedModelURL != entity->getModelURL()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1232,10 +1240,6 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
|
|||
return true;
|
||||
}
|
||||
|
||||
if (_renderAnimationProperties != entity->getAnimationProperties()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_animating != entity->isAnimatingSomething()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1249,7 +1253,7 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
|
|||
});
|
||||
|
||||
if (model && model->isLoaded()) {
|
||||
if (!entity->_dimensionsInitialized || entity->_needsInitialSimulation) {
|
||||
if (!entity->_dimensionsInitialized || entity->_needsInitialSimulation || !entity->_originalTexturesRead) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1281,16 +1285,15 @@ void ModelEntityRenderer::setCollisionMeshKey(const void*key) {
|
|||
void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
|
||||
if (_hasModel != entity->hasModel()) {
|
||||
_hasModel = entity->hasModel();
|
||||
withWriteLock([&] {
|
||||
_hasModel = entity->hasModel();
|
||||
});
|
||||
}
|
||||
|
||||
_marketplaceEntity = entity->getMarketplaceID().length() != 0;
|
||||
_animating = entity->isAnimatingSomething();
|
||||
|
||||
withWriteLock([&] {
|
||||
if (_lastModelURL != entity->getModelURL()) {
|
||||
_lastModelURL = entity->getModelURL();
|
||||
_parsedModelURL = QUrl(_lastModelURL);
|
||||
_animating = entity->isAnimatingSomething();
|
||||
if (_parsedModelURL != entity->getModelURL()) {
|
||||
_parsedModelURL = QUrl(entity->getModelURL());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1298,7 +1301,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
ModelPointer model;
|
||||
withReadLock([&] { model = _model; });
|
||||
if (!_hasModel) {
|
||||
if ((bool)model) {
|
||||
if (model) {
|
||||
model->removeFromScene(scene, transaction);
|
||||
withWriteLock([&] { _model.reset(); });
|
||||
transaction.updateItem<PayloadProxyInterface>(getRenderItemID(), [](PayloadProxyInterface& data) {
|
||||
|
@ -1312,8 +1315,9 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
}
|
||||
|
||||
// Check for addition
|
||||
if (_hasModel && !(bool)_model) {
|
||||
if (_hasModel && !model) {
|
||||
model = std::make_shared<Model>(nullptr, entity.get());
|
||||
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
|
||||
connect(model.get(), &Model::setURLFinished, this, [&](bool didVisualGeometryRequestSucceed) {
|
||||
setKey(didVisualGeometryRequestSucceed);
|
||||
emit requestRenderUpdate();
|
||||
|
@ -1323,26 +1327,34 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
}
|
||||
_didLastVisualGeometryRequestSucceed = didVisualGeometryRequestSucceed;
|
||||
});
|
||||
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
|
||||
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
|
||||
entity->setModel(model);
|
||||
withWriteLock([&] { _model = model; });
|
||||
}
|
||||
|
||||
// From here on, we are guaranteed a populated model
|
||||
withWriteLock([&] {
|
||||
if (_parsedModelURL != model->getURL()) {
|
||||
if (_parsedModelURL != model->getURL()) {
|
||||
withWriteLock([&] {
|
||||
_texturesLoaded = false;
|
||||
model->setURL(_parsedModelURL);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Nothing else to do unless the model is loaded
|
||||
if (!model->isLoaded()) {
|
||||
withWriteLock([&] {
|
||||
_prevModelLoaded = false;
|
||||
});
|
||||
emit requestRenderUpdate();
|
||||
return;
|
||||
} else if (!_prevModelLoaded) {
|
||||
withWriteLock([&] {
|
||||
_prevModelLoaded = true;
|
||||
});
|
||||
}
|
||||
|
||||
// Check for initializing the model
|
||||
// FIXME: There are several places below here where we are modifying the entity, which we should not be doing from the renderable
|
||||
if (!entity->_dimensionsInitialized) {
|
||||
EntityItemProperties properties;
|
||||
properties.setLastEdited(usecTimestampNow()); // we must set the edit time since we're editing it
|
||||
|
@ -1360,16 +1372,16 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
// Default to _originalTextures to avoid remapping immediately and lagging on load
|
||||
entity->_originalTextures = model->getTextures();
|
||||
entity->_originalTexturesRead = true;
|
||||
_currentTextures = entity->_originalTextures;
|
||||
}
|
||||
|
||||
if (_lastTextures != entity->getTextures()) {
|
||||
_texturesLoaded = false;
|
||||
_lastTextures = entity->getTextures();
|
||||
withWriteLock([&] {
|
||||
_texturesLoaded = false;
|
||||
_lastTextures = entity->getTextures();
|
||||
});
|
||||
auto newTextures = parseTexturesToMap(_lastTextures, entity->_originalTextures);
|
||||
if (newTextures != _currentTextures) {
|
||||
if (newTextures != model->getTextures()) {
|
||||
model->setTextures(newTextures);
|
||||
_currentTextures = newTextures;
|
||||
}
|
||||
}
|
||||
if (entity->_needsJointSimulation) {
|
||||
|
@ -1378,14 +1390,11 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
entity->updateModelBounds();
|
||||
entity->stopModelOverrideIfNoParent();
|
||||
|
||||
render::hifi::Tag tagMask = getTagMask();
|
||||
if (model->isVisible() != _visible) {
|
||||
// FIXME: this seems like it could be optimized if we tracked our last known visible state in
|
||||
// the renderable item. As it stands now the model checks it's visible/invisible state
|
||||
// so most of the time we don't do anything in this function.
|
||||
model->setVisibleInScene(_visible, scene);
|
||||
}
|
||||
|
||||
render::hifi::Tag tagMask = getTagMask();
|
||||
if (model->getTagMask() != tagMask) {
|
||||
model->setTagMask(tagMask, scene);
|
||||
}
|
||||
|
@ -1414,7 +1423,9 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
}
|
||||
|
||||
if (!_texturesLoaded && model->getGeometry() && model->getGeometry()->areTexturesLoaded()) {
|
||||
_texturesLoaded = true;
|
||||
withWriteLock([&] {
|
||||
_texturesLoaded = true;
|
||||
});
|
||||
model->updateRenderItems();
|
||||
} else if (!_texturesLoaded) {
|
||||
emit requestRenderUpdate();
|
||||
|
@ -1462,15 +1473,15 @@ void ModelEntityRenderer::doRender(RenderArgs* args) {
|
|||
batch.setModelTransform(getModelTransform()); // we want to include the scale as well
|
||||
DependencyManager::get<GeometryCache>()->renderWireCubeInstance(args, batch, greenColor);
|
||||
|
||||
// Enqueue updates for the next frame
|
||||
#if WANT_EXTRA_DEBUGGING
|
||||
// debugging...
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
_model->renderDebugMeshBoxes(batch);
|
||||
ModelPointer model;
|
||||
withReadLock([&] {
|
||||
model = _model;
|
||||
});
|
||||
if (model) {
|
||||
model->renderDebugMeshBoxes(batch);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Remap textures for the next frame to avoid flicker
|
||||
// remapTextures();
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::mapJoints(const TypedEntityPointer& entity, const QStringList& modelJointNames) {
|
||||
|
|
|
@ -170,7 +170,7 @@ protected:
|
|||
private:
|
||||
void animate(const TypedEntityPointer& entity);
|
||||
void mapJoints(const TypedEntityPointer& entity, const QStringList& modelJointNames);
|
||||
bool jointsMapped() const { return _jointMappingURL == _renderAnimationProperties.getURL() && _jointMappingCompleted; }
|
||||
bool jointsMapped() const { return _jointMappingCompleted; }
|
||||
|
||||
// Transparency is handled in ModelMeshPartPayload
|
||||
virtual bool isTransparent() const override { return false; }
|
||||
|
@ -179,32 +179,26 @@ private:
|
|||
ModelPointer _model;
|
||||
GeometryResource::Pointer _compoundShapeResource;
|
||||
QString _lastTextures;
|
||||
QVariantMap _currentTextures;
|
||||
bool _texturesLoaded { false };
|
||||
AnimationPropertyGroup _renderAnimationProperties;
|
||||
int _lastKnownCurrentFrame { -1 };
|
||||
#ifdef MODEL_ENTITY_USE_FADE_EFFECT
|
||||
bool _hasTransitioned{ false };
|
||||
#endif
|
||||
|
||||
bool _needsJointSimulation { false };
|
||||
const void* _collisionMeshKey { nullptr };
|
||||
|
||||
// used on client side
|
||||
bool _jointMappingCompleted{ false };
|
||||
QVector<int> _jointMapping; // domain is index into model-joints, range is index into animation-joints
|
||||
QString _jointMappingURL;
|
||||
AnimationPointer _animation;
|
||||
QString _lastModelURL;
|
||||
QUrl _parsedModelURL;
|
||||
bool _marketplaceEntity { false };
|
||||
bool _shouldHighlight { false };
|
||||
bool _animating { false };
|
||||
uint64_t _lastAnimated { 0 };
|
||||
|
||||
render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() };
|
||||
|
||||
bool _didLastVisualGeometryRequestSucceed { true };
|
||||
bool _prevModelLoaded { false };
|
||||
|
||||
void processMaterials();
|
||||
};
|
||||
|
|
|
@ -95,9 +95,6 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi
|
|||
auto newParticleProperties = entity->getParticleProperties();
|
||||
if (!newParticleProperties.valid()) {
|
||||
qCWarning(entitiesrenderer) << "Bad particle properties";
|
||||
if (!entity->getParticleProperties().valid()) {
|
||||
qCWarning(entitiesrenderer) << "Bad particle properties";
|
||||
}
|
||||
}
|
||||
|
||||
if (resultWithReadLock<bool>([&]{ return _particleProperties != newParticleProperties; })) {
|
||||
|
@ -125,6 +122,14 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
void* key = (void*)this;
|
||||
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this] () {
|
||||
withWriteLock([&] {
|
||||
updateModelTransform();
|
||||
_renderTransform = getModelTransform();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
|
||||
|
@ -189,7 +194,7 @@ ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createPa
|
|||
if (polarStart == 0.0f && polarFinish == 0.0f && emitDimensions.z == 0.0f) {
|
||||
// Emit along z-axis from position
|
||||
|
||||
particle.velocity = (emitSpeed + 0.2f * speedSpread) * (emitOrientation * Vectors::UNIT_Z);
|
||||
particle.velocity = (emitSpeed + randFloatInRange(-1.0f, 1.0f) * speedSpread) * (emitOrientation * Vectors::UNIT_Z);
|
||||
particle.acceleration = emitAcceleration + randFloatInRange(-1.0f, 1.0f) * accelerationSpread;
|
||||
|
||||
} else {
|
||||
|
@ -198,10 +203,9 @@ ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createPa
|
|||
// - Distribute points relatively evenly over ellipsoid surface
|
||||
// - Distribute points relatively evenly within ellipsoid volume
|
||||
|
||||
float elevationMinZ = sin(PI_OVER_TWO - polarFinish);
|
||||
float elevationMaxZ = sin(PI_OVER_TWO - polarStart);
|
||||
// float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * randFloat());
|
||||
float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) *randFloat());
|
||||
float elevationMinZ = sinf(PI_OVER_TWO - polarFinish);
|
||||
float elevationMaxZ = sinf(PI_OVER_TWO - polarStart);
|
||||
float elevation = asinf(elevationMinZ + (elevationMaxZ - elevationMinZ) * randFloat());
|
||||
|
||||
float azimuth;
|
||||
if (azimuthFinish >= azimuthStart) {
|
||||
|
@ -309,7 +313,6 @@ void ParticleEffectEntityRenderer::doRender(RenderArgs* args) {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
// FIXME migrate simulation to a compute stage
|
||||
stepSimulation();
|
||||
|
||||
|
@ -324,7 +327,10 @@ void ParticleEffectEntityRenderer::doRender(RenderArgs* args) {
|
|||
// In trail mode, the particles are created in world space.
|
||||
// so we only set a transform if they're not in trail mode
|
||||
if (!_particleProperties.emission.shouldTrail) {
|
||||
transform = getModelTransform();
|
||||
|
||||
withReadLock([&] {
|
||||
transform = _renderTransform;
|
||||
});
|
||||
transform.setScale(vec3(1));
|
||||
}
|
||||
batch.setModelTransform(transform);
|
||||
|
|
|
@ -45,9 +45,8 @@ private:
|
|||
|
||||
// CPU particles
|
||||
// FIXME either switch to GPU compute particles or switch to simd updating of the particles
|
||||
#if 1
|
||||
struct CpuParticle {
|
||||
float seed{ 0.0f };
|
||||
float seed { 0.0f };
|
||||
uint64_t expiration { 0 };
|
||||
float lifetime { 0.0f };
|
||||
glm::vec3 position;
|
||||
|
@ -62,19 +61,6 @@ private:
|
|||
}
|
||||
};
|
||||
using CpuParticles = std::deque<CpuParticle>;
|
||||
#else
|
||||
struct CpuParticles {
|
||||
std::vector<float> seeds;
|
||||
std::vector<float> lifetimes;
|
||||
std::vector<vec4> positions;
|
||||
std::vector<vec4> velocities;
|
||||
std::vector<vec4> accelerations;
|
||||
|
||||
size_t size() const;
|
||||
void resize(size_t size);
|
||||
void integrate(float deltaTime);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
template<typename T>
|
||||
|
|
|
@ -97,16 +97,25 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
addMaterial(graphics::MaterialLayer(_material, 0), "0");
|
||||
|
||||
_shape = entity->getShape();
|
||||
_position = entity->getWorldPosition();
|
||||
_dimensions = entity->getScaledDimensions();
|
||||
_orientation = entity->getWorldOrientation();
|
||||
_renderTransform = getModelTransform();
|
||||
});
|
||||
|
||||
if (_shape == entity::Sphere) {
|
||||
_renderTransform.postScale(SPHERE_ENTITY_SCALE);
|
||||
}
|
||||
void* key = (void*)this;
|
||||
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this] () {
|
||||
withWriteLock([&] {
|
||||
auto entity = getEntity();
|
||||
_position = entity->getWorldPosition();
|
||||
_dimensions = entity->getScaledDimensions();
|
||||
_orientation = entity->getWorldOrientation();
|
||||
bool success = false;
|
||||
auto newModelTransform = entity->getTransformToCenter(success);
|
||||
_renderTransform = success ? newModelTransform : getModelTransform();
|
||||
|
||||
_renderTransform.postScale(_dimensions);
|
||||
if (_shape == entity::Sphere) {
|
||||
_renderTransform.postScale(SPHERE_ENTITY_SCALE);
|
||||
}
|
||||
|
||||
_renderTransform.postScale(_dimensions);
|
||||
});;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ private:
|
|||
|
||||
Procedural _procedural;
|
||||
QString _lastUserData;
|
||||
Transform _renderTransform;
|
||||
entity::Shape _shape { entity::Sphere };
|
||||
std::shared_ptr<graphics::Material> _material;
|
||||
glm::vec3 _position;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "GLMHelpers.h"
|
||||
|
||||
using namespace render;
|
||||
using namespace render::entities;
|
||||
|
||||
static const int FIXED_FONT_POINT_SIZE = 40;
|
||||
|
@ -64,10 +65,20 @@ bool TextEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint
|
|||
return false;
|
||||
}
|
||||
|
||||
void TextEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
||||
void* key = (void*)this;
|
||||
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] () {
|
||||
withWriteLock([&] {
|
||||
_dimensions = entity->getScaledDimensions();
|
||||
updateModelTransform();
|
||||
_renderTransform = getModelTransform();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void TextEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
|
||||
_textColor = toGlm(entity->getTextColorX());
|
||||
_backgroundColor = toGlm(entity->getBackgroundColorX());
|
||||
_dimensions = entity->getScaledDimensions();
|
||||
_faceCamera = entity->getFaceCamera();
|
||||
_lineHeight = entity->getLineHeight();
|
||||
_text = entity->getText();
|
||||
|
@ -76,24 +87,28 @@ void TextEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe
|
|||
|
||||
void TextEntityRenderer::doRender(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderableTextEntityItem::render");
|
||||
|
||||
|
||||
Transform modelTransform;
|
||||
glm::vec3 dimensions;
|
||||
withReadLock([&] {
|
||||
modelTransform = _renderTransform;
|
||||
dimensions = _dimensions;
|
||||
});
|
||||
static const float SLIGHTLY_BEHIND = -0.005f;
|
||||
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||
bool transparent = fadeRatio < 1.0f;
|
||||
glm::vec4 textColor = glm::vec4(_textColor, fadeRatio);
|
||||
glm::vec4 backgroundColor = glm::vec4(_backgroundColor, fadeRatio);
|
||||
const glm::vec3& dimensions = _dimensions;
|
||||
|
||||
|
||||
// Render background
|
||||
glm::vec3 minCorner = glm::vec3(0.0f, -dimensions.y, SLIGHTLY_BEHIND);
|
||||
glm::vec3 maxCorner = glm::vec3(dimensions.x, 0.0f, SLIGHTLY_BEHIND);
|
||||
|
||||
|
||||
|
||||
|
||||
// Batch render calls
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
|
||||
const auto& modelTransform = getModelTransform();
|
||||
auto transformToTopLeft = modelTransform;
|
||||
if (_faceCamera) {
|
||||
//rotate about vertical to face the camera
|
||||
|
@ -105,7 +120,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
|
|||
}
|
||||
transformToTopLeft.postTranslate(dimensions * glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left
|
||||
transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed
|
||||
|
||||
|
||||
batch.setModelTransform(transformToTopLeft);
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (!_geometryID) {
|
||||
|
@ -113,11 +128,11 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
|
|||
}
|
||||
geometryCache->bindSimpleProgram(batch, false, transparent, false, false, false);
|
||||
geometryCache->renderQuad(batch, minCorner, maxCorner, backgroundColor, _geometryID);
|
||||
|
||||
|
||||
float scale = _lineHeight / _textRenderer->getFontSize();
|
||||
transformToTopLeft.setScale(scale); // Scale to have the correct line height
|
||||
batch.setModelTransform(transformToTopLeft);
|
||||
|
||||
|
||||
float leftMargin = 0.1f * _lineHeight, topMargin = 0.1f * _lineHeight;
|
||||
glm::vec2 bounds = glm::vec2(dimensions.x - 2.0f * leftMargin,
|
||||
dimensions.y - 2.0f * topMargin);
|
||||
|
|
|
@ -27,6 +27,7 @@ public:
|
|||
~TextEntityRenderer();
|
||||
private:
|
||||
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
|
||||
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
||||
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
|
||||
virtual void doRender(RenderArgs* args) override;
|
||||
int _geometryID{ 0 };
|
||||
|
@ -39,6 +40,6 @@ private:
|
|||
float _lineHeight;
|
||||
};
|
||||
|
||||
} }
|
||||
} }
|
||||
|
||||
#endif // hifi_RenderableTextEntityItem_h
|
||||
|
|
|
@ -149,8 +149,8 @@ void WebEntityRenderer::onTimeout() {
|
|||
}
|
||||
|
||||
void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
||||
// If the content type has changed, or the old content type was QML, we need to
|
||||
// destroy the existing surface (because surfaces don't support changing the root
|
||||
// If the content type has changed, or the old content type was QML, we need to
|
||||
// destroy the existing surface (because surfaces don't support changing the root
|
||||
// object, so subsequent loads of content just overlap the existing content
|
||||
bool urlChanged = false;
|
||||
{
|
||||
|
@ -187,24 +187,30 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
|
|||
if (!hasWebSurface() && !buildWebSurface(entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (urlChanged && _contentType == ContentType::HtmlContent) {
|
||||
_webSurface->getRootItem()->setProperty(URL_PROPERTY, _lastSourceUrl);
|
||||
}
|
||||
|
||||
if (_contextPosition != entity->getWorldPosition()) {
|
||||
// update globalPosition
|
||||
_contextPosition = entity->getWorldPosition();
|
||||
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(_contextPosition));
|
||||
}
|
||||
void* key = (void*)this;
|
||||
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] () {
|
||||
withWriteLock([&] {
|
||||
if (_contextPosition != entity->getWorldPosition()) {
|
||||
// update globalPosition
|
||||
_contextPosition = entity->getWorldPosition();
|
||||
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(_contextPosition));
|
||||
}
|
||||
|
||||
_lastDPI = entity->getDPI();
|
||||
_lastLocked = entity->getLocked();
|
||||
_lastDPI = entity->getDPI();
|
||||
_lastLocked = entity->getLocked();
|
||||
|
||||
glm::vec2 windowSize = getWindowSize(entity);
|
||||
_webSurface->resize(QSize(windowSize.x, windowSize.y));
|
||||
_renderTransform = getModelTransform();
|
||||
_renderTransform.postScale(entity->getScaledDimensions());
|
||||
glm::vec2 windowSize = getWindowSize(entity);
|
||||
_webSurface->resize(QSize(windowSize.x, windowSize.y));
|
||||
updateModelTransform();
|
||||
_renderTransform = getModelTransform();
|
||||
_renderTransform.postScale(entity->getScaledDimensions());
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -297,7 +303,7 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) {
|
|||
|
||||
if (_contentType == ContentType::HtmlContent) {
|
||||
// We special case YouTube URLs since we know they are videos that we should play with at least 30 FPS.
|
||||
// FIXME this doesn't handle redirects or shortened URLs, consider using a signaling method from the
|
||||
// FIXME this doesn't handle redirects or shortened URLs, consider using a signaling method from the
|
||||
// web entity
|
||||
if (QUrl(_lastSourceUrl).host().endsWith("youtube.com", Qt::CaseInsensitive)) {
|
||||
_webSurface->setMaxFps(YOUTUBE_MAX_FPS);
|
||||
|
|
|
@ -68,7 +68,6 @@ private:
|
|||
bool _lastLocked;
|
||||
QTimer _timer;
|
||||
uint64_t _lastRenderTime { 0 };
|
||||
Transform _renderTransform;
|
||||
};
|
||||
|
||||
} } // namespace
|
||||
|
|
|
@ -123,7 +123,6 @@ private:
|
|||
bool _pendingSkyboxTexture{ false };
|
||||
|
||||
QString _proceduralUserData;
|
||||
Transform _renderTransform;
|
||||
};
|
||||
|
||||
} } // namespace
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
//
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
<@include gpu/Noise.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
|
@ -119,9 +120,15 @@ void main(void) {
|
|||
// Offset for corrected vertex ordering.
|
||||
varTexcoord = vec2((UNIT_QUAD[twoTriID].xy -1.0) * vec2(0.5, -0.5));
|
||||
varColor = interpolate3Vec4(particle.color.start, particle.color.middle, particle.color.finish, age);
|
||||
vec3 colorSpread = 2.0 * vec3(hifi_hash(seed), hifi_hash(seed * 2.0), hifi_hash(seed * 3.0)) - 1.0;
|
||||
varColor.rgb = clamp(varColor.rgb + colorSpread * particle.color.spread.rgb, vec3(0), vec3(1));
|
||||
float alphaSpread = 2.0 * hifi_hash(seed * 4.0) - 1.0;
|
||||
varColor.a = clamp(varColor.a + alphaSpread * particle.color.spread.a, 0.0, 1.0);
|
||||
|
||||
// anchor point in eye space
|
||||
float radius = interpolate3Points(particle.radius.start, particle.radius.middle, particle.radius.finish, age);
|
||||
float radiusSpread = 2.0 * hifi_hash(seed * 5.0) - 1.0;
|
||||
radius = max(radius + radiusSpread * particle.radius.spread, 0.0);
|
||||
vec4 quadPos = radius * UNIT_QUAD[twoTriID];
|
||||
|
||||
vec4 anchorPoint;
|
||||
|
|
|
@ -95,7 +95,7 @@ bool DeleteEntityOperator::preRecursion(const OctreeElementPointer& element) {
|
|||
EntityItemPointer theEntity = details.entity;
|
||||
bool entityDeleted = entityTreeElement->removeEntityItem(theEntity, true); // remove it from the element
|
||||
assert(entityDeleted);
|
||||
(void)entityDeleted; // quite warning
|
||||
(void)entityDeleted; // quiet warning about unused variable
|
||||
_tree->clearEntityMapEntry(details.entity->getEntityItemID());
|
||||
_foundCount++;
|
||||
}
|
||||
|
|
|
@ -367,6 +367,10 @@ int EntityItem::expectedBytes() {
|
|||
return MINIMUM_HEADER_BYTES;
|
||||
}
|
||||
|
||||
const uint8_t PENDING_STATE_NOTHING = 0;
|
||||
const uint8_t PENDING_STATE_TAKE = 1;
|
||||
const uint8_t PENDING_STATE_RELEASE = 2;
|
||||
|
||||
// clients use this method to unpack FULL updates from entity-server
|
||||
int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) {
|
||||
setSourceUUID(args.sourceUUID);
|
||||
|
@ -678,7 +682,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
// setters to ignore what the server says.
|
||||
filterRejection = newSimOwner.getID().isNull();
|
||||
if (weOwnSimulation) {
|
||||
if (newSimOwner.getID().isNull() && !_simulationOwner.pendingRelease(lastEditedFromBufferAdjusted)) {
|
||||
if (newSimOwner.getID().isNull() && !pendingRelease(lastEditedFromBufferAdjusted)) {
|
||||
// entity-server is trying to clear our ownership (probably at our own request)
|
||||
// but we actually want to own it, therefore we ignore this clear event
|
||||
// and pretend that we own it (e.g. we assume we'll receive ownership soon)
|
||||
|
@ -693,32 +697,53 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
// recompute weOwnSimulation for later
|
||||
weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
|
||||
}
|
||||
} else if (_simulationOwner.pendingTake(now - maxPingRoundTrip)) {
|
||||
// we sent a bid already but maybe before this packet was sent from the server
|
||||
weOwnSimulation = true;
|
||||
} else if (_pendingOwnershipState == PENDING_STATE_TAKE) {
|
||||
// we're waiting to receive acceptance of a bid
|
||||
// this ownership data either satisifies our bid or does not
|
||||
bool bidIsSatisfied = newSimOwner.getID() == myNodeID &&
|
||||
(newSimOwner.getPriority() == _pendingOwnershipPriority ||
|
||||
(_pendingOwnershipPriority == VOLUNTEER_SIMULATION_PRIORITY &&
|
||||
newSimOwner.getPriority() == RECRUIT_SIMULATION_PRIORITY));
|
||||
|
||||
if (newSimOwner.getID().isNull()) {
|
||||
// the entity-server is trying to clear someone else's ownership
|
||||
// the entity-server is clearing someone else's ownership
|
||||
if (!_simulationOwner.isNull()) {
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
|
||||
somethingChanged = true;
|
||||
_simulationOwner.clearCurrentOwner();
|
||||
}
|
||||
} else if (newSimOwner.getID() == myNodeID) {
|
||||
// the entity-server is awarding us ownership which is what we want
|
||||
_simulationOwner.set(newSimOwner);
|
||||
} else {
|
||||
if (newSimOwner.getID() != _simulationOwner.getID()) {
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
|
||||
}
|
||||
if (_simulationOwner.set(newSimOwner)) {
|
||||
// the entity-server changed ownership
|
||||
somethingChanged = true;
|
||||
}
|
||||
}
|
||||
if (bidIsSatisfied || (somethingChanged && _pendingOwnershipTimestamp < now - maxPingRoundTrip)) {
|
||||
// the bid has been satisfied, or it has been invalidated by data sent AFTER the bid should have been received
|
||||
// in either case: accept our fate and clear pending state
|
||||
_pendingOwnershipState = PENDING_STATE_NOTHING;
|
||||
_pendingOwnershipPriority = 0;
|
||||
}
|
||||
weOwnSimulation = bidIsSatisfied || (_simulationOwner.getID() == myNodeID);
|
||||
} else {
|
||||
// we are not waiting to take ownership
|
||||
if (newSimOwner.getID() != _simulationOwner.getID()) {
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
|
||||
}
|
||||
if (_simulationOwner.set(newSimOwner)) {
|
||||
// the entity-server changed ownership...
|
||||
somethingChanged = true;
|
||||
if (newSimOwner.getID() == myNodeID) {
|
||||
// we have recieved ownership
|
||||
weOwnSimulation = true;
|
||||
// accept our fate and clear pendingState (just in case)
|
||||
_pendingOwnershipState = PENDING_STATE_NOTHING;
|
||||
_pendingOwnershipPriority = 0;
|
||||
}
|
||||
}
|
||||
} else if (newSimOwner.matchesValidID(myNodeID) && !_simulationOwner.pendingTake(now)) {
|
||||
// entity-server tells us that we have simulation ownership while we never requested this for this EntityItem,
|
||||
// this could happen when the user reloads the cache and entity tree.
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
|
||||
somethingChanged = true;
|
||||
_simulationOwner.clearCurrentOwner();
|
||||
weOwnSimulation = false;
|
||||
} else if (_simulationOwner.set(newSimOwner)) {
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
|
||||
somethingChanged = true;
|
||||
// recompute weOwnSimulation for later
|
||||
weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1333,18 +1358,39 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c
|
|||
properties._accelerationChanged = true;
|
||||
}
|
||||
|
||||
void EntityItem::flagForOwnershipBid(uint8_t priority) {
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY);
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
if (_simulationOwner.matchesValidID(nodeList->getSessionUUID())) {
|
||||
// we already own it
|
||||
_simulationOwner.promotePriority(priority);
|
||||
} else {
|
||||
// we don't own it yet
|
||||
_simulationOwner.setPendingPriority(priority, usecTimestampNow());
|
||||
void EntityItem::setScriptSimulationPriority(uint8_t priority) {
|
||||
uint8_t newPriority = stillHasGrabActions() ? glm::max(priority, SCRIPT_GRAB_SIMULATION_PRIORITY) : priority;
|
||||
if (newPriority != _scriptSimulationPriority) {
|
||||
// set the dirty flag to trigger a bid or ownership update
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY);
|
||||
_scriptSimulationPriority = newPriority;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItem::clearScriptSimulationPriority() {
|
||||
// DO NOT markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY) here, because this
|
||||
// is only ever called from the code that actually handles the dirty flags, and it knows best.
|
||||
_scriptSimulationPriority = stillHasGrabActions() ? SCRIPT_GRAB_SIMULATION_PRIORITY : 0;
|
||||
}
|
||||
|
||||
void EntityItem::setPendingOwnershipPriority(uint8_t priority) {
|
||||
_pendingOwnershipTimestamp = usecTimestampNow();
|
||||
_pendingOwnershipPriority = priority;
|
||||
_pendingOwnershipState = (_pendingOwnershipPriority == 0) ? PENDING_STATE_RELEASE : PENDING_STATE_TAKE;
|
||||
}
|
||||
|
||||
bool EntityItem::pendingRelease(uint64_t timestamp) const {
|
||||
return _pendingOwnershipPriority == 0 &&
|
||||
_pendingOwnershipState == PENDING_STATE_RELEASE &&
|
||||
_pendingOwnershipTimestamp >= timestamp;
|
||||
}
|
||||
|
||||
bool EntityItem::stillWaitingToTakeOwnership(uint64_t timestamp) const {
|
||||
return _pendingOwnershipPriority > 0 &&
|
||||
_pendingOwnershipState == PENDING_STATE_TAKE &&
|
||||
_pendingOwnershipTimestamp >= timestamp;
|
||||
}
|
||||
|
||||
bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
||||
bool somethingChanged = false;
|
||||
|
||||
|
@ -1977,10 +2023,6 @@ void EntityItem::clearSimulationOwnership() {
|
|||
|
||||
}
|
||||
|
||||
void EntityItem::setPendingOwnershipPriority(uint8_t priority, const quint64& timestamp) {
|
||||
_simulationOwner.setPendingPriority(priority, timestamp);
|
||||
}
|
||||
|
||||
QString EntityItem::actionsToDebugString() {
|
||||
QString result;
|
||||
QVector<QByteArray> serializedActions;
|
||||
|
@ -2076,6 +2118,7 @@ bool EntityItem::updateAction(EntitySimulationPointer simulation, const QUuid& a
|
|||
}
|
||||
|
||||
bool EntityItem::removeAction(EntitySimulationPointer simulation, const QUuid& actionID) {
|
||||
// TODO: some action
|
||||
bool success = false;
|
||||
withWriteLock([&] {
|
||||
checkWaitingToRemove(simulation);
|
||||
|
@ -2403,12 +2446,17 @@ void EntityItem::locationChanged(bool tellPhysics) {
|
|||
}
|
||||
}
|
||||
SpatiallyNestable::locationChanged(tellPhysics); // tell all the children, also
|
||||
std::pair<int32_t, glm::vec4> data(_spaceIndex, glm::vec4(getWorldPosition(), _boundingRadius));
|
||||
emit spaceUpdate(data);
|
||||
somethingChangedNotification();
|
||||
}
|
||||
|
||||
void EntityItem::dimensionsChanged() {
|
||||
requiresRecalcBoxes();
|
||||
SpatiallyNestable::dimensionsChanged(); // Do what you have to do
|
||||
_boundingRadius = 0.5f * glm::length(getScaledDimensions());
|
||||
std::pair<int32_t, glm::vec4> data(_spaceIndex, glm::vec4(getWorldPosition(), _boundingRadius));
|
||||
emit spaceUpdate(data);
|
||||
somethingChangedNotification();
|
||||
}
|
||||
|
||||
|
@ -3012,6 +3060,11 @@ void EntityItem::retrieveMarketplacePublicKey() {
|
|||
});
|
||||
}
|
||||
|
||||
void EntityItem::setSpaceIndex(int32_t index) {
|
||||
assert(_spaceIndex == -1);
|
||||
_spaceIndex = index;
|
||||
}
|
||||
|
||||
void EntityItem::preDelete() {
|
||||
}
|
||||
|
||||
|
|
|
@ -185,6 +185,7 @@ public:
|
|||
/// Dimensions in meters (0.0 - TREE_SCALE)
|
||||
glm::vec3 getScaledDimensions() const;
|
||||
virtual void setScaledDimensions(const glm::vec3& value);
|
||||
virtual glm::vec3 getRaycastDimensions() const { return getScaledDimensions(); }
|
||||
|
||||
inline const glm::vec3 getUnscaledDimensions() const { return _unscaledDimensions; }
|
||||
virtual void setUnscaledDimensions(const glm::vec3& value);
|
||||
|
@ -239,7 +240,7 @@ public:
|
|||
// position, size, and bounds related helpers
|
||||
virtual AACube getMaximumAACube(bool& success) const override;
|
||||
AACube getMinimumAACube(bool& success) const;
|
||||
AABox getAABox(bool& success) const; /// axis aligned bounding box in world-frame (meters)
|
||||
virtual AABox getAABox(bool& success) const; /// axis aligned bounding box in world-frame (meters)
|
||||
|
||||
using SpatiallyNestable::getQueryAACube;
|
||||
virtual AACube getQueryAACube(bool& success) const override;
|
||||
|
@ -311,14 +312,21 @@ public:
|
|||
const SimulationOwner& getSimulationOwner() const { return _simulationOwner; }
|
||||
void setSimulationOwner(const QUuid& id, uint8_t priority);
|
||||
void setSimulationOwner(const SimulationOwner& owner);
|
||||
void promoteSimulationPriority(uint8_t priority);
|
||||
|
||||
uint8_t getSimulationPriority() const { return _simulationOwner.getPriority(); }
|
||||
QUuid getSimulatorID() const { return _simulationOwner.getID(); }
|
||||
void clearSimulationOwnership();
|
||||
void setPendingOwnershipPriority(uint8_t priority, const quint64& timestamp);
|
||||
uint8_t getPendingOwnershipPriority() const { return _simulationOwner.getPendingPriority(); }
|
||||
void rememberHasSimulationOwnershipBid() const;
|
||||
|
||||
// TODO: move this "ScriptSimulationPriority" and "PendingOwnership" stuff into EntityMotionState
|
||||
// but first would need to do some other cleanup. In the meantime these live here as "scratch space"
|
||||
// to allow libs that don't know about each other to communicate.
|
||||
void setScriptSimulationPriority(uint8_t priority);
|
||||
void clearScriptSimulationPriority();
|
||||
uint8_t getScriptSimulationPriority() const { return _scriptSimulationPriority; }
|
||||
void setPendingOwnershipPriority(uint8_t priority);
|
||||
uint8_t getPendingOwnershipPriority() const { return _pendingOwnershipPriority; }
|
||||
bool pendingRelease(uint64_t timestamp) const;
|
||||
bool stillWaitingToTakeOwnership(uint64_t timestamp) const;
|
||||
|
||||
// Certifiable Properties
|
||||
QString getItemName() const;
|
||||
|
@ -411,7 +419,6 @@ public:
|
|||
|
||||
void getAllTerseUpdateProperties(EntityItemProperties& properties) const;
|
||||
|
||||
void flagForOwnershipBid(uint8_t priority);
|
||||
void flagForMotionStateChange() { _flags |= Simulation::DIRTY_MOTION_TYPE; }
|
||||
|
||||
QString actionsToDebugString();
|
||||
|
@ -500,6 +507,10 @@ public:
|
|||
void setCauterized(bool value) { _cauterized = value; }
|
||||
bool getCauterized() const { return _cauterized; }
|
||||
|
||||
float getBoundingRadius() const { return _boundingRadius; }
|
||||
void setSpaceIndex(int32_t index);
|
||||
int32_t getSpaceIndex() const { return _spaceIndex; }
|
||||
|
||||
virtual void preDelete();
|
||||
virtual void postParentFixup() {}
|
||||
|
||||
|
@ -517,6 +528,7 @@ public:
|
|||
|
||||
signals:
|
||||
void requestRenderUpdate();
|
||||
void spaceUpdate(std::pair<int32_t, glm::vec4> data);
|
||||
|
||||
protected:
|
||||
QHash<ChangeHandlerId, ChangeHandlerCallback> _changeHandlers;
|
||||
|
@ -668,6 +680,17 @@ protected:
|
|||
quint64 _lastUpdatedQueryAACubeTimestamp { 0 };
|
||||
uint64_t _simulationOwnershipExpiry { 0 };
|
||||
|
||||
float _boundingRadius { 0.0f };
|
||||
int32_t _spaceIndex { -1 }; // index to proxy in workload::Space
|
||||
|
||||
// TODO: move this "scriptSimulationPriority" and "pendingOwnership" stuff into EntityMotionState
|
||||
// but first would need to do some other cleanup. In the meantime these live here as "scratch space"
|
||||
// to allow libs that don't know about each other to communicate.
|
||||
uint64_t _pendingOwnershipTimestamp { 0 }; // timestamp of last owenership change request
|
||||
uint8_t _pendingOwnershipPriority { 0 }; // priority of last ownership change request
|
||||
uint8_t _pendingOwnershipState { 0 }; // TAKE or RELEASE
|
||||
uint8_t _scriptSimulationPriority { 0 }; // target priority based on script operations
|
||||
|
||||
bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera
|
||||
|
||||
bool _cloneable { ENTITY_ITEM_DEFAULT_CLONEABLE };
|
||||
|
|
|
@ -854,7 +854,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* default is Earth's gravity value.
|
||||
* @property {vec3} accelerationSpread=0,0,0 - The spread in accelerations that each particle is given. If
|
||||
* <code>emitAccelerations == {x: 0, y: -9.8, z: 0}</code> and <code>accelerationSpread ==
|
||||
* {x: 0, y: 1, z: 0}</code>, each particle will have an acceleration in the range, <code>{x: 0, y: -10.8, z: 0}</code>
|
||||
* {x: 0, y: 1, z: 0}</code>, each particle will have an acceleration in the range <code>{x: 0, y: -10.8, z: 0}</code>
|
||||
* – <code>{x: 0, y: -8.8, z: 0}</code>.
|
||||
* @property {Vec3} dimensions - The dimensions of the particle effect, i.e., a bounding box containing all the particles
|
||||
* during their lifetimes, assuming that <code>emitterShouldTrail</code> is <code>false</code>. <em>Read-only.</em>
|
||||
|
@ -879,30 +879,35 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* @property {number} azimuthStart=-Math.PI - The angle in radians from the entity's local x-axis about the entity's local
|
||||
* z-axis at which particles start being emitted; range <code>-Math.PI</code> – <code>Math.PI</code>. Particles are
|
||||
* emitted from the portion of the ellipsoid that lies between <code>azimuthStart<code> and <code>azimuthFinish</code>.
|
||||
* @property {number} azimuthFinish=Math.PI - The angle in radians from the entity's local x-axis about the entity's local
|
||||
* z-axis at which particles stop being emitted; range <code>-Math.PI</code> – <code>Math.PI</code>. Particles are
|
||||
* @property {number} azimuthFinish=Math.PI - The angle in radians from the entity's local x-axis about the entity's local
|
||||
* z-axis at which particles stop being emitted; range <code>-Math.PI</code> – <code>Math.PI</code>. Particles are
|
||||
* emitted from the portion of the ellipsoid that lies between <code>azimuthStart<code> and <code>azimuthFinish</code>.
|
||||
*
|
||||
* @property {string} textures="" - The URL of a JPG or PNG image file to display for each particle. If you want transparency,
|
||||
* @property {string} textures="" - The URL of a JPG or PNG image file to display for each particle. If you want transparency,
|
||||
* use PNG format.
|
||||
* @property {number} particleRadius=0.025 - The radius of each particle at the middle of its life.
|
||||
* @property {number} radiusStart=0.025 - The radius of each particle at the start of its life. If not explicitly set, the
|
||||
* @property {number} radiusStart=NAN - The radius of each particle at the start of its life. If NAN, the
|
||||
* <code>particleRadius</code> value is used.
|
||||
* @property {number} radiusFinish=0.025 - The radius of each particle at the end of its life. If not explicitly set, the
|
||||
* @property {number} radiusFinish=NAN - The radius of each particle at the end of its life. If NAN, the
|
||||
* <code>particleRadius</code> value is used.
|
||||
* @property {number} radiusSpread=0 - <em>Currently not used.</em>
|
||||
* @property {number} radiusSpread=0 - The spread in radius that each particle is given. If <code>particleRadius == 0.5</code>
|
||||
* and <code>radiusSpread == 0.25</code>, each particle will have a radius in the range <code>0.25</code> – <code>0.75</code>.
|
||||
* @property {Color} color=255,255,255 - The color of each particle at the middle of its life.
|
||||
* @property {Color} colorStart=255,255,255 - The color of each particle at the start of its life. If not explicitly set, the
|
||||
* @property {Color} colorStart=NAN,NAN,NAN - The color of each particle at the start of its life. If any of the values are NAN, the
|
||||
* <code>color</code> value is used.
|
||||
* @property {Color} colorFinish=255,255,255 - The color of each particle at the end of its life. If not explicitly set, the
|
||||
* @property {Color} colorFinish=NAN,NAN,NAN - The color of each particle at the end of its life. If any of the values are NAN, the
|
||||
* <code>color</code> value is used.
|
||||
* @property {Color} colorSpread=0,0,0 - <em>Currently not used.</em>
|
||||
* @property {Color} colorSpread=0,0,0 - The spread in color that each particle is given. If
|
||||
* <code>color == {red: 100, green: 100, blue: 100}</code> and <code>colorSpread ==
|
||||
* {red: 10, green: 25, blue: 50}</code>, each particle will have an acceleration in the range <code>{red: 90, green: 75, blue: 50}</code>
|
||||
* – <code>{red: 110, green: 125, blue: 150}</code>.
|
||||
* @property {number} alpha=1 - The alpha of each particle at the middle of its life.
|
||||
* @property {number} alphaStart=1 - The alpha of each particle at the start of its life. If not explicitly set, the
|
||||
* @property {number} alphaStart=NAN - The alpha of each particle at the start of its life. If NAN, the
|
||||
* <code>alpha</code> value is used.
|
||||
* @property {number} alphaFinish=1 - The alpha of each particle at the end of its life. If not explicitly set, the
|
||||
* @property {number} alphaFinish=NAN - The alpha of each particle at the end of its life. If NAN, the
|
||||
* <code>alpha</code> value is used.
|
||||
* @property {number} alphaSpread=0 - <em>Currently not used.</em>
|
||||
* @property {number} alphaSpread=0 - The spread in alpha that each particle is given. If <code>alpha == 0.5</code>
|
||||
* and <code>alphaSpread == 0.25</code>, each particle will have an alpha in the range <code>0.25</code> – <code>0.75</code>.
|
||||
*
|
||||
* @property {ShapeType} shapeType="none" - <em>Currently not used.</em> <em>Read-only.</em>
|
||||
*
|
||||
|
@ -1499,13 +1504,13 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
}
|
||||
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(lastEditedBy, QUuid, setLastEditedBy);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(position, glmVec3, setPosition);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(dimensions, glmVec3, setDimensions);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(rotation, glmQuat, setRotation);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(position, vec3, setPosition);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(dimensions, vec3, setDimensions);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(rotation, quat, setRotation);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(density, float, setDensity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(velocity, glmVec3, setVelocity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(gravity, glmVec3, setGravity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(acceleration, glmVec3, setAcceleration);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(velocity, vec3, setVelocity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(gravity, vec3, setGravity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(acceleration, vec3, setAcceleration);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(damping, float, setDamping);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(restitution, float, setRestitution);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(friction, float, setFriction);
|
||||
|
@ -1513,15 +1518,15 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(script, QString, setScript);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(scriptTimestamp, quint64, setScriptTimestamp);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(serverScripts, QString, setServerScripts);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(registrationPoint, glmVec3, setRegistrationPoint);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(angularVelocity, glmVec3, setAngularVelocity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(registrationPoint, vec3, setRegistrationPoint);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(angularVelocity, vec3, setAngularVelocity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(angularDamping, float, setAngularDamping);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(visible, bool, setVisible);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(canCastShadow, bool, setCanCastShadow);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(color, xColor, setColor);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(colorSpread, xColor, setColorSpread);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(colorStart, xColor, setColorStart);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(colorFinish, xColor, setColorFinish);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(colorStart, vec3, setColorStart);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(colorFinish, vec3, setColorFinish);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(alpha, float, setAlpha);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaSpread, float, setAlphaSpread);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaStart, float, setAlphaStart);
|
||||
|
@ -1555,15 +1560,15 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitRate, float, setEmitRate);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitSpeed, float, setEmitSpeed);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(speedSpread, float, setSpeedSpread);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitOrientation, glmQuat, setEmitOrientation);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitDimensions, glmVec3, setEmitDimensions);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitOrientation, quat, setEmitOrientation);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitDimensions, vec3, setEmitDimensions);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitRadiusStart, float, setEmitRadiusStart);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(polarStart, float, setPolarStart);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(polarFinish, float, setPolarFinish);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(azimuthStart, float, setAzimuthStart);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(azimuthFinish, float, setAzimuthFinish);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitAcceleration, glmVec3, setEmitAcceleration);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(accelerationSpread, glmVec3, setAccelerationSpread);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitAcceleration, vec3, setEmitAcceleration);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(accelerationSpread, vec3, setAccelerationSpread);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(particleRadius, float, setParticleRadius);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusSpread, float, setRadiusSpread);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusStart, float, setRadiusStart);
|
||||
|
@ -1573,8 +1578,8 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(materialMappingMode, MaterialMappingMode);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, quint16, setPriority);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(parentMaterialName, QString, setParentMaterialName);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingPos, glmVec2, setMaterialMappingPos);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingScale, glmVec2, setMaterialMappingScale);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingPos, vec2, setMaterialMappingPos);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingScale, vec2, setMaterialMappingScale);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingRot, float, setMaterialMappingRot);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialData, QString, setMaterialData);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(isVisibleInSecondaryCamera, bool, setIsVisibleInSecondaryCamera);
|
||||
|
@ -1601,7 +1606,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(skyboxMode, SkyboxMode);
|
||||
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, glmVec3, setVoxelVolumeSize);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, vec3, setVoxelVolumeSize);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelData, QByteArray, setVoxelData);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelSurfaceStyle, uint16_t, setVoxelSurfaceStyle);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(lineWidth, float, setLineWidth);
|
||||
|
@ -1648,11 +1653,11 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(parentJointIndex, quint16, setParentJointIndex);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(queryAACube, AACube, setQueryAACube);
|
||||
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(localPosition, glmVec3, setLocalPosition);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(localRotation, glmQuat, setLocalRotation);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(localVelocity, glmVec3, setLocalVelocity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(localAngularVelocity, glmVec3, setLocalAngularVelocity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(localDimensions, glmVec3, setLocalDimensions);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(localPosition, vec3, setLocalPosition);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(localRotation, quat, setLocalRotation);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(localVelocity, vec3, setLocalVelocity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(localAngularVelocity, vec3, setLocalAngularVelocity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(localDimensions, vec3, setLocalDimensions);
|
||||
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(jointRotationsSet, qVectorBool, setJointRotationsSet);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(jointRotations, qVectorQuat, setJointRotations);
|
||||
|
@ -1896,8 +1901,8 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
|
|||
ADD_PROPERTY_TO_MAP(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString);
|
||||
ADD_PROPERTY_TO_MAP(PROP_COLOR, Color, color, xColor);
|
||||
ADD_PROPERTY_TO_MAP(PROP_COLOR_SPREAD, ColorSpread, colorSpread, xColor);
|
||||
ADD_PROPERTY_TO_MAP(PROP_COLOR_START, ColorStart, colorStart, xColor);
|
||||
ADD_PROPERTY_TO_MAP(PROP_COLOR_FINISH, ColorFinish, colorFinish, xColor);
|
||||
ADD_PROPERTY_TO_MAP(PROP_COLOR_START, ColorStart, colorStart, vec3);
|
||||
ADD_PROPERTY_TO_MAP(PROP_COLOR_FINISH, ColorFinish, colorFinish, vec3);
|
||||
ADD_PROPERTY_TO_MAP(PROP_ALPHA, Alpha, alpha, float);
|
||||
ADD_PROPERTY_TO_MAP(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float);
|
||||
ADD_PROPERTY_TO_MAP(PROP_ALPHA_START, AlphaStart, alphaStart, float);
|
||||
|
@ -1952,8 +1957,8 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
|
|||
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_MODE, MaterialMappingMode, materialMappingMode, MaterialMappingMode);
|
||||
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, quint16);
|
||||
ADD_PROPERTY_TO_MAP(PROP_PARENT_MATERIAL_NAME, ParentMaterialName, parentMaterialName, QString);
|
||||
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_POS, MaterialMappingPos, materialMappingPos, glmVec2);
|
||||
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_SCALE, MaterialMappingScale, materialMappingScale, glmVec2);
|
||||
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_POS, MaterialMappingPos, materialMappingPos, vec2);
|
||||
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_SCALE, MaterialMappingScale, materialMappingScale, vec2);
|
||||
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float);
|
||||
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_DATA, MaterialData, materialData, QString);
|
||||
|
||||
|
@ -2656,8 +2661,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_START, float, setRadiusStart);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_FINISH, float, setRadiusFinish);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_SPREAD, xColor, setColorSpread);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_START, xColor, setColorStart);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_FINISH, xColor, setColorFinish);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_START, vec3, setColorStart);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_FINISH, vec3, setColorFinish);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_SPREAD, float, setAlphaSpread);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_START, float, setAlphaStart);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_FINISH, float, setAlphaFinish);
|
||||
|
@ -2729,8 +2734,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_MODE, MaterialMappingMode, setMaterialMappingMode);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_PRIORITY, quint16, setPriority);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_MATERIAL_NAME, QString, setParentMaterialName);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_POS, glmVec2, setMaterialMappingPos);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_SCALE, glmVec2, setMaterialMappingScale);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_POS, vec2, setMaterialMappingPos);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_SCALE, vec2, setMaterialMappingScale);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_ROT, float, setMaterialMappingRot);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_DATA, QString, setMaterialData);
|
||||
}
|
||||
|
@ -2800,7 +2805,7 @@ QVector<glm::vec3> EntityItemProperties::unpackStrokeColors(const QByteArray& st
|
|||
float r = (uint8_t)strokeColors[i++] / 255.0f;
|
||||
float g = (uint8_t)strokeColors[i++] / 255.0f;
|
||||
float b = (uint8_t)strokeColors[i++] / 255.0f;
|
||||
unpackedStrokeColors[j++] = glmVec3(r, g, b);
|
||||
unpackedStrokeColors[j++] = vec3(r, g, b);
|
||||
}
|
||||
} else {
|
||||
qCDebug(entities) << "WARNING - Expected received size for stroke colors does not match. Expected: "
|
||||
|
@ -2931,6 +2936,7 @@ void EntityItemProperties::markAllChanged() {
|
|||
_shapeTypeChanged = true;
|
||||
|
||||
_isEmittingChanged = true;
|
||||
_emitterShouldTrail = true;
|
||||
_maxParticlesChanged = true;
|
||||
_lifespanChanged = true;
|
||||
_emitRateChanged = true;
|
||||
|
@ -2949,15 +2955,12 @@ void EntityItemProperties::markAllChanged() {
|
|||
_radiusSpreadChanged = true;
|
||||
_colorSpreadChanged = true;
|
||||
_alphaSpreadChanged = true;
|
||||
|
||||
// Only mark the following as changed if their values are specified in the properties when the particle is created. If their
|
||||
// values are specified then they are marked as changed in getChangedProperties().
|
||||
//_radiusStartChanged = true;
|
||||
//_radiusFinishChanged = true;
|
||||
//_colorStartChanged = true;
|
||||
//_colorFinishChanged = true;
|
||||
//_alphaStartChanged = true;
|
||||
//_alphaFinishChanged = true;
|
||||
_radiusStartChanged = true;
|
||||
_radiusFinishChanged = true;
|
||||
_colorStartChanged = true;
|
||||
_colorFinishChanged = true;
|
||||
_alphaStartChanged = true;
|
||||
_alphaFinishChanged = true;
|
||||
|
||||
_materialURLChanged = true;
|
||||
_materialMappingModeChanged = true;
|
||||
|
|
|
@ -134,14 +134,14 @@ public:
|
|||
DEFINE_PROPERTY_REF(PROP_SCRIPT, Script, script, QString, ENTITY_ITEM_DEFAULT_SCRIPT);
|
||||
DEFINE_PROPERTY(PROP_SCRIPT_TIMESTAMP, ScriptTimestamp, scriptTimestamp, quint64, ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP);
|
||||
DEFINE_PROPERTY_REF(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor, particle::DEFAULT_COLOR);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR_SPREAD, ColorSpread, colorSpread, xColor, particle::DEFAULT_COLOR_SPREAD);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR_START, ColorStart, colorStart, xColor, particle::DEFAULT_COLOR);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR_FINISH, ColorFinish, colorFinish, xColor, particle::DEFAULT_COLOR);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor, ParticleEffectEntityItem::DEFAULT_XCOLOR);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR_SPREAD, ColorSpread, colorSpread, xColor, ParticleEffectEntityItem::DEFAULT_XCOLOR_SPREAD);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR_START, ColorStart, colorStart, vec3, particle::DEFAULT_COLOR_UNINITIALIZED);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR_FINISH, ColorFinish, colorFinish, vec3, particle::DEFAULT_COLOR_UNINITIALIZED);
|
||||
DEFINE_PROPERTY(PROP_ALPHA, Alpha, alpha, float, particle::DEFAULT_ALPHA);
|
||||
DEFINE_PROPERTY(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float, particle::DEFAULT_ALPHA_SPREAD);
|
||||
DEFINE_PROPERTY(PROP_ALPHA_START, AlphaStart, alphaStart, float, particle::DEFAULT_ALPHA);
|
||||
DEFINE_PROPERTY(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, float, particle::DEFAULT_ALPHA);
|
||||
DEFINE_PROPERTY(PROP_ALPHA_START, AlphaStart, alphaStart, float, particle::DEFAULT_ALPHA_START);
|
||||
DEFINE_PROPERTY(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, float, particle::DEFAULT_ALPHA_FINISH);
|
||||
DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString, "");
|
||||
DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString, "");
|
||||
DEFINE_PROPERTY_REF(PROP_REGISTRATION_POINT, RegistrationPoint, registrationPoint, glm::vec3, ENTITY_ITEM_DEFAULT_REGISTRATION_POINT);
|
||||
|
@ -228,8 +228,8 @@ public:
|
|||
DEFINE_PROPERTY_REF_ENUM(PROP_MATERIAL_MAPPING_MODE, MaterialMappingMode, materialMappingMode, MaterialMappingMode, UV);
|
||||
DEFINE_PROPERTY_REF(PROP_MATERIAL_PRIORITY, Priority, priority, quint16, 0);
|
||||
DEFINE_PROPERTY_REF(PROP_PARENT_MATERIAL_NAME, ParentMaterialName, parentMaterialName, QString, "0");
|
||||
DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_POS, MaterialMappingPos, materialMappingPos, glmVec2, glm::vec2(0, 0));
|
||||
DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_SCALE, MaterialMappingScale, materialMappingScale, glmVec2, glm::vec2(1, 1));
|
||||
DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_POS, MaterialMappingPos, materialMappingPos, vec2, glm::vec2(0, 0));
|
||||
DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_SCALE, MaterialMappingScale, materialMappingScale, vec2, glm::vec2(1, 1));
|
||||
DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float, 0);
|
||||
DEFINE_PROPERTY_REF(PROP_MATERIAL_DATA, MaterialData, materialData, QString, "");
|
||||
|
||||
|
@ -249,11 +249,11 @@ public:
|
|||
DEFINE_PROPERTY_REF(PROP_STATIC_CERTIFICATE_VERSION, StaticCertificateVersion, staticCertificateVersion, quint32, ENTITY_ITEM_DEFAULT_STATIC_CERTIFICATE_VERSION);
|
||||
|
||||
// these are used when bouncing location data into and out of scripts
|
||||
DEFINE_PROPERTY_REF(PROP_LOCAL_POSITION, LocalPosition, localPosition, glmVec3, ENTITY_ITEM_ZERO_VEC3);
|
||||
DEFINE_PROPERTY_REF(PROP_LOCAL_ROTATION, LocalRotation, localRotation, glmQuat, ENTITY_ITEM_DEFAULT_ROTATION);
|
||||
DEFINE_PROPERTY_REF(PROP_LOCAL_VELOCITY, LocalVelocity, localVelocity, glmVec3, ENTITY_ITEM_ZERO_VEC3);
|
||||
DEFINE_PROPERTY_REF(PROP_LOCAL_ANGULAR_VELOCITY, LocalAngularVelocity, localAngularVelocity, glmVec3, ENTITY_ITEM_ZERO_VEC3);
|
||||
DEFINE_PROPERTY_REF(PROP_LOCAL_DIMENSIONS, LocalDimensions, localDimensions, glmVec3, ENTITY_ITEM_ZERO_VEC3);
|
||||
DEFINE_PROPERTY_REF(PROP_LOCAL_POSITION, LocalPosition, localPosition, vec3, ENTITY_ITEM_ZERO_VEC3);
|
||||
DEFINE_PROPERTY_REF(PROP_LOCAL_ROTATION, LocalRotation, localRotation, quat, ENTITY_ITEM_DEFAULT_ROTATION);
|
||||
DEFINE_PROPERTY_REF(PROP_LOCAL_VELOCITY, LocalVelocity, localVelocity, vec3, ENTITY_ITEM_ZERO_VEC3);
|
||||
DEFINE_PROPERTY_REF(PROP_LOCAL_ANGULAR_VELOCITY, LocalAngularVelocity, localAngularVelocity, vec3, ENTITY_ITEM_ZERO_VEC3);
|
||||
DEFINE_PROPERTY_REF(PROP_LOCAL_DIMENSIONS, LocalDimensions, localDimensions, vec3, ENTITY_ITEM_ZERO_VEC3);
|
||||
|
||||
DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector<bool>, QVector<bool>());
|
||||
DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector<glm::quat>, QVector<glm::quat>());
|
||||
|
@ -339,7 +339,7 @@ public:
|
|||
void clearSimulationOwner();
|
||||
void setSimulationOwner(const QUuid& id, uint8_t priority);
|
||||
void setSimulationOwner(const QByteArray& data);
|
||||
void promoteSimulationPriority(uint8_t priority) { _simulationOwner.promotePriority(priority); }
|
||||
void setSimulationPriority(uint8_t priority) { _simulationOwner.setPriority(priority); }
|
||||
|
||||
void setActionDataDirty() { _actionDataChanged = true; }
|
||||
|
||||
|
|
|
@ -185,9 +185,6 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const AACube& v) { retu
|
|||
properties.setProperty(#P, V); \
|
||||
}
|
||||
|
||||
typedef glm::vec2 glmVec2;
|
||||
typedef glm::vec3 glmVec3;
|
||||
typedef glm::quat glmQuat;
|
||||
typedef QVector<glm::vec3> qVectorVec3;
|
||||
typedef QVector<glm::quat> qVectorQuat;
|
||||
typedef QVector<bool> qVectorBool;
|
||||
|
@ -224,7 +221,7 @@ inline QByteArray QByteArray_convertFromScriptValue(const QScriptValue& v, bool&
|
|||
return QByteArray::fromBase64(b64.toUtf8());
|
||||
}
|
||||
|
||||
inline glmVec2 glmVec2_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
|
||||
inline glm::vec2 vec2_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
|
||||
isValid = false; /// assume it can't be converted
|
||||
QScriptValue x = v.property("x");
|
||||
QScriptValue y = v.property("y");
|
||||
|
@ -241,11 +238,20 @@ inline glmVec2 glmVec2_convertFromScriptValue(const QScriptValue& v, bool& isVal
|
|||
return glm::vec2(0);
|
||||
}
|
||||
|
||||
inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
|
||||
inline glm::vec3 vec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
|
||||
isValid = false; /// assume it can't be converted
|
||||
QScriptValue x = v.property("x");
|
||||
QScriptValue y = v.property("y");
|
||||
QScriptValue z = v.property("z");
|
||||
if (!x.isValid()) {
|
||||
x = v.property("red");
|
||||
}
|
||||
if (!y.isValid()) {
|
||||
y = v.property("green");
|
||||
}
|
||||
if (!z.isValid()) {
|
||||
z = v.property("blue");
|
||||
}
|
||||
if (x.isValid() && y.isValid() && z.isValid()) {
|
||||
glm::vec3 newValue(0);
|
||||
newValue.x = x.toVariant().toFloat();
|
||||
|
@ -288,7 +294,7 @@ inline qVectorBool qVectorBool_convertFromScriptValue(const QScriptValue& v, boo
|
|||
return qVectorBoolFromScriptValue(v);
|
||||
}
|
||||
|
||||
inline glmQuat glmQuat_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
|
||||
inline glm::quat quat_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
|
||||
isValid = false; /// assume it can't be converted
|
||||
QScriptValue x = v.property("x");
|
||||
QScriptValue y = v.property("y");
|
||||
|
@ -317,6 +323,15 @@ inline xColor xColor_convertFromScriptValue(const QScriptValue& v, bool& isValid
|
|||
QScriptValue r = v.property("red");
|
||||
QScriptValue g = v.property("green");
|
||||
QScriptValue b = v.property("blue");
|
||||
if (!r.isValid()) {
|
||||
r = v.property("x");
|
||||
}
|
||||
if (!g.isValid()) {
|
||||
g = v.property("y");
|
||||
}
|
||||
if (!b.isValid()) {
|
||||
b = v.property("z");
|
||||
}
|
||||
if (r.isValid() && g.isValid() && b.isValid()) {
|
||||
newValue.red = r.toVariant().toInt();
|
||||
newValue.green = g.toVariant().toInt();
|
||||
|
|
|
@ -290,7 +290,7 @@ bool EntityScriptingInterface::addLocalEntityCopy(EntityItemProperties& properti
|
|||
|
||||
entity->setLastBroadcast(usecTimestampNow());
|
||||
// since we're creating this object we will immediately volunteer to own its simulation
|
||||
entity->flagForOwnershipBid(VOLUNTEER_SIMULATION_PRIORITY);
|
||||
entity->setScriptSimulationPriority(VOLUNTEER_SIMULATION_PRIORITY);
|
||||
properties.setLastEdited(entity->getLastEdited());
|
||||
} else {
|
||||
qCDebug(entities) << "script failed to add new Entity to local Octree";
|
||||
|
@ -494,7 +494,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
|
|||
} else {
|
||||
// we make a bid for simulation ownership
|
||||
properties.setSimulationOwner(myNodeID, SCRIPT_POKE_SIMULATION_PRIORITY);
|
||||
entity->flagForOwnershipBid(SCRIPT_POKE_SIMULATION_PRIORITY);
|
||||
entity->setScriptSimulationPriority(SCRIPT_POKE_SIMULATION_PRIORITY);
|
||||
}
|
||||
}
|
||||
if (properties.queryAACubeRelatedPropertyChanged()) {
|
||||
|
@ -739,15 +739,15 @@ QVector<QUuid> EntityScriptingInterface::findEntitiesInFrustum(QVariantMap frust
|
|||
|
||||
const QString POSITION_PROPERTY = "position";
|
||||
bool positionOK = frustum.contains(POSITION_PROPERTY);
|
||||
glm::vec3 position = positionOK ? qMapToGlmVec3(frustum[POSITION_PROPERTY]) : glm::vec3();
|
||||
glm::vec3 position = positionOK ? qMapToVec3(frustum[POSITION_PROPERTY]) : glm::vec3();
|
||||
|
||||
const QString ORIENTATION_PROPERTY = "orientation";
|
||||
bool orientationOK = frustum.contains(ORIENTATION_PROPERTY);
|
||||
glm::quat orientation = orientationOK ? qMapToGlmQuat(frustum[ORIENTATION_PROPERTY]) : glm::quat();
|
||||
glm::quat orientation = orientationOK ? qMapToQuat(frustum[ORIENTATION_PROPERTY]) : glm::quat();
|
||||
|
||||
const QString PROJECTION_PROPERTY = "projection";
|
||||
bool projectionOK = frustum.contains(PROJECTION_PROPERTY);
|
||||
glm::mat4 projection = projectionOK ? qMapToGlmMat4(frustum[PROJECTION_PROPERTY]) : glm::mat4();
|
||||
glm::mat4 projection = projectionOK ? qMapToMat4(frustum[PROJECTION_PROPERTY]) : glm::mat4();
|
||||
|
||||
const QString CENTER_RADIUS_PROPERTY = "centerRadius";
|
||||
bool centerRadiusOK = frustum.contains(CENTER_RADIUS_PROPERTY);
|
||||
|
@ -1363,7 +1363,7 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString,
|
|||
}
|
||||
action->setIsMine(true);
|
||||
success = entity->addAction(simulation, action);
|
||||
entity->flagForOwnershipBid(SCRIPT_GRAB_SIMULATION_PRIORITY);
|
||||
entity->setScriptSimulationPriority(SCRIPT_GRAB_SIMULATION_PRIORITY);
|
||||
return false; // Physics will cause a packet to be sent, so don't send from here.
|
||||
});
|
||||
if (success) {
|
||||
|
@ -1379,7 +1379,7 @@ bool EntityScriptingInterface::updateAction(const QUuid& entityID, const QUuid&
|
|||
return actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) {
|
||||
bool success = entity->updateAction(simulation, actionID, arguments);
|
||||
if (success) {
|
||||
entity->flagForOwnershipBid(SCRIPT_GRAB_SIMULATION_PRIORITY);
|
||||
entity->setScriptSimulationPriority(SCRIPT_GRAB_SIMULATION_PRIORITY);
|
||||
}
|
||||
return success;
|
||||
});
|
||||
|
@ -1393,7 +1393,7 @@ bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid&
|
|||
success = entity->removeAction(simulation, actionID);
|
||||
if (success) {
|
||||
// reduce from grab to poke
|
||||
entity->flagForOwnershipBid(SCRIPT_POKE_SIMULATION_PRIORITY);
|
||||
entity->setScriptSimulationPriority(SCRIPT_POKE_SIMULATION_PRIORITY);
|
||||
}
|
||||
return false; // Physics will cause a packet to be sent, so don't send from here.
|
||||
});
|
||||
|
|
|
@ -31,6 +31,7 @@ void EntitySimulation::setEntityTree(EntityTreePointer tree) {
|
|||
void EntitySimulation::updateEntities() {
|
||||
QMutexLocker lock(&_mutex);
|
||||
uint64_t now = usecTimestampNow();
|
||||
PerformanceTimer perfTimer("EntitySimulation::updateEntities");
|
||||
|
||||
// these methods may accumulate entries in _entitiesToBeDeleted
|
||||
expireMortalEntities(now);
|
||||
|
|
|
@ -97,6 +97,7 @@ void EntityTree::eraseAllOctreeElements(bool createNewRoot) {
|
|||
if (_simulation) {
|
||||
_simulation->clearEntities();
|
||||
}
|
||||
_staleProxies.clear();
|
||||
QHash<EntityItemID, EntityItemPointer> localMap;
|
||||
localMap.swap(_entityMap);
|
||||
this->withWriteLock([&] {
|
||||
|
@ -276,10 +277,11 @@ void EntityTree::postAddEntity(EntityItemPointer entity) {
|
|||
}
|
||||
|
||||
_isDirty = true;
|
||||
emit addingEntity(entity->getEntityItemID());
|
||||
|
||||
// find and hook up any entities with this entity as a (previously) missing parent
|
||||
fixupNeedsParentFixups();
|
||||
|
||||
emit addingEntity(entity->getEntityItemID());
|
||||
}
|
||||
|
||||
bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties, const SharedNodePointer& senderNode) {
|
||||
|
@ -359,21 +361,34 @@ bool EntityTree::updateEntity(EntityItemPointer entity, const EntityItemProperti
|
|||
// the sender is trying to take or continue ownership
|
||||
if (entity->getSimulatorID().isNull()) {
|
||||
// the sender is taking ownership
|
||||
properties.promoteSimulationPriority(RECRUIT_SIMULATION_PRIORITY);
|
||||
if (properties.getSimulationOwner().getPriority() == VOLUNTEER_SIMULATION_PRIORITY) {
|
||||
// the entity-server always promotes VOLUNTEER to RECRUIT to avoid ownership thrash
|
||||
// when dynamic objects first activate and multiple participants bid simultaneously
|
||||
properties.setSimulationPriority(RECRUIT_SIMULATION_PRIORITY);
|
||||
}
|
||||
simulationBlocked = false;
|
||||
} else if (entity->getSimulatorID() == senderID) {
|
||||
// the sender is asserting ownership, maybe changing priority
|
||||
simulationBlocked = false;
|
||||
// the entity-server always promotes VOLUNTEER to RECRUIT to avoid ownership thrash
|
||||
// when dynamic objects first activate and multiple participants bid simultaneously
|
||||
if (properties.getSimulationOwner().getPriority() == VOLUNTEER_SIMULATION_PRIORITY) {
|
||||
properties.setSimulationPriority(RECRUIT_SIMULATION_PRIORITY);
|
||||
}
|
||||
} else {
|
||||
// the sender is trying to steal ownership from another simulator
|
||||
// so we apply the rules for ownership change:
|
||||
// (1) higher priority wins
|
||||
// (2) equal priority wins if ownership filter has expired except...
|
||||
// (2) equal priority wins if ownership filter has expired
|
||||
// (3) VOLUNTEER priority is promoted to RECRUIT
|
||||
uint8_t oldPriority = entity->getSimulationPriority();
|
||||
uint8_t newPriority = properties.getSimulationOwner().getPriority();
|
||||
if (newPriority > oldPriority ||
|
||||
(newPriority == oldPriority && properties.getSimulationOwner().hasExpired())) {
|
||||
simulationBlocked = false;
|
||||
if (properties.getSimulationOwner().getPriority() == VOLUNTEER_SIMULATION_PRIORITY) {
|
||||
properties.setSimulationPriority(RECRUIT_SIMULATION_PRIORITY);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!simulationBlocked) {
|
||||
|
@ -391,6 +406,7 @@ bool EntityTree::updateEntity(EntityItemPointer entity, const EntityItemProperti
|
|||
}
|
||||
if (simulationBlocked) {
|
||||
// squash ownership and physics-related changes.
|
||||
// TODO? replace these eight calls with just one?
|
||||
properties.setSimulationOwnerChanged(false);
|
||||
properties.setPositionChanged(false);
|
||||
properties.setRotationChanged(false);
|
||||
|
@ -729,6 +745,12 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator)
|
|||
if (theEntity->isSimulated()) {
|
||||
_simulation->prepareEntityForDelete(theEntity);
|
||||
}
|
||||
|
||||
// keep a record of valid stale spaceIndices so they can be removed from the Space
|
||||
int32_t spaceIndex = theEntity->getSpaceIndex();
|
||||
if (spaceIndex != -1) {
|
||||
_staleProxies.push_back(spaceIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1853,6 +1875,7 @@ void EntityTree::addToNeedsParentFixupList(EntityItemPointer entity) {
|
|||
|
||||
void EntityTree::update(bool simulate) {
|
||||
PROFILE_RANGE(simulation_physics, "UpdateTree");
|
||||
PerformanceTimer perfTimer("updateTree");
|
||||
withWriteLock([&] {
|
||||
fixupNeedsParentFixups();
|
||||
if (simulate && _simulation) {
|
||||
|
|
|
@ -274,6 +274,8 @@ public:
|
|||
|
||||
void setMyAvatar(std::shared_ptr<AvatarData> myAvatar) { _myAvatar = myAvatar; }
|
||||
|
||||
void swapStaleProxies(std::vector<int>& proxies) { proxies.swap(_staleProxies); }
|
||||
|
||||
void setIsServerlessMode(bool value) { _serverlessDomain = value; }
|
||||
bool isServerlessMode() const { return _serverlessDomain; }
|
||||
|
||||
|
@ -408,6 +410,8 @@ private:
|
|||
static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToOverlayOperator;
|
||||
static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromOverlayOperator;
|
||||
|
||||
std::vector<int32_t> _staleProxies;
|
||||
|
||||
bool _serverlessDomain { false };
|
||||
|
||||
std::map<QString, QString> _namedPaths;
|
||||
|
|
|
@ -214,7 +214,7 @@ EntityItemID EntityTreeElement::findDetailedRayIntersection(const glm::vec3& ori
|
|||
glm::mat4 entityToWorldMatrix = translation * rotation;
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
|
||||
glm::vec3 dimensions = entity->getScaledDimensions();
|
||||
glm::vec3 dimensions = entity->getRaycastDimensions();
|
||||
glm::vec3 registrationPoint = entity->getRegistrationPoint();
|
||||
glm::vec3 corner = -(dimensions * registrationPoint);
|
||||
|
||||
|
@ -312,7 +312,7 @@ void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searc
|
|||
glm::vec3 penetration;
|
||||
if (!success || entityBox.findSpherePenetration(searchPosition, searchRadius, penetration)) {
|
||||
|
||||
glm::vec3 dimensions = entity->getScaledDimensions();
|
||||
glm::vec3 dimensions = entity->getRaycastDimensions();
|
||||
|
||||
// FIXME - consider allowing the entity to determine penetration so that
|
||||
// entities could presumably dull actuall hull testing if they wanted to
|
||||
|
|
|
@ -35,13 +35,13 @@ void KeyLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desired
|
|||
void KeyLightPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) {
|
||||
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, color, xColor, setColor);
|
||||
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, intensity, float, setIntensity);
|
||||
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, direction, glmVec3, setDirection);
|
||||
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, direction, vec3, setDirection);
|
||||
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, castShadows, bool, setCastShadows);
|
||||
|
||||
// legacy property support
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightColor, xColor, setColor, getColor);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightIntensity, float, setIntensity, getIntensity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightDirection, glmVec3, setDirection, getDirection);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightDirection, vec3, setDirection, getDirection);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightCastShadows, bool, setCastShadows, getCastShadows);
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,8 @@ uint64_t Properties::emitIntervalUsecs() const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
const xColor ParticleEffectEntityItem::DEFAULT_XCOLOR = xColor(static_cast<unsigned char>(DEFAULT_COLOR.r), static_cast<unsigned char>(DEFAULT_COLOR.g), static_cast<unsigned char>(DEFAULT_COLOR.b));
|
||||
const xColor ParticleEffectEntityItem::DEFAULT_XCOLOR_SPREAD = xColor(static_cast<unsigned char>(DEFAULT_COLOR_SPREAD.r), static_cast<unsigned char>(DEFAULT_COLOR_SPREAD.g), static_cast<unsigned char>(DEFAULT_COLOR_SPREAD.b));
|
||||
|
||||
EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
EntityItemPointer entity(new ParticleEffectEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); });
|
||||
|
@ -152,18 +154,6 @@ EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID
|
|||
return entity;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void ParticleEffectEntityItem::checkValid() {
|
||||
bool result;
|
||||
withReadLock([&] {
|
||||
result = _particleProperties.valid();
|
||||
});
|
||||
if (!result) {
|
||||
qCWarning(entities) << "Invalid particle properties";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// our non-pure virtual subclass for now...
|
||||
ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityItemID) :
|
||||
EntityItem(entityItemID)
|
||||
|
@ -180,15 +170,13 @@ void ParticleEffectEntityItem::setAlpha(float alpha) {
|
|||
|
||||
void ParticleEffectEntityItem::setAlphaStart(float alphaStart) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.alpha.range.start = glm::clamp(alphaStart, MINIMUM_ALPHA, MAXIMUM_ALPHA);
|
||||
_isAlphaStartInitialized = true;
|
||||
_particleProperties.alpha.range.start = glm::isnan(alphaStart) ? alphaStart : glm::clamp(alphaStart, MINIMUM_ALPHA, MAXIMUM_ALPHA);
|
||||
});
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setAlphaFinish(float alphaFinish) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.alpha.range.finish = glm::clamp(alphaFinish, MINIMUM_ALPHA, MAXIMUM_ALPHA);
|
||||
_isAlphaFinishInitialized = true;
|
||||
_particleProperties.alpha.range.finish = glm::isnan(alphaFinish) ? alphaFinish : glm::clamp(alphaFinish, MINIMUM_ALPHA, MAXIMUM_ALPHA);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -199,9 +187,13 @@ void ParticleEffectEntityItem::setAlphaSpread(float alphaSpread) {
|
|||
}
|
||||
|
||||
void ParticleEffectEntityItem::setLifespan(float lifespan) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.lifespan = glm::clamp(lifespan, MINIMUM_LIFESPAN, MAXIMUM_LIFESPAN);
|
||||
});
|
||||
lifespan = glm::clamp(lifespan, MINIMUM_LIFESPAN, MAXIMUM_LIFESPAN);
|
||||
if (lifespan != _particleProperties.lifespan) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.lifespan = lifespan;
|
||||
});
|
||||
computeAndUpdateDimensions();
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setEmitRate(float emitRate) {
|
||||
|
@ -232,10 +224,12 @@ void ParticleEffectEntityItem::setSpeedSpread(float speedSpread) {
|
|||
|
||||
void ParticleEffectEntityItem::setEmitOrientation(const glm::quat& emitOrientation_) {
|
||||
auto emitOrientation = glm::normalize(emitOrientation_);
|
||||
withWriteLock([&] {
|
||||
_particleProperties.emission.orientation = emitOrientation;
|
||||
});
|
||||
computeAndUpdateDimensions();
|
||||
if (emitOrientation != _particleProperties.emission.orientation) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.emission.orientation = emitOrientation;
|
||||
});
|
||||
computeAndUpdateDimensions();
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setEmitDimensions(const glm::vec3& emitDimensions_) {
|
||||
|
@ -281,15 +275,9 @@ void ParticleEffectEntityItem::setAzimuthFinish(float azimuthFinish) {
|
|||
void ParticleEffectEntityItem::setEmitAcceleration(const glm::vec3& emitAcceleration_) {
|
||||
auto emitAcceleration = glm::clamp(emitAcceleration_, vec3(MINIMUM_EMIT_ACCELERATION), vec3(MAXIMUM_EMIT_ACCELERATION));
|
||||
if (emitAcceleration != _particleProperties.emission.acceleration.target) {
|
||||
if (!_particleProperties.valid()) {
|
||||
qCWarning(entities) << "Bad particle data";
|
||||
}
|
||||
withWriteLock([&] {
|
||||
_particleProperties.emission.acceleration.target = emitAcceleration;
|
||||
});
|
||||
if (!_particleProperties.valid()) {
|
||||
qCWarning(entities) << "Bad particle data";
|
||||
}
|
||||
computeAndUpdateDimensions();
|
||||
}
|
||||
}
|
||||
|
@ -305,29 +293,43 @@ void ParticleEffectEntityItem::setAccelerationSpread(const glm::vec3& accelerati
|
|||
}
|
||||
|
||||
void ParticleEffectEntityItem::setParticleRadius(float particleRadius) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.radius.gradient.target = glm::clamp(particleRadius, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
|
||||
});
|
||||
particleRadius = glm::clamp(particleRadius, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
|
||||
if (particleRadius != _particleProperties.radius.gradient.target) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.radius.gradient.target = particleRadius;
|
||||
});
|
||||
computeAndUpdateDimensions();
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setRadiusStart(float radiusStart) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.radius.range.start = glm::clamp(radiusStart, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
|
||||
_isRadiusStartInitialized = true;
|
||||
});
|
||||
radiusStart = glm::isnan(radiusStart) ? radiusStart : glm::clamp(radiusStart, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
|
||||
if (radiusStart != _particleProperties.radius.range.start) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.radius.range.start = radiusStart;
|
||||
});
|
||||
computeAndUpdateDimensions();
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setRadiusFinish(float radiusFinish) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.radius.range.finish = glm::clamp(radiusFinish, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
|
||||
_isRadiusFinishInitialized = true;
|
||||
});
|
||||
radiusFinish = glm::isnan(radiusFinish) ? radiusFinish : glm::clamp(radiusFinish, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
|
||||
if (radiusFinish != _particleProperties.radius.range.finish) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.radius.range.finish = radiusFinish;
|
||||
});
|
||||
computeAndUpdateDimensions();
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setRadiusSpread(float radiusSpread) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.radius.gradient.spread = glm::clamp(radiusSpread, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
|
||||
});
|
||||
void ParticleEffectEntityItem::setRadiusSpread(float radiusSpread) {
|
||||
radiusSpread = glm::clamp(radiusSpread, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
|
||||
if (radiusSpread != _particleProperties.radius.gradient.spread) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.radius.gradient.spread = radiusSpread;
|
||||
});
|
||||
computeAndUpdateDimensions();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -342,8 +344,15 @@ void ParticleEffectEntityItem::computeAndUpdateDimensions() {
|
|||
glm::vec3 velocity = particleProperties.emission.speed.target * direction;
|
||||
glm::vec3 velocitySpread = particleProperties.emission.speed.spread * direction;
|
||||
glm::vec3 maxVelocity = glm::abs(velocity) + velocitySpread;
|
||||
glm::vec3 maxAccleration = glm::abs(_acceleration) + particleProperties.emission.acceleration.spread;
|
||||
glm::vec3 maxDistance = 0.5f * particleProperties.emission.dimensions + time * maxVelocity + (0.5f * time * time) * maxAccleration;
|
||||
glm::vec3 maxAccleration = glm::abs(particleProperties.emission.acceleration.target) + particleProperties.emission.acceleration.spread;
|
||||
float maxRadius = particleProperties.radius.gradient.target;
|
||||
if (!glm::isnan(particleProperties.radius.range.start)) {
|
||||
maxRadius = glm::max(maxRadius, particleProperties.radius.range.start);
|
||||
}
|
||||
if (!glm::isnan(particleProperties.radius.range.finish)) {
|
||||
maxRadius = glm::max(maxRadius, particleProperties.radius.range.finish);
|
||||
}
|
||||
glm::vec3 maxDistance = 0.5f * particleProperties.emission.dimensions + time * maxVelocity + (0.5f * time * time) * maxAccleration + vec3(maxRadius + particleProperties.radius.gradient.spread);
|
||||
if (isNaN(maxDistance)) {
|
||||
qCWarning(entities) << "Bad particle data";
|
||||
return;
|
||||
|
@ -390,7 +399,6 @@ EntityItemProperties ParticleEffectEntityItem::getProperties(EntityPropertyFlags
|
|||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitterShouldTrail, getEmitterShouldTrail);
|
||||
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
@ -441,18 +449,26 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert
|
|||
return somethingChanged;
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setColor(const rgbColor& value) {
|
||||
memcpy(_particleColorHack, value, sizeof(rgbColor));
|
||||
_particleProperties.color.gradient.target.red = value[RED_INDEX];
|
||||
_particleProperties.color.gradient.target.green = value[GREEN_INDEX];
|
||||
_particleProperties.color.gradient.target.blue = value[BLUE_INDEX];
|
||||
void ParticleEffectEntityItem::setColor(const vec3& value) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.color.gradient.target = value;
|
||||
});
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setColor(const xColor& value) {
|
||||
_particleProperties.color.gradient.target = value;
|
||||
_particleColorHack[RED_INDEX] = value.red;
|
||||
_particleColorHack[GREEN_INDEX] = value.green;
|
||||
_particleColorHack[BLUE_INDEX] = value.blue;
|
||||
withWriteLock([&] {
|
||||
_particleProperties.color.gradient.target.r = value.red;
|
||||
_particleProperties.color.gradient.target.g = value.green;
|
||||
_particleProperties.color.gradient.target.b = value.blue;
|
||||
});
|
||||
}
|
||||
|
||||
xColor ParticleEffectEntityItem::getXColor() const {
|
||||
xColor color;
|
||||
color.red = _particleProperties.color.gradient.target.r;
|
||||
color.green = _particleProperties.color.gradient.target.g;
|
||||
color.blue = _particleProperties.color.gradient.target.b;
|
||||
return color;
|
||||
}
|
||||
|
||||
int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
|
@ -463,15 +479,15 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
|
|||
int bytesRead = 0;
|
||||
const unsigned char* dataAt = data;
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor);
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR, xColor, setColor);
|
||||
READ_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, bool, setIsEmitting);
|
||||
READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType);
|
||||
READ_ENTITY_PROPERTY(PROP_MAX_PARTICLES, quint32, setMaxParticles);
|
||||
READ_ENTITY_PROPERTY(PROP_LIFESPAN, float, setLifespan);
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_RATE, float, setEmitRate);
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration);
|
||||
READ_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, vec3, setEmitAcceleration);
|
||||
READ_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, vec3, setAccelerationSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, setParticleRadius);
|
||||
READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures);
|
||||
|
||||
|
@ -480,8 +496,8 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
|
|||
READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish);
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_SPREAD, xColor, setColorSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_START, xColor, setColorStart);
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_FINISH, xColor, setColorFinish);
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_START, vec3, setColorStart);
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_FINISH, vec3, setColorFinish);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart);
|
||||
|
@ -489,8 +505,8 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
|
|||
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_SPEED, float, setEmitSpeed);
|
||||
READ_ENTITY_PROPERTY(PROP_SPEED_SPREAD, float, setSpeedSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, glm::quat, setEmitOrientation);
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, glm::vec3, setEmitDimensions);
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, quat, setEmitOrientation);
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, vec3, setEmitDimensions);
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_RADIUS_START, float, setEmitRadiusStart);
|
||||
READ_ENTITY_PROPERTY(PROP_POLAR_START, float, setPolarStart);
|
||||
READ_ENTITY_PROPERTY(PROP_POLAR_FINISH, float, setPolarFinish);
|
||||
|
@ -548,7 +564,7 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData,
|
|||
OctreeElement::AppendState& appendState) const {
|
||||
|
||||
bool successPropertyFits = true;
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR, getXColor());
|
||||
APPEND_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, getIsEmitting());
|
||||
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType());
|
||||
APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, getMaxParticles());
|
||||
|
@ -585,10 +601,10 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData,
|
|||
void ParticleEffectEntityItem::debugDump() const {
|
||||
quint64 now = usecTimestampNow();
|
||||
qCDebug(entities) << "PA EFFECT EntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||
qCDebug(entities) << " color:" <<
|
||||
_particleProperties.color.gradient.target.red << "," <<
|
||||
_particleProperties.color.gradient.target.green << "," <<
|
||||
_particleProperties.color.gradient.target.blue;
|
||||
qCDebug(entities) << " color:" <<
|
||||
_particleProperties.color.gradient.target.r << "," <<
|
||||
_particleProperties.color.gradient.target.g << "," <<
|
||||
_particleProperties.color.gradient.target.b;
|
||||
qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition());
|
||||
qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions());
|
||||
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
||||
|
@ -604,15 +620,9 @@ void ParticleEffectEntityItem::setShapeType(ShapeType type) {
|
|||
}
|
||||
|
||||
void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) {
|
||||
_particleProperties.maxParticles = glm::clamp(maxParticles, MINIMUM_MAX_PARTICLES, MAXIMUM_MAX_PARTICLES);
|
||||
}
|
||||
|
||||
QString ParticleEffectEntityItem::getTextures() const {
|
||||
QString result;
|
||||
withReadLock([&] {
|
||||
result = _particleProperties.textures;
|
||||
withWriteLock([&] {
|
||||
_particleProperties.maxParticles = glm::clamp(maxParticles, MINIMUM_MAX_PARTICLES, MAXIMUM_MAX_PARTICLES);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setTextures(const QString& textures) {
|
||||
|
@ -621,25 +631,69 @@ void ParticleEffectEntityItem::setTextures(const QString& textures) {
|
|||
});
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setColorStart(const vec3& colorStart) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.color.range.start = colorStart;
|
||||
});
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setColorFinish(const vec3& colorFinish) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.color.range.finish = colorFinish;
|
||||
});
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setColorSpread(const xColor& value) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.color.gradient.spread.r = value.red;
|
||||
_particleProperties.color.gradient.spread.g = value.green;
|
||||
_particleProperties.color.gradient.spread.b = value.blue;
|
||||
});
|
||||
}
|
||||
|
||||
xColor ParticleEffectEntityItem::getColorSpread() const {
|
||||
xColor color;
|
||||
color.red = _particleProperties.color.gradient.spread.r;
|
||||
color.green = _particleProperties.color.gradient.spread.g;
|
||||
color.blue = _particleProperties.color.gradient.spread.b;
|
||||
return color;
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setEmitterShouldTrail(bool emitterShouldTrail) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.emission.shouldTrail = emitterShouldTrail;
|
||||
});
|
||||
}
|
||||
|
||||
particle::Properties ParticleEffectEntityItem::getParticleProperties() const {
|
||||
particle::Properties result;
|
||||
withReadLock([&] {
|
||||
result = _particleProperties;
|
||||
});
|
||||
withReadLock([&] {
|
||||
result = _particleProperties;
|
||||
|
||||
// Special case the properties that get treated differently if they're unintialized
|
||||
result.color.range.start = getColorStart();
|
||||
result.color.range.finish = getColorFinish();
|
||||
result.alpha.range.start = getAlphaStart();
|
||||
result.alpha.range.finish = getAlphaFinish();
|
||||
result.radius.range.start = getRadiusStart();
|
||||
result.radius.range.finish = getRadiusFinish();
|
||||
// Special case the properties that get treated differently if they're unintialized
|
||||
if (glm::any(glm::isnan(result.color.range.start))) {
|
||||
result.color.range.start = getColor();
|
||||
}
|
||||
if (glm::any(glm::isnan(result.color.range.finish))) {
|
||||
result.color.range.finish = getColor();
|
||||
}
|
||||
if (glm::isnan(result.alpha.range.start)) {
|
||||
result.alpha.range.start = getAlpha();
|
||||
}
|
||||
if (glm::isnan(result.alpha.range.finish)) {
|
||||
result.alpha.range.finish = getAlpha();
|
||||
}
|
||||
if (glm::isnan(result.radius.range.start)) {
|
||||
result.radius.range.start = getParticleRadius();
|
||||
}
|
||||
if (glm::isnan(result.radius.range.finish)) {
|
||||
result.radius.range.finish = getParticleRadius();
|
||||
}
|
||||
});
|
||||
|
||||
if (!result.valid()) {
|
||||
qCWarning(entities) << "failed validation";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -19,12 +19,14 @@
|
|||
|
||||
namespace particle {
|
||||
static const float SCRIPT_MAXIMUM_PI = 3.1416f; // Round up so that reasonable property values work
|
||||
static const xColor DEFAULT_COLOR = { 255, 255, 255 };
|
||||
static const xColor DEFAULT_COLOR_SPREAD = { 0, 0, 0 };
|
||||
static const float UNINITIALIZED = NAN;
|
||||
static const vec3 DEFAULT_COLOR = { 255, 255, 255 };
|
||||
static const vec3 DEFAULT_COLOR_UNINITIALIZED = { UNINITIALIZED, UNINITIALIZED, UNINITIALIZED };
|
||||
static const vec3 DEFAULT_COLOR_SPREAD = { 0, 0, 0 };
|
||||
static const float DEFAULT_ALPHA = 1.0f;
|
||||
static const float DEFAULT_ALPHA_SPREAD = 0.0f;
|
||||
static const float DEFAULT_ALPHA_START = DEFAULT_ALPHA;
|
||||
static const float DEFAULT_ALPHA_FINISH = DEFAULT_ALPHA;
|
||||
static const float DEFAULT_ALPHA_START = UNINITIALIZED;
|
||||
static const float DEFAULT_ALPHA_FINISH = UNINITIALIZED;
|
||||
static const float MINIMUM_ALPHA = 0.0f;
|
||||
static const float MAXIMUM_ALPHA = 1.0f;
|
||||
static const quint32 DEFAULT_MAX_PARTICLES = 1000;
|
||||
|
@ -65,8 +67,8 @@ namespace particle {
|
|||
static const float MINIMUM_PARTICLE_RADIUS = 0.0f;
|
||||
static const float MAXIMUM_PARTICLE_RADIUS = (float)TREE_SCALE;
|
||||
static const float DEFAULT_RADIUS_SPREAD = 0.0f;
|
||||
static const float DEFAULT_RADIUS_START = DEFAULT_PARTICLE_RADIUS;
|
||||
static const float DEFAULT_RADIUS_FINISH = DEFAULT_PARTICLE_RADIUS;
|
||||
static const float DEFAULT_RADIUS_START = UNINITIALIZED;
|
||||
static const float DEFAULT_RADIUS_FINISH = UNINITIALIZED;
|
||||
static const QString DEFAULT_TEXTURES = "";
|
||||
static const bool DEFAULT_EMITTER_SHOULD_TRAIL = false;
|
||||
|
||||
|
@ -145,12 +147,12 @@ namespace particle {
|
|||
};
|
||||
|
||||
struct Properties {
|
||||
RangeGradient<xColor> color{ DEFAULT_COLOR, DEFAULT_COLOR, DEFAULT_COLOR, DEFAULT_COLOR_SPREAD };
|
||||
RangeGradient<float> alpha{ DEFAULT_ALPHA, DEFAULT_ALPHA_START, DEFAULT_ALPHA_FINISH, DEFAULT_ALPHA_SPREAD };
|
||||
float radiusStart{ DEFAULT_EMIT_RADIUS_START };
|
||||
RangeGradient<float> radius{ DEFAULT_PARTICLE_RADIUS, DEFAULT_RADIUS_START, DEFAULT_RADIUS_FINISH, DEFAULT_RADIUS_SPREAD };
|
||||
float lifespan{ DEFAULT_LIFESPAN };
|
||||
uint32_t maxParticles{ DEFAULT_MAX_PARTICLES };
|
||||
RangeGradient<vec3> color { DEFAULT_COLOR, DEFAULT_COLOR_UNINITIALIZED, DEFAULT_COLOR_UNINITIALIZED, DEFAULT_COLOR_SPREAD };
|
||||
RangeGradient<float> alpha { DEFAULT_ALPHA, DEFAULT_ALPHA_START, DEFAULT_ALPHA_FINISH, DEFAULT_ALPHA_SPREAD };
|
||||
float radiusStart { DEFAULT_EMIT_RADIUS_START };
|
||||
RangeGradient<float> radius { DEFAULT_PARTICLE_RADIUS, DEFAULT_RADIUS_START, DEFAULT_RADIUS_FINISH, DEFAULT_RADIUS_SPREAD };
|
||||
float lifespan { DEFAULT_LIFESPAN };
|
||||
uint32_t maxParticles { DEFAULT_MAX_PARTICLES };
|
||||
EmitProperties emission;
|
||||
Range<float> polar { DEFAULT_POLAR_START, DEFAULT_POLAR_FINISH };
|
||||
Range<float> azimuth { DEFAULT_AZIMUTH_START, DEFAULT_AZIMUTH_FINISH };
|
||||
|
@ -176,10 +178,10 @@ namespace particle {
|
|||
return *this;
|
||||
}
|
||||
|
||||
glm::vec4 getColorStart() const { return glm::vec4(ColorUtils::sRGBToLinearVec3(toGlm(color.range.start)), alpha.range.start); }
|
||||
glm::vec4 getColorMiddle() const { return glm::vec4(ColorUtils::sRGBToLinearVec3(toGlm(color.gradient.target)), alpha.gradient.target); }
|
||||
glm::vec4 getColorFinish() const { return glm::vec4(ColorUtils::sRGBToLinearVec3(toGlm(color.range.finish)), alpha.range.finish); }
|
||||
glm::vec4 getColorSpread() const { return glm::vec4(ColorUtils::sRGBToLinearVec3(toGlm(color.gradient.spread)), alpha.gradient.spread); }
|
||||
vec4 getColorStart() const { return vec4(ColorUtils::sRGBToLinearVec3(color.range.start / 255.0f), alpha.range.start); }
|
||||
vec4 getColorMiddle() const { return vec4(ColorUtils::sRGBToLinearVec3(color.gradient.target / 255.0f), alpha.gradient.target); }
|
||||
vec4 getColorFinish() const { return vec4(ColorUtils::sRGBToLinearVec3(color.range.finish / 255.0f), alpha.range.finish); }
|
||||
vec4 getColorSpread() const { return vec4(ColorUtils::sRGBToLinearVec3(color.gradient.spread / 255.0f), alpha.gradient.spread); }
|
||||
};
|
||||
} // namespace particles
|
||||
|
||||
|
@ -215,37 +217,29 @@ public:
|
|||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
||||
bool& somethingChanged) override;
|
||||
|
||||
const rgbColor& getColor() const { return _particleColorHack; }
|
||||
xColor getXColor() const { return _particleProperties.color.gradient.target; }
|
||||
glm::vec3 getColorRGB() const { return ColorUtils::sRGBToLinearVec3(toGlm(getXColor())); }
|
||||
xColor getXColor() const;
|
||||
vec3 getColor() const { return _particleProperties.color.gradient.target; }
|
||||
|
||||
void setColor(const rgbColor& value);
|
||||
void setColor(const vec3& value);
|
||||
void setColor(const xColor& value);
|
||||
|
||||
bool _isColorStartInitialized = false;
|
||||
void setColorStart(const xColor& colorStart) { _particleProperties.color.range.start = colorStart; _isColorStartInitialized = true; }
|
||||
xColor getColorStart() const { return _isColorStartInitialized ? _particleProperties.color.range.start : getXColor(); }
|
||||
glm::vec3 getColorStartRGB() const { return _isColorStartInitialized ? ColorUtils::sRGBToLinearVec3(toGlm(_particleProperties.color.range.start)) : getColorRGB(); }
|
||||
void setColorStart(const vec3& colorStart);
|
||||
vec3 getColorStart() const { return _particleProperties.color.range.start; }
|
||||
|
||||
bool _isColorFinishInitialized = false;
|
||||
void setColorFinish(const xColor& colorFinish) { _particleProperties.color.range.finish = colorFinish; _isColorFinishInitialized = true; }
|
||||
xColor getColorFinish() const { return _isColorFinishInitialized ? _particleProperties.color.range.finish : getXColor(); }
|
||||
glm::vec3 getColorFinishRGB() const { return _isColorFinishInitialized ? ColorUtils::sRGBToLinearVec3(toGlm(_particleProperties.color.range.finish)) : getColorRGB(); }
|
||||
void setColorFinish(const vec3& colorFinish);
|
||||
vec3 getColorFinish() const { return _particleProperties.color.range.finish; }
|
||||
|
||||
void setColorSpread(const xColor& colorSpread) { _particleProperties.color.gradient.spread = colorSpread; }
|
||||
xColor getColorSpread() const { return _particleProperties.color.gradient.spread; }
|
||||
glm::vec3 getColorSpreadRGB() const { return ColorUtils::sRGBToLinearVec3(toGlm(_particleProperties.color.gradient.spread)); }
|
||||
void setColorSpread(const xColor& colorSpread);
|
||||
xColor getColorSpread() const;
|
||||
|
||||
void setAlpha(float alpha);
|
||||
float getAlpha() const { return _particleProperties.alpha.gradient.target; }
|
||||
|
||||
bool _isAlphaStartInitialized = false;
|
||||
void setAlphaStart(float alphaStart);
|
||||
float getAlphaStart() const { return _isAlphaStartInitialized ? _particleProperties.alpha.range.start : _particleProperties.alpha.gradient.target; }
|
||||
float getAlphaStart() const { return _particleProperties.alpha.range.start; }
|
||||
|
||||
bool _isAlphaFinishInitialized = false;
|
||||
void setAlphaFinish(float alphaFinish);
|
||||
float getAlphaFinish() const { return _isAlphaFinishInitialized ? _particleProperties.alpha.range.finish : _particleProperties.alpha.gradient.target; }
|
||||
float getAlphaFinish() const { return _particleProperties.alpha.range.finish; }
|
||||
|
||||
void setAlphaSpread(float alphaSpread);
|
||||
float getAlphaSpread() const { return _particleProperties.alpha.gradient.spread; }
|
||||
|
@ -303,31 +297,31 @@ public:
|
|||
void setParticleRadius(float particleRadius);
|
||||
float getParticleRadius() const { return _particleProperties.radius.gradient.target; }
|
||||
|
||||
bool _isRadiusStartInitialized = false;
|
||||
void setRadiusStart(float radiusStart);
|
||||
float getRadiusStart() const { return _isRadiusStartInitialized ? _particleProperties.radius.range.start : _particleProperties.radius.gradient.target; }
|
||||
float getRadiusStart() const { return _particleProperties.radius.range.start; }
|
||||
|
||||
bool _isRadiusFinishInitialized = false;
|
||||
void setRadiusFinish(float radiusFinish);
|
||||
float getRadiusFinish() const { return _isRadiusFinishInitialized ? _particleProperties.radius.range.finish : _particleProperties.radius.gradient.target; }
|
||||
float getRadiusFinish() const { return _particleProperties.radius.range.finish; }
|
||||
|
||||
void setRadiusSpread(float radiusSpread);
|
||||
float getRadiusSpread() const { return _particleProperties.radius.gradient.spread; }
|
||||
|
||||
void computeAndUpdateDimensions();
|
||||
|
||||
QString getTextures() const;
|
||||
void setTextures(const QString& textures);
|
||||
QString getTextures() const { return _particleProperties.textures; }
|
||||
|
||||
bool getEmitterShouldTrail() const { return _particleProperties.emission.shouldTrail; }
|
||||
void setEmitterShouldTrail(bool emitterShouldTrail) { _particleProperties.emission.shouldTrail = emitterShouldTrail; }
|
||||
void setEmitterShouldTrail(bool emitterShouldTrail);
|
||||
|
||||
virtual bool supportsDetailedRayIntersection() const override { return false; }
|
||||
|
||||
particle::Properties getParticleProperties() const;
|
||||
particle::Properties getParticleProperties() const;
|
||||
|
||||
static const xColor DEFAULT_XCOLOR;
|
||||
static const xColor DEFAULT_XCOLOR_SPREAD;
|
||||
|
||||
protected:
|
||||
rgbColor _particleColorHack;
|
||||
particle::Properties _particleProperties;
|
||||
bool _isEmitting { true };
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue