mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 17:14:59 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into one
This commit is contained in:
commit
6011ef5390
132 changed files with 12150 additions and 2901 deletions
|
@ -21,6 +21,7 @@ To produce an executable installer on Windows, the following are required:
|
|||
- [NSISpcre Plug-in for Nullsoft](http://nsis.sourceforge.net/NSISpcre_plug-in) - 1.0
|
||||
- [nsisSlideshow Plug-in for Nullsoft](http://nsis.sourceforge.net/NsisSlideshow_plug-in) - 1.7
|
||||
- [Nsisunz plug-in for Nullsoft](http://nsis.sourceforge.net/Nsisunz_plug-in)
|
||||
- [ApplicationID plug-in for Nullsoft](http://nsis.sourceforge.net/ApplicationID_plug-in) - 1.0
|
||||
|
||||
Run the `package` target to create an executable installer using the Nullsoft Scriptable Install System.
|
||||
|
||||
|
|
|
@ -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') {
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
|
|
@ -18,6 +18,7 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
set(BUILD_GLOBAL_SERVICES "DEVELOPMENT")
|
||||
set(USE_STABLE_GLOBAL_SERVICES 0)
|
||||
set(BUILD_NUMBER 0)
|
||||
set(APP_USER_MODEL_ID "com.highfidelity.sandbox-dev")
|
||||
|
||||
set_from_env(RELEASE_TYPE RELEASE_TYPE "DEV")
|
||||
set_from_env(RELEASE_NUMBER RELEASE_NUMBER "")
|
||||
|
@ -172,6 +173,7 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
if (PRODUCTION_BUILD)
|
||||
set(INTERFACE_SHORTCUT_NAME "High Fidelity Interface")
|
||||
set(CONSOLE_SHORTCUT_NAME "Sandbox")
|
||||
set(APP_USER_MODEL_ID "com.highfidelity.sandbox")
|
||||
else ()
|
||||
set(INTERFACE_SHORTCUT_NAME "High Fidelity Interface - ${BUILD_VERSION_NO_SHA}")
|
||||
set(CONSOLE_SHORTCUT_NAME "Sandbox - ${BUILD_VERSION_NO_SHA}")
|
||||
|
|
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()
|
||||
|
||||
|
|
@ -49,3 +49,4 @@ set(ADD_REMOVE_ICON_PATH "@ADD_REMOVE_ICON_PATH@")
|
|||
set(SERVER_COMPONENT_CONDITIONAL "@SERVER_COMPONENT_CONDITIONAL@")
|
||||
set(CLIENT_COMPONENT_CONDITIONAL "@CLIENT_COMPONENT_CONDITIONAL@")
|
||||
set(INSTALLER_TYPE "@INSTALLER_TYPE@")
|
||||
set(APP_USER_MODEL_ID "@APP_USER_MODEL_ID@")
|
||||
|
|
|
@ -905,6 +905,8 @@ Function HandlePostInstallOptions
|
|||
${If} $DesktopServerState == ${BST_CHECKED}
|
||||
CreateShortCut "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
|
||||
!insertmacro WriteInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ YES
|
||||
; Set appUserModelId
|
||||
ApplicationID::Set "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "@APP_USER_MODEL_ID@"
|
||||
${Else}
|
||||
!insertmacro WriteInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ NO
|
||||
${EndIf}
|
||||
|
@ -1162,6 +1164,8 @@ Section "-Core installation"
|
|||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \
|
||||
"$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
|
||||
; Set appUserModelId
|
||||
ApplicationID::Set "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" "@APP_USER_MODEL_ID@"
|
||||
${EndIf}
|
||||
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\@UNINSTALLER_NAME@"
|
||||
|
|
|
@ -3,5 +3,6 @@
|
|||
"buildNumber": "@BUILD_NUMBER@",
|
||||
"stableBuild": "@STABLE_BUILD@",
|
||||
"buildIdentifier": "@BUILD_VERSION@",
|
||||
"organization": "@BUILD_ORGANIZATION@"
|
||||
"organization": "@BUILD_ORGANIZATION@",
|
||||
"appUserModelId": "@APP_USER_MODEL_ID@"
|
||||
}
|
||||
|
|
|
@ -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})
|
||||
|
|
BIN
interface/resources/images/buttonBezel.png
Normal file
BIN
interface/resources/images/buttonBezel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
interface/resources/images/buttonBezel_highlight.png
Normal file
BIN
interface/resources/images/buttonBezel_highlight.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
|
@ -171,6 +171,10 @@ FocusScope {
|
|||
}
|
||||
}
|
||||
|
||||
function textAt(index) {
|
||||
return comboBox.textAt(index);
|
||||
}
|
||||
|
||||
HifiControls.Label {
|
||||
id: comboBoxLabel
|
||||
text: root.label
|
||||
|
|
|
@ -17,6 +17,10 @@ import "../controls-uit" as HifiControls
|
|||
SpinBox {
|
||||
id: spinBox
|
||||
|
||||
HifiConstants {
|
||||
id: hifi
|
||||
}
|
||||
|
||||
property int colorScheme: hifi.colorSchemes.light
|
||||
readonly property bool isLightColorScheme: colorScheme === hifi.colorSchemes.light
|
||||
property string label: ""
|
||||
|
@ -31,8 +35,8 @@ SpinBox {
|
|||
property real maximumValue: 0.0
|
||||
|
||||
property real realValue: 0.0
|
||||
property real realFrom: 0.0
|
||||
property real realTo: 100.0
|
||||
property real realFrom: minimumValue
|
||||
property real realTo: maximumValue
|
||||
property real realStepSize: 1.0
|
||||
|
||||
signal editingFinished()
|
||||
|
@ -53,7 +57,8 @@ SpinBox {
|
|||
onValueChanged: realValue = value/factor
|
||||
|
||||
stepSize: realStepSize*factor
|
||||
value: realValue*factor
|
||||
value: Math.round(realValue*factor)
|
||||
|
||||
to : realTo*factor
|
||||
from : realFrom*factor
|
||||
|
||||
|
@ -81,6 +86,7 @@ SpinBox {
|
|||
}
|
||||
|
||||
valueFromText: function(text, locale) {
|
||||
spinBox.value = 0; // Force valueChanged signal to be emitted so that validator fires.
|
||||
return Number.fromLocaleString(locale, text)*factor;
|
||||
}
|
||||
|
||||
|
@ -110,7 +116,7 @@ SpinBox {
|
|||
anchors.centerIn: parent
|
||||
text: hifi.glyphs.caratUp
|
||||
size: hifi.dimensions.spinnerSize
|
||||
color: spinBox.down.pressed || spinBox.up.hovered ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.gray
|
||||
color: spinBox.up.pressed || spinBox.up.hovered ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.gray
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,26 +155,14 @@ SpinBox {
|
|||
visible: spinBox.labelInside != ""
|
||||
}
|
||||
|
||||
// MouseArea {
|
||||
// anchors.fill: parent
|
||||
// propagateComposedEvents: true
|
||||
// onWheel: {
|
||||
// if(spinBox.activeFocus)
|
||||
// wheel.accepted = false
|
||||
// else
|
||||
// wheel.accepted = true
|
||||
// }
|
||||
// onPressed: {
|
||||
// mouse.accepted = false
|
||||
// }
|
||||
// onReleased: {
|
||||
// mouse.accepted = false
|
||||
// }
|
||||
// onClicked: {
|
||||
// mouse.accepted = false
|
||||
// }
|
||||
// onDoubleClicked: {
|
||||
// mouse.accepted = false
|
||||
// }
|
||||
// }
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton
|
||||
onWheel: {
|
||||
if (wheel.angleDelta.y > 0)
|
||||
value += stepSize
|
||||
else
|
||||
value -= stepSize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -119,8 +119,8 @@ Item {
|
|||
colorScheme: hifi.colorSchemes.dark
|
||||
currentIndex: attachment ? model.indexOf(attachment.jointName) : -1
|
||||
onCurrentIndexChanged: {
|
||||
if (completed && attachment && currentIndex != -1 && currentText && currentText !== attachment.jointName) {
|
||||
attachment.jointName = currentText;
|
||||
if (completed && attachment && currentIndex != -1 && attachment.jointName !== model[currentIndex]) {
|
||||
attachment.jointName = model[currentIndex];
|
||||
updateAttachment();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,10 +69,15 @@ Item {
|
|||
id: stack
|
||||
initialItem: inputConfiguration
|
||||
property alias messageVisible: imageMessageBox.visible
|
||||
property alias selectedPlugin: box.currentText
|
||||
Rectangle {
|
||||
id: inputConfiguration
|
||||
anchors.fill: parent
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
height: 230
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
|
@ -168,7 +173,7 @@ Item {
|
|||
text: "show all input devices"
|
||||
|
||||
onClicked: {
|
||||
inputPlugins();
|
||||
box.model = inputPlugins();
|
||||
changeSource();
|
||||
}
|
||||
}
|
||||
|
@ -208,25 +213,28 @@ Item {
|
|||
anchors.leftMargin: 10
|
||||
anchors.topMargin: 30
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: loaderRectangle
|
||||
z: -1
|
||||
color: hifi.colors.baseGray
|
||||
width: parent.width
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: inputConfiguration.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
Loader {
|
||||
id: loader
|
||||
asynchronous: false
|
||||
|
||||
width: inputConfiguration.width
|
||||
anchors.left: inputConfiguration.left
|
||||
anchors.right: inputConfiguration.right
|
||||
anchors.top: configurationHeader.bottom
|
||||
anchors.topMargin: 10
|
||||
anchors.bottom: inputConfiguration.bottom
|
||||
|
||||
source: InputConfiguration.configurationLayout(box.currentText);
|
||||
anchors.fill: parent
|
||||
source: InputConfiguration.configurationLayout(box.textAt(box.currentIndex));
|
||||
onLoaded: {
|
||||
if (loader.item.hasOwnProperty("pluginName")) {
|
||||
if (box.currentText === "HTC Vive") {
|
||||
if (box.textAt(box.currentIndex) === "HTC Vive") {
|
||||
loader.item.pluginName = "OpenVR";
|
||||
} else {
|
||||
loader.item.pluginName = box.currentText;
|
||||
loader.item.pluginName = box.textAt(box.currentIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -252,11 +260,12 @@ Item {
|
|||
|
||||
function changeSource() {
|
||||
loader.source = "";
|
||||
var selectedDevice = box.textAt(box.currentIndex);
|
||||
var source = "";
|
||||
if (box.currentText == "Vive") {
|
||||
if (selectedDevice == "HTC Vive") {
|
||||
source = InputConfiguration.configurationLayout("OpenVR");
|
||||
} else {
|
||||
source = InputConfiguration.configurationLayout(box.currentText);
|
||||
source = InputConfiguration.configurationLayout(selectedDevice);
|
||||
}
|
||||
|
||||
loader.source = source;
|
||||
|
|
|
@ -24,6 +24,7 @@ Rectangle {
|
|||
color: hifi.colors.baseGray;
|
||||
signal sendToScript(var message);
|
||||
property bool keyboardEnabled: false
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
property bool keyboardRasied: false
|
||||
|
||||
|
@ -235,10 +236,11 @@ Rectangle {
|
|||
|
||||
Keyboard {
|
||||
id: keyboard
|
||||
raised: parent.keyboardEnabled
|
||||
raised: parent.keyboardEnabled && parent.keyboardRaised
|
||||
numeric: parent.punctuationMode
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 40
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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"
|
||||
|
@ -198,7 +198,6 @@
|
|||
|
||||
#include <GPUIdent.h>
|
||||
#include <gl/GLHelpers.h>
|
||||
#include <src/scripting/LimitlessVoiceRecognitionScriptingInterface.h>
|
||||
#include <src/scripting/GooglePolyScriptingInterface.h>
|
||||
#include <EntityScriptClient.h>
|
||||
#include <ModelScriptingInterface.h>
|
||||
|
@ -792,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
|
||||
|
@ -921,7 +920,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
DependencyManager::set<OffscreenQmlSurfaceCache>();
|
||||
DependencyManager::set<EntityScriptClient>();
|
||||
DependencyManager::set<EntityScriptServerLogClient>();
|
||||
DependencyManager::set<LimitlessVoiceRecognitionScriptingInterface>();
|
||||
DependencyManager::set<GooglePolyScriptingInterface>();
|
||||
DependencyManager::set<OctreeStatsProvider>(nullptr, qApp->getOcteeSceneStats());
|
||||
DependencyManager::set<AvatarBookmarks>();
|
||||
|
@ -2243,9 +2241,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
DependencyManager::get<EntityTreeRenderer>()->setSetPrecisionPickingOperator([&](unsigned int rayPickID, bool value) {
|
||||
DependencyManager::get<PickManager>()->setPrecisionPicking(rayPickID, value);
|
||||
});
|
||||
EntityTreeRenderer::setRenderDebugHullsOperator([] {
|
||||
return Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls);
|
||||
});
|
||||
|
||||
// Preload Tablet sounds
|
||||
DependencyManager::get<TabletScriptingInterface>()->preloadSounds();
|
||||
|
@ -5858,14 +5853,10 @@ void Application::update(float deltaTime) {
|
|||
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("limitless");
|
||||
PerformanceTimer perfTimer("AnimDebugDraw");
|
||||
AnimDebugDraw::getInstance().update();
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("limitless");
|
||||
DependencyManager::get<LimitlessVoiceRecognitionScriptingInterface>()->update();
|
||||
}
|
||||
|
||||
{ // Game loop is done, mark the end of the frame for the scene transactions and the render loop to take over
|
||||
PerformanceTimer perfTimer("enqueueFrame");
|
||||
|
@ -6574,7 +6565,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
|
|||
scriptEngine->registerGlobalObject("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("Users", DependencyManager::get<UsersScriptingInterface>().data());
|
||||
|
||||
scriptEngine->registerGlobalObject("LimitlessSpeechRecognition", DependencyManager::get<LimitlessVoiceRecognitionScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("GooglePoly", DependencyManager::get<GooglePolyScriptingInterface>().data());
|
||||
|
||||
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
|
||||
|
|
|
@ -205,10 +205,6 @@ void Application::runRenderFrame(RenderArgs* renderArgs) {
|
|||
|
||||
RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE;
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) {
|
||||
renderDebugFlags = static_cast<RenderArgs::DebugFlags>(renderDebugFlags |
|
||||
static_cast<int>(RenderArgs::RENDER_DEBUG_HULLS));
|
||||
}
|
||||
renderArgs->_debugFlags = renderDebugFlags;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -725,7 +725,6 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowOwned,
|
||||
0, false, drawStatusConfig, SLOT(setShowNetwork(bool)));
|
||||
}
|
||||
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowHulls, 0, false, qApp->getEntities().data(), SIGNAL(setRenderDebugHulls()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowBulletWireframe, 0, false, qApp, SLOT(setShowBulletWireframe(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowBulletAABBs, 0, false, qApp, SLOT(setShowBulletAABBs(bool)));
|
||||
|
@ -813,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,
|
||||
|
|
|
@ -141,7 +141,6 @@ namespace MenuOption {
|
|||
const QString Overlays = "Show Overlays";
|
||||
const QString PackageModel = "Package Model as .fst...";
|
||||
const QString Pair = "Pair";
|
||||
const QString PhysicsShowHulls = "Draw Collision Shapes";
|
||||
const QString PhysicsShowOwned = "Highlight Simulation Ownership";
|
||||
const QString VerboseLogging = "Verbose Logging";
|
||||
const QString PhysicsShowBulletWireframe = "Show Bullet Collision";
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -56,7 +56,8 @@ class QScriptEngine;
|
|||
* @property {Uuid} tabletID - The UUID of the tablet body model overlay.
|
||||
* @property {Uuid} tabletScreenID - The UUID of the tablet's screen overlay.
|
||||
* @property {Uuid} homeButtonID - The UUID of the tablet's "home" button overlay.
|
||||
* @property {Uuid} homeButtonHighlightID - The UUID of the tablet's "home" button highlight overlay.
|
||||
* @property {Uuid} homeButtonHighlightMaterialID - The UUID of the material entity used to highlight tablet button
|
||||
* @property {Uuid} homeButtonUnhighlightMaterialID - The UUID of the material entity use to unhighlight the entity
|
||||
*/
|
||||
class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Dependency {
|
||||
Q_OBJECT
|
||||
|
@ -67,8 +68,9 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen
|
|||
Q_PROPERTY(bool tabletContextualMode READ getTabletContextualMode)
|
||||
Q_PROPERTY(QUuid tabletID READ getCurrentTabletFrameID WRITE setCurrentTabletFrameID)
|
||||
Q_PROPERTY(QUuid homeButtonID READ getCurrentHomeButtonID WRITE setCurrentHomeButtonID)
|
||||
Q_PROPERTY(QUuid homeButtonHighlightID READ getCurrentHomeButtonHightlightID WRITE setCurrentHomeButtonHightlightID)
|
||||
Q_PROPERTY(QUuid tabletScreenID READ getCurrentTabletScreenID WRITE setCurrentTabletScreenID)
|
||||
Q_PROPERTY(QUuid homeButtonHighlightMaterialID READ getCurrentHomeButtonHighlightMaterialID WRITE setCurrentHomeButtonHighlightMaterialID)
|
||||
Q_PROPERTY(QUuid homeButtonUnhighlightMaterialID READ getCurrentHomeButtonUnhighlightMaterialID WRITE setCurrentHomeButtonUnhighlightMaterialID)
|
||||
|
||||
public:
|
||||
|
||||
|
@ -372,20 +374,24 @@ public:
|
|||
void setCurrentHomeButtonID(QUuid homeButtonID) { _homeButtonID = homeButtonID; }
|
||||
QUuid getCurrentHomeButtonID() const { return _homeButtonID; }
|
||||
|
||||
void setCurrentHomeButtonHightlightID(QUuid homeButtonHightlightID) { _homeButtonHightlightID = homeButtonHightlightID; }
|
||||
QUuid getCurrentHomeButtonHightlightID() const { return _homeButtonHightlightID; }
|
||||
|
||||
void setCurrentTabletScreenID(QUuid tabletID) { _tabletScreenID = tabletID; }
|
||||
QUuid getCurrentTabletScreenID() const { return _tabletScreenID; }
|
||||
|
||||
void setCurrentHomeButtonHighlightMaterialID(QUuid homeButtonHighlightMaterialID) { _homeButtonHighlightMaterialID = homeButtonHighlightMaterialID; }
|
||||
QUuid getCurrentHomeButtonHighlightMaterialID() { return _homeButtonHighlightMaterialID; }
|
||||
|
||||
void setCurrentHomeButtonUnhighlightMaterialID(QUuid homeButtonUnhighlightMaterialID) { _homeButtonUnhighlightMaterialID = homeButtonUnhighlightMaterialID; }
|
||||
QUuid getCurrentHomeButtonUnhighlightMaterialID() { return _homeButtonUnhighlightMaterialID; }
|
||||
|
||||
private:
|
||||
bool _showTablet { false };
|
||||
bool _tabletContextualMode { false };
|
||||
QUuid _tabletUIID; // this is the entityID of the tablet frame
|
||||
QUuid _tabletScreenID; // this is the overlayID which is part of (a child of) the tablet-ui.
|
||||
QUuid _homeButtonID;
|
||||
QUuid _homeButtonHightlightID;
|
||||
QUuid _tabletEntityID;
|
||||
QUuid _homeButtonHighlightMaterialID;
|
||||
QUuid _homeButtonUnhighlightMaterialID;
|
||||
|
||||
// Get the position of the HMD
|
||||
glm::vec3 getPosition() const;
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
#include "LimitlessConnection.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <src/InterfaceLogging.h>
|
||||
#include <src/ui/AvatarInputs.h>
|
||||
#include "LimitlessVoiceRecognitionScriptingInterface.h"
|
||||
|
||||
LimitlessConnection::LimitlessConnection() :
|
||||
_streamingAudioForTranscription(false)
|
||||
{
|
||||
}
|
||||
|
||||
void LimitlessConnection::startListening(QString authCode) {
|
||||
_transcribeServerSocket.reset(new QTcpSocket(this));
|
||||
connect(_transcribeServerSocket.get(), &QTcpSocket::readyRead, this,
|
||||
&LimitlessConnection::transcriptionReceived);
|
||||
connect(_transcribeServerSocket.get(), &QTcpSocket::disconnected, this, [this](){stopListening();});
|
||||
|
||||
static const auto host = "gserv_devel.studiolimitless.com";
|
||||
_transcribeServerSocket->connectToHost(host, 1407);
|
||||
_transcribeServerSocket->waitForConnected();
|
||||
QString requestHeader = QString::asprintf("Authorization: %s\r\nfs: %i\r\n",
|
||||
authCode.toLocal8Bit().data(), AudioConstants::SAMPLE_RATE);
|
||||
qCDebug(interfaceapp) << "Sending Limitless Audio Stream Request: " << requestHeader;
|
||||
_transcribeServerSocket->write(requestHeader.toLocal8Bit());
|
||||
_transcribeServerSocket->waitForBytesWritten();
|
||||
}
|
||||
|
||||
void LimitlessConnection::stopListening() {
|
||||
emit onFinishedSpeaking(_currentTranscription);
|
||||
_streamingAudioForTranscription = false;
|
||||
_currentTranscription = "";
|
||||
if (!isConnected())
|
||||
return;
|
||||
_transcribeServerSocket->close();
|
||||
disconnect(_transcribeServerSocket.get(), &QTcpSocket::readyRead, this,
|
||||
&LimitlessConnection::transcriptionReceived);
|
||||
_transcribeServerSocket.release()->deleteLater();
|
||||
disconnect(DependencyManager::get<AudioClient>().data(), &AudioClient::inputReceived, this,
|
||||
&LimitlessConnection::audioInputReceived);
|
||||
qCDebug(interfaceapp) << "Connection to Limitless Voice Server closed.";
|
||||
}
|
||||
|
||||
void LimitlessConnection::audioInputReceived(const QByteArray& inputSamples) {
|
||||
if (isConnected()) {
|
||||
_transcribeServerSocket->write(inputSamples.data(), inputSamples.size());
|
||||
_transcribeServerSocket->waitForBytesWritten();
|
||||
}
|
||||
}
|
||||
|
||||
void LimitlessConnection::transcriptionReceived() {
|
||||
while (_transcribeServerSocket && _transcribeServerSocket->bytesAvailable() > 0) {
|
||||
const QByteArray data = _transcribeServerSocket->readAll();
|
||||
_serverDataBuffer.append(data);
|
||||
int begin = _serverDataBuffer.indexOf('<');
|
||||
int end = _serverDataBuffer.indexOf('>');
|
||||
while (begin > -1 && end > -1) {
|
||||
const int len = end - begin;
|
||||
const QByteArray serverMessage = _serverDataBuffer.mid(begin+1, len-1);
|
||||
if (serverMessage.contains("1407")) {
|
||||
qCDebug(interfaceapp) << "Limitless Speech Server denied the request.";
|
||||
// Don't spam the server with further false requests please.
|
||||
DependencyManager::get<LimitlessVoiceRecognitionScriptingInterface>()->setListeningToVoice(true);
|
||||
stopListening();
|
||||
return;
|
||||
} else if (serverMessage.contains("1408")) {
|
||||
qCDebug(interfaceapp) << "Limitless Audio request authenticated!";
|
||||
_serverDataBuffer.clear();
|
||||
connect(DependencyManager::get<AudioClient>().data(), &AudioClient::inputReceived, this,
|
||||
&LimitlessConnection::audioInputReceived);
|
||||
return;
|
||||
}
|
||||
QJsonObject json = QJsonDocument::fromJson(serverMessage.data()).object();
|
||||
_serverDataBuffer.remove(begin, len+1);
|
||||
_currentTranscription = json["alternatives"].toArray()[0].toObject()["transcript"].toString();
|
||||
emit onReceivedTranscription(_currentTranscription);
|
||||
if (json["isFinal"] == true) {
|
||||
qCDebug(interfaceapp) << "Final transcription: " << _currentTranscription;
|
||||
stopListening();
|
||||
return;
|
||||
}
|
||||
begin = _serverDataBuffer.indexOf('<');
|
||||
end = _serverDataBuffer.indexOf('>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LimitlessConnection::isConnected() const {
|
||||
return _transcribeServerSocket.get() && _transcribeServerSocket->isWritable()
|
||||
&& _transcribeServerSocket->state() != QAbstractSocket::SocketState::UnconnectedState;
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
//
|
||||
// SpeechRecognitionScriptingInterface.h
|
||||
// interface/src/scripting
|
||||
//
|
||||
// Created by Trevor Berninger on 3/24/17.
|
||||
// Copyright 2017 Limitless ltd.
|
||||
//
|
||||
// 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_LimitlessConnection_h
|
||||
#define hifi_LimitlessConnection_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QFuture>
|
||||
#include <QtNetwork/QTcpSocket>
|
||||
|
||||
#include <AudioClient.h>
|
||||
|
||||
class LimitlessConnection : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
LimitlessConnection();
|
||||
|
||||
Q_INVOKABLE void startListening(QString authCode);
|
||||
Q_INVOKABLE void stopListening();
|
||||
|
||||
std::atomic<bool> _streamingAudioForTranscription;
|
||||
|
||||
signals:
|
||||
void onReceivedTranscription(QString speech);
|
||||
void onFinishedSpeaking(QString speech);
|
||||
|
||||
private:
|
||||
void transcriptionReceived();
|
||||
void audioInputReceived(const QByteArray& inputSamples);
|
||||
|
||||
bool isConnected() const;
|
||||
|
||||
std::unique_ptr<QTcpSocket> _transcribeServerSocket;
|
||||
QByteArray _serverDataBuffer;
|
||||
QString _currentTranscription;
|
||||
};
|
||||
|
||||
#endif //hifi_LimitlessConnection_h
|
|
@ -1,66 +0,0 @@
|
|||
//
|
||||
// SpeechRecognitionScriptingInterface.h
|
||||
// interface/src/scripting
|
||||
//
|
||||
// Created by Trevor Berninger on 3/20/17.
|
||||
// Copyright 2017 Limitless ltd.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "LimitlessVoiceRecognitionScriptingInterface.h"
|
||||
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
#include "InterfaceLogging.h"
|
||||
#include "ui/AvatarInputs.h"
|
||||
|
||||
const float LimitlessVoiceRecognitionScriptingInterface::_audioLevelThreshold = 0.33f;
|
||||
const int LimitlessVoiceRecognitionScriptingInterface::_voiceTimeoutDuration = 2000;
|
||||
|
||||
LimitlessVoiceRecognitionScriptingInterface::LimitlessVoiceRecognitionScriptingInterface() :
|
||||
_shouldStartListeningForVoice(false)
|
||||
{
|
||||
_voiceTimer.setSingleShot(true);
|
||||
connect(&_voiceTimer, &QTimer::timeout, this, &LimitlessVoiceRecognitionScriptingInterface::voiceTimeout);
|
||||
connect(&_connection, &LimitlessConnection::onReceivedTranscription, this, [this](QString transcription){emit onReceivedTranscription(transcription);});
|
||||
connect(&_connection, &LimitlessConnection::onFinishedSpeaking, this, [this](QString transcription){emit onFinishedSpeaking(transcription);});
|
||||
moveToNewNamedThread(&_connection, "Limitless Connection");
|
||||
}
|
||||
|
||||
void LimitlessVoiceRecognitionScriptingInterface::update() {
|
||||
const float audioLevel = AvatarInputs::getInstance()->loudnessToAudioLevel(DependencyManager::get<AudioClient>()->getAudioAverageInputLoudness());
|
||||
|
||||
if (_shouldStartListeningForVoice) {
|
||||
if (_connection._streamingAudioForTranscription) {
|
||||
if (audioLevel > _audioLevelThreshold) {
|
||||
if (_voiceTimer.isActive()) {
|
||||
_voiceTimer.stop();
|
||||
}
|
||||
} else if (!_voiceTimer.isActive()){
|
||||
_voiceTimer.start(_voiceTimeoutDuration);
|
||||
}
|
||||
} else if (audioLevel > _audioLevelThreshold) {
|
||||
// to make sure invoke doesn't get called twice before the method actually gets called
|
||||
_connection._streamingAudioForTranscription = true;
|
||||
QMetaObject::invokeMethod(&_connection, "startListening", Q_ARG(QString, authCode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LimitlessVoiceRecognitionScriptingInterface::setListeningToVoice(bool listening) {
|
||||
_shouldStartListeningForVoice = listening;
|
||||
}
|
||||
|
||||
void LimitlessVoiceRecognitionScriptingInterface::setAuthKey(QString key) {
|
||||
authCode = key;
|
||||
}
|
||||
|
||||
void LimitlessVoiceRecognitionScriptingInterface::voiceTimeout() {
|
||||
if (_connection._streamingAudioForTranscription) {
|
||||
QMetaObject::invokeMethod(&_connection, "stopListening");
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
//
|
||||
// SpeechRecognitionScriptingInterface.h
|
||||
// interface/src/scripting
|
||||
//
|
||||
// Created by Trevor Berninger on 3/20/17.
|
||||
// Copyright 2017 Limitless ltd.
|
||||
//
|
||||
// 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_SpeechRecognitionScriptingInterface_h
|
||||
#define hifi_SpeechRecognitionScriptingInterface_h
|
||||
|
||||
#include <AudioClient.h>
|
||||
#include <QObject>
|
||||
#include <QFuture>
|
||||
#include "LimitlessConnection.h"
|
||||
|
||||
class LimitlessVoiceRecognitionScriptingInterface : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
public:
|
||||
LimitlessVoiceRecognitionScriptingInterface();
|
||||
|
||||
void update();
|
||||
|
||||
QString authCode;
|
||||
|
||||
public slots:
|
||||
void setListeningToVoice(bool listening);
|
||||
void setAuthKey(QString key);
|
||||
|
||||
signals:
|
||||
void onReceivedTranscription(QString speech);
|
||||
void onFinishedSpeaking(QString speech);
|
||||
|
||||
private:
|
||||
|
||||
bool _shouldStartListeningForVoice;
|
||||
static const float _audioLevelThreshold;
|
||||
static const int _voiceTimeoutDuration;
|
||||
|
||||
QTimer _voiceTimer;
|
||||
LimitlessConnection _connection;
|
||||
|
||||
void voiceTimeout();
|
||||
};
|
||||
|
||||
#endif //hifi_SpeechRecognitionScriptingInterface_h
|
|
@ -182,7 +182,7 @@ public:
|
|||
|
||||
/**jsdoc
|
||||
* Get the list of avatars, entities, and overlays stored in a selection list.
|
||||
* @function Selection.getList
|
||||
* @function Selection.getSelectedItemsList
|
||||
* @param {string} listName - The name of the selection list.
|
||||
* @returns {Selection.SelectedItemsList} The content of a selection list. If the list name doesn't exist, the function
|
||||
* returns an empty object with no properties.
|
||||
|
@ -257,7 +257,7 @@ public:
|
|||
void onSelectedItemsListChanged(const QString& listName);
|
||||
|
||||
signals:
|
||||
/**jsoc
|
||||
/**jsdoc
|
||||
* Triggered when a list's content changes.
|
||||
* @function Selection.selectedItemsListChanged
|
||||
* @param {string} listName - The name of the selection list that changed.
|
||||
|
|
|
@ -434,7 +434,7 @@ 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();
|
||||
}
|
||||
|
|
|
@ -283,7 +283,7 @@ QVariant Base3DOverlay::getProperty(const QString& property) {
|
|||
}
|
||||
|
||||
bool Base3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -69,11 +69,11 @@ public:
|
|||
virtual QVariant getProperty(const QString& property) override;
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal);
|
||||
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false);
|
||||
|
||||
virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo) {
|
||||
return findRayIntersection(origin, direction, distance, face, surfaceNormal);
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking = false) {
|
||||
return findRayIntersection(origin, direction, distance, face, surfaceNormal, precisionPicking);
|
||||
}
|
||||
|
||||
virtual SpatialParentTree* getParentTree() const override;
|
||||
|
|
|
@ -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);
|
||||
|
@ -521,7 +519,7 @@ QVariant Circle3DOverlay::getProperty(const QString& property) {
|
|||
}
|
||||
|
||||
bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal) {
|
||||
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
|
||||
|
||||
// Scale the dimensions by the diameter
|
||||
glm::vec2 dimensions = getOuterRadius() * 2.0f * getDimensions();
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
void setMinorTickMarksColor(const xColor& value) { _minorTickMarksColor = value; }
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override;
|
||||
|
||||
virtual Circle3DOverlay* createClone() const override;
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ public:
|
|||
virtual Grid3DOverlay* createClone() const override;
|
||||
|
||||
// Grids are UI tools, and may not be intersected (pickable)
|
||||
virtual bool findRayIntersection(const glm::vec3&, const glm::vec3&, float&, BoxFace&, glm::vec3&) override { return false; }
|
||||
virtual bool findRayIntersection(const glm::vec3&, const glm::vec3&, float&, BoxFace&, glm::vec3&, bool precisionPicking = false) override { return false; }
|
||||
|
||||
protected:
|
||||
Transform evalRenderTransform() override;
|
||||
|
|
|
@ -258,7 +258,7 @@ void Image3DOverlay::setURL(const QString& url) {
|
|||
}
|
||||
|
||||
bool Image3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
|
||||
if (_texture && _texture->isLoaded()) {
|
||||
// Make sure position and rotation is updated.
|
||||
Transform transform = getTransform();
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
bool isTransparent() override { return Base3DOverlay::isTransparent() || _alphaTexture; }
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override;
|
||||
|
||||
virtual Image3DOverlay* createClone() const override;
|
||||
|
||||
|
|
|
@ -509,16 +509,16 @@ QVariant ModelOverlay::getProperty(const QString& property) {
|
|||
}
|
||||
|
||||
bool ModelOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
|
||||
|
||||
QVariantMap extraInfo;
|
||||
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, extraInfo);
|
||||
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, extraInfo, precisionPicking);
|
||||
}
|
||||
|
||||
bool ModelOverlay::findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo) {
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) {
|
||||
|
||||
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, extraInfo);
|
||||
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, extraInfo, precisionPicking);
|
||||
}
|
||||
|
||||
ModelOverlay* ModelOverlay::createClone() const {
|
||||
|
|
|
@ -45,9 +45,9 @@ public:
|
|||
void setProperties(const QVariantMap& properties) override;
|
||||
QVariant getProperty(const QString& property) override;
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override;
|
||||
virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo) override;
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking = false) override;
|
||||
|
||||
virtual ModelOverlay* createClone() const override;
|
||||
|
||||
|
|
|
@ -554,7 +554,7 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionVector(const PickRay
|
|||
glm::vec3 thisSurfaceNormal;
|
||||
QVariantMap thisExtraInfo;
|
||||
if (thisOverlay->findRayIntersectionExtraInfo(ray.origin, ray.direction, thisDistance,
|
||||
thisFace, thisSurfaceNormal, thisExtraInfo)) {
|
||||
thisFace, thisSurfaceNormal, thisExtraInfo, precisionPicking)) {
|
||||
bool isDrawInFront = thisOverlay->getDrawInFront();
|
||||
if ((bestIsFront && isDrawInFront && thisDistance < bestDistance)
|
||||
|| (!bestIsFront && (isDrawInFront || thisDistance < bestDistance))) {
|
||||
|
|
|
@ -71,7 +71,7 @@ QVariant Planar3DOverlay::getProperty(const QString& property) {
|
|||
}
|
||||
|
||||
bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
|
||||
// FIXME - face and surfaceNormal not being returned
|
||||
return findRayRectangleIntersection(origin, direction, getWorldOrientation(), getWorldPosition(), getDimensions(), distance);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
virtual QVariant getProperty(const QString& property) override;
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override;
|
||||
|
||||
protected:
|
||||
glm::vec2 _dimensions;
|
||||
|
|
|
@ -76,7 +76,7 @@ QVariant Volume3DOverlay::getProperty(const QString& property) {
|
|||
}
|
||||
|
||||
bool Volume3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
|
||||
// extents is the entity relative, scaled, centered extents of the entity
|
||||
glm::mat4 worldToEntityMatrix;
|
||||
Transform transform = getTransform();
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
QVariant getProperty(const QString& property) override;
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override;
|
||||
|
||||
protected:
|
||||
// Centered local bounding box
|
||||
|
|
|
@ -622,7 +622,7 @@ void Web3DOverlay::setScriptURL(const QString& scriptURL) {
|
|||
}
|
||||
}
|
||||
|
||||
bool Web3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
||||
bool Web3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
|
||||
glm::vec2 dimensions = getDimensions();
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
glm::vec3 position = getWorldPosition();
|
||||
|
|
|
@ -53,7 +53,7 @@ public:
|
|||
QVariant getProperty(const QString& property) override;
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override;
|
||||
|
||||
virtual Web3DOverlay* createClone() const override;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include "AudioLogging.h"
|
||||
#include "AudioSRC.h"
|
||||
|
||||
#include "flump3dec.h"
|
||||
|
||||
QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, const SharedSoundPointer& in) {
|
||||
return engine->newQObject(new SoundScriptingInterface(in), QScriptEngine::ScriptOwnership);
|
||||
}
|
||||
|
@ -90,19 +92,35 @@ void SoundProcessor::run() {
|
|||
QString fileName = _url.fileName().toLower();
|
||||
|
||||
static const QString WAV_EXTENSION = ".wav";
|
||||
static const QString MP3_EXTENSION = ".mp3";
|
||||
static const QString RAW_EXTENSION = ".raw";
|
||||
|
||||
if (fileName.endsWith(WAV_EXTENSION)) {
|
||||
|
||||
QByteArray outputAudioByteArray;
|
||||
|
||||
int sampleRate = interpretAsWav(rawAudioByteArray, outputAudioByteArray);
|
||||
if (sampleRate == 0) {
|
||||
qCDebug(audio) << "Unsupported WAV file type";
|
||||
qCWarning(audio) << "Unsupported WAV file type";
|
||||
emit onError(300, "Failed to load sound file, reason: unsupported WAV file type");
|
||||
return;
|
||||
}
|
||||
|
||||
downSample(outputAudioByteArray, sampleRate);
|
||||
|
||||
} else if (fileName.endsWith(MP3_EXTENSION)) {
|
||||
|
||||
QByteArray outputAudioByteArray;
|
||||
|
||||
int sampleRate = interpretAsMP3(rawAudioByteArray, outputAudioByteArray);
|
||||
if (sampleRate == 0) {
|
||||
qCWarning(audio) << "Unsupported MP3 file type";
|
||||
emit onError(300, "Failed to load sound file, reason: unsupported MP3 file type");
|
||||
return;
|
||||
}
|
||||
|
||||
downSample(outputAudioByteArray, sampleRate);
|
||||
|
||||
} else if (fileName.endsWith(RAW_EXTENSION)) {
|
||||
// check if this was a stereo raw file
|
||||
// since it's raw the only way for us to know that is if the file was called .stereo.raw
|
||||
|
@ -113,8 +131,9 @@ void SoundProcessor::run() {
|
|||
|
||||
// Process as 48khz RAW file
|
||||
downSample(rawAudioByteArray, 48000);
|
||||
|
||||
} else {
|
||||
qCDebug(audio) << "Unknown sound file type";
|
||||
qCWarning(audio) << "Unknown sound file type";
|
||||
emit onError(300, "Failed to load sound file, reason: unknown sound file type");
|
||||
return;
|
||||
}
|
||||
|
@ -204,7 +223,7 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA
|
|||
// Read the "RIFF" chunk
|
||||
RIFFHeader riff;
|
||||
if (waveStream.readRawData((char*)&riff, sizeof(RIFFHeader)) != sizeof(RIFFHeader)) {
|
||||
qCDebug(audio) << "Not a valid WAVE file.";
|
||||
qCWarning(audio) << "Not a valid WAVE file.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -212,11 +231,11 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA
|
|||
if (strncmp(riff.descriptor.id, "RIFF", 4) == 0) {
|
||||
waveStream.setByteOrder(QDataStream::LittleEndian);
|
||||
} else {
|
||||
qCDebug(audio) << "Currently not supporting big-endian audio files.";
|
||||
qCWarning(audio) << "Currently not supporting big-endian audio files.";
|
||||
return 0;
|
||||
}
|
||||
if (strncmp(riff.type, "WAVE", 4) != 0) {
|
||||
qCDebug(audio) << "Not a valid WAVE file.";
|
||||
qCWarning(audio) << "Not a valid WAVE file.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -224,7 +243,7 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA
|
|||
chunk fmt;
|
||||
while (true) {
|
||||
if (waveStream.readRawData((char*)&fmt, sizeof(chunk)) != sizeof(chunk)) {
|
||||
qCDebug(audio) << "Not a valid WAVE file.";
|
||||
qCWarning(audio) << "Not a valid WAVE file.";
|
||||
return 0;
|
||||
}
|
||||
if (strncmp(fmt.id, "fmt ", 4) == 0) {
|
||||
|
@ -236,14 +255,14 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA
|
|||
// Read the "fmt " chunk
|
||||
WAVEFormat wave;
|
||||
if (waveStream.readRawData((char*)&wave, sizeof(WAVEFormat)) != sizeof(WAVEFormat)) {
|
||||
qCDebug(audio) << "Not a valid WAVE file.";
|
||||
qCWarning(audio) << "Not a valid WAVE file.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Parse the "fmt " chunk
|
||||
if (qFromLittleEndian<quint16>(wave.audioFormat) != WAVEFORMAT_PCM &&
|
||||
qFromLittleEndian<quint16>(wave.audioFormat) != WAVEFORMAT_EXTENSIBLE) {
|
||||
qCDebug(audio) << "Currently not supporting non PCM audio files.";
|
||||
qCWarning(audio) << "Currently not supporting non PCM audio files.";
|
||||
return 0;
|
||||
}
|
||||
if (qFromLittleEndian<quint16>(wave.numChannels) == 2) {
|
||||
|
@ -251,11 +270,11 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA
|
|||
} else if (qFromLittleEndian<quint16>(wave.numChannels) == 4) {
|
||||
_isAmbisonic = true;
|
||||
} else if (qFromLittleEndian<quint16>(wave.numChannels) != 1) {
|
||||
qCDebug(audio) << "Currently not supporting audio files with other than 1/2/4 channels.";
|
||||
qCWarning(audio) << "Currently not supporting audio files with other than 1/2/4 channels.";
|
||||
return 0;
|
||||
}
|
||||
if (qFromLittleEndian<quint16>(wave.bitsPerSample) != 16) {
|
||||
qCDebug(audio) << "Currently not supporting non 16bit audio files.";
|
||||
qCWarning(audio) << "Currently not supporting non 16bit audio files.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -266,7 +285,7 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA
|
|||
chunk data;
|
||||
while (true) {
|
||||
if (waveStream.readRawData((char*)&data, sizeof(chunk)) != sizeof(chunk)) {
|
||||
qCDebug(audio) << "Not a valid WAVE file.";
|
||||
qCWarning(audio) << "Not a valid WAVE file.";
|
||||
return 0;
|
||||
}
|
||||
if (strncmp(data.id, "data", 4) == 0) {
|
||||
|
@ -279,10 +298,101 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA
|
|||
quint32 outputAudioByteArraySize = qFromLittleEndian<quint32>(data.size);
|
||||
outputAudioByteArray.resize(outputAudioByteArraySize);
|
||||
if (waveStream.readRawData(outputAudioByteArray.data(), outputAudioByteArraySize) != (int)outputAudioByteArraySize) {
|
||||
qCDebug(audio) << "Error reading WAV file";
|
||||
qCWarning(audio) << "Error reading WAV file";
|
||||
return 0;
|
||||
}
|
||||
|
||||
_duration = (float)(outputAudioByteArraySize / (wave.sampleRate * wave.numChannels * wave.bitsPerSample / 8.0f));
|
||||
return wave.sampleRate;
|
||||
}
|
||||
|
||||
// returns MP3 sample rate, used for resampling
|
||||
int SoundProcessor::interpretAsMP3(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray) {
|
||||
using namespace flump3dec;
|
||||
|
||||
static const int MP3_SAMPLES_MAX = 1152;
|
||||
static const int MP3_CHANNELS_MAX = 2;
|
||||
static const int MP3_BUFFER_SIZE = MP3_SAMPLES_MAX * MP3_CHANNELS_MAX * sizeof(int16_t);
|
||||
uint8_t mp3Buffer[MP3_BUFFER_SIZE];
|
||||
|
||||
// create bitstream
|
||||
Bit_stream_struc *bitstream = bs_new();
|
||||
if (bitstream == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// create decoder
|
||||
mp3tl *decoder = mp3tl_new(bitstream, MP3TL_MODE_16BIT);
|
||||
if (decoder == nullptr) {
|
||||
bs_free(bitstream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// initialize
|
||||
bs_set_data(bitstream, (uint8_t*)inputAudioByteArray.data(), inputAudioByteArray.size());
|
||||
int frameCount = 0;
|
||||
int sampleRate = 0;
|
||||
int numChannels = 0;
|
||||
|
||||
// skip ID3 tag, if present
|
||||
Mp3TlRetcode result = mp3tl_skip_id3(decoder);
|
||||
|
||||
while (!(result == MP3TL_ERR_NO_SYNC || result == MP3TL_ERR_NEED_DATA)) {
|
||||
|
||||
mp3tl_sync(decoder);
|
||||
|
||||
// find MP3 header
|
||||
const fr_header *header = nullptr;
|
||||
result = mp3tl_decode_header(decoder, &header);
|
||||
|
||||
if (result == MP3TL_ERR_OK) {
|
||||
|
||||
if (frameCount++ == 0) {
|
||||
|
||||
qCDebug(audio) << "Decoding MP3 with bitrate =" << header->bitrate
|
||||
<< "sample rate =" << header->sample_rate
|
||||
<< "channels =" << header->channels;
|
||||
|
||||
// save header info
|
||||
sampleRate = header->sample_rate;
|
||||
numChannels = header->channels;
|
||||
|
||||
// skip Xing header, if present
|
||||
result = mp3tl_skip_xing(decoder, header);
|
||||
}
|
||||
|
||||
// decode MP3 frame
|
||||
if (result == MP3TL_ERR_OK) {
|
||||
|
||||
result = mp3tl_decode_frame(decoder, mp3Buffer, MP3_BUFFER_SIZE);
|
||||
|
||||
// fill bad frames with silence
|
||||
int len = header->frame_samples * header->channels * sizeof(int16_t);
|
||||
if (result == MP3TL_ERR_BAD_FRAME) {
|
||||
memset(mp3Buffer, 0, len);
|
||||
}
|
||||
|
||||
if (result == MP3TL_ERR_OK || result == MP3TL_ERR_BAD_FRAME) {
|
||||
outputAudioByteArray.append((char*)mp3Buffer, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// free decoder
|
||||
mp3tl_free(decoder);
|
||||
|
||||
// free bitstream
|
||||
bs_free(bitstream);
|
||||
|
||||
int outputAudioByteArraySize = outputAudioByteArray.size();
|
||||
if (outputAudioByteArraySize == 0) {
|
||||
qCWarning(audio) << "Error decoding MP3 file";
|
||||
return 0;
|
||||
}
|
||||
|
||||
_isStereo = (numChannels == 2);
|
||||
_isAmbisonic = false;
|
||||
_duration = (float)outputAudioByteArraySize / (sampleRate * numChannels * sizeof(int16_t));
|
||||
return sampleRate;
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ public:
|
|||
|
||||
void downSample(const QByteArray& rawAudioByteArray, int sampleRate);
|
||||
int interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray);
|
||||
int interpretAsMP3(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray);
|
||||
|
||||
signals:
|
||||
void onSuccess(QByteArray data, bool stereo, bool ambisonic, float duration);
|
||||
|
|
8205
libraries/audio/src/flump3dec.cpp
Normal file
8205
libraries/audio/src/flump3dec.cpp
Normal file
File diff suppressed because it is too large
Load diff
428
libraries/audio/src/flump3dec.h
Normal file
428
libraries/audio/src/flump3dec.h
Normal file
|
@ -0,0 +1,428 @@
|
|||
/*
|
||||
* FLUENDO S.A.
|
||||
* Copyright (C) <2005 - 2011> <support@fluendo.com>
|
||||
*
|
||||
* This Source Code is licensed under MIT license and the explanations attached
|
||||
* in MIT License Statements.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* MIT license Statements for Fluendo's mp3 plug-in Source Code
|
||||
* ------------------------------------------------------------
|
||||
*
|
||||
* Fluendo's mp3 software Source Code (the "Source Code") is licensed under the
|
||||
* MIT license provisions.
|
||||
*
|
||||
* The MIT license is an open source license that permits the User to operate and
|
||||
* use in many forms the Source Code, which would be governed under its
|
||||
* regulations.
|
||||
*
|
||||
* The purpose of this note is to clarify the intellectual property rights granted
|
||||
* over the Source Code by Fluendo, as well as other legal issues that concern
|
||||
* your use of it.
|
||||
*
|
||||
* MIT license contents and provisions
|
||||
* -----------------------------------
|
||||
*
|
||||
* The MIT license allows you to do the following things with the Source Code:
|
||||
*
|
||||
* - Copy and use the Source Code alone or jointly with other code for any
|
||||
* purposes.
|
||||
* Copy of the Source Code is not limited and is royalty-free.
|
||||
*
|
||||
* - Merge the Source Code with other code for developing new applications with no
|
||||
* limits.
|
||||
*
|
||||
* - Modifying the Source Code for developing the plug-in or for implementing the
|
||||
* plug-in in other applications for any purposes. The MIT License does not
|
||||
* require you to share these modifications with anyone.
|
||||
*
|
||||
* - Publish, distribute, sublicense and sell copies of the Source Code to third
|
||||
* parties.
|
||||
*
|
||||
* - Permit anyone to whom the Source Code is licensed to enjoy the rights above
|
||||
* subject to the MIT license provisions.
|
||||
*
|
||||
* By licensing this Source Code under the MIT License, Fluendo is offering to the
|
||||
* community the rights set out above without restriction and without any
|
||||
* obligation for the User of the Source Code to release his/her modifications
|
||||
* back to the community. Anyone operating with the Source Code released from
|
||||
* Fluendo must grant the same MIT license rights to the community, except for any
|
||||
* modifications operated on the Source Code which can be granted under a
|
||||
* different license (even a proprietary license).
|
||||
*
|
||||
* All these rights granted to the User for the Source Code hold a limitation
|
||||
* which is to include MIT permission notice and the following copyright notice:
|
||||
* "Copyright 2005 Fluendo, S.L. This Source Code is licensed under MIT license
|
||||
* and the explanations attached in MIT License Statements". These notices shall
|
||||
* be included in all copies of the Source Code or in substantial parts of the
|
||||
* Source Code which may be released separately or with modifications.
|
||||
*
|
||||
* Patents over the plug-in and/or Source Code
|
||||
* -------------------------------------------
|
||||
*
|
||||
* The binaries that can be created by compiling this Source Code released by
|
||||
* Fluendo might be covered by patents in various parts of the world. Fluendo
|
||||
* does not own or claim to own any patents on the techniques used in the code.
|
||||
* (Such patents are owned or claimed to be owned by Thompson Licensing, S.A. and
|
||||
* some other entities as the case may be).
|
||||
*
|
||||
* Fluendo has got the relevant licenses to cover its own activities with the
|
||||
* Source Code but it is not authorized to sublicense nor to grant the rights
|
||||
* which it has acquired over the patents. In this sense, you can work and deal
|
||||
* freely with the Source Code under MIT provisions set out above, bearing in mind
|
||||
* that some activities might not be allowed under applicable patent regulations
|
||||
* and that Fluendo is not granting any rights in relation to such patents.
|
||||
*
|
||||
* The patent license granted to Fluendo only covers Fluendo's own Software and
|
||||
* Source Code activities. In any case, this software license does not allow you
|
||||
* to redistribute or copy complete, ready to use mp3 software decoder binaries
|
||||
* made from the Source Code as made available by Fluendo. You can of course
|
||||
* distribute binaries you make yourself under any terms allowed by the MIT
|
||||
* license and whatever necessary rights you have or have acquired according to
|
||||
* applicable patent regulations.
|
||||
*
|
||||
* As Fluendo can not assure that any of the activities you undertake do not
|
||||
* infringe any patents or other industrial or intellectual property rights,
|
||||
* Fluendo hereby disclaims any liability for any patent infringement that may be
|
||||
* claimed to you or to any other person from any legitimate right’s owner, as
|
||||
* stated in MIT license. So it is your responsibility to get information and to
|
||||
* acquire the necessary patent licenses to undertake your activities legally.
|
||||
*/
|
||||
|
||||
//
|
||||
// Modifications and bug fixes copyright 2018 High Fidelity, Inc.
|
||||
// Now passes ISO/IEC 11172-4 "full accuracy" compliance testing.
|
||||
//
|
||||
|
||||
#ifndef __FLUMP3DEC_H__
|
||||
#define __FLUMP3DEC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if 0
|
||||
#include <stdio.h>
|
||||
#define G_GINT64_FORMAT "lld"
|
||||
#define G_GUINT64_FORMAT "llu"
|
||||
|
||||
#define GST_LOG(f, ...) do { printf(f "\n", __VA_ARGS__); } while (0)
|
||||
#define GST_DEBUG(f, ...) do { printf(f "\n", __VA_ARGS__); } while (0)
|
||||
#define GST_WARNING(f, ...) do { printf(f "\n", __VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define GST_LOG(f, ...) do {} while (0)
|
||||
#define GST_DEBUG(f, ...) do {} while (0)
|
||||
#define GST_WARNING(f, ...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#define g_assert(cond) assert(cond)
|
||||
#define g_return_if_fail(cond) { if (!(cond)) return; }
|
||||
#define g_return_val_if_fail(cond, val) { if (!(cond)) return (val); }
|
||||
|
||||
namespace flump3dec {
|
||||
|
||||
typedef char gchar;
|
||||
typedef unsigned char guchar;
|
||||
typedef int gint;
|
||||
typedef unsigned int guint;
|
||||
typedef float gfloat;
|
||||
typedef double gdouble;
|
||||
typedef int gboolean;
|
||||
typedef size_t gsize;
|
||||
|
||||
typedef int8_t gint8;
|
||||
typedef uint8_t guint8;
|
||||
typedef int16_t gint16;
|
||||
typedef uint16_t guint16;
|
||||
typedef int32_t gint32;
|
||||
typedef uint32_t guint32;
|
||||
typedef int64_t gint64;
|
||||
typedef uint64_t guint64;
|
||||
|
||||
/* Accumulator optimization on bitstream management */
|
||||
#define ENABLE_OPT_BS 1
|
||||
|
||||
/* Bit stream reader definitions */
|
||||
#define MAX_LENGTH 32 /* Maximum length of word written or
|
||||
read from bit stream */
|
||||
#define BS_BYTE_SIZE 8
|
||||
|
||||
#if ENABLE_OPT_BS
|
||||
#define BS_ACUM_SIZE 32
|
||||
#else
|
||||
#define BS_ACUM_SIZE 8
|
||||
#endif
|
||||
|
||||
typedef struct BSReader
|
||||
{
|
||||
guint64 bitpos; /* Number of bits read so far */
|
||||
|
||||
gsize size; /* Number of bytes in the buffer list */
|
||||
const guint8 *data; /* Current data buffer */
|
||||
guint8 *cur_byte; /* ptr to the current byte */
|
||||
guint8 cur_bit; /* the next bit to be used in the current byte,
|
||||
* numbered from 8 down to 1 */
|
||||
gsize cur_used; /* Number of bytes _completely_ consumed out of
|
||||
* the 'cur buffer' */
|
||||
} BSReader;
|
||||
|
||||
typedef struct Bit_stream_struc
|
||||
{
|
||||
BSReader master; /* Master tracking position, advanced
|
||||
* by bs_consume() */
|
||||
BSReader read; /* Current read position, set back to the
|
||||
* master by bs_reset() */
|
||||
} Bit_stream_struc;
|
||||
|
||||
/* Create and initialise a new bitstream reader */
|
||||
Bit_stream_struc *bs_new ();
|
||||
|
||||
/* Release a bitstream reader */
|
||||
void bs_free (Bit_stream_struc * bs);
|
||||
|
||||
/* Reset the current read position to the master position */
|
||||
static inline void
|
||||
bs_reset (Bit_stream_struc * bs)
|
||||
{
|
||||
memcpy (&bs->read, &bs->master, sizeof (BSReader));
|
||||
}
|
||||
|
||||
/* Reset master and read states */
|
||||
static inline void
|
||||
bs_flush (Bit_stream_struc * bs)
|
||||
{
|
||||
g_return_if_fail (bs != NULL);
|
||||
|
||||
bs->master.cur_bit = 8;
|
||||
bs->master.size = 0;
|
||||
bs->master.cur_used = 0;
|
||||
bs->master.cur_byte = NULL;
|
||||
bs->master.data = NULL;
|
||||
bs->master.bitpos = 0;
|
||||
|
||||
bs_reset (bs);
|
||||
}
|
||||
|
||||
/* Set data as the stream for processing */
|
||||
gboolean bs_set_data (Bit_stream_struc * bs, const guint8 * data, gsize size);
|
||||
|
||||
/* Advance the master position by Nbits */
|
||||
void bs_consume (Bit_stream_struc * bs, guint32 Nbits);
|
||||
|
||||
/* Number of bits available for reading */
|
||||
static inline gsize bs_bits_avail (Bit_stream_struc * bs)
|
||||
{
|
||||
return ((bs->read.size - bs->read.cur_used) * 8 + (bs->read.cur_bit - 8));
|
||||
}
|
||||
|
||||
/* Extract N bytes from the bitstream into the out array. */
|
||||
void bs_getbytes (Bit_stream_struc * bs, guint8 * out, guint32 N);
|
||||
|
||||
/* Advance the read pointer by N bits */
|
||||
void bs_skipbits (Bit_stream_struc * bs, guint32 N);
|
||||
|
||||
/* give number of consumed bytes */
|
||||
static inline gsize bs_get_consumed (Bit_stream_struc * bs)
|
||||
{
|
||||
return bs->master.cur_used;
|
||||
}
|
||||
|
||||
/* Current bitstream position in bits */
|
||||
static inline guint64
|
||||
bs_pos (Bit_stream_struc * bs)
|
||||
{
|
||||
return bs->master.bitpos;
|
||||
}
|
||||
|
||||
/* Current read bitstream position in bits */
|
||||
static inline guint64
|
||||
bs_read_pos (Bit_stream_struc * bs)
|
||||
{
|
||||
return bs->read.bitpos;
|
||||
}
|
||||
|
||||
/* Advances the read position to the first bit of next frame or
|
||||
* last byte in the buffer when the sync code is not found */
|
||||
gboolean bs_seek_sync (Bit_stream_struc * bs);
|
||||
|
||||
/* Read N bits from the stream */
|
||||
/* bs - bit stream structure */
|
||||
/* N - number of bits to read from the bit stream */
|
||||
/* v - output value */
|
||||
static inline guint32
|
||||
bs_getbits (Bit_stream_struc * bs, guint32 N)
|
||||
{
|
||||
guint32 val = 0;
|
||||
gint j = N;
|
||||
|
||||
g_assert (N <= MAX_LENGTH);
|
||||
|
||||
while (j > 0) {
|
||||
gint tmp;
|
||||
gint k;
|
||||
gint mask;
|
||||
|
||||
/* Move to the next byte if we consumed the current one */
|
||||
if (bs->read.cur_bit == 0) {
|
||||
bs->read.cur_bit = 8;
|
||||
bs->read.cur_used++;
|
||||
bs->read.cur_byte++;
|
||||
}
|
||||
|
||||
/* Protect against data limit */
|
||||
if ((bs->read.cur_used >= bs->read.size)) {
|
||||
GST_WARNING ("Attempted to read beyond data");
|
||||
/* Return the bits we got so far */
|
||||
return val;
|
||||
}
|
||||
/* Take as many bits as we can from the current byte */
|
||||
k = MIN (j, bs->read.cur_bit);
|
||||
|
||||
/* We want the k bits from the current byte, starting from
|
||||
* the cur_bit. Mask out the top 'already used' bits, then shift
|
||||
* the bits we want down to the bottom */
|
||||
mask = (1 << bs->read.cur_bit) - 1;
|
||||
tmp = bs->read.cur_byte[0] & mask;
|
||||
|
||||
/* Trim off the bits we're leaving for next time */
|
||||
tmp = tmp >> (bs->read.cur_bit - k);
|
||||
|
||||
/* Adjust our tracking vars */
|
||||
bs->read.cur_bit -= k;
|
||||
j -= k;
|
||||
bs->read.bitpos += k;
|
||||
|
||||
/* Put these bits in the right spot in the output */
|
||||
val |= tmp << j;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Read 1 bit from the stream */
|
||||
static inline guint32
|
||||
bs_get1bit (Bit_stream_struc * bs)
|
||||
{
|
||||
return bs_getbits (bs, 1);
|
||||
}
|
||||
|
||||
/* read the next byte aligned N bits from the bit stream */
|
||||
static inline guint32
|
||||
bs_getbits_aligned (Bit_stream_struc * bs, guint32 N)
|
||||
{
|
||||
guint32 align;
|
||||
|
||||
align = bs->read.cur_bit;
|
||||
if (align != 8 && align != 0)
|
||||
bs_getbits (bs, align);
|
||||
|
||||
return bs_getbits (bs, N);
|
||||
}
|
||||
|
||||
/* MPEG Header Definitions - ID Bit Values */
|
||||
#define MPEG_VERSION_1 0x03
|
||||
#define MPEG_VERSION_2 0x02
|
||||
#define MPEG_VERSION_2_5 0x00
|
||||
|
||||
/* Header Information Structure */
|
||||
typedef struct
|
||||
{
|
||||
/* Stuff read straight from the MPEG header */
|
||||
guint version;
|
||||
guint layer;
|
||||
gboolean error_protection;
|
||||
|
||||
gint bitrate_idx; /* Index into the bitrate tables */
|
||||
guint srate_idx; /* Index into the sample rate table */
|
||||
|
||||
gboolean padding;
|
||||
gboolean extension;
|
||||
guint mode;
|
||||
guint mode_ext;
|
||||
gboolean copyright;
|
||||
gboolean original;
|
||||
guint emphasis;
|
||||
|
||||
/* Derived attributes */
|
||||
guint bitrate; /* Bitrate of the frame, kbps */
|
||||
guint sample_rate; /* sample rate in Hz */
|
||||
guint sample_size; /* in bits */
|
||||
guint frame_samples; /* Number of samples per channels in this
|
||||
frame */
|
||||
guint channels; /* Number of channels in the frame */
|
||||
|
||||
guint bits_per_slot; /* Number of bits per slot */
|
||||
guint frame_slots; /* Total number of data slots in this frame */
|
||||
guint main_slots; /* Slots of main data in this frame */
|
||||
guint frame_bits; /* Number of bits in the frame, including header
|
||||
and sync word */
|
||||
guint side_info_slots; /* Number of slots of side info in the frame */
|
||||
} fr_header;
|
||||
|
||||
typedef struct mp3tl mp3tl;
|
||||
typedef enum
|
||||
{
|
||||
MP3TL_ERR_OK = 0, /* Successful return code */
|
||||
MP3TL_ERR_NO_SYNC, /* There was no sync word in the data buffer */
|
||||
MP3TL_ERR_NEED_DATA, /* Not enough data in the buffer for the requested op */
|
||||
MP3TL_ERR_BAD_FRAME, /* The frame data was corrupt and skipped */
|
||||
MP3TL_ERR_STREAM, /* Encountered invalid data in the stream */
|
||||
MP3TL_ERR_UNSUPPORTED_STREAM, /* Encountered valid but unplayable data in
|
||||
* the stream */
|
||||
MP3TL_ERR_PARAM, /* Invalid parameter was passed in */
|
||||
MP3TL_ERR_UNKNOWN /* Unspecified internal decoder error (bug) */
|
||||
} Mp3TlRetcode;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MP3TL_MODE_16BIT = 0 /* Decoder mode to use */
|
||||
} Mp3TlMode;
|
||||
|
||||
mp3tl *mp3tl_new (Bit_stream_struc * bs, Mp3TlMode mode);
|
||||
|
||||
void mp3tl_free (mp3tl * tl);
|
||||
|
||||
void mp3tl_set_eos (mp3tl * tl, gboolean more_data);
|
||||
Mp3TlRetcode mp3tl_sync (mp3tl * tl);
|
||||
Mp3TlRetcode mp3tl_gather_frame (mp3tl * tl, guint64 * _offset, gint * _length);
|
||||
Mp3TlRetcode mp3tl_decode_header (mp3tl * tl, const fr_header ** ret_hdr);
|
||||
Mp3TlRetcode mp3tl_skip_frame (mp3tl * tl);
|
||||
Mp3TlRetcode mp3tl_decode_frame (mp3tl * tl, guint8 * samples, guint bufsize);
|
||||
const char *mp3tl_get_err_reason (mp3tl * tl);
|
||||
void mp3tl_flush (mp3tl * tl);
|
||||
|
||||
Mp3TlRetcode mp3tl_skip_id3 (mp3tl * tl);
|
||||
Mp3TlRetcode mp3tl_skip_xing (mp3tl * tl, const fr_header * hdr);
|
||||
|
||||
} // namespace flump3dec
|
||||
|
||||
#endif //__FLUMP3DEC_H__
|
|
@ -42,7 +42,6 @@
|
|||
|
||||
size_t std::hash<EntityItemID>::operator()(const EntityItemID& id) const { return qHash(id); }
|
||||
std::function<bool()> EntityTreeRenderer::_entitiesShouldFadeFunction;
|
||||
std::function<bool()> EntityTreeRenderer::_renderDebugHullsOperator = [] { return false; };
|
||||
|
||||
QString resolveScriptURL(const QString& scriptUrl) {
|
||||
auto normalizedScriptUrl = DependencyManager::get<ResourceManager>()->normalizeURL(scriptUrl);
|
||||
|
|
|
@ -116,14 +116,10 @@ public:
|
|||
EntityItemPointer getEntity(const EntityItemID& id);
|
||||
void onEntityChanged(const EntityItemID& id);
|
||||
|
||||
static void setRenderDebugHullsOperator(std::function<bool()> renderDebugHullsOperator) { _renderDebugHullsOperator = renderDebugHullsOperator; }
|
||||
static bool shouldRenderDebugHulls() { return _renderDebugHullsOperator(); }
|
||||
|
||||
signals:
|
||||
void enterEntity(const EntityItemID& entityItemID);
|
||||
void leaveEntity(const EntityItemID& entityItemID);
|
||||
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
||||
void setRenderDebugHulls();
|
||||
|
||||
public slots:
|
||||
void addingEntity(const EntityItemID& entityID);
|
||||
|
@ -259,8 +255,6 @@ private:
|
|||
static int _entitiesScriptEngineCount;
|
||||
static CalculateEntityLoadingPriority _calculateEntityLoadingPriorityFunc;
|
||||
static std::function<bool()> _entitiesShouldFadeFunction;
|
||||
|
||||
static std::function<bool()> _renderDebugHullsOperator;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <QtCore/QUrlQuery>
|
||||
|
||||
#include <AbstractViewStateInterface.h>
|
||||
#include <CollisionRenderMeshCache.h>
|
||||
#include <Model.h>
|
||||
#include <PerfStat.h>
|
||||
#include <render/Scene.h>
|
||||
|
@ -35,8 +34,6 @@
|
|||
#include "EntitiesRendererLogging.h"
|
||||
|
||||
|
||||
static CollisionRenderMeshCache collisionMeshCache;
|
||||
|
||||
void ModelEntityWrapper::setModel(const ModelPointer& model) {
|
||||
withWriteLock([&] {
|
||||
if (_model != model) {
|
||||
|
@ -1052,10 +1049,7 @@ using namespace render;
|
|||
using namespace render::entities;
|
||||
|
||||
ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {
|
||||
connect(DependencyManager::get<EntityTreeRenderer>().data(), &EntityTreeRenderer::setRenderDebugHulls, this, [&] {
|
||||
_needsCollisionGeometryUpdate = true;
|
||||
emit requestRenderUpdate();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) {
|
||||
|
@ -1215,10 +1209,6 @@ bool ModelEntityRenderer::needsRenderUpdate() const {
|
|||
if (model->getRenderItemsNeedUpdate()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_needsCollisionGeometryUpdate) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Parent::needsRenderUpdate();
|
||||
}
|
||||
|
@ -1285,12 +1275,7 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
|
|||
}
|
||||
|
||||
void ModelEntityRenderer::setCollisionMeshKey(const void*key) {
|
||||
if (key != _collisionMeshKey) {
|
||||
if (_collisionMeshKey) {
|
||||
collisionMeshCache.releaseMesh(_collisionMeshKey);
|
||||
}
|
||||
_collisionMeshKey = key;
|
||||
}
|
||||
_collisionMeshKey = key;
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
||||
|
@ -1339,7 +1324,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
_didLastVisualGeometryRequestSucceed = didVisualGeometryRequestSucceed;
|
||||
});
|
||||
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
|
||||
connect(entity.get(), &RenderableModelEntityItem::requestCollisionGeometryUpdate, this, &ModelEntityRenderer::flagForCollisionGeometryUpdate);
|
||||
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
|
||||
entity->setModel(model);
|
||||
withWriteLock([&] { _model = model; });
|
||||
|
@ -1412,26 +1396,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
model->setCanCastShadow(_canCastShadow, scene);
|
||||
}
|
||||
|
||||
if (_needsCollisionGeometryUpdate) {
|
||||
setCollisionMeshKey(entity->getCollisionMeshKey());
|
||||
_needsCollisionGeometryUpdate = false;
|
||||
ShapeType type = entity->getShapeType();
|
||||
if (DependencyManager::get<EntityTreeRenderer>()->shouldRenderDebugHulls() && type != SHAPE_TYPE_STATIC_MESH && type != SHAPE_TYPE_NONE) {
|
||||
// NOTE: it is OK if _collisionMeshKey is nullptr
|
||||
graphics::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey);
|
||||
// NOTE: the model will render the collisionGeometry if it has one
|
||||
_model->setCollisionMesh(mesh);
|
||||
} else {
|
||||
if (_collisionMeshKey) {
|
||||
// release mesh
|
||||
collisionMeshCache.releaseMesh(_collisionMeshKey);
|
||||
}
|
||||
// clear model's collision geometry
|
||||
graphics::MeshPointer mesh = nullptr;
|
||||
_model->setCollisionMesh(mesh);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, "Fixup");
|
||||
if (model->needsFixupInScene()) {
|
||||
|
@ -1487,11 +1451,6 @@ void ModelEntityRenderer::setIsVisibleInSecondaryCamera(bool value) {
|
|||
setKey(_didLastVisualGeometryRequestSucceed);
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::flagForCollisionGeometryUpdate() {
|
||||
_needsCollisionGeometryUpdate = true;
|
||||
emit requestRenderUpdate();
|
||||
}
|
||||
|
||||
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items
|
||||
void ModelEntityRenderer::doRender(RenderArgs* args) {
|
||||
DETAILED_PROFILE_RANGE(render_detail, "MetaModelRender");
|
||||
|
|
|
@ -161,7 +161,6 @@ protected:
|
|||
virtual bool needsRenderUpdate() const override;
|
||||
virtual void doRender(RenderArgs* args) override;
|
||||
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
||||
void flagForCollisionGeometryUpdate();
|
||||
void setCollisionMeshKey(const void* key);
|
||||
|
||||
render::hifi::Tag getTagMask() const override;
|
||||
|
@ -189,7 +188,6 @@ private:
|
|||
#endif
|
||||
|
||||
bool _needsJointSimulation { false };
|
||||
bool _needsCollisionGeometryUpdate { false };
|
||||
const void* _collisionMeshKey { nullptr };
|
||||
|
||||
// used on client side
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -815,8 +815,13 @@ unsigned int LimitedNodeList::broadcastToNodes(std::unique_ptr<NLPacket> packet,
|
|||
|
||||
eachNode([&](const SharedNodePointer& node){
|
||||
if (node && destinationNodeTypes.contains(node->getType())) {
|
||||
sendUnreliablePacket(*packet, *node);
|
||||
++n;
|
||||
if (packet->isReliable()) {
|
||||
auto packetCopy = NLPacket::createCopy(*packet);
|
||||
sendPacket(std::move(packetCopy), *node);
|
||||
} else {
|
||||
sendUnreliablePacket(*packet, *node);
|
||||
}
|
||||
++n;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -47,7 +47,7 @@ bool CauterizedModel::updateGeometry() {
|
|||
return needsFullUpdate;
|
||||
}
|
||||
|
||||
void CauterizedModel::createVisibleRenderItemSet() {
|
||||
void CauterizedModel::createRenderItemSet() {
|
||||
if (_isCauterized) {
|
||||
assert(isLoaded());
|
||||
const auto& meshes = _renderGeometry->getMeshes();
|
||||
|
@ -94,15 +94,10 @@ void CauterizedModel::createVisibleRenderItemSet() {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
Model::createVisibleRenderItemSet();
|
||||
Model::createRenderItemSet();
|
||||
}
|
||||
}
|
||||
|
||||
void CauterizedModel::createCollisionRenderItemSet() {
|
||||
// Temporary HACK: use base class method for now
|
||||
Model::createCollisionRenderItemSet();
|
||||
}
|
||||
|
||||
void CauterizedModel::updateClusterMatrices() {
|
||||
PerformanceTimer perfTimer("CauterizedModel::updateClusterMatrices");
|
||||
|
||||
|
@ -186,12 +181,6 @@ void CauterizedModel::updateRenderItems() {
|
|||
if (!_addedToScene) {
|
||||
return;
|
||||
}
|
||||
|
||||
glm::vec3 scale = getScale();
|
||||
if (_collisionGeometry) {
|
||||
// _collisionGeometry is already scaled
|
||||
scale = glm::vec3(1.0f);
|
||||
}
|
||||
_needsUpdateClusterMatrices = true;
|
||||
_renderItemsNeedUpdate = false;
|
||||
|
||||
|
|
|
@ -31,9 +31,8 @@ public:
|
|||
void deleteGeometry() override;
|
||||
bool updateGeometry() override;
|
||||
|
||||
void createVisibleRenderItemSet() override;
|
||||
void createCollisionRenderItemSet() override;
|
||||
|
||||
void createRenderItemSet() override;
|
||||
|
||||
virtual void updateClusterMatrices() override;
|
||||
void updateRenderItems() override;
|
||||
|
||||
|
|
|
@ -47,51 +47,9 @@ int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >();
|
|||
float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f;
|
||||
#define HTTP_INVALID_COM "http://invalid.com"
|
||||
|
||||
const int NUM_COLLISION_HULL_COLORS = 24;
|
||||
std::vector<graphics::MaterialPointer> _collisionMaterials;
|
||||
|
||||
void initCollisionMaterials() {
|
||||
// generates bright colors in red, green, blue, yellow, magenta, and cyan spectrums
|
||||
// (no browns, greys, or dark shades)
|
||||
float component[NUM_COLLISION_HULL_COLORS] = {
|
||||
0.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.2f, 0.4f, 0.6f, 0.8f,
|
||||
1.0f, 1.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f, 1.0f,
|
||||
0.8f, 0.6f, 0.4f, 0.2f
|
||||
};
|
||||
_collisionMaterials.reserve(NUM_COLLISION_HULL_COLORS);
|
||||
|
||||
// each component gets the same cuve
|
||||
// but offset by a multiple of one third the full width
|
||||
int numComponents = 3;
|
||||
int sectionWidth = NUM_COLLISION_HULL_COLORS / numComponents;
|
||||
int greenPhase = sectionWidth;
|
||||
int bluePhase = 2 * sectionWidth;
|
||||
|
||||
// we stride through the colors to scatter adjacent shades
|
||||
// so they don't tend to group together for large models
|
||||
for (int i = 0; i < sectionWidth; ++i) {
|
||||
for (int j = 0; j < numComponents; ++j) {
|
||||
graphics::MaterialPointer material;
|
||||
material = std::make_shared<graphics::Material>();
|
||||
int index = j * sectionWidth + i;
|
||||
float red = component[index % NUM_COLLISION_HULL_COLORS];
|
||||
float green = component[(index + greenPhase) % NUM_COLLISION_HULL_COLORS];
|
||||
float blue = component[(index + bluePhase) % NUM_COLLISION_HULL_COLORS];
|
||||
material->setAlbedo(glm::vec3(red, green, blue));
|
||||
material->setMetallic(0.02f);
|
||||
material->setRoughness(0.5f);
|
||||
_collisionMaterials.push_back(material);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) :
|
||||
QObject(parent),
|
||||
_renderGeometry(),
|
||||
_collisionGeometry(),
|
||||
_renderWatcher(_renderGeometry),
|
||||
_spatiallyNestableOverride(spatiallyNestableOverride),
|
||||
_translation(0.0f),
|
||||
|
@ -310,16 +268,6 @@ void Model::updateRenderItems() {
|
|||
});
|
||||
}
|
||||
|
||||
Transform collisionMeshOffset;
|
||||
collisionMeshOffset.setIdentity();
|
||||
foreach(auto itemID, self->_collisionRenderItemsMap.keys()) {
|
||||
transaction.updateItem<MeshPartPayload>(itemID, [renderItemKeyGlobalFlags, modelTransform, collisionMeshOffset](MeshPartPayload& data) {
|
||||
// update the model transform for this render item.
|
||||
data.updateKey(renderItemKeyGlobalFlags);
|
||||
data.updateTransform(modelTransform, collisionMeshOffset);
|
||||
});
|
||||
}
|
||||
|
||||
AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
|
||||
});
|
||||
}
|
||||
|
@ -777,11 +725,6 @@ void Model::updateRenderItemsKey(const render::ScenePointer& scene) {
|
|||
data.updateKey(renderItemsKey);
|
||||
});
|
||||
}
|
||||
foreach(auto item, _collisionRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [renderItemsKey](ModelMeshPartPayload& data) {
|
||||
data.updateKey(renderItemsKey);
|
||||
});
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
|
@ -862,49 +805,37 @@ const render::ItemKey Model::getRenderItemKeyGlobalFlags() const {
|
|||
bool Model::addToScene(const render::ScenePointer& scene,
|
||||
render::Transaction& transaction,
|
||||
render::Item::Status::Getters& statusGetters) {
|
||||
bool readyToRender = _collisionGeometry || isLoaded();
|
||||
if (!_addedToScene && readyToRender) {
|
||||
createRenderItemSet();
|
||||
if (!_addedToScene && isLoaded()) {
|
||||
updateClusterMatrices();
|
||||
if (_modelMeshRenderItems.empty()) {
|
||||
createRenderItemSet();
|
||||
}
|
||||
}
|
||||
|
||||
bool somethingAdded = false;
|
||||
if (_collisionGeometry) {
|
||||
if (_collisionRenderItemsMap.empty()) {
|
||||
foreach (auto renderItem, _collisionRenderItems) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
|
||||
if (_collisionRenderItems.empty() && statusGetters.size()) {
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
}
|
||||
transaction.resetItem(item, renderPayload);
|
||||
_collisionRenderItemsMap.insert(item, renderPayload);
|
||||
|
||||
if (_modelMeshRenderItemsMap.empty()) {
|
||||
|
||||
bool hasTransparent = false;
|
||||
size_t verticesCount = 0;
|
||||
foreach(auto renderItem, _modelMeshRenderItems) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
|
||||
if (_modelMeshRenderItemsMap.empty() && statusGetters.size()) {
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
}
|
||||
somethingAdded = !_collisionRenderItemsMap.empty();
|
||||
transaction.resetItem(item, renderPayload);
|
||||
|
||||
hasTransparent = hasTransparent || renderItem.get()->getShapeKey().isTranslucent();
|
||||
verticesCount += renderItem.get()->getVerticesCount();
|
||||
_modelMeshRenderItemsMap.insert(item, renderPayload);
|
||||
_modelMeshRenderItemIDs.emplace_back(item);
|
||||
}
|
||||
} else {
|
||||
if (_modelMeshRenderItemsMap.empty()) {
|
||||
somethingAdded = !_modelMeshRenderItemsMap.empty();
|
||||
|
||||
bool hasTransparent = false;
|
||||
size_t verticesCount = 0;
|
||||
foreach(auto renderItem, _modelMeshRenderItems) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
|
||||
if (_modelMeshRenderItemsMap.empty() && statusGetters.size()) {
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
}
|
||||
transaction.resetItem(item, renderPayload);
|
||||
|
||||
hasTransparent = hasTransparent || renderItem.get()->getShapeKey().isTranslucent();
|
||||
verticesCount += renderItem.get()->getVerticesCount();
|
||||
_modelMeshRenderItemsMap.insert(item, renderPayload);
|
||||
_modelMeshRenderItemIDs.emplace_back(item);
|
||||
}
|
||||
somethingAdded = !_modelMeshRenderItemsMap.empty();
|
||||
|
||||
_renderInfoVertexCount = verticesCount;
|
||||
_renderInfoDrawCalls = _modelMeshRenderItemsMap.count();
|
||||
_renderInfoHasTransparent = hasTransparent;
|
||||
}
|
||||
_renderInfoVertexCount = verticesCount;
|
||||
_renderInfoDrawCalls = _modelMeshRenderItemsMap.count();
|
||||
_renderInfoHasTransparent = hasTransparent;
|
||||
}
|
||||
|
||||
if (somethingAdded) {
|
||||
|
@ -926,11 +857,6 @@ void Model::removeFromScene(const render::ScenePointer& scene, render::Transacti
|
|||
_modelMeshMaterialNames.clear();
|
||||
_modelMeshRenderItemShapes.clear();
|
||||
|
||||
foreach(auto item, _collisionRenderItemsMap.keys()) {
|
||||
transaction.removeItem(item);
|
||||
}
|
||||
_collisionRenderItems.clear();
|
||||
_collisionRenderItemsMap.clear();
|
||||
_addedToScene = false;
|
||||
|
||||
_renderInfoVertexCount = 0;
|
||||
|
@ -1504,7 +1430,6 @@ void Model::deleteGeometry() {
|
|||
_rig.destroyAnimGraph();
|
||||
_blendedBlendshapeCoefficients.clear();
|
||||
_renderGeometry.reset();
|
||||
_collisionGeometry.reset();
|
||||
}
|
||||
|
||||
void Model::overrideModelTransformAndOffset(const Transform& transform, const glm::vec3& offset) {
|
||||
|
@ -1533,19 +1458,6 @@ const render::ItemIDs& Model::fetchRenderItemIDs() const {
|
|||
}
|
||||
|
||||
void Model::createRenderItemSet() {
|
||||
updateClusterMatrices();
|
||||
if (_collisionGeometry) {
|
||||
if (_collisionRenderItems.empty()) {
|
||||
createCollisionRenderItemSet();
|
||||
}
|
||||
} else {
|
||||
if (_modelMeshRenderItems.empty()) {
|
||||
createVisibleRenderItemSet();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void Model::createVisibleRenderItemSet() {
|
||||
assert(isLoaded());
|
||||
const auto& meshes = _renderGeometry->getMeshes();
|
||||
|
||||
|
@ -1591,41 +1503,6 @@ void Model::createVisibleRenderItemSet() {
|
|||
}
|
||||
}
|
||||
|
||||
void Model::createCollisionRenderItemSet() {
|
||||
assert((bool)_collisionGeometry);
|
||||
if (_collisionMaterials.empty()) {
|
||||
initCollisionMaterials();
|
||||
}
|
||||
|
||||
const auto& meshes = _collisionGeometry->getMeshes();
|
||||
|
||||
// We should not have any existing renderItems if we enter this section of code
|
||||
Q_ASSERT(_collisionRenderItems.isEmpty());
|
||||
|
||||
Transform identity;
|
||||
identity.setIdentity();
|
||||
Transform offset;
|
||||
offset.postTranslate(_offset);
|
||||
|
||||
// Run through all of the meshes, and place them into their segregated, but unsorted buckets
|
||||
uint32_t numMeshes = (uint32_t)meshes.size();
|
||||
for (uint32_t i = 0; i < numMeshes; i++) {
|
||||
const auto& mesh = meshes.at(i);
|
||||
if (!mesh) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the render payloads
|
||||
int numParts = (int)mesh->getNumParts();
|
||||
for (int partIndex = 0; partIndex < numParts; partIndex++) {
|
||||
graphics::MaterialPointer& material = _collisionMaterials[partIndex % NUM_COLLISION_HULL_COLORS];
|
||||
auto payload = std::make_shared<MeshPartPayload>(mesh, partIndex, material);
|
||||
payload->updateTransform(identity, offset);
|
||||
_collisionRenderItems << payload;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Model::isRenderable() const {
|
||||
return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty());
|
||||
}
|
||||
|
@ -1709,15 +1586,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
void Model::setCollisionMesh(graphics::MeshPointer mesh) {
|
||||
if (mesh) {
|
||||
_collisionGeometry = std::make_shared<CollisionRenderGeometry>(mesh);
|
||||
} else {
|
||||
_collisionGeometry.reset();
|
||||
}
|
||||
_needsFixupInScene = true;
|
||||
}
|
||||
|
||||
ModelBlender::ModelBlender() :
|
||||
_pendingBlenders(0) {
|
||||
}
|
||||
|
|
|
@ -153,8 +153,6 @@ public:
|
|||
|
||||
/// Returns a reference to the shared geometry.
|
||||
const Geometry::Pointer& getGeometry() const { return _renderGeometry; }
|
||||
/// Returns a reference to the shared collision geometry.
|
||||
const Geometry::Pointer& getCollisionGeometry() const { return _collisionGeometry; }
|
||||
|
||||
const QVariantMap getTextures() const { assert(isLoaded()); return _renderGeometry->getTextures(); }
|
||||
Q_INVOKABLE virtual void setTextures(const QVariantMap& textures);
|
||||
|
@ -260,7 +258,6 @@ public:
|
|||
|
||||
// returns 'true' if needs fullUpdate after geometry change
|
||||
virtual bool updateGeometry();
|
||||
void setCollisionMesh(graphics::MeshPointer mesh);
|
||||
|
||||
void setLoadingPriority(float priority) { _loadingPriority = priority; }
|
||||
|
||||
|
@ -362,7 +359,6 @@ protected:
|
|||
bool getJointPosition(int jointIndex, glm::vec3& position) const;
|
||||
|
||||
Geometry::Pointer _renderGeometry; // only ever set by its watcher
|
||||
Geometry::Pointer _collisionGeometry;
|
||||
|
||||
GeometryResourceWatcher _renderWatcher;
|
||||
|
||||
|
@ -430,9 +426,7 @@ protected:
|
|||
QVector<TriangleSet> _modelSpaceMeshTriangleSets; // model space triangles for all sub meshes
|
||||
|
||||
|
||||
void createRenderItemSet();
|
||||
virtual void createVisibleRenderItemSet();
|
||||
virtual void createCollisionRenderItemSet();
|
||||
virtual void createRenderItemSet();
|
||||
|
||||
bool _isWireframe;
|
||||
bool _useDualQuaternionSkinning { false };
|
||||
|
@ -443,9 +437,6 @@ protected:
|
|||
|
||||
static AbstractViewStateInterface* _viewState;
|
||||
|
||||
QVector<std::shared_ptr<MeshPartPayload>> _collisionRenderItems;
|
||||
QMap<render::ItemID, render::PayloadPointer> _collisionRenderItemsMap;
|
||||
|
||||
QVector<std::shared_ptr<ModelMeshPartPayload>> _modelMeshRenderItems;
|
||||
QMap<render::ItemID, render::PayloadPointer> _modelMeshRenderItemsMap;
|
||||
render::ItemIDs _modelMeshRenderItemIDs;
|
||||
|
|
|
@ -432,10 +432,13 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) {
|
|||
ScriptEngine::Type type = scriptEngine->getType();
|
||||
auto scriptCache = DependencyManager::get<ScriptCache>();
|
||||
scriptCache->deleteScript(scriptURL);
|
||||
connect(scriptEngine.data(), &ScriptEngine::finished,
|
||||
this, [this, isUserLoaded, type](QString scriptName, ScriptEnginePointer engine) {
|
||||
reloadScript(scriptName, isUserLoaded)->setType(type);
|
||||
});
|
||||
|
||||
if (!scriptEngine->isStopping()) {
|
||||
connect(scriptEngine.data(), &ScriptEngine::finished,
|
||||
this, [this, isUserLoaded, type](QString scriptName, ScriptEnginePointer engine) {
|
||||
reloadScript(scriptName, isUserLoaded)->setType(type);
|
||||
});
|
||||
}
|
||||
}
|
||||
scriptEngine->stop();
|
||||
stoppedScript = true;
|
||||
|
@ -594,7 +597,7 @@ void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptEnginePo
|
|||
}
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
if (removed && !_isReloading) {
|
||||
// Update settings with removed script
|
||||
saveScripts();
|
||||
emit scriptCountChanged();
|
||||
|
|
|
@ -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;
|
||||
|
|
103
scripts/developer/tests/ControlsGallery.qml
Normal file
103
scripts/developer/tests/ControlsGallery.qml
Normal file
|
@ -0,0 +1,103 @@
|
|||
import QtQuick 2.10
|
||||
import QtQuick.Window 2.10
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.3
|
||||
import "qrc:////qml//styles-uit" as HifiStylesUit
|
||||
import "qrc:////qml//controls-uit" as HifiControlsUit
|
||||
|
||||
//uncomment to use from qmlscratch tool
|
||||
//import '../../../interface/resources/qml/controls-uit' as HifiControlsUit
|
||||
//import '../../../interface/resources/qml/styles-uit'
|
||||
|
||||
//uncomment to use with HIFI_USE_SOURCE_TREE_RESOURCES=1
|
||||
//import '../../../resources/qml/controls-uit' as HifiControlsUit
|
||||
//import '../../../resources/qml/styles-uit'
|
||||
|
||||
Item {
|
||||
visible: true
|
||||
width: 640
|
||||
height: 480
|
||||
|
||||
Introspector {
|
||||
id: introspector
|
||||
properties: ['realFrom', 'realTo', 'realValue', 'realStepSize', 'decimals']
|
||||
visible: true
|
||||
y: 50
|
||||
x: 130
|
||||
}
|
||||
|
||||
HifiStylesUit.HifiConstants {
|
||||
id: hifi
|
||||
}
|
||||
|
||||
TabBar {
|
||||
id: bar
|
||||
width: parent.width
|
||||
TabButton {
|
||||
text: "Spinbox"
|
||||
}
|
||||
TabButton {
|
||||
text: "... Other Controls"
|
||||
}
|
||||
}
|
||||
|
||||
StackLayout {
|
||||
id: controlsLayout
|
||||
currentIndex: bar.currentIndex
|
||||
anchors.top: bar.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: 20
|
||||
|
||||
Item {
|
||||
id: spinboxTab
|
||||
anchors.fill: parent
|
||||
|
||||
Column {
|
||||
spacing: 20
|
||||
|
||||
HifiControlsUit.SpinBox {
|
||||
realValue: 5.0
|
||||
realFrom: 16.0
|
||||
realTo: 20.0
|
||||
decimals: 2
|
||||
realStepSize: 0.01
|
||||
|
||||
width: 100
|
||||
height: 30
|
||||
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
|
||||
onFocusChanged: {
|
||||
if(focus) {
|
||||
introspector.object = this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.SpinBox {
|
||||
realValue: 5.0
|
||||
realFrom: 1.0
|
||||
realTo: 20.0
|
||||
decimals: 2
|
||||
realStepSize: 0.01
|
||||
|
||||
width: 100
|
||||
height: 30
|
||||
|
||||
colorScheme: hifi.colorSchemes.light
|
||||
|
||||
onFocusChanged: {
|
||||
if(focus) {
|
||||
introspector.object = this
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
id: otherTab
|
||||
}
|
||||
}
|
||||
}
|
166
scripts/developer/tests/Introspector.qml
Normal file
166
scripts/developer/tests/Introspector.qml
Normal file
|
@ -0,0 +1,166 @@
|
|||
import QtQuick 2.1;
|
||||
import QtQuick.Window 2.1;
|
||||
|
||||
MouseArea {
|
||||
id: base;
|
||||
opacity: 0.65;
|
||||
// anchors.fill: parent;
|
||||
width: 400;
|
||||
height: 300;
|
||||
|
||||
drag.target: list;
|
||||
onWheel: { }
|
||||
|
||||
onClicked: { object = null }
|
||||
property var object: null
|
||||
onObjectChanged: {
|
||||
visible = (object != null)
|
||||
}
|
||||
|
||||
property var properties: []
|
||||
onPropertiesChanged: {
|
||||
console.debug('properties: ', JSON.stringify(properties, 4, 0))
|
||||
}
|
||||
|
||||
function getPropertiesList(obj) {
|
||||
var props = [];
|
||||
var propertiesObject = obj;
|
||||
if(properties.length !== 0) {
|
||||
propertiesObject = {};
|
||||
for(var i = 0; i < properties.length; ++i) {
|
||||
propertiesObject[properties[i]] = properties[i];
|
||||
}
|
||||
}
|
||||
|
||||
for(var prop in propertiesObject) {
|
||||
|
||||
var info = {'name' : prop};
|
||||
var value = obj[prop];
|
||||
var typeOfValue = typeof(value);
|
||||
|
||||
if(typeof(value) === 'string') {
|
||||
info['type'] = 'string'
|
||||
} else if(typeof(value) === 'number') {
|
||||
if(Number.isInteger(value))
|
||||
info['type'] = 'int'
|
||||
else
|
||||
info['type'] = 'float'
|
||||
} else if(typeof(value) === 'boolean') {
|
||||
info['type'] = 'boolean'
|
||||
} else if(typeof(value) === 'function') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
if(prop !== 'parent' && prop !== 'data' && prop !== 'children')
|
||||
console.debug('typeof(value): ', typeof(value), JSON.stringify(value, null, 4));
|
||||
*/
|
||||
|
||||
info['subName'] = ''
|
||||
props.push(info);
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: "lightgray";
|
||||
anchors.fill: list;
|
||||
anchors.margins: -50;
|
||||
}
|
||||
ListView {
|
||||
id: list;
|
||||
x: 50;
|
||||
y: 50;
|
||||
width: 400;
|
||||
height: 300;
|
||||
spacing: 5;
|
||||
model: object !== null ? getPropertiesList(object) : [];
|
||||
header: Text {
|
||||
text: object !== null ? object.toString () : '';
|
||||
font.bold: true;
|
||||
font.pixelSize: 20;
|
||||
}
|
||||
delegate: Row {
|
||||
spacing: 20;
|
||||
|
||||
Column {
|
||||
width: 180;
|
||||
|
||||
Text {
|
||||
text: (modelData ["subName"] !== "" ? (modelData ["name"] + "." + modelData ["subName"]) : modelData ["name"]);
|
||||
font.pixelSize: 16;
|
||||
}
|
||||
}
|
||||
Column {
|
||||
width: 200;
|
||||
|
||||
Text {
|
||||
text: {
|
||||
return modelData ["type"]
|
||||
}
|
||||
font.pixelSize: 10;
|
||||
}
|
||||
TextInput {
|
||||
id: input;
|
||||
text: display;
|
||||
width: parent.width;
|
||||
font.pixelSize: 16;
|
||||
font.underline: (text !== display);
|
||||
Keys.onReturnPressed: { save (); }
|
||||
Keys.onEnterPressed: { save (); }
|
||||
Keys.onEscapePressed: { cancel (); }
|
||||
|
||||
property string display : "";
|
||||
|
||||
function save () {
|
||||
var tmp;
|
||||
switch (modelData ["type"]) {
|
||||
case 'boolean':
|
||||
tmp = (text === "true" || text === "1");
|
||||
break;
|
||||
case 'float':
|
||||
tmp = parseFloat (text);
|
||||
break;
|
||||
case 'int':
|
||||
tmp = parseInt (text);
|
||||
break;
|
||||
case 'string':
|
||||
tmp = text;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (modelData ["subName"] !== "") {
|
||||
object [modelData ["name"]][modelData ["subName"]] = tmp;
|
||||
}
|
||||
else {
|
||||
object [modelData ["name"]] = tmp;
|
||||
}
|
||||
text = display;
|
||||
}
|
||||
|
||||
function cancel () {
|
||||
text = display;
|
||||
}
|
||||
|
||||
Binding on text { value: input.display; }
|
||||
Binding on display {
|
||||
value: {
|
||||
var ret = (modelData ["subName"] !== ""
|
||||
? object [modelData ["name"]][modelData ["subName"]]
|
||||
: object [modelData ["name"]]);
|
||||
return ret.toString ();
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
z: -1;
|
||||
color: "white";
|
||||
anchors.fill: parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
scripts/developer/tests/controlsGallery.js
Normal file
23
scripts/developer/tests/controlsGallery.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
||||
console.debug('controlsGallery: creating window')
|
||||
|
||||
var qml = Script.resolvePath('ControlsGallery.qml');
|
||||
var qmlWindow = new OverlayWindow({
|
||||
title: 'Hifi Controls Gallery',
|
||||
source: qml,
|
||||
height: 480,
|
||||
width: 640,
|
||||
visible: true
|
||||
});
|
||||
|
||||
console.debug('controlsGallery: creating window... done')
|
||||
|
||||
qmlWindow.closed.connect(function() { Script.stop(); });
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
console.debug('controlsGallery: end of scripting')
|
||||
delete qmlWindow;
|
||||
});
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
|
@ -46,6 +46,7 @@ function init() {
|
|||
|
||||
function onMuteClicked() {
|
||||
Audio.muted = !Audio.muted;
|
||||
Menu.triggerOption("Out of Bounds Vector Access");
|
||||
}
|
||||
|
||||
function onMutePressed() {
|
||||
|
|
Binary file not shown.
BIN
scripts/system/assets/animations/Love.fbx
Normal file
BIN
scripts/system/assets/animations/Love.fbx
Normal file
Binary file not shown.
BIN
scripts/system/assets/animations/Sit1.fbx
Normal file
BIN
scripts/system/assets/animations/Sit1.fbx
Normal file
Binary file not shown.
BIN
scripts/system/assets/animations/Sit2.fbx
Normal file
BIN
scripts/system/assets/animations/Sit2.fbx
Normal file
Binary file not shown.
BIN
scripts/system/assets/animations/Sit3.fbx
Normal file
BIN
scripts/system/assets/animations/Sit3.fbx
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue