mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 01:24:03 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into autoTesterUpdate
This commit is contained in:
commit
6311f63f42
38 changed files with 509 additions and 158 deletions
|
@ -27,7 +27,8 @@ android {
|
|||
'-DRELEASE_TYPE=' + RELEASE_TYPE,
|
||||
'-DSTABLE_BUILD=' + STABLE_BUILD,
|
||||
'-DDISABLE_QML=OFF',
|
||||
'-DDISABLE_KTX_CACHE=OFF'
|
||||
'-DDISABLE_KTX_CACHE=OFF',
|
||||
'-DUSE_BREAKPAD=' + (project.hasProperty("BACKTRACE_URL") && project.hasProperty("BACKTRACE_TOKEN") ? 'ON' : 'OFF');
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
|
@ -46,6 +47,10 @@ android {
|
|||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
buildConfigField "String", "BACKTRACE_URL", "\"" + (project.hasProperty("BACKTRACE_URL") ? BACKTRACE_URL : '') + "\""
|
||||
buildConfigField "String", "BACKTRACE_TOKEN", "\"" + (project.hasProperty("BACKTRACE_TOKEN") ? BACKTRACE_TOKEN : '') + "\""
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
|
@ -53,6 +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 : '') + "\""
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -67,6 +67,12 @@
|
|||
android:name=".SplashActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.AppCompat.Translucent.NoActionBar" />
|
||||
|
||||
<service
|
||||
android:name=".BreakpadUploaderService"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:process=":breakpad_uploader"/>
|
||||
</application>
|
||||
|
||||
<uses-feature android:name="android.software.vr.mode" android:required="true"/>
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
package io.highfidelity.hifiinterface;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.FileObserver;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
public class BreakpadUploaderService extends Service {
|
||||
|
||||
private static final String ANNOTATIONS_JSON = "annotations.json";
|
||||
private static final String TAG = "Interface";
|
||||
public static final String EXT_DMP = "dmp";
|
||||
private static final long DUMP_DELAY = 5000;
|
||||
|
||||
private FileObserver fileObserver;
|
||||
|
||||
public BreakpadUploaderService() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
URL baseUrl;
|
||||
|
||||
baseUrl = getUrl();
|
||||
|
||||
if (baseUrl == null) {
|
||||
stopSelf();
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
new Thread(() -> {
|
||||
File[] matchingFiles = getFilesByExtension(getObbDir(), EXT_DMP);
|
||||
for (File file : matchingFiles) {
|
||||
uploadDumpAndDelete(file, baseUrl);
|
||||
}
|
||||
}).start();
|
||||
|
||||
fileObserver = new FileObserver(getObbDir().getPath()) {
|
||||
@Override
|
||||
public void onEvent(int event, String path) {
|
||||
if (path == null) {
|
||||
return;
|
||||
}
|
||||
if (FileObserver.CREATE == event && EXT_DMP.equals(getExtension(path))) {
|
||||
URL baseUrl = getUrl();
|
||||
if (baseUrl != null) {
|
||||
new Timer().schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
uploadDumpAndDelete(new File(getObbDir(), path), baseUrl);
|
||||
}
|
||||
}, DUMP_DELAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fileObserver.startWatching();
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
private URL getUrl() {
|
||||
String parameters = getAnnotationsAsUrlEncodedParameters();
|
||||
try {
|
||||
return new URL(BuildConfig.BACKTRACE_URL+ "/post?format=minidump&token=" + BuildConfig.BACKTRACE_TOKEN + (parameters.isEmpty() ? "" : ("&" + parameters)));
|
||||
} catch (MalformedURLException e) {
|
||||
Log.e(TAG, "Could not initialize Breakpad URL", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void uploadDumpAndDelete(File file, URL url) {
|
||||
int size = (int) file.length();
|
||||
byte[] bytes = new byte[size];
|
||||
try {
|
||||
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
|
||||
buf.read(bytes, 0, bytes.length);
|
||||
buf.close();
|
||||
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setDoOutput(true);
|
||||
urlConnection.setChunkedStreamingMode(0);
|
||||
|
||||
OutputStream ostream = urlConnection.getOutputStream();
|
||||
|
||||
OutputStream out = new BufferedOutputStream(ostream);
|
||||
out.write(bytes, 0, size);
|
||||
|
||||
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
|
||||
in.read();
|
||||
if (urlConnection.getResponseCode() == 200) {
|
||||
file.delete();
|
||||
}
|
||||
urlConnection.disconnect();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error uploading file " + file.getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private File[] getFilesByExtension(File dir, final String extension) {
|
||||
return dir.listFiles(pathName -> getExtension(pathName.getName()).equals(extension));
|
||||
}
|
||||
|
||||
private String getExtension(String fileName) {
|
||||
String extension = "";
|
||||
|
||||
int i = fileName.lastIndexOf('.');
|
||||
int p = Math.max(fileName.lastIndexOf('/'), fileName.lastIndexOf('\\'));
|
||||
|
||||
if (i > p) {
|
||||
extension = fileName.substring(i+1);
|
||||
}
|
||||
|
||||
return extension;
|
||||
}
|
||||
|
||||
|
||||
public String getAnnotationsAsUrlEncodedParameters() {
|
||||
String parameters = "";
|
||||
File annotationsFile = new File(getObbDir(), ANNOTATIONS_JSON);
|
||||
if (annotationsFile.exists()) {
|
||||
JsonParser parser = new JsonParser();
|
||||
try {
|
||||
JsonObject json = (JsonObject) parser.parse(new FileReader(annotationsFile));
|
||||
for (String k: json.keySet()) {
|
||||
if (!json.get(k).getAsString().isEmpty()) {
|
||||
String key = k.contains("/") ? k.substring(k.indexOf("/") + 1) : k;
|
||||
if (!parameters.isEmpty()) {
|
||||
parameters += "&";
|
||||
}
|
||||
parameters += URLEncoder.encode(key, "UTF-8") + "=" + URLEncoder.encode(json.get(k).getAsString(), "UTF-8");
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(TAG, "Error reading annotations file", e);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Log.e(TAG, "Error reading annotations file", e);
|
||||
}
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
}
|
|
@ -56,6 +56,8 @@ public class InterfaceActivity extends QtActivity {
|
|||
private AssetManager assetManager;
|
||||
|
||||
private static boolean inVrMode;
|
||||
|
||||
private boolean nativeEnterBackgroundCallEnqueued = false;
|
||||
// private GvrApi gvrApi;
|
||||
// Opaque native pointer to the Application C++ object.
|
||||
// This object is owned by the InterfaceActivity instance and passed to the native methods.
|
||||
|
@ -121,13 +123,18 @@ public class InterfaceActivity extends QtActivity {
|
|||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
nativeEnterBackground();
|
||||
if (super.isLoading) {
|
||||
nativeEnterBackgroundCallEnqueued = true;
|
||||
} else {
|
||||
nativeEnterBackground();
|
||||
}
|
||||
//gvrApi.pauseTracking();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
nativeEnterBackgroundCallEnqueued = false;
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
}
|
||||
|
||||
|
@ -256,6 +263,9 @@ public class InterfaceActivity extends QtActivity {
|
|||
|
||||
public void onAppLoadedComplete() {
|
||||
super.isLoading = false;
|
||||
if (nativeEnterBackgroundCallEnqueued) {
|
||||
nativeEnterBackground();
|
||||
}
|
||||
}
|
||||
|
||||
public void performHapticFeedback(int duration) {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package io.highfidelity.hifiinterface;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.app.Activity;
|
||||
|
||||
import android.content.DialogInterface;
|
||||
import android.app.AlertDialog;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
@ -24,20 +24,31 @@ public class PermissionChecker extends Activity {
|
|||
private static final int REQUEST_PERMISSIONS = 20;
|
||||
|
||||
private static final boolean CHOOSE_AVATAR_ON_STARTUP = false;
|
||||
private static final String TAG = "Interface";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Intent myIntent = new Intent(this, BreakpadUploaderService.class);
|
||||
startService(myIntent);
|
||||
if (CHOOSE_AVATAR_ON_STARTUP) {
|
||||
showMenu();
|
||||
}
|
||||
this.requestAppPermissions(new
|
||||
String[]{
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
Manifest.permission.RECORD_AUDIO,
|
||||
Manifest.permission.CAMERA}
|
||||
,2,REQUEST_PERMISSIONS);
|
||||
|
||||
File obbDir = getObbDir();
|
||||
if (!obbDir.exists()) {
|
||||
if (obbDir.mkdirs()) {
|
||||
Log.d(TAG, "Obb dir created");
|
||||
}
|
||||
}
|
||||
|
||||
requestAppPermissions(new
|
||||
String[]{
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
Manifest.permission.RECORD_AUDIO,
|
||||
Manifest.permission.CAMERA}
|
||||
,2,REQUEST_PERMISSIONS);
|
||||
|
||||
}
|
||||
|
||||
|
@ -124,6 +135,4 @@ public class PermissionChecker extends Activity {
|
|||
launchActivityWithPermissions();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -149,6 +149,13 @@ def packages = [
|
|||
file: 'etc2comp-patched-armv8-libcpp.tgz',
|
||||
versionId: 'bHhGECRAQR1vkpshBcK6ByNc1BQIM8gU',
|
||||
checksum: '14b02795d774457a33bbc60e00a786bc'
|
||||
],
|
||||
breakpad: [
|
||||
file: 'breakpad.zip',
|
||||
versionId: '2OwvCCZrF171wnte5T44AnjTYFhhJsGJ',
|
||||
checksum: 'a46062a3167dfedd4fb4916136e204d2',
|
||||
sharedLibFolder: 'lib',
|
||||
includeLibs: ['libbreakpad_client.a','libbreakpad.a']
|
||||
]
|
||||
]
|
||||
|
||||
|
@ -367,6 +374,7 @@ task verifyPolyvox(type: Verify) { def p = packages['polyvox']; src new File(bas
|
|||
task verifyTBB(type: Verify) { def p = packages['tbb']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
task verifyHifiAC(type: Verify) { def p = packages['hifiAC']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
task verifyEtc2Comp(type: Verify) { def p = packages['etc2comp']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
task verifyBreakpad(type: Verify) { def p = packages['breakpad']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
|
||||
task verifyDependencyDownloads(dependsOn: downloadDependencies) { }
|
||||
verifyDependencyDownloads.dependsOn verifyQt
|
||||
|
@ -378,6 +386,7 @@ verifyDependencyDownloads.dependsOn verifyPolyvox
|
|||
verifyDependencyDownloads.dependsOn verifyTBB
|
||||
verifyDependencyDownloads.dependsOn verifyHifiAC
|
||||
verifyDependencyDownloads.dependsOn verifyEtc2Comp
|
||||
verifyDependencyDownloads.dependsOn verifyBreakpad
|
||||
|
||||
task extractDependencies(dependsOn: verifyDependencyDownloads) {
|
||||
doLast {
|
||||
|
@ -615,4 +624,4 @@ task testElf (dependsOn: 'externalNativeBuildDebug') {
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
|
22
cmake/macros/TargetBreakpad.cmake
Normal file
22
cmake/macros/TargetBreakpad.cmake
Normal file
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# Copyright 2018 High Fidelity, Inc.
|
||||
# Created by Gabriel Calero & Cristian Duarte on 2018/03/13
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_BREAKPAD)
|
||||
if (ANDROID)
|
||||
set(INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/breakpad)
|
||||
set(BREAKPAD_INCLUDE_DIRS "${INSTALL_DIR}/include" CACHE TYPE INTERNAL)
|
||||
set(LIB_DIR ${INSTALL_DIR}/lib)
|
||||
list(APPEND BREAKPAD_LIBRARIES ${LIB_DIR}/libbreakpad_client.a)
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BREAKPAD_INCLUDE_DIRS})
|
||||
if (USE_BREAKPAD)
|
||||
add_definitions(-DHAS_BREAKPAD)
|
||||
endif()
|
||||
endif()
|
||||
target_link_libraries(${TARGET_NAME} ${BREAKPAD_LIBRARIES})
|
||||
endmacro()
|
||||
|
||||
|
|
@ -226,6 +226,7 @@ target_openssl()
|
|||
target_bullet()
|
||||
target_opengl()
|
||||
add_crashpad()
|
||||
target_breakpad()
|
||||
|
||||
# perform standard include and linking for found externals
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
|
|
|
@ -87,8 +87,8 @@ Column {
|
|||
description: description,
|
||||
online_users: data.details.connections || data.details.concurrency || 0,
|
||||
// Server currently doesn't give isStacked (undefined). Could give bool.
|
||||
drillDownToPlace: (data.isStacked === undefined) ? (data.action !== 'concurrency') : data.isStacked,
|
||||
isStacked: !!data.isStacked
|
||||
drillDownToPlace: data.is_stacked || (data.action === 'concurrency'),
|
||||
isStacked: !!data.is_stacked
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -150,8 +150,8 @@
|
|||
#include "audio/AudioScope.h"
|
||||
#include "avatar/AvatarManager.h"
|
||||
#include "avatar/MyHead.h"
|
||||
#include "CrashRecoveryHandler.h"
|
||||
#include "CrashHandler.h"
|
||||
#include "Crashpad.h"
|
||||
#include "devices/DdeFaceTracker.h"
|
||||
#include "DiscoverabilityManager.h"
|
||||
#include "GLCanvas.h"
|
||||
|
@ -791,7 +791,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
|
||||
bool previousSessionCrashed { false };
|
||||
if (!inTestMode) {
|
||||
previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt);
|
||||
previousSessionCrashed = CrashRecoveryHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt);
|
||||
}
|
||||
|
||||
// get dir to use for cache
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
// CrashHandler.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by David Rowe on 24 Aug 2015.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
// Created by Clement Brisset on 01/19/18.
|
||||
// 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
|
||||
|
@ -12,22 +12,10 @@
|
|||
#ifndef hifi_CrashHandler_h
|
||||
#define hifi_CrashHandler_h
|
||||
|
||||
#include <QString>
|
||||
#include <string>
|
||||
|
||||
class CrashHandler {
|
||||
bool startCrashHandler();
|
||||
void setCrashAnnotation(std::string name, std::string value);
|
||||
|
||||
public:
|
||||
static bool checkForResetSettings(bool wasLikelyCrash, bool suppressPrompt = false);
|
||||
|
||||
private:
|
||||
enum Action {
|
||||
DELETE_INTERFACE_INI,
|
||||
RETAIN_IMPORTANT_INFO,
|
||||
DO_NOTHING
|
||||
};
|
||||
|
||||
static Action promptUserForAction(bool showCrashMessage);
|
||||
static void handleCrash(Action action);
|
||||
};
|
||||
|
||||
#endif // hifi_CrashHandler_h
|
||||
#endif
|
70
interface/src/CrashHandler_Breakpad.cpp
Normal file
70
interface/src/CrashHandler_Breakpad.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// CrashHandler_Breakpad.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Clement Brisset on 01/19/18.
|
||||
// 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 "CrashHandler.h"
|
||||
|
||||
#if HAS_BREAKPAD
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <client/linux/handler/exception_handler.h>
|
||||
#include <client/linux/handler/minidump_descriptor.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMap>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtAndroidExtras/QAndroidJniObject>
|
||||
|
||||
#include <SettingHelpers.h>
|
||||
|
||||
google_breakpad::ExceptionHandler* gBreakpadHandler;
|
||||
|
||||
std::mutex annotationMutex;
|
||||
QMap<QString, QString> annotations;
|
||||
|
||||
static bool breakpad_dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) {
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
QString obbDir() {
|
||||
QAndroidJniObject mediaDir = QAndroidJniObject::callStaticObjectMethod("android/os/Environment", "getExternalStorageDirectory", "()Ljava/io/File;");
|
||||
QAndroidJniObject mediaPath = mediaDir.callObjectMethod( "getAbsolutePath", "()Ljava/lang/String;" );
|
||||
QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
|
||||
QAndroidJniObject package = activity.callObjectMethod("getPackageName", "()Ljava/lang/String;");
|
||||
QString dataAbsPath = mediaPath.toString()+"/Android/obb/" + package.toString();
|
||||
return dataAbsPath;
|
||||
}
|
||||
|
||||
bool startCrashHandler() {
|
||||
|
||||
gBreakpadHandler = new google_breakpad::ExceptionHandler(
|
||||
google_breakpad::MinidumpDescriptor(obbDir().toStdString()),
|
||||
nullptr, breakpad_dumpCallback, nullptr, true, -1);
|
||||
return true;
|
||||
}
|
||||
|
||||
void setCrashAnnotation(std::string name, std::string value) {
|
||||
std::lock_guard<std::mutex> guard(annotationMutex);
|
||||
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();
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Crashpad.cpp
|
||||
// CrashHandler_Crashpad.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Clement Brisset on 01/19/18.
|
||||
|
@ -9,7 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Crashpad.h"
|
||||
#include "CrashHandler.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
|
@ -117,14 +117,4 @@ void setCrashAnnotation(std::string name, std::string value) {
|
|||
crashpadAnnotations->SetKeyValue(name, value);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool startCrashHandler() {
|
||||
qDebug() << "No crash handler available.";
|
||||
return false;
|
||||
}
|
||||
|
||||
void setCrashAnnotation(std::string name, std::string value) {
|
||||
}
|
||||
|
||||
#endif
|
27
interface/src/CrashHandler_None.cpp
Normal file
27
interface/src/CrashHandler_None.cpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// CrashHandler_None.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Clement Brisset on 01/19/18.
|
||||
// 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 "CrashHandler.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <QDebug>
|
||||
|
||||
#if !defined(HAS_CRASHPAD) && !defined(HAS_BREAKPAD)
|
||||
|
||||
bool startCrashHandler() {
|
||||
qDebug() << "No crash handler available.";
|
||||
return false;
|
||||
}
|
||||
|
||||
void setCrashAnnotation(std::string name, std::string value) {
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// CrashHandler.cpp
|
||||
// CrashRecoveryHandler.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by David Rowe on 24 Aug 2015.
|
||||
|
@ -9,7 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "CrashHandler.h"
|
||||
#include "CrashRecoveryHandler.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDialog>
|
||||
|
@ -30,7 +30,7 @@
|
|||
#include <SettingHelpers.h>
|
||||
|
||||
|
||||
bool CrashHandler::checkForResetSettings(bool wasLikelyCrash, bool suppressPrompt) {
|
||||
bool CrashRecoveryHandler::checkForResetSettings(bool wasLikelyCrash, bool suppressPrompt) {
|
||||
QSettings::setDefaultFormat(JSON_FORMAT);
|
||||
QSettings settings;
|
||||
settings.beginGroup("Developer");
|
||||
|
@ -59,7 +59,7 @@ bool CrashHandler::checkForResetSettings(bool wasLikelyCrash, bool suppressPromp
|
|||
return wasLikelyCrash;
|
||||
}
|
||||
|
||||
CrashHandler::Action CrashHandler::promptUserForAction(bool showCrashMessage) {
|
||||
CrashRecoveryHandler::Action CrashRecoveryHandler::promptUserForAction(bool showCrashMessage) {
|
||||
QDialog crashDialog;
|
||||
QLabel* label;
|
||||
if (showCrashMessage) {
|
||||
|
@ -94,20 +94,20 @@ CrashHandler::Action CrashHandler::promptUserForAction(bool showCrashMessage) {
|
|||
|
||||
if (result == QDialog::Accepted) {
|
||||
if (option1->isChecked()) {
|
||||
return CrashHandler::DELETE_INTERFACE_INI;
|
||||
return CrashRecoveryHandler::DELETE_INTERFACE_INI;
|
||||
}
|
||||
if (option2->isChecked()) {
|
||||
return CrashHandler::RETAIN_IMPORTANT_INFO;
|
||||
return CrashRecoveryHandler::RETAIN_IMPORTANT_INFO;
|
||||
}
|
||||
}
|
||||
|
||||
// Dialog cancelled or "do nothing" option chosen
|
||||
return CrashHandler::DO_NOTHING;
|
||||
return CrashRecoveryHandler::DO_NOTHING;
|
||||
}
|
||||
|
||||
void CrashHandler::handleCrash(CrashHandler::Action action) {
|
||||
if (action != CrashHandler::DELETE_INTERFACE_INI && action != CrashHandler::RETAIN_IMPORTANT_INFO) {
|
||||
// CrashHandler::DO_NOTHING or unexpected value
|
||||
void CrashRecoveryHandler::handleCrash(CrashRecoveryHandler::Action action) {
|
||||
if (action != CrashRecoveryHandler::DELETE_INTERFACE_INI && action != CrashRecoveryHandler::RETAIN_IMPORTANT_INFO) {
|
||||
// CrashRecoveryHandler::DO_NOTHING or unexpected value
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,7 @@ void CrashHandler::handleCrash(CrashHandler::Action action) {
|
|||
QUrl address;
|
||||
bool tutorialComplete = false;
|
||||
|
||||
if (action == CrashHandler::RETAIN_IMPORTANT_INFO) {
|
||||
if (action == CrashRecoveryHandler::RETAIN_IMPORTANT_INFO) {
|
||||
// Read avatar info
|
||||
|
||||
// Location and orientation
|
||||
|
@ -151,7 +151,7 @@ void CrashHandler::handleCrash(CrashHandler::Action action) {
|
|||
settingsFile.remove();
|
||||
}
|
||||
|
||||
if (action == CrashHandler::RETAIN_IMPORTANT_INFO) {
|
||||
if (action == CrashRecoveryHandler::RETAIN_IMPORTANT_INFO) {
|
||||
// Write avatar info
|
||||
|
||||
// Location and orientation
|
33
interface/src/CrashRecoveryHandler.h
Normal file
33
interface/src/CrashRecoveryHandler.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// CrashRecoveryHandler.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by David Rowe on 24 Aug 2015.
|
||||
// Copyright 2015 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_CrashRecoveryHandler_h
|
||||
#define hifi_CrashRecoveryHandler_h
|
||||
|
||||
#include <QString>
|
||||
|
||||
class CrashRecoveryHandler {
|
||||
|
||||
public:
|
||||
static bool checkForResetSettings(bool wasLikelyCrash, bool suppressPrompt = false);
|
||||
|
||||
private:
|
||||
enum Action {
|
||||
DELETE_INTERFACE_INI,
|
||||
RETAIN_IMPORTANT_INFO,
|
||||
DO_NOTHING
|
||||
};
|
||||
|
||||
static Action promptUserForAction(bool showCrashMessage);
|
||||
static void handleCrash(Action action);
|
||||
};
|
||||
|
||||
#endif // hifi_CrashRecoveryHandler_h
|
|
@ -1,20 +0,0 @@
|
|||
//
|
||||
// Crashpad.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Clement Brisset on 01/19/18.
|
||||
// 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_Crashpad_h
|
||||
#define hifi_Crashpad_h
|
||||
|
||||
#include <string>
|
||||
|
||||
bool startCrashHandler();
|
||||
void setCrashAnnotation(std::string name, std::string value);
|
||||
|
||||
#endif // hifi_Crashpad_h
|
|
@ -23,7 +23,7 @@
|
|||
#include <UserActivityLogger.h>
|
||||
#include <UUID.h>
|
||||
|
||||
#include "Crashpad.h"
|
||||
#include "CrashHandler.h"
|
||||
#include "Menu.h"
|
||||
|
||||
const Discoverability::Mode DEFAULT_DISCOVERABILITY_MODE = Discoverability::Connections;
|
||||
|
|
|
@ -812,7 +812,7 @@ Menu::Menu() {
|
|||
});
|
||||
essLogAction->setEnabled(nodeList->getThisNodeCanRez());
|
||||
|
||||
action = addActionToQMenuAndActionHash(developerMenu, "Script Log (HMD friendly)...", Qt::NoButton,
|
||||
addActionToQMenuAndActionHash(developerMenu, "Script Log (HMD friendly)...", Qt::NoButton,
|
||||
qApp, SLOT(showScriptLogs()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::VerboseLogging, 0, false,
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include "AddressManager.h"
|
||||
#include "Application.h"
|
||||
#include "Crashpad.h"
|
||||
#include "CrashHandler.h"
|
||||
#include "InterfaceLogging.h"
|
||||
#include "UserActivityLogger.h"
|
||||
#include "MainWindow.h"
|
||||
|
|
|
@ -319,6 +319,15 @@ public slots:
|
|||
* {@link Window.processingGifStarted|processingGifStarted} and {@link Window.processingGifCompleted|processingGifCompleted}
|
||||
* are emitted. The path to store the snapshots and the length of the animated GIF to capture are specified in Settings >
|
||||
* General > Snapshots.
|
||||
*
|
||||
* If user has supplied a specific filename for the snapshot:
|
||||
* If the user's requested filename has a suffix that's contained within SUPPORTED_IMAGE_FORMATS,
|
||||
* 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`.
|
||||
* 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
|
||||
* @function Window.takeSnapshot
|
||||
* @param {boolean} [notify=true] - This value is passed on through the {@link Window.stillSnapshotTaken|stillSnapshotTaken}
|
||||
* signal.
|
||||
|
|
|
@ -50,6 +50,7 @@ const QString DATETIME_FORMAT = "yyyy-MM-dd_hh-mm-ss";
|
|||
const QString SNAPSHOTS_DIRECTORY = "Snapshots";
|
||||
const QString URL = "highfidelity_url";
|
||||
static const int SNAPSHOT_360_TIMER_INTERVAL = 350;
|
||||
static const QList<QString> SUPPORTED_IMAGE_FORMATS = { "jpg", "jpeg", "png" };
|
||||
|
||||
Snapshot::Snapshot() {
|
||||
_snapshotTimer.setSingleShot(false);
|
||||
|
@ -67,7 +68,6 @@ Snapshot::Snapshot() {
|
|||
}
|
||||
|
||||
SnapshotMetaData* Snapshot::parseSnapshotData(QString snapshotPath) {
|
||||
|
||||
if (!QFile(snapshotPath).exists()) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -95,7 +95,6 @@ SnapshotMetaData* Snapshot::parseSnapshotData(QString snapshotPath) {
|
|||
}
|
||||
|
||||
QString Snapshot::saveSnapshot(QImage image, const QString& filename, const QString& pathname) {
|
||||
|
||||
QFile* snapshotFile = savedFileForSnapshot(image, false, filename, pathname);
|
||||
|
||||
if (snapshotFile) {
|
||||
|
@ -122,11 +121,15 @@ static const glm::quat CAMERA_ORIENTATION_LEFT(glm::quat(glm::radians(glm::vec3(
|
|||
static const glm::quat CAMERA_ORIENTATION_BACK(glm::quat(glm::radians(glm::vec3(0.0f, 180.0f, 0.0f))));
|
||||
static const glm::quat CAMERA_ORIENTATION_RIGHT(glm::quat(glm::radians(glm::vec3(0.0f, 270.0f, 0.0f))));
|
||||
static const glm::quat CAMERA_ORIENTATION_UP(glm::quat(glm::radians(glm::vec3(90.0f, 0.0f, 0.0f))));
|
||||
void Snapshot::save360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const bool& notify, const QString& filename) {
|
||||
void Snapshot::save360Snapshot(const glm::vec3& cameraPosition,
|
||||
const bool& cubemapOutputFormat,
|
||||
const bool& notify,
|
||||
const QString& filename) {
|
||||
_snapshotFilename = filename;
|
||||
_notify360 = notify;
|
||||
_cubemapOutputFormat = cubemapOutputFormat;
|
||||
SecondaryCameraJobConfig* secondaryCameraRenderConfig = static_cast<SecondaryCameraJobConfig*>(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCamera"));
|
||||
SecondaryCameraJobConfig* secondaryCameraRenderConfig =
|
||||
static_cast<SecondaryCameraJobConfig*>(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCamera"));
|
||||
|
||||
// Save initial values of secondary camera render config
|
||||
_oldEnabled = secondaryCameraRenderConfig->isEnabled();
|
||||
|
@ -141,9 +144,11 @@ void Snapshot::save360Snapshot(const glm::vec3& cameraPosition, const bool& cube
|
|||
}
|
||||
|
||||
// Initialize some secondary camera render config options for 360 snapshot capture
|
||||
static_cast<ToneMappingConfig*>(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCameraJob.ToneMapping"))->setCurve(0);
|
||||
static_cast<ToneMappingConfig*>(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCameraJob.ToneMapping"))
|
||||
->setCurve(0);
|
||||
|
||||
secondaryCameraRenderConfig->resetSizeSpectatorCamera(static_cast<int>(CUBEMAP_SIDE_PIXEL_DIMENSION), static_cast<int>(CUBEMAP_SIDE_PIXEL_DIMENSION));
|
||||
secondaryCameraRenderConfig->resetSizeSpectatorCamera(static_cast<int>(CUBEMAP_SIDE_PIXEL_DIMENSION),
|
||||
static_cast<int>(CUBEMAP_SIDE_PIXEL_DIMENSION));
|
||||
secondaryCameraRenderConfig->setProperty("attachedEntityId", "");
|
||||
secondaryCameraRenderConfig->setPosition(cameraPosition);
|
||||
secondaryCameraRenderConfig->setProperty("vFoV", SNAPSHOT_360_FOV);
|
||||
|
@ -159,7 +164,8 @@ void Snapshot::save360Snapshot(const glm::vec3& cameraPosition, const bool& cube
|
|||
}
|
||||
|
||||
void Snapshot::takeNextSnapshot() {
|
||||
SecondaryCameraJobConfig* config = static_cast<SecondaryCameraJobConfig*>(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCamera"));
|
||||
SecondaryCameraJobConfig* config =
|
||||
static_cast<SecondaryCameraJobConfig*>(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCamera"));
|
||||
|
||||
// Order is:
|
||||
// 0. Down
|
||||
|
@ -191,7 +197,9 @@ void Snapshot::takeNextSnapshot() {
|
|||
_snapshotTimer.stop();
|
||||
|
||||
// Reset secondary camera render config
|
||||
static_cast<ToneMappingConfig*>(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCameraJob.ToneMapping"))->setCurve(1);
|
||||
static_cast<ToneMappingConfig*>(
|
||||
qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCameraJob.ToneMapping"))
|
||||
->setCurve(1);
|
||||
config->resetSizeSpectatorCamera(qApp->getWindow()->geometry().width(), qApp->getWindow()->geometry().height());
|
||||
config->setProperty("attachedEntityId", _oldAttachedEntityId);
|
||||
config->setProperty("vFoV", _oldvFoV);
|
||||
|
@ -338,8 +346,10 @@ QTemporaryFile* Snapshot::saveTempSnapshot(QImage image) {
|
|||
return static_cast<QTemporaryFile*>(savedFileForSnapshot(image, true));
|
||||
}
|
||||
|
||||
QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QString& userSelectedFilename, const QString& userSelectedPathname) {
|
||||
|
||||
QFile* Snapshot::savedFileForSnapshot(QImage& shot,
|
||||
bool isTemporary,
|
||||
const QString& userSelectedFilename,
|
||||
const QString& userSelectedPathname) {
|
||||
// adding URL to snapshot
|
||||
QUrl currentURL = DependencyManager::get<AddressManager>()->currentPublicAddress();
|
||||
shot.setText(URL, currentURL.toString());
|
||||
|
@ -350,12 +360,23 @@ QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QSt
|
|||
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
|
||||
// If user has requested specific filename then use it, else create the filename
|
||||
// 'jpg" is appended, as the image is saved in jpg format. This is the case for all snapshots
|
||||
// (see definition of FILENAME_PATH_FORMAT)
|
||||
// If user has supplied a specific filename for the snapshot:
|
||||
// If the user's requested filename has a suffix that's contained within SUPPORTED_IMAGE_FORMATS,
|
||||
// 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`.
|
||||
// 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
|
||||
QString filename;
|
||||
if (!userSelectedFilename.isNull()) {
|
||||
filename = userSelectedFilename + ".jpg";
|
||||
QFileInfo snapshotFileInfo(userSelectedFilename);
|
||||
QString userSelectedFilenameSuffix = snapshotFileInfo.suffix();
|
||||
if (SUPPORTED_IMAGE_FORMATS.contains(userSelectedFilenameSuffix)) {
|
||||
filename = userSelectedFilename;
|
||||
} else {
|
||||
filename = userSelectedFilename + ".jpg";
|
||||
}
|
||||
} else {
|
||||
filename = FILENAME_PATH_FORMAT.arg(username, now.toString(DATETIME_FORMAT));
|
||||
}
|
||||
|
@ -372,11 +393,13 @@ QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QSt
|
|||
}
|
||||
|
||||
if (snapshotFullPath.isEmpty()) {
|
||||
snapshotFullPath = OffscreenUi::getExistingDirectory(nullptr, "Choose Snapshots Directory", QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
|
||||
snapshotFullPath =
|
||||
OffscreenUi::getExistingDirectory(nullptr, "Choose Snapshots Directory",
|
||||
QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
|
||||
_snapshotsLocation.set(snapshotFullPath);
|
||||
}
|
||||
|
||||
if (!snapshotFullPath.isEmpty()) { // not cancelled
|
||||
if (!snapshotFullPath.isEmpty()) { // not cancelled
|
||||
|
||||
if (!snapshotFullPath.endsWith(QDir::separator())) {
|
||||
snapshotFullPath.append(QDir::separator());
|
||||
|
@ -393,7 +416,9 @@ QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QSt
|
|||
qApp->getApplicationCompositor().getReticleInterface()->setVisible(true);
|
||||
qApp->getApplicationCompositor().getReticleInterface()->setAllowMouseCapture(true);
|
||||
|
||||
snapshotFullPath = OffscreenUi::getExistingDirectory(nullptr, "Write Error - Choose New Snapshots Directory", QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
|
||||
snapshotFullPath =
|
||||
OffscreenUi::getExistingDirectory(nullptr, "Write Error - Choose New Snapshots Directory",
|
||||
QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
|
||||
if (snapshotFullPath.isEmpty()) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -412,7 +437,6 @@ QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QSt
|
|||
|
||||
return imageFile;
|
||||
}
|
||||
|
||||
}
|
||||
// Either we were asked for a tempororary, or the user didn't set a directory.
|
||||
QTemporaryFile* imageTempFile = new QTemporaryFile(QDir::tempPath() + "/XXXXXX-" + filename);
|
||||
|
@ -430,11 +454,10 @@ QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QSt
|
|||
}
|
||||
|
||||
void Snapshot::uploadSnapshot(const QString& filename, const QUrl& href) {
|
||||
|
||||
const QString SNAPSHOT_UPLOAD_URL = "/api/v1/snapshots";
|
||||
QUrl url = href;
|
||||
if (url.isEmpty()) {
|
||||
SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(filename);
|
||||
SnapshotMetaData* snapshotData = parseSnapshotData(filename);
|
||||
if (snapshotData) {
|
||||
url = snapshotData->getURL();
|
||||
}
|
||||
|
@ -444,7 +467,7 @@ void Snapshot::uploadSnapshot(const QString& filename, const QUrl& href) {
|
|||
url = QUrl(DependencyManager::get<AddressManager>()->currentShareableAddress());
|
||||
}
|
||||
SnapshotUploader* uploader = new SnapshotUploader(url, filename);
|
||||
|
||||
|
||||
QFile* file = new QFile(filename);
|
||||
Q_ASSERT(file->exists());
|
||||
file->open(QIODevice::ReadOnly);
|
||||
|
@ -458,20 +481,16 @@ void Snapshot::uploadSnapshot(const QString& filename, const QUrl& href) {
|
|||
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||||
QVariant("form-data; name=\"image\"; filename=\"" + file->fileName() + "\""));
|
||||
imagePart.setBodyDevice(file);
|
||||
|
||||
|
||||
QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||
file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart
|
||||
file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart
|
||||
multiPart->append(imagePart);
|
||||
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
JSONCallbackParameters callbackParams(uploader, "uploadSuccess", uploader, "uploadFailure");
|
||||
|
||||
accountManager->sendRequest(SNAPSHOT_UPLOAD_URL,
|
||||
AccountManagerAuth::Required,
|
||||
QNetworkAccessManager::PostOperation,
|
||||
callbackParams,
|
||||
nullptr,
|
||||
multiPart);
|
||||
accountManager->sendRequest(SNAPSHOT_UPLOAD_URL, AccountManagerAuth::Required, QNetworkAccessManager::PostOperation,
|
||||
callbackParams, nullptr, multiPart);
|
||||
}
|
||||
|
||||
QString Snapshot::getSnapshotsLocation() {
|
||||
|
|
|
@ -201,13 +201,12 @@ void Circle3DOverlay::render(RenderArgs* args) {
|
|||
|
||||
float tickMarkAngle = getMajorTickMarksAngle();
|
||||
float angle = _startAt - fmodf(_startAt, tickMarkAngle) + tickMarkAngle;
|
||||
float angleInRadians = glm::radians(angle);
|
||||
float tickMarkLength = getMajorTickMarksLength();
|
||||
float startRadius = (tickMarkLength > 0.0f) ? _innerRadius : _outerRadius;
|
||||
float endRadius = startRadius + tickMarkLength;
|
||||
|
||||
while (angle <= _endAt) {
|
||||
angleInRadians = glm::radians(angle);
|
||||
float angleInRadians = glm::radians(angle);
|
||||
|
||||
glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius);
|
||||
glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius);
|
||||
|
@ -223,13 +222,12 @@ void Circle3DOverlay::render(RenderArgs* args) {
|
|||
|
||||
float tickMarkAngle = getMinorTickMarksAngle();
|
||||
float angle = _startAt - fmodf(_startAt, tickMarkAngle) + tickMarkAngle;
|
||||
float angleInRadians = glm::radians(angle);
|
||||
float tickMarkLength = getMinorTickMarksLength();
|
||||
float startRadius = (tickMarkLength > 0.0f) ? _innerRadius : _outerRadius;
|
||||
float endRadius = startRadius + tickMarkLength;
|
||||
|
||||
while (angle <= _endAt) {
|
||||
angleInRadians = glm::radians(angle);
|
||||
float angleInRadians = glm::radians(angle);
|
||||
|
||||
glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius);
|
||||
glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius);
|
||||
|
|
|
@ -105,8 +105,10 @@ QStringList Animation::getJointNames() const {
|
|||
return result;
|
||||
}
|
||||
QStringList names;
|
||||
foreach (const FBXJoint& joint, _geometry->joints) {
|
||||
names.append(joint.name);
|
||||
if (_geometry) {
|
||||
foreach (const FBXJoint& joint, _geometry->joints) {
|
||||
names.append(joint.name);
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
@ -114,11 +116,15 @@ QStringList Animation::getJointNames() const {
|
|||
QVector<FBXAnimationFrame> Animation::getFrames() const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QVector<FBXAnimationFrame> result;
|
||||
BLOCKING_INVOKE_METHOD(const_cast<Animation*>(this), "getFrames",
|
||||
BLOCKING_INVOKE_METHOD(const_cast<Animation*>(this), "getFrames",
|
||||
Q_RETURN_ARG(QVector<FBXAnimationFrame>, result));
|
||||
return result;
|
||||
}
|
||||
return _geometry->animationFrames;
|
||||
if (_geometry) {
|
||||
return _geometry->animationFrames;
|
||||
} else {
|
||||
return QVector<FBXAnimationFrame>();
|
||||
}
|
||||
}
|
||||
|
||||
const QVector<FBXAnimationFrame>& Animation::getFramesReference() const {
|
||||
|
|
|
@ -2423,9 +2423,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
|
|||
if (appendState != OctreeElement::COMPLETED) {
|
||||
didntFitProperties = propertiesDidntFit;
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
packetData->endSubTree();
|
||||
|
||||
const char* finalizedData = reinterpret_cast<const char*>(packetData->getFinalizedData());
|
||||
|
@ -2436,7 +2434,6 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
|
|||
buffer.resize(finalizedSize);
|
||||
} else {
|
||||
qCDebug(entities) << "ERROR - encoded edit message doesn't fit in output buffer.";
|
||||
success = false;
|
||||
appendState = OctreeElement::NONE; // if we got here, then we didn't include the item
|
||||
// maybe we should assert!!!
|
||||
}
|
||||
|
@ -2444,7 +2441,6 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
|
|||
packetData->discardSubTree();
|
||||
}
|
||||
|
||||
|
||||
return appendState;
|
||||
}
|
||||
|
||||
|
@ -2834,7 +2830,6 @@ bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityIt
|
|||
outputLength = sizeof(numberOfIds);
|
||||
|
||||
memcpy(copyAt, entityItemID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID);
|
||||
copyAt += NUM_BYTES_RFC4122_UUID;
|
||||
outputLength += NUM_BYTES_RFC4122_UUID;
|
||||
|
||||
buffer.resize(outputLength);
|
||||
|
@ -2856,7 +2851,6 @@ bool EntityItemProperties::encodeCloneEntityMessage(const EntityItemID& entityID
|
|||
outputLength += NUM_BYTES_RFC4122_UUID;
|
||||
|
||||
memcpy(copyAt, newEntityID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID);
|
||||
copyAt += NUM_BYTES_RFC4122_UUID;
|
||||
outputLength += NUM_BYTES_RFC4122_UUID;
|
||||
|
||||
buffer.resize(outputLength);
|
||||
|
|
|
@ -67,11 +67,12 @@
|
|||
// when multiple participants (with variable ping-times to the server) bid simultaneously for a
|
||||
// recently activated entity.
|
||||
//
|
||||
// (9) When a participant changes an entity's transform/velocity it will bid at priority = POKE (=127)
|
||||
// (9) When a participant changes an entity's transform/velocity (via script) it will bid at
|
||||
// priority = POKE (=127).
|
||||
//
|
||||
// (10) When an entity touches MyAvatar the participant it will bid at priority = POKE.
|
||||
// (10) When an entity collides with MyAvatar the participant it will bid at priority = POKE.
|
||||
//
|
||||
// (11) When a participant grabs an entity it will bid at priority = GRAB (=128).
|
||||
// (11) When a participant grabs (via script) an entity it will bid at priority = GRAB (=128).
|
||||
//
|
||||
// (12) When entityA, locally owned at priority = N, collides with an unowned entityB the owner will
|
||||
// also bid for entityB at priority = N-1 (or VOLUNTEER, whichever is larger).
|
||||
|
@ -79,7 +80,7 @@
|
|||
// (13) When an entity comes to rest and is deactivated in the physics simulation the owner will
|
||||
// send an update to: clear their ownerhsip, set priority to zero, and set the object's
|
||||
// velocities to be zero. As per a normal bid, the owner does NOT assume that its ownership
|
||||
// has been cleared until it hears from the entity-server. This, if the packet is lost the
|
||||
// has been cleared until it hears from the entity-server. Thus, if the packet is lost the
|
||||
// owner will re-send after some period.
|
||||
//
|
||||
// (14) When an entity's ownership priority drops below VOLUNTEER other participants may bid for it
|
||||
|
|
|
@ -63,13 +63,13 @@ Sysmem& Sysmem::operator=(const Sysmem& sysmem) {
|
|||
|
||||
Sysmem::~Sysmem() {
|
||||
deallocateMemory( _data, _size );
|
||||
_data = NULL;
|
||||
_data = nullptr;
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
Size Sysmem::allocate(Size size) {
|
||||
if (size != _size) {
|
||||
Byte* newData = NULL;
|
||||
Byte* newData = nullptr;
|
||||
Size newSize = 0;
|
||||
if (size > 0) {
|
||||
Size allocated = allocateMemory(&newData, size);
|
||||
|
@ -90,7 +90,7 @@ Size Sysmem::allocate(Size size) {
|
|||
|
||||
Size Sysmem::resize(Size size) {
|
||||
if (size != _size) {
|
||||
Byte* newData = NULL;
|
||||
Byte* newData = nullptr;
|
||||
Size newSize = 0;
|
||||
if (size > 0) {
|
||||
Size allocated = allocateMemory(&newData, size);
|
||||
|
@ -124,7 +124,7 @@ Size Sysmem::setData( Size size, const Byte* bytes ) {
|
|||
}
|
||||
|
||||
Size Sysmem::setSubData( Size offset, Size size, const Byte* bytes) {
|
||||
if (size && ((offset + size) <= getSize()) && bytes) {
|
||||
if (_data && size && ((offset + size) <= getSize()) && bytes) {
|
||||
memcpy( _data + offset, bytes, size );
|
||||
return size;
|
||||
}
|
||||
|
|
|
@ -140,7 +140,6 @@ struct IrradianceKTXPayload {
|
|||
data += sizeof(Version);
|
||||
|
||||
memcpy(&_irradianceSH, data, sizeof(SphericalHarmonics));
|
||||
data += sizeof(SphericalHarmonics);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -267,8 +267,6 @@ bool PacketSender::nonThreadedProcess() {
|
|||
// Keep average packets and time for "second half" of check interval
|
||||
_lastPPSCheck += (elapsedSinceLastCheck / 2);
|
||||
_packetsOverCheckInterval = (_packetsOverCheckInterval / 2);
|
||||
|
||||
elapsedSinceLastCheck = now - _lastPPSCheck;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -296,12 +294,10 @@ bool PacketSender::nonThreadedProcess() {
|
|||
DependencyManager::get<NodeList>()->sendPacketList(std::move(packetPair.second.second), *packetPair.first);
|
||||
}
|
||||
|
||||
|
||||
packetsSentThisCall += packetCount;
|
||||
_packetsOverCheckInterval += packetCount;
|
||||
_totalPacketsSent += packetCount;
|
||||
|
||||
|
||||
_totalBytesSent += packetSize;
|
||||
emit packetSent(packetSize); // FIXME should include number of packets?
|
||||
_lastSendTime = now;
|
||||
|
|
|
@ -401,7 +401,6 @@ int Octree::readElementData(const OctreeElementPointer& destinationElement, cons
|
|||
// tell the element to read the subsequent data
|
||||
int rootDataSize = _rootElement->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead, args);
|
||||
bytesRead += rootDataSize;
|
||||
bytesLeftToRead -= rootDataSize;
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
|
|
|
@ -69,7 +69,7 @@ bool CharacterGhostObject::rayTest(const btVector3& start,
|
|||
const btVector3& end,
|
||||
CharacterRayResult& result) const {
|
||||
if (_world && _inWorld) {
|
||||
_world->rayTest(start, end, result);
|
||||
btGhostObject::rayTest(start, end, result);
|
||||
}
|
||||
return result.hasHit();
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
class CharacterGhostShape;
|
||||
|
||||
class CharacterGhostObject : public btPairCachingGhostObject {
|
||||
class CharacterGhostObject : public btGhostObject {
|
||||
public:
|
||||
CharacterGhostObject() { }
|
||||
~CharacterGhostObject();
|
||||
|
|
|
@ -92,7 +92,7 @@ void ObjectMotionState::setMass(float mass) {
|
|||
}
|
||||
|
||||
float ObjectMotionState::getMass() const {
|
||||
if (_shape) {
|
||||
if (_shape && _shape->getShapeType() != TRIANGLE_MESH_SHAPE_PROXYTYPE) {
|
||||
// scale the density by the current Aabb volume to get mass
|
||||
btTransform transform;
|
||||
transform.setIdentity();
|
||||
|
@ -348,8 +348,10 @@ void ObjectMotionState::updateLastKinematicStep() {
|
|||
|
||||
void ObjectMotionState::updateBodyMassProperties() {
|
||||
float mass = getMass();
|
||||
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
||||
_body->getCollisionShape()->calculateLocalInertia(mass, inertia);
|
||||
btVector3 inertia(1.0f, 1.0f, 1.0f);
|
||||
if (mass > 0.0f) {
|
||||
_body->getCollisionShape()->calculateLocalInertia(mass, inertia);
|
||||
}
|
||||
_body->setMassProps(mass, inertia);
|
||||
_body->updateInertiaTensor();
|
||||
}
|
||||
|
|
|
@ -61,7 +61,6 @@ PointerFrameHeaderList parseFrameHeaders(uchar* const start, const size_t& size)
|
|||
current += sizeof(FrameSize);
|
||||
header.fileOffset = current - start;
|
||||
if (end - current < header.size) {
|
||||
current = end;
|
||||
break;
|
||||
}
|
||||
current += header.size;
|
||||
|
|
|
@ -402,8 +402,10 @@ MenuWrapper* Menu::addMenu(const QString& menuName, const QString& grouping) {
|
|||
|
||||
// hook our show/hide for popup menus, so we can keep track of whether or not one
|
||||
// of our submenus is currently showing.
|
||||
connect(menu->_realMenu, &QMenu::aboutToShow, []() { _isSomeSubmenuShown = true; });
|
||||
connect(menu->_realMenu, &QMenu::aboutToHide, []() { _isSomeSubmenuShown = false; });
|
||||
if (menu && menu->_realMenu) {
|
||||
connect(menu->_realMenu, &QMenu::aboutToShow, []() { _isSomeSubmenuShown = true; });
|
||||
connect(menu->_realMenu, &QMenu::aboutToHide, []() { _isSomeSubmenuShown = false; });
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ void OculusControllerManager::checkForConnectedDevices() {
|
|||
unsigned int controllerConnected = ovr_GetConnectedControllerTypes(session);
|
||||
|
||||
if (!_remote && (controllerConnected & ovrControllerType_Remote) == ovrControllerType_Remote) {
|
||||
if (OVR_SUCCESS(ovr_GetInputState(session, ovrControllerType_Remote, &_inputState))) {
|
||||
if (OVR_SUCCESS(ovr_GetInputState(session, ovrControllerType_Remote, &_remoteInputState))) {
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
_remote = std::make_shared<RemoteDevice>(*this);
|
||||
userInputMapper->registerDevice(_remote);
|
||||
|
@ -59,7 +59,7 @@ void OculusControllerManager::checkForConnectedDevices() {
|
|||
}
|
||||
|
||||
if (!_touch && (controllerConnected & ovrControllerType_Touch) != 0) {
|
||||
if (OVR_SUCCESS(ovr_GetInputState(session, ovrControllerType_Touch, &_inputState))) {
|
||||
if (OVR_SUCCESS(ovr_GetInputState(session, ovrControllerType_Touch, &_touchInputState))) {
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
_touch = std::make_shared<TouchDevice>(*this);
|
||||
userInputMapper->registerDevice(_touch);
|
||||
|
@ -90,13 +90,13 @@ void OculusControllerManager::pluginUpdate(float deltaTime, const controller::In
|
|||
|
||||
ovr::withSession([&](ovrSession session) {
|
||||
if (_touch) {
|
||||
updateTouch = OVR_SUCCESS(ovr_GetInputState(session, ovrControllerType_Touch, &_inputState));
|
||||
updateTouch = OVR_SUCCESS(ovr_GetInputState(session, ovrControllerType_Touch, &_touchInputState));
|
||||
if (!updateTouch) {
|
||||
qCWarning(oculusLog) << "Unable to read Oculus touch input state" << ovr::getError();
|
||||
}
|
||||
}
|
||||
if (_remote) {
|
||||
updateRemote = OVR_SUCCESS(ovr_GetInputState(session, ovrControllerType_Remote, &_inputState));
|
||||
updateRemote = OVR_SUCCESS(ovr_GetInputState(session, ovrControllerType_Remote, &_remoteInputState));
|
||||
if (!updateRemote) {
|
||||
qCWarning(oculusLog) << "Unable to read Oculus remote input state" << ovr::getError();
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ QString OculusControllerManager::RemoteDevice::getDefaultMappingConfig() const {
|
|||
|
||||
void OculusControllerManager::RemoteDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
|
||||
_buttonPressedMap.clear();
|
||||
const auto& inputState = _parent._inputState;
|
||||
const auto& inputState = _parent._remoteInputState;
|
||||
for (const auto& pair : BUTTON_MAP) {
|
||||
if (inputState.Buttons & pair.first) {
|
||||
_buttonPressedMap.insert(pair.second);
|
||||
|
@ -257,7 +257,7 @@ void OculusControllerManager::TouchDevice::update(float deltaTime,
|
|||
|
||||
using namespace controller;
|
||||
// Axes
|
||||
const auto& inputState = _parent._inputState;
|
||||
const auto& inputState = _parent._touchInputState;
|
||||
_axisStateMap[LX] = inputState.Thumbstick[ovrHand_Left].x;
|
||||
_axisStateMap[LY] = inputState.Thumbstick[ovrHand_Left].y;
|
||||
_axisStateMap[LT] = inputState.IndexTrigger[ovrHand_Left];
|
||||
|
|
|
@ -103,7 +103,8 @@ private:
|
|||
|
||||
void checkForConnectedDevices();
|
||||
|
||||
ovrInputState _inputState {};
|
||||
ovrInputState _remoteInputState {};
|
||||
ovrInputState _touchInputState {};
|
||||
RemoteDevice::Pointer _remote;
|
||||
TouchDevice::Pointer _touch;
|
||||
static const char* NAME;
|
||||
|
|
|
@ -46,6 +46,7 @@ function init() {
|
|||
|
||||
function onMuteClicked() {
|
||||
Audio.muted = !Audio.muted;
|
||||
Menu.triggerOption("Out of Bounds Vector Access");
|
||||
}
|
||||
|
||||
function onMutePressed() {
|
||||
|
|
Loading…
Reference in a new issue