Merge branch 'master' of github.com:highfidelity/hifi into one

This commit is contained in:
Sam Gateau 2018-06-18 12:50:19 -07:00
commit 6011ef5390
132 changed files with 12150 additions and 2901 deletions

View file

@ -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.

View file

@ -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 : '') + "\""
}
}

View file

@ -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"/>

View file

@ -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;
}
}

View file

@ -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) {

View file

@ -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();
}
}
}

View file

@ -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') {
}
}
}
*/
*/

View file

@ -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}")

View 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()

View file

@ -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@")

View file

@ -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@"

View file

@ -3,5 +3,6 @@
"buildNumber": "@BUILD_NUMBER@",
"stableBuild": "@STABLE_BUILD@",
"buildIdentifier": "@BUILD_VERSION@",
"organization": "@BUILD_ORGANIZATION@"
"organization": "@BUILD_ORGANIZATION@",
"appUserModelId": "@APP_USER_MODEL_ID@"
}

View file

@ -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})

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -171,6 +171,10 @@ FocusScope {
}
}
function textAt(index) {
return comboBox.textAt(index);
}
HifiControls.Label {
id: comboBoxLabel
text: root.label

View file

@ -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
}
}
}

View file

@ -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
};
}

View file

@ -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();
}
}

View file

@ -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;

View file

@ -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

View file

@ -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()) {

View file

@ -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;
}

View file

@ -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

View 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

View file

@ -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

View 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

View file

@ -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

View 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

View file

@ -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

View file

@ -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;

View file

@ -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,

View file

@ -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";

View file

@ -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"

View file

@ -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;

View file

@ -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;
}

View file

@ -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

View file

@ -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");
}
}

View file

@ -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

View file

@ -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.

View file

@ -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();
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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();

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -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;

View file

@ -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 {

View file

@ -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;

View file

@ -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))) {

View file

@ -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);
}

View file

@ -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;

View file

@ -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();

View file

@ -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

View file

@ -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();

View file

@ -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;

View file

@ -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 {

View file

@ -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;
}

View file

@ -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);

File diff suppressed because it is too large Load diff

View 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 rights 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__

View file

@ -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);

View file

@ -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;
};

View file

@ -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");

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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;
}

View file

@ -140,7 +140,6 @@ struct IrradianceKTXPayload {
data += sizeof(Version);
memcpy(&_irradianceSH, data, sizeof(SphericalHarmonics));
data += sizeof(SphericalHarmonics);
return true;
}

View file

@ -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;
}
});

View file

@ -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;

View file

@ -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;

View file

@ -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();
}

View file

@ -23,7 +23,7 @@
class CharacterGhostShape;
class CharacterGhostObject : public btPairCachingGhostObject {
class CharacterGhostObject : public btGhostObject {
public:
CharacterGhostObject() { }
~CharacterGhostObject();

View file

@ -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();
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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) {
}

View file

@ -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;

View file

@ -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();

View file

@ -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;
}

View file

@ -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];

View file

@ -103,7 +103,8 @@ private:
void checkForConnectedDevices();
ovrInputState _inputState {};
ovrInputState _remoteInputState {};
ovrInputState _touchInputState {};
RemoteDevice::Pointer _remote;
TouchDevice::Pointer _touch;
static const char* NAME;

View 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
}
}
}

View 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;
}
}
}
}
}
}

View 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

View file

@ -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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show more