mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-07 18:32:45 +02:00
Merge remote-tracking branch 'upstream/master' into android_new_login
This commit is contained in:
commit
5afc9c6df3
205 changed files with 2740 additions and 1304 deletions
|
@ -180,6 +180,7 @@ add_subdirectory(tools)
|
|||
|
||||
if (BUILD_TESTS)
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(tests-manual)
|
||||
endif()
|
||||
|
||||
if (BUILD_INSTALLER)
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/AppTheme">
|
||||
android:theme="@style/Theme.AppCompat.Translucent.NoActionBar">
|
||||
</activity>
|
||||
<activity
|
||||
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation"
|
||||
|
|
|
@ -221,18 +221,19 @@ Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeLogin(JNIEnv *en
|
|||
env->ReleaseStringUTFChars(username_, c_username);
|
||||
env->ReleaseStringUTFChars(password_, c_password);
|
||||
|
||||
QSharedPointer<AccountManager> accountManager = AndroidHelper::instance().getAccountManager();
|
||||
auto accountManager = AndroidHelper::instance().getAccountManager();
|
||||
|
||||
__loginCompletedListener = QAndroidJniObject(instance);
|
||||
__usernameChangedListener = QAndroidJniObject(usernameChangedListener);
|
||||
|
||||
QObject::connect(accountManager.data(), &AccountManager::loginComplete, [](const QUrl& authURL) {
|
||||
QString username = AndroidHelper::instance().getAccountManager()->getAccountInfo().getUsername();
|
||||
AndroidHelper::instance().notifyLoginComplete(true);
|
||||
jboolean jSuccess = (jboolean) true;
|
||||
__loginCompletedListener.callMethod<void>("handleLoginCompleted", "(Z)V", jSuccess);
|
||||
});
|
||||
|
||||
QObject::connect(accountManager.data(), &AccountManager::loginFailed, []() {
|
||||
AndroidHelper::instance().notifyLoginComplete(false);
|
||||
jboolean jSuccess = (jboolean) false;
|
||||
__loginCompletedListener.callMethod<void>("handleLoginCompleted", "(Z)V", jSuccess);
|
||||
});
|
||||
|
||||
QObject::connect(accountManager.data(), &AccountManager::usernameChanged, [](const QString& username) {
|
||||
|
@ -240,11 +241,6 @@ Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeLogin(JNIEnv *en
|
|||
__usernameChangedListener.callMethod<void>("handleUsernameChanged", "(Ljava/lang/String;)V", string.object<jstring>());
|
||||
});
|
||||
|
||||
QObject::connect(&AndroidHelper::instance(), &AndroidHelper::loginComplete, [](bool success) {
|
||||
jboolean jSuccess = (jboolean) success;
|
||||
__loginCompletedListener.callMethod<void>("handleLoginCompleted", "(Z)V", jSuccess);
|
||||
});
|
||||
|
||||
QMetaObject::invokeMethod(accountManager.data(), "requestAccessToken",
|
||||
Q_ARG(const QString&, username), Q_ARG(const QString&, password));
|
||||
}
|
||||
|
|
|
@ -37,8 +37,6 @@ public class InterfaceActivity extends QtActivity {
|
|||
|
||||
//public static native void handleHifiURL(String hifiURLString);
|
||||
private native long nativeOnCreate(InterfaceActivity instance, AssetManager assetManager);
|
||||
//private native void nativeOnPause();
|
||||
//private native void nativeOnResume();
|
||||
private native void nativeOnDestroy();
|
||||
private native void nativeGotoUrl(String url);
|
||||
private native void nativeEnterBackground();
|
||||
|
@ -113,29 +111,26 @@ public class InterfaceActivity extends QtActivity {
|
|||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
//nativeOnPause();
|
||||
nativeEnterBackground();
|
||||
//gvrApi.pauseTracking();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
if (!isLoading) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
}
|
||||
nativeEnterForeground();
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
nativeEnterBackground();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
//nativeOnResume();
|
||||
nativeEnterForeground();
|
||||
//gvrApi.resumeTracking();
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,6 @@ public class PermissionChecker extends Activity {
|
|||
}
|
||||
|
||||
private void launchActivityWithPermissions(){
|
||||
finish();
|
||||
Intent i = new Intent(this, InterfaceActivity.class);
|
||||
startActivity(i);
|
||||
finish();
|
||||
|
|
|
@ -37,10 +37,7 @@ public class SplashActivity extends Activity {
|
|||
}
|
||||
|
||||
public void onAppLoadedComplete() {
|
||||
// Give interface more time so textures don't fail(got deleted) on Adreno (joystick)
|
||||
new Handler(getMainLooper()).postDelayed(() -> {
|
||||
startActivity(new Intent(this, MainActivity.class));
|
||||
new Handler(getMainLooper()).postDelayed(() -> SplashActivity.this.finish(), 1000);
|
||||
}, 500);
|
||||
startActivity(new Intent(this, MainActivity.class));
|
||||
SplashActivity.this.finish();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,10 +60,12 @@ public class DomainAdapter extends RecyclerView.Adapter<DomainAdapter.ViewHolder
|
|||
mDomains = new Domain[domain.size()];
|
||||
mDomains = domain.toArray(mDomains);
|
||||
notifyDataSetChanged();
|
||||
if (mDomains.length == 0) {
|
||||
if (mAdapterListener != null) mAdapterListener.onEmptyAdapter();
|
||||
} else {
|
||||
if (mAdapterListener != null) mAdapterListener.onNonEmptyAdapter();
|
||||
if (mAdapterListener != null) {
|
||||
if (mDomains.length == 0) {
|
||||
mAdapterListener.onEmptyAdapter();
|
||||
} else {
|
||||
mAdapterListener.onNonEmptyAdapter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -646,6 +646,7 @@ public class QtActivity extends Activity {
|
|||
super.onStop();
|
||||
QtApplication.invokeDelegate();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimaryDark"
|
||||
android:background="@color/colorPrimaryDark"
|
||||
android:elevation="4dp"
|
||||
/>
|
||||
|
||||
|
@ -36,7 +36,9 @@
|
|||
android:layout_gravity="start"
|
||||
app:headerLayout="@layout/navigation_header"
|
||||
android:fitsSystemWindows="true"
|
||||
app:menu="@menu/menu_navigation">
|
||||
android:background="@color/colorPrimaryDark"
|
||||
app:menu="@menu/menu_navigation"
|
||||
>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:context="io.highfidelity.hifiinterface.MainActivity">
|
||||
android:background="@color/colorPrimary"
|
||||
tools:context="io.highfidelity.hifiinterface.MainActivity"
|
||||
tools:showIn="@layout/activity_home">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/searchView"
|
||||
|
|
|
@ -124,15 +124,14 @@ macro(SETUP_HIFI_TESTCASE)
|
|||
# This target will also build + run the other test targets using ctest when built.
|
||||
|
||||
add_custom_target(${TEST_TARGET}
|
||||
COMMAND ctest .
|
||||
SOURCES ${TEST_PROJ_SRC_FILES} # display source files under the testcase target
|
||||
DEPENDS ${${TEST_PROJ_NAME}_TARGETS})
|
||||
|
||||
set_target_properties(${TEST_TARGET} PROPERTIES
|
||||
FOLDER "Tests"
|
||||
EXCLUDE_FROM_DEFAULT_BUILD TRUE
|
||||
EXCLUDE_FROM_ALL TRUE)
|
||||
|
||||
set_target_properties(${TEST_TARGET} PROPERTIES FOLDER "Tests")
|
||||
|
||||
list (APPEND ALL_TEST_TARGETS ${TEST_TARGET})
|
||||
set(ALL_TEST_TARGETS "${ALL_TEST_TARGETS}" PARENT_SCOPE)
|
||||
else ()
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
//
|
||||
// Sends messages over the EventBridge when text input is required.
|
||||
//
|
||||
|
||||
/* global document, window, console, setTimeout, setInterval, EventBridge */
|
||||
|
||||
(function () {
|
||||
var POLL_FREQUENCY = 500; // ms
|
||||
var MAX_WARNINGS = 3;
|
||||
|
@ -37,22 +40,24 @@
|
|||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function shouldSetNumeric() {
|
||||
return document.activeElement.type === "number";
|
||||
};
|
||||
}
|
||||
|
||||
function scheduleBringToView(timeout) {
|
||||
|
||||
var timer = setTimeout(function () {
|
||||
clearTimeout(timer);
|
||||
|
||||
setTimeout(function () {
|
||||
// If the element is not visible because the keyboard has been raised over the top of it, scroll it up into view.
|
||||
// If the element is not visible because the keyboard raising has moved it off screen, scroll it down into view.
|
||||
var elementRect = document.activeElement.getBoundingClientRect();
|
||||
var absoluteElementTop = elementRect.top + window.scrollY;
|
||||
var middle = absoluteElementTop - (window.innerHeight / 2);
|
||||
|
||||
window.scrollTo(0, middle);
|
||||
var VISUAL_MARGIN = 3;
|
||||
var delta = elementRect.y + elementRect.height + VISUAL_MARGIN - window.innerHeight;
|
||||
if (delta > 0) {
|
||||
window.scrollBy(0, delta);
|
||||
} else if (elementRect.y < VISUAL_MARGIN) {
|
||||
window.scrollBy(0, elementRect.y - VISUAL_MARGIN);
|
||||
}
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
|
@ -62,11 +67,13 @@
|
|||
var passwordField = shouldSetPasswordField();
|
||||
|
||||
if (isWindowFocused &&
|
||||
(keyboardRaised !== window.isKeyboardRaised || numericKeyboard !== window.isNumericKeyboard || passwordField !== window.isPasswordField)) {
|
||||
(keyboardRaised !== window.isKeyboardRaised || numericKeyboard !== window.isNumericKeyboard
|
||||
|| passwordField !== window.isPasswordField)) {
|
||||
|
||||
if (typeof EventBridge !== "undefined" && EventBridge !== null) {
|
||||
EventBridge.emitWebEvent(
|
||||
keyboardRaised ? ("_RAISE_KEYBOARD" + (numericKeyboard ? "_NUMERIC" : "") + (passwordField ? "_PASSWORD" : "")) : "_LOWER_KEYBOARD"
|
||||
keyboardRaised ? ("_RAISE_KEYBOARD" + (numericKeyboard ? "_NUMERIC" : "")
|
||||
+ (passwordField ? "_PASSWORD" : "")) : "_LOWER_KEYBOARD"
|
||||
);
|
||||
} else {
|
||||
if (numWarnings < MAX_WARNINGS) {
|
||||
|
@ -77,7 +84,7 @@
|
|||
|
||||
if (!window.isKeyboardRaised) {
|
||||
scheduleBringToView(250); // Allow time for keyboard to be raised in QML.
|
||||
// 2DO: should it be rather done from 'client area height changed' event?
|
||||
// 2DO: should it be rather done from 'client area height changed' event?
|
||||
}
|
||||
|
||||
window.isKeyboardRaised = keyboardRaised;
|
||||
|
|
|
@ -84,11 +84,9 @@ Item {
|
|||
height: undefined // invalidate so that the image's size sets the height
|
||||
focus: true
|
||||
|
||||
style: OriginalStyles.ButtonStyle {
|
||||
background: Image {
|
||||
id: buttonImage
|
||||
source: "../../images/steam-sign-in.png"
|
||||
}
|
||||
background: Image {
|
||||
id: buttonImage
|
||||
source: "../../images/steam-sign-in.png"
|
||||
}
|
||||
onClicked: signInBody.login()
|
||||
}
|
||||
|
|
|
@ -20,15 +20,10 @@ import "../fileDialog"
|
|||
Item {
|
||||
// Set from OffscreenUi::assetDialog()
|
||||
property alias dir: assetTableModel.folder
|
||||
property alias filter: selectionType.filtersString // FIXME: Currently only supports simple filters, "*.xxx".
|
||||
property int options // Not used.
|
||||
property alias filter: selectionType.filtersString
|
||||
property int options
|
||||
|
||||
property bool selectDirectory: false
|
||||
|
||||
// Not implemented.
|
||||
//property bool saveDialog: false;
|
||||
//property bool multiSelect: false;
|
||||
|
||||
property bool singleClickNavigate: false
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
@ -85,7 +80,6 @@ Item {
|
|||
size: 28
|
||||
width: height
|
||||
enabled: destination !== ""
|
||||
//onClicked: d.navigateHome();
|
||||
onClicked: assetTableModel.folder = destination;
|
||||
}
|
||||
}
|
||||
|
@ -228,7 +222,9 @@ Item {
|
|||
|
||||
function onGetAllMappings(error, map) {
|
||||
var mappings,
|
||||
fileTypeFilter,
|
||||
fileTypeFilters = [],
|
||||
filterListStart,
|
||||
filterListEnd,
|
||||
index,
|
||||
path,
|
||||
fileName,
|
||||
|
@ -249,7 +245,16 @@ Item {
|
|||
|
||||
if (error === "") {
|
||||
mappings = Object.keys(map);
|
||||
fileTypeFilter = filter.replace("*", "").toLowerCase();
|
||||
filter = filter.replace(/\s/g, '');
|
||||
filterListStart = filter.indexOf("(");
|
||||
filterListEnd = filter.indexOf(")");
|
||||
if (filterListStart !== -1 && filterListEnd !== -1) {
|
||||
var FIRST_EXTENSION_OFFSET = 2;
|
||||
fileTypeFilters = filter.substring(filterListStart + FIRST_EXTENSION_OFFSET
|
||||
, filterListEnd).toLowerCase().split("*");
|
||||
} else if (filter !== "") {
|
||||
fileTypeFilters[0] = filter.replace("*", "").toLowerCase();
|
||||
}
|
||||
|
||||
for (i = 0, length = mappings.length; i < length; i++) {
|
||||
index = mappings[i].lastIndexOf("/");
|
||||
|
@ -260,7 +265,24 @@ Item {
|
|||
fileIsDir = false;
|
||||
isValid = false;
|
||||
|
||||
if (fileType.toLowerCase() === fileTypeFilter) {
|
||||
if (fileTypeFilters.length > 1) {
|
||||
if (fileTypeFilters.indexOf(fileType.toLowerCase()) !== -1) {
|
||||
if (path === folder) {
|
||||
isValid = !selectDirectory;
|
||||
} else if (path.length > folder.length) {
|
||||
subDirectory = path.slice(folder.length);
|
||||
index = subDirectory.indexOf("/");
|
||||
if (index === subDirectory.lastIndexOf("/")) {
|
||||
fileName = subDirectory.slice(0, index);
|
||||
if (subDirectories.indexOf(fileName) === -1) {
|
||||
fileIsDir = true;
|
||||
isValid = true;
|
||||
subDirectories.push(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (fileType.toLowerCase() === fileTypeFilters[0] || fileTypeFilters.length === 0) {
|
||||
if (path === folder) {
|
||||
isValid = !selectDirectory;
|
||||
} else if (path.length > folder.length) {
|
||||
|
|
|
@ -787,7 +787,7 @@ Rectangle {
|
|||
}
|
||||
lightboxPopup.button2text = "CONFIRM";
|
||||
lightboxPopup.button2method = function() {
|
||||
Commerce.replaceContentSet(root.itemHref);
|
||||
Commerce.replaceContentSet(root.itemHref, root.certificateId);
|
||||
lightboxPopup.visible = false;
|
||||
rezzedNotifContainer.visible = true;
|
||||
rezzedNotifContainerTimer.start();
|
||||
|
|
|
@ -49,6 +49,7 @@ Item {
|
|||
property string upgradeTitle;
|
||||
property bool updateAvailable: root.upgradeUrl !== "" && !root.isShowingMyItems;
|
||||
property bool isShowingMyItems;
|
||||
property bool valid;
|
||||
|
||||
property string originalStatusText;
|
||||
property string originalStatusColor;
|
||||
|
@ -239,6 +240,7 @@ Item {
|
|||
width: 62;
|
||||
|
||||
onLoaded: {
|
||||
item.enabled = root.valid;
|
||||
item.buttonGlyphText = hifi.glyphs.gift;
|
||||
item.buttonText = "Gift";
|
||||
item.buttonClicked = function() {
|
||||
|
@ -463,7 +465,7 @@ Item {
|
|||
|
||||
Item {
|
||||
id: statusContainer;
|
||||
visible: root.purchaseStatus === "pending" || root.purchaseStatus === "invalidated" || root.numberSold > -1;
|
||||
visible: root.purchaseStatus === "pending" || !root.valid || root.numberSold > -1;
|
||||
anchors.left: itemName.left;
|
||||
anchors.right: itemName.right;
|
||||
anchors.top: itemName.bottom;
|
||||
|
@ -480,7 +482,7 @@ Item {
|
|||
text: {
|
||||
if (root.purchaseStatus === "pending") {
|
||||
"PENDING..."
|
||||
} else if (root.purchaseStatus === "invalidated") {
|
||||
} else if (!root.valid) {
|
||||
"INVALIDATED"
|
||||
} else if (root.numberSold > -1) {
|
||||
("Sales: " + root.numberSold + "/" + (root.limitedRun === -1 ? "\u221e" : root.limitedRun))
|
||||
|
@ -492,7 +494,7 @@ Item {
|
|||
color: {
|
||||
if (root.purchaseStatus === "pending") {
|
||||
hifi.colors.blueAccent
|
||||
} else if (root.purchaseStatus === "invalidated") {
|
||||
} else if (!root.valid) {
|
||||
hifi.colors.redAccent
|
||||
} else {
|
||||
hifi.colors.baseGray
|
||||
|
@ -506,7 +508,7 @@ Item {
|
|||
text: {
|
||||
if (root.purchaseStatus === "pending") {
|
||||
hifi.glyphs.question
|
||||
} else if (root.purchaseStatus === "invalidated") {
|
||||
} else if (!root.valid) {
|
||||
hifi.glyphs.question
|
||||
} else {
|
||||
""
|
||||
|
@ -523,7 +525,7 @@ Item {
|
|||
color: {
|
||||
if (root.purchaseStatus === "pending") {
|
||||
hifi.colors.blueAccent
|
||||
} else if (root.purchaseStatus === "invalidated") {
|
||||
} else if (!root.valid) {
|
||||
hifi.colors.redAccent
|
||||
} else {
|
||||
hifi.colors.baseGray
|
||||
|
@ -538,7 +540,7 @@ Item {
|
|||
onClicked: {
|
||||
if (root.purchaseStatus === "pending") {
|
||||
sendToPurchases({method: 'showPendingLightbox'});
|
||||
} else if (root.purchaseStatus === "invalidated") {
|
||||
} else if (!root.valid) {
|
||||
sendToPurchases({method: 'showInvalidatedLightbox'});
|
||||
}
|
||||
}
|
||||
|
@ -546,7 +548,7 @@ Item {
|
|||
if (root.purchaseStatus === "pending") {
|
||||
statusText.color = hifi.colors.blueHighlight;
|
||||
statusIcon.color = hifi.colors.blueHighlight;
|
||||
} else if (root.purchaseStatus === "invalidated") {
|
||||
} else if (!root.valid) {
|
||||
statusText.color = hifi.colors.redAccent;
|
||||
statusIcon.color = hifi.colors.redAccent;
|
||||
}
|
||||
|
@ -555,7 +557,7 @@ Item {
|
|||
if (root.purchaseStatus === "pending") {
|
||||
statusText.color = hifi.colors.blueAccent;
|
||||
statusIcon.color = hifi.colors.blueAccent;
|
||||
} else if (root.purchaseStatus === "invalidated") {
|
||||
} else if (!root.valid) {
|
||||
statusText.color = hifi.colors.redHighlight;
|
||||
statusIcon.color = hifi.colors.redHighlight;
|
||||
}
|
||||
|
@ -645,8 +647,8 @@ Item {
|
|||
width: 160;
|
||||
height: 40;
|
||||
enabled: root.hasPermissionToRezThis &&
|
||||
root.purchaseStatus !== "invalidated" &&
|
||||
MyAvatar.skeletonModelURL !== root.itemHref;
|
||||
MyAvatar.skeletonModelURL !== root.itemHref &&
|
||||
root.valid;
|
||||
|
||||
onHoveredChanged: {
|
||||
if (hovered) {
|
||||
|
|
|
@ -616,6 +616,7 @@ Rectangle {
|
|||
upgradeTitle: model.upgrade_title;
|
||||
itemType: model.itemType;
|
||||
isShowingMyItems: root.isShowingMyItems;
|
||||
valid: model.valid;
|
||||
anchors.topMargin: 10;
|
||||
anchors.bottomMargin: 10;
|
||||
|
||||
|
@ -995,10 +996,6 @@ Rectangle {
|
|||
|
||||
for (var i = 0; i < purchasesModel.count; i++) {
|
||||
if (purchasesModel.get(i).title.toLowerCase().indexOf(filterBar.text.toLowerCase()) !== -1) {
|
||||
if (!purchasesModel.get(i).valid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (purchasesModel.get(i).status !== "confirmed" && !root.isShowingMyItems) {
|
||||
tempPurchasesModel.insert(0, purchasesModel.get(i));
|
||||
} else if ((root.isShowingMyItems && purchasesModel.get(i).edition_number === "0") ||
|
||||
|
@ -1055,10 +1052,6 @@ Rectangle {
|
|||
var currentId;
|
||||
for (var i = 0; i < tempPurchasesModel.count; i++) {
|
||||
currentId = tempPurchasesModel.get(i).id;
|
||||
|
||||
if (!purchasesModel.get(i).valid) {
|
||||
continue;
|
||||
}
|
||||
filteredPurchasesModel.append(tempPurchasesModel.get(i));
|
||||
filteredPurchasesModel.setProperty(i, 'cardBackVisible', false);
|
||||
filteredPurchasesModel.setProperty(i, 'isInstalled', ((root.installedApps).indexOf(currentId) > -1));
|
||||
|
|
|
@ -172,7 +172,7 @@ StackView {
|
|||
source: InputConfiguration.configurationLayout(box.currentText);
|
||||
onLoaded: {
|
||||
if (loader.item.hasOwnProperty("pluginName")) {
|
||||
if (box.currentText === "Vive") {
|
||||
if (box.currentText === "HTC Vive") {
|
||||
loader.item.pluginName = "OpenVR";
|
||||
} else {
|
||||
loader.item.pluginName = box.currentText;
|
||||
|
|
47
interface/resources/shaders/splashSkybox.frag
Normal file
47
interface/resources/shaders/splashSkybox.frag
Normal file
|
@ -0,0 +1,47 @@
|
|||
const vec3 COLOR = vec3(0x00, 0xD8, 0x02) / vec3(0xFF);
|
||||
const float CUTOFF = 0.65;
|
||||
const float NOISE_MULT = 8.0;
|
||||
const float NOISE_POWER = 1.0;
|
||||
|
||||
float noise4D(vec4 p) {
|
||||
return fract(sin(dot(p ,vec4(12.9898,78.233,126.7235, 593.2241))) * 43758.5453);
|
||||
}
|
||||
|
||||
float worley4D(vec4 p) {
|
||||
float r = 3.0;
|
||||
vec4 f = floor(p);
|
||||
vec4 x = fract(p);
|
||||
for(int i = -1; i<=1; i++)
|
||||
{
|
||||
for(int j = -1; j<=1; j++)
|
||||
{
|
||||
for(int k = -1; k<=1; k++)
|
||||
{
|
||||
for (int l = -1; l <= 1; l++) {
|
||||
vec4 q = vec4(float(i),float(j),float(k), float(l));
|
||||
vec4 v = q + vec4(noise4D((q+f)*1.11), noise4D((q+f)*1.14), noise4D((q+f)*1.17), noise4D((q+f)*1.20)) - x;
|
||||
float d = dot(v, v);
|
||||
r = min(r, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return sqrt(r);
|
||||
}
|
||||
|
||||
|
||||
vec3 mainColor(vec3 direction) {
|
||||
float n = worley4D(vec4(direction * NOISE_MULT, iGlobalTime / 3.0));
|
||||
n = 1.0 - n;
|
||||
n = pow(n, NOISE_POWER);
|
||||
if (n < CUTOFF) {
|
||||
return vec3(0.0);
|
||||
}
|
||||
|
||||
n = (n - CUTOFF) / (1.0 - CUTOFF);
|
||||
return COLOR * (1.0 - n);
|
||||
}
|
||||
|
||||
vec3 getSkyboxColor() {
|
||||
return mainColor(normalize(_normal));
|
||||
}
|
|
@ -10,10 +10,9 @@
|
|||
//
|
||||
#include "AndroidHelper.h"
|
||||
#include <QDebug>
|
||||
#include <AccountManager.h>
|
||||
|
||||
AndroidHelper::AndroidHelper() :
|
||||
_accountManager ()
|
||||
{
|
||||
AndroidHelper::AndroidHelper() {
|
||||
}
|
||||
|
||||
AndroidHelper::~AndroidHelper() {
|
||||
|
@ -27,24 +26,17 @@ void AndroidHelper::init() {
|
|||
_accountManager->setIsAgent(true);
|
||||
_accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL());
|
||||
_accountManager->setSessionID(DependencyManager::get<AccountManager>()->getSessionID());
|
||||
|
||||
connect(_accountManager.data(), &AccountManager::loginComplete, [](const QUrl& authURL) {
|
||||
DependencyManager::get<AccountManager>()->setAccountInfo(AndroidHelper::instance().getAccountManager()->getAccountInfo());
|
||||
DependencyManager::get<AccountManager>()->setAuthURL(authURL);
|
||||
DependencyManager::get<AccountManager>()->setAccountInfo(AndroidHelper::instance().getAccountManager()->getAccountInfo());
|
||||
DependencyManager::get<AccountManager>()->setAuthURL(authURL);
|
||||
});
|
||||
|
||||
connect(_accountManager.data(), &AccountManager::logoutComplete, [] () {
|
||||
DependencyManager::get<AccountManager>()->logout();
|
||||
DependencyManager::get<AccountManager>()->logout();
|
||||
});
|
||||
|
||||
_accountManager->moveToThread(&workerThread);
|
||||
}
|
||||
|
||||
QSharedPointer<AccountManager> AndroidHelper::getAccountManager() {
|
||||
Q_ASSERT(_accountManager);
|
||||
return _accountManager;
|
||||
}
|
||||
|
||||
void AndroidHelper::requestActivity(const QString &activityName, const bool backToScene) {
|
||||
emit androidActivityRequested(activityName, backToScene);
|
||||
}
|
||||
|
@ -53,10 +45,6 @@ void AndroidHelper::notifyLoadComplete() {
|
|||
emit qtAppLoadComplete();
|
||||
}
|
||||
|
||||
void AndroidHelper::notifyLoginComplete(bool success) {
|
||||
emit loginComplete(success);
|
||||
}
|
||||
|
||||
void AndroidHelper::performHapticFeedback(const QString& feedbackConstant) {
|
||||
emit hapticFeedbackRequested(feedbackConstant);
|
||||
}
|
||||
|
|
|
@ -27,11 +27,9 @@ public:
|
|||
void requestActivity(const QString &activityName, const bool backToScene);
|
||||
void notifyLoadComplete();
|
||||
|
||||
void notifyLoginComplete(bool success);
|
||||
void performHapticFeedback(const QString& feedbackConstant);
|
||||
|
||||
QSharedPointer<AccountManager> getAccountManager();
|
||||
|
||||
QSharedPointer<AccountManager> getAccountManager() { return _accountManager; }
|
||||
AndroidHelper(AndroidHelper const&) = delete;
|
||||
void operator=(AndroidHelper const&) = delete;
|
||||
|
||||
|
@ -41,7 +39,7 @@ public slots:
|
|||
signals:
|
||||
void androidActivityRequested(const QString &activityName, const bool backToScene);
|
||||
void qtAppLoadComplete();
|
||||
void loginComplete(bool success);
|
||||
|
||||
void hapticFeedbackRequested(const QString &feedbackConstant);
|
||||
|
||||
private:
|
||||
|
|
|
@ -144,16 +144,7 @@
|
|||
#include <trackers/EyeTracker.h>
|
||||
#include <avatars-renderer/ScriptAvatar.h>
|
||||
#include <RenderableEntityItem.h>
|
||||
|
||||
#include <AnimationLogging.h>
|
||||
#include <AvatarLogging.h>
|
||||
#include <ScriptEngineLogging.h>
|
||||
#include <ModelFormatLogging.h>
|
||||
#include <controllers/Logging.h>
|
||||
#include <NetworkLogging.h>
|
||||
#include <shared/StorageLogging.h>
|
||||
#include <ScriptEngineLogging.h>
|
||||
#include <ui/Logging.h>
|
||||
#include <procedural/ProceduralSkybox.h>
|
||||
|
||||
#include "AudioClient.h"
|
||||
#include "audio/AudioScope.h"
|
||||
|
@ -385,7 +376,7 @@ Setting::Handle<int> maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTRE
|
|||
static const QString MARKETPLACE_CDN_HOSTNAME = "mpassets.highfidelity.com";
|
||||
static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // milliseconds
|
||||
static const QString DESKTOP_DISPLAY_PLUGIN_NAME = "Desktop";
|
||||
|
||||
static const QString ACTIVE_DISPLAY_PLUGIN_SETTING_NAME = "activeDisplayPlugin";
|
||||
static const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system";
|
||||
|
||||
const std::vector<std::pair<QString, Application::AcceptURLMethod>> Application::_acceptedExtensions {
|
||||
|
@ -743,6 +734,11 @@ extern DisplayPluginList getDisplayPlugins();
|
|||
extern InputPluginList getInputPlugins();
|
||||
extern void saveInputPluginSettings(const InputPluginList& plugins);
|
||||
|
||||
// Parameters used for running tests from teh command line
|
||||
const QString TEST_SCRIPT_COMMAND{ "--testScript" };
|
||||
const QString TEST_QUIT_WHEN_FINISHED_OPTION{ "quitWhenFinished" };
|
||||
const QString TEST_RESULTS_LOCATION_COMMAND{ "--testResultsLocation" };
|
||||
|
||||
bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
||||
const char** constArgv = const_cast<const char**>(argv);
|
||||
|
||||
|
@ -777,7 +773,22 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
|
||||
static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset";
|
||||
bool suppressPrompt = cmdOptionExists(argc, const_cast<const char**>(argv), SUPPRESS_SETTINGS_RESET);
|
||||
bool previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt);
|
||||
|
||||
// Ignore any previous crashes if running from command line with a test script.
|
||||
bool inTestMode { false };
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
QString parameter(argv[i]);
|
||||
if (parameter == TEST_SCRIPT_COMMAND) {
|
||||
inTestMode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool previousSessionCrashed { false };
|
||||
if (!inTestMode) {
|
||||
previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt);
|
||||
}
|
||||
|
||||
// get dir to use for cache
|
||||
static const auto CACHE_SWITCH = "--cache";
|
||||
QString cacheDir = getCmdOption(argc, const_cast<const char**>(argv), CACHE_SWITCH);
|
||||
|
@ -1000,14 +1011,34 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning()));
|
||||
setProperty(hifi::properties::CRASHED, _previousSessionCrashed);
|
||||
{
|
||||
const QString TEST_SCRIPT = "--testScript";
|
||||
const QStringList args = arguments();
|
||||
|
||||
for (int i = 0; i < args.size() - 1; ++i) {
|
||||
if (args.at(i) == TEST_SCRIPT) {
|
||||
if (args.at(i) == TEST_SCRIPT_COMMAND && (i + 1) < args.size()) {
|
||||
QString testScriptPath = args.at(i + 1);
|
||||
if (QFileInfo(testScriptPath).exists()) {
|
||||
|
||||
// If the URL scheme is http(s) or ftp, then use as is, else - treat it as a local file
|
||||
// This is done so as not break previous command line scripts
|
||||
if (testScriptPath.left(URL_SCHEME_HTTP.length()) == URL_SCHEME_HTTP ||
|
||||
testScriptPath.left(URL_SCHEME_FTP.length()) == URL_SCHEME_FTP) {
|
||||
|
||||
setProperty(hifi::properties::TEST, QUrl::fromUserInput(testScriptPath));
|
||||
} else if (QFileInfo(testScriptPath).exists()) {
|
||||
setProperty(hifi::properties::TEST, QUrl::fromLocalFile(testScriptPath));
|
||||
}
|
||||
|
||||
// quite when finished parameter must directly follow the test script
|
||||
if ((i + 2) < args.size() && args.at(i + 2) == TEST_QUIT_WHEN_FINISHED_OPTION) {
|
||||
quitWhenFinished = true;
|
||||
}
|
||||
} else if (args.at(i) == TEST_RESULTS_LOCATION_COMMAND) {
|
||||
// Set test snapshot location only if it is a writeable directory
|
||||
QString path(args.at(i + 1));
|
||||
|
||||
QFileInfo fileInfo(path);
|
||||
if (fileInfo.isDir() && fileInfo.isWritable()) {
|
||||
TestScriptingInterface::getInstance()->setTestResultsLocation(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1332,10 +1363,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
QCoreApplication::processEvents();
|
||||
_glWidget->createContext();
|
||||
|
||||
// Create the main thread context, the GPU backend, and the display plugins
|
||||
// Create the main thread context, the GPU backend
|
||||
initializeGL();
|
||||
DependencyManager::get<TextureCache>()->setGPUContext(_gpuContext);
|
||||
qCDebug(interfaceapp, "Initialized Display.");
|
||||
qCDebug(interfaceapp, "Initialized GL");
|
||||
|
||||
// Initialize the display plugin architecture
|
||||
initializeDisplayPlugins();
|
||||
qCDebug(interfaceapp, "Initialized Display");
|
||||
|
||||
// Create the rendering engine. This can be slow on some machines due to lots of
|
||||
// GPU pipeline creation.
|
||||
initializeRenderEngine();
|
||||
|
@ -1345,8 +1380,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
// Needs to happen AFTER the render engine initialization to access its configuration
|
||||
initializeUi();
|
||||
|
||||
updateVerboseLogging();
|
||||
|
||||
init();
|
||||
qCDebug(interfaceapp, "init() complete.");
|
||||
|
||||
|
@ -1686,6 +1719,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
|
||||
loadSettings();
|
||||
|
||||
updateVerboseLogging();
|
||||
|
||||
// Now that we've loaded the menu and thus switched to the previous display plugin
|
||||
// we can unlock the desktop repositioning code, since all the positions will be
|
||||
// relative to the desktop size for this plugin
|
||||
|
@ -2138,14 +2173,24 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
return entityServerNode && !isPhysicsEnabled();
|
||||
});
|
||||
|
||||
_snapshotSound = DependencyManager::get<SoundCache>()->getSound(PathUtils::resourcesUrl("sounds/snap.wav"));
|
||||
_snapshotSound = DependencyManager::get<SoundCache>()->getSound(PathUtils::resourcesUrl("sounds/snapshot/snap.wav"));
|
||||
|
||||
QVariant testProperty = property(hifi::properties::TEST);
|
||||
qDebug() << testProperty;
|
||||
if (testProperty.isValid()) {
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>();
|
||||
const auto testScript = property(hifi::properties::TEST).toUrl();
|
||||
scriptEngines->loadScript(testScript, false);
|
||||
|
||||
// Set last parameter to exit interface when the test script finishes, if so requested
|
||||
scriptEngines->loadScript(testScript, false, false, false, false, quitWhenFinished);
|
||||
|
||||
// This is done so we don't get a "connection time-out" message when we haven't passed in a URL.
|
||||
if (arguments().contains("--url")) {
|
||||
auto reply = SandboxUtils::getStatus();
|
||||
connect(reply, &QNetworkReply::finished, this, [=] {
|
||||
handleSandboxStatus(reply);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
PROFILE_RANGE(render, "GetSandboxStatus");
|
||||
auto reply = SandboxUtils::getStatus();
|
||||
|
@ -2225,43 +2270,19 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
}
|
||||
|
||||
void Application::updateVerboseLogging() {
|
||||
bool enable = Menu::getInstance()->isOptionChecked(MenuOption::VerboseLogging);
|
||||
auto menu = Menu::getInstance();
|
||||
if (!menu) {
|
||||
return;
|
||||
}
|
||||
bool enable = menu->isOptionChecked(MenuOption::VerboseLogging);
|
||||
|
||||
const_cast<QLoggingCategory*>(&animation())->setEnabled(QtDebugMsg, enable);
|
||||
const_cast<QLoggingCategory*>(&animation())->setEnabled(QtInfoMsg, enable);
|
||||
|
||||
const_cast<QLoggingCategory*>(&avatars())->setEnabled(QtDebugMsg, enable);
|
||||
const_cast<QLoggingCategory*>(&avatars())->setEnabled(QtInfoMsg, enable);
|
||||
|
||||
const_cast<QLoggingCategory*>(&scriptengine())->setEnabled(QtDebugMsg, enable);
|
||||
const_cast<QLoggingCategory*>(&scriptengine())->setEnabled(QtInfoMsg, enable);
|
||||
|
||||
const_cast<QLoggingCategory*>(&modelformat())->setEnabled(QtDebugMsg, enable);
|
||||
const_cast<QLoggingCategory*>(&modelformat())->setEnabled(QtInfoMsg, enable);
|
||||
|
||||
const_cast<QLoggingCategory*>(&controllers())->setEnabled(QtDebugMsg, enable);
|
||||
const_cast<QLoggingCategory*>(&controllers())->setEnabled(QtInfoMsg, enable);
|
||||
|
||||
const_cast<QLoggingCategory*>(&resourceLog())->setEnabled(QtDebugMsg, enable);
|
||||
const_cast<QLoggingCategory*>(&resourceLog())->setEnabled(QtInfoMsg, enable);
|
||||
|
||||
const_cast<QLoggingCategory*>(&networking())->setEnabled(QtDebugMsg, enable);
|
||||
const_cast<QLoggingCategory*>(&networking())->setEnabled(QtInfoMsg, enable);
|
||||
|
||||
const_cast<QLoggingCategory*>(&asset_client())->setEnabled(QtDebugMsg, enable);
|
||||
const_cast<QLoggingCategory*>(&asset_client())->setEnabled(QtInfoMsg, enable);
|
||||
|
||||
const_cast<QLoggingCategory*>(&messages_client())->setEnabled(QtDebugMsg, enable);
|
||||
const_cast<QLoggingCategory*>(&messages_client())->setEnabled(QtInfoMsg, enable);
|
||||
|
||||
const_cast<QLoggingCategory*>(&storagelogging())->setEnabled(QtDebugMsg, enable);
|
||||
const_cast<QLoggingCategory*>(&storagelogging())->setEnabled(QtInfoMsg, enable);
|
||||
|
||||
const_cast<QLoggingCategory*>(&uiLogging())->setEnabled(QtDebugMsg, enable);
|
||||
const_cast<QLoggingCategory*>(&uiLogging())->setEnabled(QtInfoMsg, enable);
|
||||
|
||||
const_cast<QLoggingCategory*>(&glLogging())->setEnabled(QtDebugMsg, enable);
|
||||
const_cast<QLoggingCategory*>(&glLogging())->setEnabled(QtInfoMsg, enable);
|
||||
QString rules =
|
||||
"hifi.*.debug=%1\n"
|
||||
"hifi.*.info=%1\n"
|
||||
"hifi.audio-stream.debug=false\n"
|
||||
"hifi.audio-stream.info=false";
|
||||
rules = rules.arg(enable ? "true" : "false");
|
||||
QLoggingCategory::setFilterRules(rules);
|
||||
}
|
||||
|
||||
void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo) {
|
||||
|
@ -2374,6 +2395,10 @@ void Application::onAboutToQuit() {
|
|||
}
|
||||
}
|
||||
|
||||
// The active display plugin needs to be loaded before the menu system is active,
|
||||
// so its persisted explicitly here
|
||||
Setting::Handle<QString>{ ACTIVE_DISPLAY_PLUGIN_SETTING_NAME }.set(getActiveDisplayPlugin()->getName());
|
||||
|
||||
getActiveDisplayPlugin()->deactivate();
|
||||
if (_autoSwitchDisplayModeSupportedHMDPlugin
|
||||
&& _autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) {
|
||||
|
@ -2613,10 +2638,84 @@ void Application::initializeGL() {
|
|||
_glWidget->makeCurrent();
|
||||
_gpuContext = std::make_shared<gpu::Context>();
|
||||
|
||||
DependencyManager::get<TextureCache>()->setGPUContext(_gpuContext);
|
||||
|
||||
// Restore the default main thread context
|
||||
_offscreenContext->makeCurrent();
|
||||
}
|
||||
|
||||
updateDisplayMode();
|
||||
static const QString SPLASH_SKYBOX{ "{\"ProceduralEntity\":{ \"version\":2, \"shaderUrl\":\"qrc:///shaders/splashSkybox.frag\" } }" };
|
||||
|
||||
void Application::initializeDisplayPlugins() {
|
||||
auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins();
|
||||
Setting::Handle<QString> activeDisplayPluginSetting{ ACTIVE_DISPLAY_PLUGIN_SETTING_NAME, displayPlugins.at(0)->getName() };
|
||||
auto lastActiveDisplayPluginName = activeDisplayPluginSetting.get();
|
||||
|
||||
auto defaultDisplayPlugin = displayPlugins.at(0);
|
||||
// Once time initialization code
|
||||
DisplayPluginPointer targetDisplayPlugin;
|
||||
foreach(auto displayPlugin, displayPlugins) {
|
||||
displayPlugin->setContext(_gpuContext);
|
||||
if (displayPlugin->getName() == lastActiveDisplayPluginName) {
|
||||
targetDisplayPlugin = displayPlugin;
|
||||
}
|
||||
QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged,
|
||||
[this](const QSize& size) { resizeGL(); });
|
||||
QObject::connect(displayPlugin.get(), &DisplayPlugin::resetSensorsRequested, this, &Application::requestReset);
|
||||
}
|
||||
|
||||
// The default display plugin needs to be activated first, otherwise the display plugin thread
|
||||
// may be launched by an external plugin, which is bad
|
||||
setDisplayPlugin(defaultDisplayPlugin);
|
||||
|
||||
// Now set the desired plugin if it's not the same as the default plugin
|
||||
if (targetDisplayPlugin != defaultDisplayPlugin) {
|
||||
setDisplayPlugin(targetDisplayPlugin);
|
||||
}
|
||||
|
||||
// Submit a default frame to render until the engine starts up
|
||||
updateRenderArgs(0.0f);
|
||||
|
||||
_offscreenContext->makeCurrent();
|
||||
|
||||
#define ENABLE_SPLASH_FRAME 0
|
||||
#if ENABLE_SPLASH_FRAME
|
||||
{
|
||||
QMutexLocker viewLocker(&_renderArgsMutex);
|
||||
|
||||
if (_appRenderArgs._isStereo) {
|
||||
_gpuContext->enableStereo(true);
|
||||
_gpuContext->setStereoProjections(_appRenderArgs._eyeProjections);
|
||||
_gpuContext->setStereoViews(_appRenderArgs._eyeOffsets);
|
||||
}
|
||||
|
||||
// Frame resources
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
gpu::FramebufferPointer finalFramebuffer = framebufferCache->getFramebuffer();
|
||||
std::shared_ptr<ProceduralSkybox> procedural = std::make_shared<ProceduralSkybox>();
|
||||
procedural->parse(SPLASH_SKYBOX);
|
||||
|
||||
_gpuContext->beginFrame(_appRenderArgs._view, _appRenderArgs._headPose);
|
||||
gpu::doInBatch("splashFrame", _gpuContext, [&](gpu::Batch& batch) {
|
||||
batch.resetStages();
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(finalFramebuffer);
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, { 0, 0, 0, 1 });
|
||||
batch.enableSkybox(true);
|
||||
batch.enableStereo(_appRenderArgs._isStereo);
|
||||
batch.setViewportTransform({ 0, 0, finalFramebuffer->getSize() });
|
||||
procedural->render(batch, _appRenderArgs._renderArgs.getViewFrustum());
|
||||
});
|
||||
auto frame = _gpuContext->endFrame();
|
||||
frame->frameIndex = 0;
|
||||
frame->framebuffer = finalFramebuffer;
|
||||
frame->pose = _appRenderArgs._headPose;
|
||||
frame->framebufferRecycler = [framebufferCache, procedural](const gpu::FramebufferPointer& framebuffer) {
|
||||
framebufferCache->releaseFramebuffer(framebuffer);
|
||||
};
|
||||
_displayPlugin->submitFrame(frame);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Application::initializeRenderEngine() {
|
||||
|
@ -2640,6 +2739,7 @@ void Application::initializeRenderEngine() {
|
|||
}
|
||||
|
||||
extern void setupPreferences();
|
||||
static void addDisplayPluginToMenu(const DisplayPluginPointer& displayPlugin, bool active);
|
||||
|
||||
void Application::initializeUi() {
|
||||
// Build a shared canvas / context for the Chromium processes
|
||||
|
@ -2788,10 +2888,25 @@ void Application::initializeUi() {
|
|||
offscreenSurfaceCache->reserve(TabletScriptingInterface::QML, 1);
|
||||
offscreenSurfaceCache->reserve(Web3DOverlay::QML, 2);
|
||||
|
||||
// Now that the menu is instantiated, ensure the display plugin menu is properly updated
|
||||
updateDisplayMode();
|
||||
flushMenuUpdates();
|
||||
|
||||
// Now that the menu is instantiated, ensure the display plugin menu is properly updated
|
||||
{
|
||||
auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins();
|
||||
// first sort the plugins into groupings: standard, advanced, developer
|
||||
std::stable_sort(displayPlugins.begin(), displayPlugins.end(),
|
||||
[](const DisplayPluginPointer& a, const DisplayPluginPointer& b)->bool { return a->getGrouping() < b->getGrouping(); });
|
||||
|
||||
// concatenate the groupings into a single list in the order: standard, advanced, developer
|
||||
for(const auto& displayPlugin : displayPlugins) {
|
||||
addDisplayPluginToMenu(displayPlugin, _displayPlugin == displayPlugin);
|
||||
}
|
||||
|
||||
// after all plugins have been added to the menu, add a separator to the menu
|
||||
auto parent = getPrimaryMenu()->getMenu(MenuOption::OutputMenu);
|
||||
parent->addSeparator();
|
||||
}
|
||||
|
||||
// The display plugins are created before the menu now, so we need to do this here to hide the menu bar
|
||||
// now that it exists
|
||||
if (_window && _window->isFullScreen()) {
|
||||
|
@ -2942,7 +3057,7 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
|
|||
_thirdPersonHMDCameraBoomValid = false;
|
||||
|
||||
_myCamera.setOrientation(myAvatar->getHead()->getOrientation());
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) {
|
||||
if (isOptionChecked(MenuOption::CenterPlayerInView)) {
|
||||
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
||||
+ _myCamera.getOrientation() * boomOffset);
|
||||
}
|
||||
|
@ -3197,7 +3312,6 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
|
|||
qCDebug(interfaceapp) << "First run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("default location") : addressLookupString);
|
||||
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
|
||||
#else
|
||||
showHelp();
|
||||
DependencyManager::get<AddressManager>()->goToEntry();
|
||||
sentTo = SENT_TO_ENTRY;
|
||||
#endif
|
||||
|
@ -5745,6 +5859,32 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
|
||||
|
||||
updateRenderArgs(deltaTime);
|
||||
|
||||
// HACK
|
||||
// load the view frustum
|
||||
// FIXME: This preDisplayRender call is temporary until we create a separate render::scene for the mirror rendering.
|
||||
// Then we can move this logic into the Avatar::simulate call.
|
||||
myAvatar->preDisplaySide(&_appRenderArgs._renderArgs);
|
||||
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("limitless");
|
||||
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");
|
||||
getMain3DScene()->enqueueFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::updateRenderArgs(float deltaTime) {
|
||||
editRenderArgs([this, deltaTime](AppRenderArgs& appRenderArgs) {
|
||||
PerformanceTimer perfTimer("editRenderArgs");
|
||||
appRenderArgs._headPose = getHMDSensorPose();
|
||||
|
@ -5768,9 +5908,9 @@ void Application::update(float deltaTime) {
|
|||
QMutexLocker viewLocker(&_viewMutex);
|
||||
// adjust near clip plane to account for sensor scaling.
|
||||
auto adjustedProjection = glm::perspective(glm::radians(_fieldOfView.get()),
|
||||
getActiveDisplayPlugin()->getRecommendedAspectRatio(),
|
||||
DEFAULT_NEAR_CLIP * sensorToWorldScale,
|
||||
DEFAULT_FAR_CLIP);
|
||||
getActiveDisplayPlugin()->getRecommendedAspectRatio(),
|
||||
DEFAULT_NEAR_CLIP * sensorToWorldScale,
|
||||
DEFAULT_FAR_CLIP);
|
||||
_viewFrustum.setProjection(adjustedProjection);
|
||||
_viewFrustum.calculate();
|
||||
}
|
||||
|
@ -5786,8 +5926,14 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
{
|
||||
PROFILE_RANGE(render, "/resizeGL");
|
||||
PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
bool showWarnings = false;
|
||||
bool suppressShortTimings = false;
|
||||
auto menu = Menu::getInstance();
|
||||
if (menu) {
|
||||
suppressShortTimings = menu->isOptionChecked(MenuOption::SuppressShortTimings);
|
||||
showWarnings = menu->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
}
|
||||
PerformanceWarning::setSuppressShortTimings(suppressShortTimings);
|
||||
PerformanceWarning warn(showWarnings, "Application::paintGL()");
|
||||
resizeGL();
|
||||
}
|
||||
|
@ -5843,12 +5989,6 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
// HACK
|
||||
// load the view frustum
|
||||
// FIXME: This preDisplayRender call is temporary until we create a separate render::scene for the mirror rendering.
|
||||
// Then we can move this logic into the Avatar::simulate call.
|
||||
myAvatar->preDisplaySide(&appRenderArgs._renderArgs);
|
||||
|
||||
{
|
||||
QMutexLocker viewLocker(&_viewMutex);
|
||||
_myCamera.loadViewFrustum(_displayViewFrustum);
|
||||
|
@ -5860,21 +6000,6 @@ void Application::update(float deltaTime) {
|
|||
appRenderArgs._renderArgs.setViewFrustum(_displayViewFrustum);
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("limitless");
|
||||
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");
|
||||
getMain3DScene()->enqueueFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::queryAvatars() {
|
||||
|
@ -7486,7 +7611,9 @@ void Application::loadAvatarBrowser() const {
|
|||
void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio, const QString& filename) {
|
||||
postLambdaEvent([notify, includeAnimated, aspectRatio, filename, this] {
|
||||
// Get a screenshot and save it
|
||||
QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio), filename);
|
||||
QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio), filename,
|
||||
TestScriptingInterface::getInstance()->getTestResultsLocation());
|
||||
|
||||
// If we're not doing an animated snapshot as well...
|
||||
if (!includeAnimated) {
|
||||
// Tell the dependency manager that the capture of the still snapshot has taken place.
|
||||
|
@ -7500,7 +7627,9 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa
|
|||
|
||||
void Application::takeSecondaryCameraSnapshot(const QString& filename) {
|
||||
postLambdaEvent([filename, this] {
|
||||
QString snapshotPath = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename);
|
||||
QString snapshotPath = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename,
|
||||
TestScriptingInterface::getInstance()->getTestResultsLocation());
|
||||
|
||||
emit DependencyManager::get<WindowScriptingInterface>()->stillSnapshotTaken(snapshotPath, true);
|
||||
});
|
||||
}
|
||||
|
@ -7513,15 +7642,19 @@ void Application::shareSnapshot(const QString& path, const QUrl& href) {
|
|||
}
|
||||
|
||||
float Application::getRenderResolutionScale() const {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::RenderResolutionOne)) {
|
||||
auto menu = Menu::getInstance();
|
||||
if (!menu) {
|
||||
return 1.0f;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderResolutionTwoThird)) {
|
||||
}
|
||||
if (menu->isOptionChecked(MenuOption::RenderResolutionOne)) {
|
||||
return 1.0f;
|
||||
} else if (menu->isOptionChecked(MenuOption::RenderResolutionTwoThird)) {
|
||||
return 0.666f;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderResolutionHalf)) {
|
||||
} else if (menu->isOptionChecked(MenuOption::RenderResolutionHalf)) {
|
||||
return 0.5f;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderResolutionThird)) {
|
||||
} else if (menu->isOptionChecked(MenuOption::RenderResolutionThird)) {
|
||||
return 0.333f;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderResolutionQuarter)) {
|
||||
} else if (menu->isOptionChecked(MenuOption::RenderResolutionQuarter)) {
|
||||
return 0.25f;
|
||||
} else {
|
||||
return 1.0f;
|
||||
|
@ -7745,7 +7878,7 @@ DisplayPluginPointer Application::getActiveDisplayPlugin() const {
|
|||
|
||||
static const char* EXCLUSION_GROUP_KEY = "exclusionGroup";
|
||||
|
||||
static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool active = false) {
|
||||
static void addDisplayPluginToMenu(const DisplayPluginPointer& displayPlugin, bool active) {
|
||||
auto menu = Menu::getInstance();
|
||||
QString name = displayPlugin->getName();
|
||||
auto grouping = displayPlugin->getGrouping();
|
||||
|
@ -7790,65 +7923,12 @@ void Application::updateDisplayMode() {
|
|||
qFatal("Attempted to switch display plugins from a non-main thread");
|
||||
}
|
||||
|
||||
auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins();
|
||||
|
||||
// Once time initialization code
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
foreach(auto displayPlugin, displayPlugins) {
|
||||
displayPlugin->setContext(_gpuContext);
|
||||
QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged,
|
||||
[this](const QSize& size) { resizeGL(); });
|
||||
QObject::connect(displayPlugin.get(), &DisplayPlugin::resetSensorsRequested, this, &Application::requestReset);
|
||||
}
|
||||
});
|
||||
|
||||
// Once time initialization code that depends on the UI being available
|
||||
auto menu = Menu::getInstance();
|
||||
if (menu) {
|
||||
static std::once_flag onceUi;
|
||||
std::call_once(onceUi, [&] {
|
||||
bool first = true;
|
||||
|
||||
// first sort the plugins into groupings: standard, advanced, developer
|
||||
DisplayPluginList standard;
|
||||
DisplayPluginList advanced;
|
||||
DisplayPluginList developer;
|
||||
foreach(auto displayPlugin, displayPlugins) {
|
||||
displayPlugin->setContext(_gpuContext);
|
||||
auto grouping = displayPlugin->getGrouping();
|
||||
switch (grouping) {
|
||||
case Plugin::ADVANCED:
|
||||
advanced.push_back(displayPlugin);
|
||||
break;
|
||||
case Plugin::DEVELOPER:
|
||||
developer.push_back(displayPlugin);
|
||||
break;
|
||||
default:
|
||||
standard.push_back(displayPlugin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// concatenate the groupings into a single list in the order: standard, advanced, developer
|
||||
standard.insert(std::end(standard), std::begin(advanced), std::end(advanced));
|
||||
standard.insert(std::end(standard), std::begin(developer), std::end(developer));
|
||||
|
||||
foreach(auto displayPlugin, standard) {
|
||||
addDisplayPluginToMenu(displayPlugin, first);
|
||||
first = false;
|
||||
}
|
||||
|
||||
// after all plugins have been added to the menu, add a separator to the menu
|
||||
auto parent = menu->getMenu(MenuOption::OutputMenu);
|
||||
parent->addSeparator();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
auto displayPlugins = getDisplayPlugins();
|
||||
|
||||
// Default to the first item on the list, in case none of the menu items match
|
||||
DisplayPluginPointer newDisplayPlugin = displayPlugins.at(0);
|
||||
auto menu = getPrimaryMenu();
|
||||
if (menu) {
|
||||
foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) {
|
||||
QString name = displayPlugin->getName();
|
||||
|
@ -7872,6 +7952,14 @@ void Application::updateDisplayMode() {
|
|||
}
|
||||
|
||||
void Application::setDisplayPlugin(DisplayPluginPointer newDisplayPlugin) {
|
||||
if (newDisplayPlugin == _displayPlugin) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME don't have the application directly set the state of the UI,
|
||||
// instead emit a signal that the display plugin is changing and let
|
||||
// the desktop lock itself. Reduces coupling between the UI and display
|
||||
// plugins
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
auto desktop = offscreenUi->getDesktop();
|
||||
auto menu = Menu::getInstance();
|
||||
|
@ -7882,8 +7970,8 @@ void Application::setDisplayPlugin(DisplayPluginPointer newDisplayPlugin) {
|
|||
bool wasRepositionLocked = false;
|
||||
if (desktop) {
|
||||
// Tell the desktop to no reposition (which requires plugin info), until we have set the new plugin, below.
|
||||
wasRepositionLocked = offscreenUi->getDesktop()->property("repositionLocked").toBool();
|
||||
offscreenUi->getDesktop()->setProperty("repositionLocked", true);
|
||||
wasRepositionLocked = desktop->property("repositionLocked").toBool();
|
||||
desktop->setProperty("repositionLocked", true);
|
||||
}
|
||||
|
||||
if (_displayPlugin) {
|
||||
|
@ -8188,15 +8276,17 @@ void Application::saveNextPhysicsStats(QString filename) {
|
|||
void Application::enterBackground() {
|
||||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(),
|
||||
"stop", Qt::BlockingQueuedConnection);
|
||||
getActiveDisplayPlugin()->deactivate();
|
||||
if (getActiveDisplayPlugin()->isActive()) {
|
||||
getActiveDisplayPlugin()->deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::enterForeground() {
|
||||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(),
|
||||
"start", Qt::BlockingQueuedConnection);
|
||||
if (!getActiveDisplayPlugin() || !getActiveDisplayPlugin()->activate()) {
|
||||
if (!getActiveDisplayPlugin() || getActiveDisplayPlugin()->isActive() || !getActiveDisplayPlugin()->activate()) {
|
||||
qWarning() << "Could not re-activate display plugin";
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -148,6 +148,7 @@ public:
|
|||
Q_INVOKABLE QString getUserAgent();
|
||||
|
||||
void initializeGL();
|
||||
void initializeDisplayPlugins();
|
||||
void initializeRenderEngine();
|
||||
void initializeUi();
|
||||
|
||||
|
@ -667,6 +668,7 @@ private:
|
|||
|
||||
using RenderArgsEditor = std::function <void (AppRenderArgs&)>;
|
||||
void editRenderArgs(RenderArgsEditor editor);
|
||||
void updateRenderArgs(float deltaTime);
|
||||
|
||||
|
||||
Overlays _overlays;
|
||||
|
@ -746,5 +748,7 @@ private:
|
|||
|
||||
std::atomic<bool> _pendingIdleEvent { true };
|
||||
std::atomic<bool> _pendingRenderEvent { true };
|
||||
|
||||
bool quitWhenFinished { false };
|
||||
};
|
||||
#endif // hifi_Application_h
|
||||
|
|
|
@ -13,8 +13,9 @@
|
|||
|
||||
#include <display-plugins/CompositorHelper.h>
|
||||
#include <FramebufferCache.h>
|
||||
#include "ui/Stats.h"
|
||||
#include <plugins/PluginManager.h>
|
||||
#include <SceneScriptingInterface.h>
|
||||
#include "ui/Stats.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
||||
|
@ -233,3 +234,4 @@ void Application::runRenderFrame(RenderArgs* renderArgs) {
|
|||
_renderEngine->run();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ void LODManager::autoAdjustLOD(float realTimeDelta) {
|
|||
// Note: we MUST clamp the blend to 1.0 for stability
|
||||
float blend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE) ? realTimeDelta / LOD_ADJUST_RUNNING_AVG_TIMESCALE : 1.0f;
|
||||
_avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * maxRenderTime; // msec
|
||||
if (!_automaticLODAdjust) {
|
||||
if (!_automaticLODAdjust || _avgRenderTime == 0.0f) {
|
||||
// early exit
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -193,7 +193,6 @@ namespace MenuOption {
|
|||
const QString ShowOtherLookAtVectors = "Show Other Eye Vectors";
|
||||
const QString EnableLookAtSnapping = "Enable LookAt Snapping";
|
||||
const QString ShowRealtimeEntityStats = "Show Realtime Entity Stats";
|
||||
const QString StandingHMDSensorMode = "Standing HMD Sensor Mode";
|
||||
const QString SimulateEyeTracking = "Simulate";
|
||||
const QString SMIEyeTracking = "SMI Eye Tracking";
|
||||
const QString SparseTextureManagement = "Enable Sparse Texture Management";
|
||||
|
|
|
@ -2039,7 +2039,7 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
|||
}
|
||||
}
|
||||
|
||||
void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
|
||||
void MyAvatar::preDisplaySide(const RenderArgs* renderArgs) {
|
||||
|
||||
// toggle using the cauterizedBones depending on where the camera is and the rendering pass type.
|
||||
const bool shouldDrawHead = shouldRenderHead(renderArgs);
|
||||
|
|
|
@ -272,7 +272,7 @@ public:
|
|||
|
||||
void update(float deltaTime);
|
||||
virtual void postUpdate(float deltaTime, const render::ScenePointer& scene) override;
|
||||
void preDisplaySide(RenderArgs* renderArgs);
|
||||
void preDisplaySide(const RenderArgs* renderArgs);
|
||||
|
||||
const glm::mat4& getHMDSensorMatrix() const { return _hmdSensorMatrix; }
|
||||
const glm::vec3& getHMDSensorPosition() const { return _hmdSensorPosition; }
|
||||
|
|
|
@ -160,3 +160,29 @@ void TestScriptingInterface::clearCaches() {
|
|||
qApp->reloadResourceCaches();
|
||||
}
|
||||
|
||||
// Writes a JSON object from javascript to a file
|
||||
void TestScriptingInterface::saveObject(QVariant variant, const QString& filename) {
|
||||
if (_testResultsLocation.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonDocument jsonDocument;
|
||||
jsonDocument = QJsonDocument::fromVariant(variant);
|
||||
if (jsonDocument.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray jsonData = jsonDocument.toJson();
|
||||
|
||||
// Append trailing slash if needed
|
||||
if (_testResultsLocation.right(1) != "/") {
|
||||
_testResultsLocation += "/";
|
||||
}
|
||||
|
||||
QString filepath = QDir::cleanPath(_testResultsLocation + filename);
|
||||
QFile file(filepath);
|
||||
|
||||
file.open(QFile::WriteOnly);
|
||||
file.write(jsonData);
|
||||
file.close();
|
||||
}
|
||||
|
|
|
@ -18,6 +18,10 @@ class QScriptValue;
|
|||
class TestScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
void setTestResultsLocation(const QString path) { _testResultsLocation = path; }
|
||||
const QString& getTestResultsLocation() { return _testResultsLocation; };
|
||||
|
||||
public slots:
|
||||
static TestScriptingInterface* getInstance();
|
||||
|
||||
|
@ -46,7 +50,6 @@ public slots:
|
|||
*/
|
||||
void waitIdle();
|
||||
|
||||
|
||||
bool waitForConnection(qint64 maxWaitMs = 10000);
|
||||
|
||||
void wait(int milliseconds);
|
||||
|
@ -83,8 +86,14 @@ public slots:
|
|||
*/
|
||||
void clearCaches();
|
||||
|
||||
/**jsdoc
|
||||
* Save a JSON object to a file in the test results location
|
||||
*/
|
||||
void saveObject(QVariant v, const QString& filename);
|
||||
|
||||
private:
|
||||
bool waitForCondition(qint64 maxWaitMs, std::function<bool()> condition);
|
||||
QString _testResultsLocation;
|
||||
};
|
||||
|
||||
#endif // hifi_TestScriptingInterface_h
|
||||
#endif // hifi_TestScriptingInterface_h
|
||||
|
|
|
@ -74,9 +74,9 @@ SnapshotMetaData* Snapshot::parseSnapshotData(QString snapshotPath) {
|
|||
return data;
|
||||
}
|
||||
|
||||
QString Snapshot::saveSnapshot(QImage image, const QString& filename) {
|
||||
QString Snapshot::saveSnapshot(QImage image, const QString& filename, const QString& pathname) {
|
||||
|
||||
QFile* snapshotFile = savedFileForSnapshot(image, false, filename);
|
||||
QFile* snapshotFile = savedFileForSnapshot(image, false, filename, pathname);
|
||||
|
||||
// we don't need the snapshot file, so close it, grab its filename and delete it
|
||||
snapshotFile->close();
|
||||
|
@ -93,7 +93,7 @@ QTemporaryFile* Snapshot::saveTempSnapshot(QImage image) {
|
|||
return static_cast<QTemporaryFile*>(savedFileForSnapshot(image, true));
|
||||
}
|
||||
|
||||
QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QString& userSelectedFilename) {
|
||||
QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QString& userSelectedFilename, const QString& userSelectedPathname) {
|
||||
|
||||
// adding URL to snapshot
|
||||
QUrl currentURL = DependencyManager::get<AddressManager>()->currentPublicAddress();
|
||||
|
@ -118,7 +118,13 @@ QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QSt
|
|||
const int IMAGE_QUALITY = 100;
|
||||
|
||||
if (!isTemporary) {
|
||||
QString snapshotFullPath = snapshotsLocation.get();
|
||||
// If user has requested specific path then use it, else use the application value
|
||||
QString snapshotFullPath;
|
||||
if (!userSelectedPathname.isNull()) {
|
||||
snapshotFullPath = userSelectedPathname;
|
||||
} else {
|
||||
snapshotFullPath = snapshotsLocation.get();
|
||||
}
|
||||
|
||||
if (snapshotFullPath.isEmpty()) {
|
||||
snapshotFullPath = OffscreenUi::getExistingDirectory(nullptr, "Choose Snapshots Directory", QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
|
||||
|
|
|
@ -38,7 +38,7 @@ class Snapshot : public QObject, public Dependency {
|
|||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
public:
|
||||
static QString saveSnapshot(QImage image, const QString& filename);
|
||||
static QString saveSnapshot(QImage image, const QString& filename, const QString& pathname = QString());
|
||||
static QTemporaryFile* saveTempSnapshot(QImage image);
|
||||
static SnapshotMetaData* parseSnapshotData(QString snapshotPath);
|
||||
|
||||
|
@ -52,7 +52,10 @@ public slots:
|
|||
Q_INVOKABLE QString getSnapshotsLocation();
|
||||
Q_INVOKABLE void setSnapshotsLocation(const QString& location);
|
||||
private:
|
||||
static QFile* savedFileForSnapshot(QImage & image, bool isTemporary, const QString& userSelectedFilename = QString());
|
||||
static QFile* savedFileForSnapshot(QImage& image,
|
||||
bool isTemporary,
|
||||
const QString& userSelectedFilename = QString(),
|
||||
const QString& userSelectedPathname = QString());
|
||||
};
|
||||
|
||||
#endif // hifi_Snapshot_h
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
bool intersects { false };
|
||||
OverlayID overlayID { UNKNOWN_OVERLAY_ID };
|
||||
float distance { 0 };
|
||||
BoxFace face;
|
||||
BoxFace face { UNKNOWN_FACE };
|
||||
glm::vec3 surfaceNormal;
|
||||
glm::vec3 intersection;
|
||||
QVariantMap extraInfo;
|
||||
|
|
|
@ -12,5 +12,4 @@
|
|||
#include "AudioLogging.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(audio, "hifi.audio")
|
||||
Q_LOGGING_CATEGORY(audiostream, "hifi.audio-stream", QtWarningMsg)
|
||||
|
||||
Q_LOGGING_CATEGORY(audiostream, "hifi.audio-stream")
|
||||
|
|
|
@ -28,69 +28,76 @@ void Basic2DWindowOpenGLDisplayPlugin::customizeContext() {
|
|||
qreal dpi = getFullscreenTarget()->physicalDotsPerInch();
|
||||
_virtualPadPixelSize = dpi * VirtualPad::Manager::BASE_DIAMETER_PIXELS / VirtualPad::Manager::DPI;
|
||||
|
||||
auto iconPath = PathUtils::resourcesPath() + "images/analog_stick.png";
|
||||
auto image = QImage(iconPath);
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
image = image.scaled(_virtualPadPixelSize, _virtualPadPixelSize, Qt::KeepAspectRatio);
|
||||
if (!_virtualPadStickTexture) {
|
||||
auto iconPath = PathUtils::resourcesPath() + "images/analog_stick.png";
|
||||
auto image = QImage(iconPath);
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
image = image.scaled(_virtualPadPixelSize, _virtualPadPixelSize, Qt::KeepAspectRatio);
|
||||
|
||||
_virtualPadStickTexture = gpu::Texture::createStrict(
|
||||
gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
|
||||
image.width(), image.height(),
|
||||
gpu::Texture::MAX_NUM_MIPS,
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
|
||||
_virtualPadStickTexture->setSource("virtualPad stick");
|
||||
auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
|
||||
_virtualPadStickTexture->setUsage(usage.build());
|
||||
_virtualPadStickTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
|
||||
_virtualPadStickTexture->assignStoredMip(0, image.byteCount(), image.constBits());
|
||||
_virtualPadStickTexture->setAutoGenerateMips(true);
|
||||
_virtualPadStickTexture = gpu::Texture::createStrict(
|
||||
gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
|
||||
image.width(), image.height(),
|
||||
gpu::Texture::MAX_NUM_MIPS,
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
|
||||
_virtualPadStickTexture->setSource("virtualPad stick");
|
||||
auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
|
||||
_virtualPadStickTexture->setUsage(usage.build());
|
||||
_virtualPadStickTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
|
||||
_virtualPadStickTexture->assignStoredMip(0, image.byteCount(), image.constBits());
|
||||
_virtualPadStickTexture->setAutoGenerateMips(true);
|
||||
}
|
||||
}
|
||||
|
||||
iconPath = PathUtils::resourcesPath() + "images/analog_stick_base.png";
|
||||
image = QImage(iconPath);
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
image = image.scaled(_virtualPadPixelSize, _virtualPadPixelSize, Qt::KeepAspectRatio);
|
||||
if (!_virtualPadStickBaseTexture) {
|
||||
auto iconPath = PathUtils::resourcesPath() + "images/analog_stick_base.png";
|
||||
auto image = QImage(iconPath);
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
image = image.scaled(_virtualPadPixelSize, _virtualPadPixelSize, Qt::KeepAspectRatio);
|
||||
|
||||
_virtualPadStickBaseTexture = gpu::Texture::createStrict(
|
||||
gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
|
||||
image.width(), image.height(),
|
||||
gpu::Texture::MAX_NUM_MIPS,
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
|
||||
_virtualPadStickBaseTexture->setSource("virtualPad base");
|
||||
auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
|
||||
_virtualPadStickBaseTexture->setUsage(usage.build());
|
||||
_virtualPadStickBaseTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
|
||||
_virtualPadStickBaseTexture->assignStoredMip(0, image.byteCount(), image.constBits());
|
||||
_virtualPadStickBaseTexture->setAutoGenerateMips(true);
|
||||
_virtualPadStickBaseTexture = gpu::Texture::createStrict(
|
||||
gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
|
||||
image.width(), image.height(),
|
||||
gpu::Texture::MAX_NUM_MIPS,
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
|
||||
_virtualPadStickBaseTexture->setSource("virtualPad base");
|
||||
auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
|
||||
_virtualPadStickBaseTexture->setUsage(usage.build());
|
||||
_virtualPadStickBaseTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
|
||||
_virtualPadStickBaseTexture->assignStoredMip(0, image.byteCount(), image.constBits());
|
||||
_virtualPadStickBaseTexture->setAutoGenerateMips(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_virtualPadJumpBtnPixelSize = dpi * VirtualPad::Manager::JUMP_BTN_FULL_PIXELS / VirtualPad::Manager::DPI;
|
||||
iconPath = PathUtils::resourcesPath() + "images/fly.png";
|
||||
image = QImage(iconPath);
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
image = image.scaled(_virtualPadJumpBtnPixelSize, _virtualPadJumpBtnPixelSize, Qt::KeepAspectRatio);
|
||||
image = image.mirrored();
|
||||
if (!_virtualPadJumpBtnTexture) {
|
||||
auto iconPath = PathUtils::resourcesPath() + "images/fly.png";
|
||||
auto image = QImage(iconPath);
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
image = image.scaled(_virtualPadJumpBtnPixelSize, _virtualPadJumpBtnPixelSize, Qt::KeepAspectRatio);
|
||||
image = image.mirrored();
|
||||
|
||||
_virtualPadJumpBtnTexture = gpu::Texture::createStrict(
|
||||
gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
|
||||
image.width(), image.height(),
|
||||
gpu::Texture::MAX_NUM_MIPS,
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
|
||||
_virtualPadJumpBtnTexture->setSource("virtualPad jump");
|
||||
auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
|
||||
_virtualPadJumpBtnTexture->setUsage(usage.build());
|
||||
_virtualPadJumpBtnTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
|
||||
_virtualPadJumpBtnTexture->assignStoredMip(0, image.byteCount(), image.constBits());
|
||||
_virtualPadJumpBtnTexture->setAutoGenerateMips(true);
|
||||
_virtualPadJumpBtnTexture = gpu::Texture::createStrict(
|
||||
gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
|
||||
image.width(), image.height(),
|
||||
gpu::Texture::MAX_NUM_MIPS,
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
|
||||
_virtualPadJumpBtnTexture->setSource("virtualPad jump");
|
||||
auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
|
||||
_virtualPadJumpBtnTexture->setUsage(usage.build());
|
||||
_virtualPadJumpBtnTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
|
||||
_virtualPadJumpBtnTexture->assignStoredMip(0, image.byteCount(), image.constBits());
|
||||
_virtualPadJumpBtnTexture->setAutoGenerateMips(true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Parent::customizeContext();
|
||||
|
@ -124,44 +131,32 @@ void Basic2DWindowOpenGLDisplayPlugin::compositeExtra() {
|
|||
// render stick base
|
||||
auto stickBaseTransform = DependencyManager::get<CompositorHelper>()->getPoint2DTransform(virtualPadManager.getLeftVirtualPad()->getFirstTouch(),
|
||||
_virtualPadPixelSize, _virtualPadPixelSize);
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setProjectionTransform(mat4());
|
||||
batch.setPipeline(_cursorPipeline);
|
||||
batch.setResourceTexture(0, _virtualPadStickBaseTexture);
|
||||
batch.resetViewTransform();
|
||||
batch.setModelTransform(stickBaseTransform);
|
||||
batch.setViewportTransform(ivec4(uvec2(0), getRecommendedRenderSize()));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
// render stick head
|
||||
auto stickTransform = DependencyManager::get<CompositorHelper>()->getPoint2DTransform(virtualPadManager.getLeftVirtualPad()->getCurrentTouch(),
|
||||
_virtualPadPixelSize, _virtualPadPixelSize);
|
||||
_virtualPadPixelSize, _virtualPadPixelSize);
|
||||
auto jumpTransform = DependencyManager::get<CompositorHelper>()->getPoint2DTransform(virtualPadManager.getJumpButtonPosition(),
|
||||
_virtualPadJumpBtnPixelSize, _virtualPadJumpBtnPixelSize);
|
||||
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(_compositeFramebuffer);
|
||||
batch.resetViewTransform();
|
||||
batch.setProjectionTransform(mat4());
|
||||
batch.setPipeline(_cursorPipeline);
|
||||
batch.setResourceTexture(0, _virtualPadStickTexture);
|
||||
batch.resetViewTransform();
|
||||
batch.setModelTransform(stickTransform);
|
||||
batch.setViewportTransform(ivec4(uvec2(0), getRecommendedRenderSize()));
|
||||
|
||||
batch.setResourceTexture(0, _virtualPadStickBaseTexture);
|
||||
batch.setModelTransform(stickBaseTransform);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
if (!virtualPadManager.getLeftVirtualPad()->isBeingTouched()) {
|
||||
// render stick head
|
||||
auto jumpTransform = DependencyManager::get<CompositorHelper>()->getPoint2DTransform(virtualPadManager.getJumpButtonPosition(),
|
||||
_virtualPadJumpBtnPixelSize, _virtualPadJumpBtnPixelSize);
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setProjectionTransform(mat4());
|
||||
batch.setPipeline(_cursorPipeline);
|
||||
|
||||
batch.setResourceTexture(0, _virtualPadStickTexture);
|
||||
batch.setModelTransform(stickTransform);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
||||
if (!virtualPadManager.getLeftVirtualPad()->isBeingTouched()) {
|
||||
batch.setResourceTexture(0, _virtualPadJumpBtnTexture);
|
||||
batch.resetViewTransform();
|
||||
batch.setModelTransform(jumpTransform);
|
||||
batch.setViewportTransform(ivec4(uvec2(0), getRecommendedRenderSize()));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
Parent::compositeExtra();
|
||||
|
|
|
@ -336,9 +336,8 @@ void OpenGLDisplayPlugin::deactivate() {
|
|||
|
||||
_container->showDisplayPluginsTools(false);
|
||||
if (!_container->currentDisplayActions().isEmpty()) {
|
||||
auto menu = _container->getPrimaryMenu();
|
||||
foreach(auto itemInfo, _container->currentDisplayActions()) {
|
||||
menu->removeMenuItem(itemInfo.first, itemInfo.second);
|
||||
_container->removeMenuItem(itemInfo.first, itemInfo.second);
|
||||
}
|
||||
_container->currentDisplayActions().clear();
|
||||
}
|
||||
|
|
|
@ -251,7 +251,7 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
|
|||
updateAmbientLightFromEntity(entity);
|
||||
}
|
||||
|
||||
if (skyboxChanged) {
|
||||
if (skyboxChanged || _proceduralUserData != entity->getUserData()) {
|
||||
updateKeyBackgroundFromEntity(entity);
|
||||
}
|
||||
|
||||
|
@ -295,6 +295,10 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint
|
|||
return true;
|
||||
}
|
||||
|
||||
if (entity->getUserData() != _proceduralUserData) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (_typedEntity->getCompoundShapeURL() != _lastShapeURL) {
|
||||
return true;
|
||||
|
|
|
@ -77,7 +77,6 @@ void EntityEditPacketSender::queueEditAvatarEntityMessage(PacketType type,
|
|||
_myAvatar->updateAvatarEntity(entityItemID, binaryProperties);
|
||||
|
||||
entity->setLastBroadcast(usecTimestampNow());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
@ -85,10 +84,6 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type,
|
|||
EntityTreePointer entityTree,
|
||||
EntityItemID entityItemID,
|
||||
const EntityItemProperties& properties) {
|
||||
if (!_shouldSend) {
|
||||
return; // bail early
|
||||
}
|
||||
|
||||
if (properties.getClientOnly() && properties.getOwningAvatarID() == _myAvatar->getID()) {
|
||||
// this is an avatar-based entity --> update our avatar-data rather than sending to the entity-server
|
||||
queueEditAvatarEntityMessage(type, entityTree, entityItemID, properties);
|
||||
|
@ -147,9 +142,6 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type,
|
|||
}
|
||||
|
||||
void EntityEditPacketSender::queueEraseEntityMessage(const EntityItemID& entityItemID) {
|
||||
if (!_shouldSend) {
|
||||
return; // bail early
|
||||
}
|
||||
|
||||
// in case this was a clientOnly entity:
|
||||
if(_myAvatar) {
|
||||
|
|
|
@ -1070,7 +1070,7 @@ bool EntityItem::stepKinematicMotion(float timeElapsed) {
|
|||
|
||||
const float MAX_TIME_ELAPSED = 1.0f; // seconds
|
||||
if (timeElapsed > MAX_TIME_ELAPSED) {
|
||||
qCWarning(entities) << "kinematic timestep = " << timeElapsed << " truncated to " << MAX_TIME_ELAPSED;
|
||||
qCDebug(entities) << "kinematic timestep = " << timeElapsed << " truncated to " << MAX_TIME_ELAPSED;
|
||||
}
|
||||
timeElapsed = glm::min(timeElapsed, MAX_TIME_ELAPSED);
|
||||
|
||||
|
|
|
@ -481,8 +481,8 @@ public slots:
|
|||
/**jsdoc
|
||||
* Gets the status of server entity script attached to an entity
|
||||
* @function Entities.getServerScriptStatus
|
||||
* @property {Uuid} entityID - The ID of the entity to get the server entity script status for.
|
||||
* @property {Entities~getServerScriptStatusCallback} callback - The function to call upon completion.
|
||||
* @param {Uuid} entityID - The ID of the entity to get the server entity script status for.
|
||||
* @param {Entities~getServerScriptStatusCallback} callback - The function to call upon completion.
|
||||
* @returns {boolean} <code>true</code> always.
|
||||
*/
|
||||
/**jsdoc
|
||||
|
|
|
@ -103,12 +103,15 @@ void OffscreenGLCanvas::onMessageLogged(const QOpenGLDebugMessage& debugMessage)
|
|||
|
||||
bool OffscreenGLCanvas::makeCurrent() {
|
||||
bool result = _context->makeCurrent(_offscreenSurface);
|
||||
std::call_once(_reportOnce, []{
|
||||
qCDebug(glLogging) << "GL Version: " << QString((const char*) glGetString(GL_VERSION));
|
||||
qCDebug(glLogging) << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
qCDebug(glLogging) << "GL Vendor: " << QString((const char*) glGetString(GL_VENDOR));
|
||||
qCDebug(glLogging) << "GL Renderer: " << QString((const char*) glGetString(GL_RENDERER));
|
||||
});
|
||||
if (glGetString) {
|
||||
std::call_once(_reportOnce, [] {
|
||||
qCDebug(glLogging) << "GL Version: " << QString((const char*)glGetString(GL_VERSION));
|
||||
qCDebug(glLogging) << "GL Shader Language Version: "
|
||||
<< QString((const char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
qCDebug(glLogging) << "GL Vendor: " << QString((const char*)glGetString(GL_VENDOR));
|
||||
qCDebug(glLogging) << "GL Renderer: " << QString((const char*)glGetString(GL_RENDERER));
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ std::string GL41Backend::getBackendShaderHeader() const {
|
|||
static const std::string header(
|
||||
R"SHADER(#version 410 core
|
||||
#define GPU_GL410
|
||||
#define PRECISIONQ
|
||||
#define BITFIELD int
|
||||
)SHADER");
|
||||
return header;
|
||||
|
|
|
@ -18,7 +18,6 @@ std::string GL45Backend::getBackendShaderHeader() const {
|
|||
static const std::string header(
|
||||
R"SHADER(#version 450 core
|
||||
#define GPU_GL450
|
||||
#define PRECISIONQ
|
||||
#define BITFIELD int
|
||||
)SHADER"
|
||||
#ifdef GPU_SSBO_TRANSFORM_OBJECT
|
||||
|
|
|
@ -17,10 +17,9 @@ std::string GLESBackend::getBackendShaderHeader() const {
|
|||
static const std::string header(
|
||||
R"SHADER(#version 310 es
|
||||
#extension GL_EXT_texture_buffer : enable
|
||||
precision lowp float; // check precision 2
|
||||
precision lowp samplerBuffer;
|
||||
precision lowp sampler2DShadow;
|
||||
#define PRECISIONQ highp
|
||||
precision highp float;
|
||||
precision highp samplerBuffer;
|
||||
precision highp sampler2DShadow;
|
||||
#define BITFIELD highp int
|
||||
)SHADER");
|
||||
return header;
|
||||
|
|
|
@ -50,47 +50,50 @@ enum Type : uint8_t {
|
|||
};
|
||||
// Array providing the size in bytes for a given scalar type
|
||||
static const int TYPE_SIZE[NUM_TYPES] = {
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
4, // FLOAT
|
||||
4, // INT32
|
||||
4, // UINT32
|
||||
2, // HALF
|
||||
2, // INT16
|
||||
2, // UINT16
|
||||
1, // INT8
|
||||
1, // UINT8
|
||||
|
||||
// normalized values
|
||||
4,
|
||||
4,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
4,
|
||||
4, // NINT32
|
||||
4, // NUINT32
|
||||
2, // NINT16
|
||||
2, // NUINT16
|
||||
1, // NINT8
|
||||
1, // NUINT8
|
||||
1, // NUINT2
|
||||
1, // NINT2_10_10_10
|
||||
|
||||
1
|
||||
1, // COMPRESSED
|
||||
};
|
||||
|
||||
// Array answering the question Does this type is integer or not
|
||||
static const bool TYPE_IS_INTEGER[NUM_TYPES] = {
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false, // FLOAT
|
||||
true, // INT32
|
||||
true, // UINT32
|
||||
false, // HALF
|
||||
true, // INT16
|
||||
true, // UINT16
|
||||
true, // INT8
|
||||
true, // UINT8
|
||||
|
||||
// Normalized values
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false, // NINT32
|
||||
false, // NUINT32
|
||||
false, // NINT16
|
||||
false, // NUINT16
|
||||
false, // NINT8
|
||||
false, // NUINT8
|
||||
false, // NUINT2
|
||||
false, // NINT2_10_10_10
|
||||
|
||||
false,
|
||||
false, // COMPRESSED
|
||||
};
|
||||
|
||||
// Dimension of an Element
|
||||
|
@ -367,9 +370,9 @@ public:
|
|||
static const Element PART_DRAWCALL;
|
||||
|
||||
protected:
|
||||
uint8 _semantic;
|
||||
uint8 _dimension : 4;
|
||||
uint8 _type : 4;
|
||||
uint16 _semantic : 7;
|
||||
uint16 _dimension : 4;
|
||||
uint16 _type : 5;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -46,13 +46,14 @@ struct GPUKTXPayload {
|
|||
|
||||
memcpy(data, &_samplerDesc, sizeof(Sampler::Desc));
|
||||
data += sizeof(Sampler::Desc);
|
||||
|
||||
|
||||
// We can't copy the bitset in Texture::Usage in a crossplateform manner
|
||||
// So serialize it manually
|
||||
*(uint32*)data = _usage._flags.to_ulong();
|
||||
uint32 usageData = _usage._flags.to_ulong();
|
||||
memcpy(data, &usageData, sizeof(uint32));
|
||||
data += sizeof(uint32);
|
||||
|
||||
*(TextureUsageType*)data = _usageType;
|
||||
memcpy(data, &_usageType, sizeof(TextureUsageType));
|
||||
data += sizeof(TextureUsageType);
|
||||
|
||||
return data + PADDING;
|
||||
|
@ -77,13 +78,15 @@ struct GPUKTXPayload {
|
|||
|
||||
memcpy(&_samplerDesc, data, sizeof(Sampler::Desc));
|
||||
data += sizeof(Sampler::Desc);
|
||||
|
||||
|
||||
// We can't copy the bitset in Texture::Usage in a crossplateform manner
|
||||
// So unserialize it manually
|
||||
_usage = Texture::Usage(*(const uint32*)data);
|
||||
uint32 usageData;
|
||||
memcpy(&usageData, data, sizeof(uint32));
|
||||
_usage = Texture::Usage(usageData);
|
||||
data += sizeof(uint32);
|
||||
|
||||
_usageType = *(const TextureUsageType*)data;
|
||||
memcpy(&_usageType, data, sizeof(TextureUsageType));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -710,4 +713,4 @@ bool Texture::evalTextureFormat(const ktx::Header& header, Element& mipFormat, E
|
|||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ vec3 getLightIrradiance(Light l) { return lightIrradiance_getIrradiance(l.irradi
|
|||
// Light Ambient
|
||||
|
||||
struct LightAmbient {
|
||||
PRECISIONQ vec4 _ambient;
|
||||
vec4 _ambient;
|
||||
SphericalHarmonics _ambientSphere;
|
||||
mat4 transform;
|
||||
};
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
#define LightIrradianceConstRef LightIrradiance
|
||||
|
||||
struct LightIrradiance {
|
||||
PRECISIONQ vec4 colorIntensity;
|
||||
vec4 colorIntensity;
|
||||
// falloffRadius, cutoffRadius, falloffSpot, spare
|
||||
PRECISIONQ vec4 attenuation;
|
||||
vec4 attenuation;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
#define LightVolumeConstRef LightVolume
|
||||
|
||||
struct LightVolume {
|
||||
PRECISIONQ vec4 positionRadius;
|
||||
PRECISIONQ vec4 directionSpotCos;
|
||||
vec4 positionRadius;
|
||||
vec4 directionSpotCos;
|
||||
};
|
||||
|
||||
bool lightVolume_isPoint(LightVolume lv) { return bool(lv.directionSpotCos.w < 0.f); }
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
// to what is provided by the uniform buffer, or the material key has the wrong bits
|
||||
|
||||
struct Material {
|
||||
PRECISIONQ vec4 _emissiveOpacity;
|
||||
PRECISIONQ vec4 _albedoRoughness;
|
||||
PRECISIONQ vec4 _fresnelMetallic;
|
||||
PRECISIONQ vec4 _scatteringSpare2Key;
|
||||
vec4 _emissiveOpacity;
|
||||
vec4 _albedoRoughness;
|
||||
vec4 _fresnelMetallic;
|
||||
vec4 _scatteringSpare2Key;
|
||||
};
|
||||
|
||||
uniform materialBuffer {
|
||||
|
@ -64,7 +64,4 @@ const BITFIELD OCCLUSION_MAP_BIT = 0x00004000;
|
|||
const BITFIELD LIGHTMAP_MAP_BIT = 0x00008000;
|
||||
const BITFIELD SCATTERING_MAP_BIT = 0x00010000;
|
||||
|
||||
#ifdef GL_ES
|
||||
precision lowp float;
|
||||
#endif
|
||||
<@endif@>
|
||||
|
|
|
@ -16,15 +16,15 @@
|
|||
#define SphericalHarmonicsConstRef SphericalHarmonics
|
||||
|
||||
struct SphericalHarmonics {
|
||||
PRECISIONQ vec4 L00;
|
||||
PRECISIONQ vec4 L1m1;
|
||||
PRECISIONQ vec4 L10;
|
||||
PRECISIONQ vec4 L11;
|
||||
PRECISIONQ vec4 L2m2;
|
||||
PRECISIONQ vec4 L2m1;
|
||||
PRECISIONQ vec4 L20;
|
||||
PRECISIONQ vec4 L21;
|
||||
PRECISIONQ vec4 L22;
|
||||
vec4 L00;
|
||||
vec4 L1m1;
|
||||
vec4 L10;
|
||||
vec4 L11;
|
||||
vec4 L2m2;
|
||||
vec4 L2m1;
|
||||
vec4 L20;
|
||||
vec4 L21;
|
||||
vec4 L22;
|
||||
};
|
||||
|
||||
vec4 sphericalHarmonics_evalSphericalLight(SphericalHarmonicsConstRef sh, vec3 direction) {
|
||||
|
|
|
@ -35,8 +35,11 @@ void main(void) {
|
|||
#ifdef PROCEDURAL
|
||||
|
||||
vec3 color = getSkyboxColor();
|
||||
// Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline
|
||||
color = pow(color, vec3(2.2));
|
||||
// Protect from NaNs and negative values
|
||||
color = mix(color, vec3(0), isnan(color));
|
||||
color = max(color, vec3(0));
|
||||
// Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline
|
||||
color = pow(color, vec3(2.2));
|
||||
_fragColor = vec4(color, 0.0);
|
||||
|
||||
// FIXME: scribe does not yet scrub out else statements
|
||||
|
|
|
@ -97,7 +97,7 @@ public:
|
|||
|
||||
int getCheckInPacketsSinceLastReply() const { return _checkInPacketsSinceLastReply; }
|
||||
void sentCheckInPacket();
|
||||
void domainListReceived() { _checkInPacketsSinceLastReply = 0; }
|
||||
void clearPendingCheckins() { _checkInPacketsSinceLastReply = 0; }
|
||||
|
||||
/**jsdoc
|
||||
* <p>The reasons that you may be refused connection to a domain are defined by numeric values:</p>
|
||||
|
|
117
libraries/networking/src/HMACAuth.cpp
Normal file
117
libraries/networking/src/HMACAuth.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
//
|
||||
// HMACAuth.cpp
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Simon Walton on 3/19/2018.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "HMACAuth.h"
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
#include <QUuid>
|
||||
#include "NetworkLogging.h"
|
||||
#include <cassert>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000
|
||||
HMACAuth::HMACAuth(AuthMethod authMethod)
|
||||
: _hmacContext(HMAC_CTX_new())
|
||||
, _authMethod(authMethod) { }
|
||||
|
||||
HMACAuth::~HMACAuth()
|
||||
{
|
||||
HMAC_CTX_free(_hmacContext);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
HMACAuth::HMACAuth(AuthMethod authMethod)
|
||||
: _hmacContext(new HMAC_CTX())
|
||||
, _authMethod(authMethod) {
|
||||
HMAC_CTX_init(_hmacContext);
|
||||
}
|
||||
|
||||
HMACAuth::~HMACAuth() {
|
||||
HMAC_CTX_cleanup(_hmacContext);
|
||||
delete _hmacContext;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool HMACAuth::setKey(const char* keyValue, int keyLen) {
|
||||
const EVP_MD* sslStruct = nullptr;
|
||||
|
||||
switch (_authMethod) {
|
||||
case MD5:
|
||||
sslStruct = EVP_md5();
|
||||
break;
|
||||
|
||||
case SHA1:
|
||||
sslStruct = EVP_sha1();
|
||||
break;
|
||||
|
||||
case SHA224:
|
||||
sslStruct = EVP_sha224();
|
||||
break;
|
||||
|
||||
case SHA256:
|
||||
sslStruct = EVP_sha256();
|
||||
break;
|
||||
|
||||
case RIPEMD160:
|
||||
sslStruct = EVP_ripemd160();
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
QMutexLocker lock(&_lock);
|
||||
return (bool) HMAC_Init_ex(_hmacContext, keyValue, keyLen, sslStruct, nullptr);
|
||||
}
|
||||
|
||||
bool HMACAuth::setKey(const QUuid& uidKey) {
|
||||
const QByteArray rfcBytes(uidKey.toRfc4122());
|
||||
return setKey(rfcBytes.constData(), rfcBytes.length());
|
||||
}
|
||||
|
||||
bool HMACAuth::addData(const char* data, int dataLen) {
|
||||
QMutexLocker lock(&_lock);
|
||||
return (bool) HMAC_Update(_hmacContext, reinterpret_cast<const unsigned char*>(data), dataLen);
|
||||
}
|
||||
|
||||
HMACAuth::HMACHash HMACAuth::result() {
|
||||
HMACHash hashValue(EVP_MAX_MD_SIZE);
|
||||
unsigned int hashLen;
|
||||
QMutexLocker lock(&_lock);
|
||||
|
||||
auto hmacResult = HMAC_Final(_hmacContext, &hashValue[0], &hashLen);
|
||||
|
||||
if (hmacResult) {
|
||||
hashValue.resize((size_t)hashLen);
|
||||
} else {
|
||||
// the HMAC_FINAL call failed - should not be possible to get into this state
|
||||
qCWarning(networking) << "Error occured calling HMAC_Final";
|
||||
assert(hmacResult);
|
||||
}
|
||||
|
||||
// Clear state for possible reuse.
|
||||
HMAC_Init_ex(_hmacContext, nullptr, 0, nullptr, nullptr);
|
||||
return hashValue;
|
||||
}
|
||||
|
||||
bool HMACAuth::calculateHash(HMACHash& hashResult, const char* data, int dataLen) {
|
||||
QMutexLocker lock(&_lock);
|
||||
if (!addData(data, dataLen)) {
|
||||
qCWarning(networking) << "Error occured calling HMACAuth::addData()";
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
hashResult = result();
|
||||
return true;
|
||||
}
|
47
libraries/networking/src/HMACAuth.h
Normal file
47
libraries/networking/src/HMACAuth.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// HMACAuth.h
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Simon Walton on 3/19/2018.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_HMACAuth_h
|
||||
#define hifi_HMACAuth_h
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <QtCore/QMutex>
|
||||
|
||||
class QUuid;
|
||||
|
||||
class HMACAuth {
|
||||
public:
|
||||
enum AuthMethod { MD5, SHA1, SHA224, SHA256, RIPEMD160 };
|
||||
using HMACHash = std::vector<unsigned char>;
|
||||
|
||||
explicit HMACAuth(AuthMethod authMethod = MD5);
|
||||
~HMACAuth();
|
||||
|
||||
bool setKey(const char* keyValue, int keyLen);
|
||||
bool setKey(const QUuid& uidKey);
|
||||
// Calculate complete hash in one.
|
||||
bool calculateHash(HMACHash& hashResult, const char* data, int dataLen);
|
||||
|
||||
// Append to data to be hashed.
|
||||
bool addData(const char* data, int dataLen);
|
||||
// Get the resulting hash from calls to addData().
|
||||
// Note that only one hash may be calculated at a time for each
|
||||
// HMACAuth instance if this interface is used.
|
||||
HMACHash result();
|
||||
|
||||
private:
|
||||
QMutex _lock { QMutex::Recursive };
|
||||
struct hmac_ctx_st* _hmacContext;
|
||||
AuthMethod _authMethod;
|
||||
};
|
||||
|
||||
#endif // hifi_HMACAuth_h
|
|
@ -36,6 +36,7 @@
|
|||
#include "HifiSockAddr.h"
|
||||
#include "NetworkLogging.h"
|
||||
#include "udt/Packet.h"
|
||||
#include "HMACAuth.h"
|
||||
|
||||
static Setting::Handle<quint16> LIMITED_NODELIST_LOCAL_PORT("LimitedNodeList.LocalPort", 0);
|
||||
|
||||
|
@ -332,15 +333,20 @@ bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packe
|
|||
if (verifiedPacket && !ignoreVerification) {
|
||||
|
||||
QByteArray packetHeaderHash = NLPacket::verificationHashInHeader(packet);
|
||||
QByteArray expectedHash = NLPacket::hashForPacketAndSecret(packet, sourceNode->getConnectionSecret());
|
||||
QByteArray expectedHash;
|
||||
auto sourceNodeHMACAuth = sourceNode->getAuthenticateHash();
|
||||
if (sourceNode->getAuthenticateHash()) {
|
||||
expectedHash = NLPacket::hashForPacketAndHMAC(packet, *sourceNodeHMACAuth);
|
||||
}
|
||||
|
||||
// check if the md5 hash in the header matches the hash we would expect
|
||||
if (packetHeaderHash != expectedHash) {
|
||||
// check if the HMAC-md5 hash in the header matches the hash we would expect
|
||||
if (!sourceNodeHMACAuth || packetHeaderHash != expectedHash) {
|
||||
static QMultiMap<QUuid, PacketType> hashDebugSuppressMap;
|
||||
|
||||
if (!hashDebugSuppressMap.contains(sourceID, headerType)) {
|
||||
qCDebug(networking) << packetHeaderHash << expectedHash;
|
||||
qCDebug(networking) << "Packet hash mismatch on" << headerType << "- Sender" << sourceID;
|
||||
qCDebug(networking) << "Packet len:" << packet.getDataSize() << "Expected hash:" <<
|
||||
expectedHash.toHex() << "Actual:" << packetHeaderHash.toHex();
|
||||
|
||||
hashDebugSuppressMap.insert(sourceID, headerType);
|
||||
}
|
||||
|
@ -372,15 +378,15 @@ void LimitedNodeList::collectPacketStats(const NLPacket& packet) {
|
|||
_numCollectedBytes += packet.getDataSize();
|
||||
}
|
||||
|
||||
void LimitedNodeList::fillPacketHeader(const NLPacket& packet, const QUuid& connectionSecret) {
|
||||
void LimitedNodeList::fillPacketHeader(const NLPacket& packet, HMACAuth* hmacAuth) {
|
||||
if (!PacketTypeEnum::getNonSourcedPackets().contains(packet.getType())) {
|
||||
packet.writeSourceID(getSessionLocalID());
|
||||
}
|
||||
|
||||
if (!connectionSecret.isNull()
|
||||
if (hmacAuth
|
||||
&& !PacketTypeEnum::getNonSourcedPackets().contains(packet.getType())
|
||||
&& !PacketTypeEnum::getNonVerifiedPackets().contains(packet.getType())) {
|
||||
packet.writeVerificationHashGivenSecret(connectionSecret);
|
||||
packet.writeVerificationHash(*hmacAuth);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -396,17 +402,17 @@ qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const Node&
|
|||
emit dataSent(destinationNode.getType(), packet.getDataSize());
|
||||
destinationNode.recordBytesSent(packet.getDataSize());
|
||||
|
||||
return sendUnreliablePacket(packet, *destinationNode.getActiveSocket(), destinationNode.getConnectionSecret());
|
||||
return sendUnreliablePacket(packet, *destinationNode.getActiveSocket(), destinationNode.getAuthenticateHash());
|
||||
}
|
||||
|
||||
qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const HifiSockAddr& sockAddr,
|
||||
const QUuid& connectionSecret) {
|
||||
HMACAuth* hmacAuth) {
|
||||
Q_ASSERT(!packet.isPartOfMessage());
|
||||
Q_ASSERT_X(!packet.isReliable(), "LimitedNodeList::sendUnreliablePacket",
|
||||
"Trying to send a reliable packet unreliably.");
|
||||
|
||||
collectPacketStats(packet);
|
||||
fillPacketHeader(packet, connectionSecret);
|
||||
fillPacketHeader(packet, hmacAuth);
|
||||
|
||||
return _nodeSocket.writePacket(packet, sockAddr);
|
||||
}
|
||||
|
@ -419,7 +425,7 @@ qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const Node&
|
|||
emit dataSent(destinationNode.getType(), packet->getDataSize());
|
||||
destinationNode.recordBytesSent(packet->getDataSize());
|
||||
|
||||
return sendPacket(std::move(packet), *activeSocket, destinationNode.getConnectionSecret());
|
||||
return sendPacket(std::move(packet), *activeSocket, destinationNode.getAuthenticateHash());
|
||||
} else {
|
||||
qCDebug(networking) << "LimitedNodeList::sendPacket called without active socket for node" << destinationNode << "- not sending";
|
||||
return ERROR_SENDING_PACKET_BYTES;
|
||||
|
@ -427,18 +433,18 @@ qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const Node&
|
|||
}
|
||||
|
||||
qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const HifiSockAddr& sockAddr,
|
||||
const QUuid& connectionSecret) {
|
||||
HMACAuth* hmacAuth) {
|
||||
Q_ASSERT(!packet->isPartOfMessage());
|
||||
if (packet->isReliable()) {
|
||||
collectPacketStats(*packet);
|
||||
fillPacketHeader(*packet, connectionSecret);
|
||||
fillPacketHeader(*packet, hmacAuth);
|
||||
|
||||
auto size = packet->getDataSize();
|
||||
_nodeSocket.writePacket(std::move(packet), sockAddr);
|
||||
|
||||
return size;
|
||||
} else {
|
||||
return sendUnreliablePacket(*packet, sockAddr, connectionSecret);
|
||||
return sendUnreliablePacket(*packet, sockAddr, hmacAuth);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -447,13 +453,14 @@ qint64 LimitedNodeList::sendUnreliableUnorderedPacketList(NLPacketList& packetLi
|
|||
|
||||
if (activeSocket) {
|
||||
qint64 bytesSent = 0;
|
||||
auto connectionSecret = destinationNode.getConnectionSecret();
|
||||
auto connectionHash = destinationNode.getAuthenticateHash();
|
||||
|
||||
// close the last packet in the list
|
||||
packetList.closeCurrentPacket();
|
||||
|
||||
while (!packetList._packets.empty()) {
|
||||
bytesSent += sendPacket(packetList.takeFront<NLPacket>(), *activeSocket, connectionSecret);
|
||||
bytesSent += sendPacket(packetList.takeFront<NLPacket>(), *activeSocket,
|
||||
connectionHash);
|
||||
}
|
||||
|
||||
emit dataSent(destinationNode.getType(), bytesSent);
|
||||
|
@ -466,14 +473,14 @@ qint64 LimitedNodeList::sendUnreliableUnorderedPacketList(NLPacketList& packetLi
|
|||
}
|
||||
|
||||
qint64 LimitedNodeList::sendUnreliableUnorderedPacketList(NLPacketList& packetList, const HifiSockAddr& sockAddr,
|
||||
const QUuid& connectionSecret) {
|
||||
HMACAuth* hmacAuth) {
|
||||
qint64 bytesSent = 0;
|
||||
|
||||
// close the last packet in the list
|
||||
packetList.closeCurrentPacket();
|
||||
|
||||
while (!packetList._packets.empty()) {
|
||||
bytesSent += sendPacket(packetList.takeFront<NLPacket>(), sockAddr, connectionSecret);
|
||||
bytesSent += sendPacket(packetList.takeFront<NLPacket>(), sockAddr, hmacAuth);
|
||||
}
|
||||
|
||||
return bytesSent;
|
||||
|
@ -501,7 +508,7 @@ qint64 LimitedNodeList::sendPacketList(std::unique_ptr<NLPacketList> packetList,
|
|||
for (std::unique_ptr<udt::Packet>& packet : packetList->_packets) {
|
||||
NLPacket* nlPacket = static_cast<NLPacket*>(packet.get());
|
||||
collectPacketStats(*nlPacket);
|
||||
fillPacketHeader(*nlPacket, destinationNode.getConnectionSecret());
|
||||
fillPacketHeader(*nlPacket, destinationNode.getAuthenticateHash());
|
||||
}
|
||||
|
||||
return _nodeSocket.writePacketList(std::move(packetList), *activeSocket);
|
||||
|
@ -524,7 +531,7 @@ qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const Node&
|
|||
auto& destinationSockAddr = (overridenSockAddr.isNull()) ? *destinationNode.getActiveSocket()
|
||||
: overridenSockAddr;
|
||||
|
||||
return sendPacket(std::move(packet), destinationSockAddr, destinationNode.getConnectionSecret());
|
||||
return sendPacket(std::move(packet), destinationSockAddr, destinationNode.getAuthenticateHash());
|
||||
}
|
||||
|
||||
int LimitedNodeList::updateNodeWithDataFromPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
||||
|
|
|
@ -138,19 +138,17 @@ public:
|
|||
// use sendUnreliablePacket to send an unreliable packet (that you do not need to move)
|
||||
// either to a node (via its active socket) or to a manual sockaddr
|
||||
qint64 sendUnreliablePacket(const NLPacket& packet, const Node& destinationNode);
|
||||
qint64 sendUnreliablePacket(const NLPacket& packet, const HifiSockAddr& sockAddr,
|
||||
const QUuid& connectionSecret = QUuid());
|
||||
qint64 sendUnreliablePacket(const NLPacket& packet, const HifiSockAddr& sockAddr, HMACAuth* hmacAuth = nullptr);
|
||||
|
||||
// use sendPacket to send a moved unreliable or reliable NL packet to a node's active socket or manual sockaddr
|
||||
qint64 sendPacket(std::unique_ptr<NLPacket> packet, const Node& destinationNode);
|
||||
qint64 sendPacket(std::unique_ptr<NLPacket> packet, const HifiSockAddr& sockAddr,
|
||||
const QUuid& connectionSecret = QUuid());
|
||||
qint64 sendPacket(std::unique_ptr<NLPacket> packet, const HifiSockAddr& sockAddr, HMACAuth* hmacAuth = nullptr);
|
||||
|
||||
// use sendUnreliableUnorderedPacketList to unreliably send separate packets from the packet list
|
||||
// either to a node's active socket or to a manual sockaddr
|
||||
qint64 sendUnreliableUnorderedPacketList(NLPacketList& packetList, const Node& destinationNode);
|
||||
qint64 sendUnreliableUnorderedPacketList(NLPacketList& packetList, const HifiSockAddr& sockAddr,
|
||||
const QUuid& connectionSecret = QUuid());
|
||||
HMACAuth* hmacAuth = nullptr);
|
||||
|
||||
// use sendPacketList to send reliable packet lists (ordered or unordered) to a node's active socket
|
||||
// or to a manual sock addr
|
||||
|
@ -372,7 +370,7 @@ protected:
|
|||
qint64 writePacket(const NLPacket& packet, const HifiSockAddr& destinationSockAddr,
|
||||
const QUuid& connectionSecret = QUuid());
|
||||
void collectPacketStats(const NLPacket& packet);
|
||||
void fillPacketHeader(const NLPacket& packet, const QUuid& connectionSecret = QUuid());
|
||||
void fillPacketHeader(const NLPacket& packet, HMACAuth* hmacAuth = nullptr);
|
||||
|
||||
void setLocalSocket(const HifiSockAddr& sockAddr);
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include "NLPacket.h"
|
||||
|
||||
#include "HMACAuth.h"
|
||||
|
||||
int NLPacket::localHeaderSize(PacketType type) {
|
||||
bool nonSourced = PacketTypeEnum::getNonSourcedPackets().contains(type);
|
||||
bool nonVerified = PacketTypeEnum::getNonVerifiedPackets().contains(type);
|
||||
|
@ -150,18 +152,16 @@ QByteArray NLPacket::verificationHashInHeader(const udt::Packet& packet) {
|
|||
return QByteArray(packet.getData() + offset, NUM_BYTES_MD5_HASH);
|
||||
}
|
||||
|
||||
QByteArray NLPacket::hashForPacketAndSecret(const udt::Packet& packet, const QUuid& connectionSecret) {
|
||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||
|
||||
QByteArray NLPacket::hashForPacketAndHMAC(const udt::Packet& packet, HMACAuth& hash) {
|
||||
int offset = Packet::totalHeaderSize(packet.isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion)
|
||||
+ NUM_BYTES_LOCALID + NUM_BYTES_MD5_HASH;
|
||||
|
||||
// add the packet payload and the connection UUID
|
||||
hash.addData(packet.getData() + offset, packet.getDataSize() - offset);
|
||||
hash.addData(connectionSecret.toRfc4122());
|
||||
|
||||
// return the hash
|
||||
return hash.result();
|
||||
HMACAuth::HMACHash hashResult;
|
||||
if (!hash.calculateHash(hashResult, packet.getData() + offset, packet.getDataSize() - offset)) {
|
||||
return QByteArray();
|
||||
}
|
||||
return QByteArray((const char*) hashResult.data(), (int) hashResult.size());
|
||||
}
|
||||
|
||||
void NLPacket::writeTypeAndVersion() {
|
||||
|
@ -214,14 +214,14 @@ void NLPacket::writeSourceID(LocalID sourceID) const {
|
|||
_sourceID = sourceID;
|
||||
}
|
||||
|
||||
void NLPacket::writeVerificationHashGivenSecret(const QUuid& connectionSecret) const {
|
||||
void NLPacket::writeVerificationHash(HMACAuth& hmacAuth) const {
|
||||
Q_ASSERT(!PacketTypeEnum::getNonSourcedPackets().contains(_type) &&
|
||||
!PacketTypeEnum::getNonVerifiedPackets().contains(_type));
|
||||
|
||||
auto offset = Packet::totalHeaderSize(isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion)
|
||||
+ NUM_BYTES_LOCALID;
|
||||
|
||||
QByteArray verificationHash = hashForPacketAndSecret(*this, connectionSecret);
|
||||
QByteArray verificationHash = hashForPacketAndHMAC(*this, hmacAuth);
|
||||
|
||||
memcpy(_packet.get() + offset, verificationHash.data(), verificationHash.size());
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include "udt/Packet.h"
|
||||
|
||||
class HMACAuth;
|
||||
|
||||
class NLPacket : public udt::Packet {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -69,7 +71,7 @@ public:
|
|||
|
||||
static LocalID sourceIDInHeader(const udt::Packet& packet);
|
||||
static QByteArray verificationHashInHeader(const udt::Packet& packet);
|
||||
static QByteArray hashForPacketAndSecret(const udt::Packet& packet, const QUuid& connectionSecret);
|
||||
static QByteArray hashForPacketAndHMAC(const udt::Packet& packet, HMACAuth& hash);
|
||||
|
||||
PacketType getType() const { return _type; }
|
||||
void setType(PacketType type);
|
||||
|
@ -78,9 +80,9 @@ public:
|
|||
void setVersion(PacketVersion version);
|
||||
|
||||
LocalID getSourceID() const { return _sourceID; }
|
||||
|
||||
|
||||
void writeSourceID(LocalID sourceID) const;
|
||||
void writeVerificationHashGivenSecret(const QUuid& connectionSecret) const;
|
||||
void writeVerificationHash(HMACAuth& hmacAuth) const;
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ NodeType_t NodeType::fromString(QString type) {
|
|||
|
||||
|
||||
Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket,
|
||||
const HifiSockAddr& localSocket, QObject* parent) :
|
||||
const HifiSockAddr& localSocket, QObject* parent) :
|
||||
NetworkPeer(uuid, publicSocket, localSocket, parent),
|
||||
_type(type),
|
||||
_pingMs(-1), // "Uninitialized"
|
||||
|
@ -108,6 +108,7 @@ void Node::setType(char type) {
|
|||
_symmetricSocket.setObjectName(typeString);
|
||||
}
|
||||
|
||||
|
||||
void Node::updateClockSkewUsec(qint64 clockSkewSample) {
|
||||
_clockSkewMovingPercentile.updatePercentile(clockSkewSample);
|
||||
_clockSkewUsec = (quint64)_clockSkewMovingPercentile.getValueAtPercentile();
|
||||
|
@ -194,3 +195,16 @@ QDebug operator<<(QDebug debug, const Node& node) {
|
|||
debug.nospace() << node.getPublicSocket() << "/" << node.getLocalSocket();
|
||||
return debug.nospace();
|
||||
}
|
||||
|
||||
void Node::setConnectionSecret(const QUuid& connectionSecret) {
|
||||
if (_connectionSecret == connectionSecret) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_authenticateHash) {
|
||||
_authenticateHash.reset(new HMACAuth());
|
||||
}
|
||||
|
||||
_connectionSecret = connectionSecret;
|
||||
_authenticateHash->setKey(_connectionSecret);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "SimpleMovingAverage.h"
|
||||
#include "MovingPercentile.h"
|
||||
#include "NodePermissions.h"
|
||||
#include "HMACAuth.h"
|
||||
|
||||
class Node : public NetworkPeer {
|
||||
Q_OBJECT
|
||||
|
@ -55,7 +56,8 @@ public:
|
|||
void setIsUpstream(bool isUpstream) { _isUpstream = isUpstream; }
|
||||
|
||||
const QUuid& getConnectionSecret() const { return _connectionSecret; }
|
||||
void setConnectionSecret(const QUuid& connectionSecret) { _connectionSecret = connectionSecret; }
|
||||
void setConnectionSecret(const QUuid& connectionSecret);
|
||||
HMACAuth* getAuthenticateHash() const { return _authenticateHash.get(); }
|
||||
|
||||
NodeData* getLinkedData() const { return _linkedData.get(); }
|
||||
void setLinkedData(std::unique_ptr<NodeData> linkedData) { _linkedData = std::move(linkedData); }
|
||||
|
@ -97,6 +99,7 @@ private:
|
|||
NodeType_t _type;
|
||||
|
||||
QUuid _connectionSecret;
|
||||
std::unique_ptr<HMACAuth> _authenticateHash { nullptr };
|
||||
std::unique_ptr<NodeData> _linkedData;
|
||||
bool _isReplicated { false };
|
||||
int _pingMs;
|
||||
|
|
|
@ -594,6 +594,8 @@ void NodeList::processDomainServerConnectionTokenPacket(QSharedPointer<ReceivedM
|
|||
}
|
||||
// read in the connection token from the packet, then send domain-server checkin
|
||||
_domainHandler.setConnectionToken(QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)));
|
||||
|
||||
_domainHandler.clearPendingCheckins();
|
||||
sendDomainServerCheckIn();
|
||||
}
|
||||
|
||||
|
@ -605,7 +607,7 @@ void NodeList::processDomainServerList(QSharedPointer<ReceivedMessage> message)
|
|||
}
|
||||
|
||||
// this is a packet from the domain server, reset the count of un-replied check-ins
|
||||
_domainHandler.domainListReceived();
|
||||
_domainHandler.clearPendingCheckins();
|
||||
|
||||
// emit our signal so listeners know we just heard from the DS
|
||||
emit receivedDomainServerList();
|
||||
|
|
|
@ -92,7 +92,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::AvatarQuery:
|
||||
return static_cast<PacketVersion>(AvatarQueryVersion::ConicalFrustums);
|
||||
default:
|
||||
return 20;
|
||||
return 21;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ const int OctreeEditPacketSender::DEFAULT_MAX_PENDING_MESSAGES = PacketSender::D
|
|||
|
||||
|
||||
OctreeEditPacketSender::OctreeEditPacketSender() :
|
||||
_shouldSend(true),
|
||||
_maxPendingMessages(DEFAULT_MAX_PENDING_MESSAGES),
|
||||
_releaseQueuedMessagesPending(false)
|
||||
{
|
||||
|
@ -146,10 +145,6 @@ void OctreeEditPacketSender::queuePendingPacketToNodes(std::unique_ptr<NLPacket>
|
|||
}
|
||||
|
||||
void OctreeEditPacketSender::queuePacketToNodes(std::unique_ptr<NLPacket> packet) {
|
||||
if (!_shouldSend) {
|
||||
return; // bail early
|
||||
}
|
||||
|
||||
assert(serversExist()); // we must have servers to be here!!
|
||||
|
||||
auto node = DependencyManager::get<NodeList>()->soloNodeOfType(getMyNodeType());
|
||||
|
@ -162,10 +157,6 @@ void OctreeEditPacketSender::queuePacketToNodes(std::unique_ptr<NLPacket> packet
|
|||
// NOTE: editMessage - is JUST the octcode/color and does not contain the packet header
|
||||
void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, QByteArray& editMessage) {
|
||||
|
||||
if (!_shouldSend) {
|
||||
return; // bail early
|
||||
}
|
||||
|
||||
// If we don't have servers, then we will simply queue up all of these packets and wait till we have
|
||||
// servers for processing
|
||||
if (!serversExist()) {
|
||||
|
|
|
@ -41,12 +41,10 @@ public:
|
|||
|
||||
/// are we in sending mode. If we're not in sending mode then all packets and messages will be ignored and
|
||||
/// not queued and not sent
|
||||
bool getShouldSend() const { return _shouldSend; }
|
||||
|
||||
/// set sending mode. By default we are set to shouldSend=TRUE and packets will be sent. If shouldSend=FALSE, then we'll
|
||||
/// switch to not sending mode, and all packets and messages will be ignored, not queued, and not sent. This might be used
|
||||
/// in an application like interface when all octree features are disabled.
|
||||
void setShouldSend(bool shouldSend) { _shouldSend = shouldSend; }
|
||||
|
||||
/// if you're running in non-threaded mode, you must call this method regularly
|
||||
virtual bool process() override;
|
||||
|
@ -76,7 +74,6 @@ public slots:
|
|||
protected:
|
||||
using EditMessagePair = std::pair<PacketType, QByteArray>;
|
||||
|
||||
bool _shouldSend;
|
||||
void queuePacketToNode(const QUuid& nodeID, std::unique_ptr<NLPacket> packet);
|
||||
void queuePacketListToNode(const QUuid& nodeUUID, std::unique_ptr<NLPacketList> packetList);
|
||||
|
||||
|
|
|
@ -349,7 +349,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
|||
|
||||
if (_numInactiveUpdates > 0) {
|
||||
const uint8_t MAX_NUM_INACTIVE_UPDATES = 20;
|
||||
if (_numInactiveUpdates > MAX_NUM_INACTIVE_UPDATES) {
|
||||
if (_numInactiveUpdates > MAX_NUM_INACTIVE_UPDATES || isServerlessMode()) {
|
||||
// clear local ownership (stop sending updates) and let the server clear itself
|
||||
_entity->clearSimulationOwnership();
|
||||
return false;
|
||||
|
@ -731,7 +731,9 @@ void EntityMotionState::measureBodyAcceleration() {
|
|||
// hence the equation for acceleration is: a = (v1 / (1 - D)^dt - v0) / dt
|
||||
glm::vec3 velocity = getBodyLinearVelocityGTSigma();
|
||||
|
||||
_measuredAcceleration = (velocity / powf(1.0f - _body->getLinearDamping(), dt) - _lastVelocity) * invDt;
|
||||
const float MIN_DAMPING_FACTOR = 0.01f;
|
||||
float invDampingAttenuationFactor = 1.0f / glm::max(powf(1.0f - _body->getLinearDamping(), dt), MIN_DAMPING_FACTOR);
|
||||
_measuredAcceleration = (velocity * invDampingAttenuationFactor - _lastVelocity) * invDt;
|
||||
_lastVelocity = velocity;
|
||||
if (numSubsteps > PHYSICS_ENGINE_MAX_NUM_SUBSTEPS) {
|
||||
// we fall in here when _lastMeasureStep is old: the body has just become active
|
||||
|
@ -833,3 +835,9 @@ void EntityMotionState::clearObjectVelocities() const {
|
|||
}
|
||||
_entity->setAcceleration(glm::vec3(0.0f));
|
||||
}
|
||||
|
||||
bool EntityMotionState::isServerlessMode() {
|
||||
EntityTreeElementPointer element = _entity->getElement();
|
||||
EntityTreePointer tree = element ? element->getTree() : nullptr;
|
||||
return tree ? tree->isServerlessMode() : false;
|
||||
}
|
||||
|
|
|
@ -156,6 +156,8 @@ protected:
|
|||
uint8_t _numInactiveUpdates { 1 };
|
||||
uint8_t _bidPriority { 0 };
|
||||
bool _serverVariablesSet { false };
|
||||
|
||||
bool isServerlessMode();
|
||||
};
|
||||
|
||||
#endif // hifi_EntityMotionState_h
|
||||
|
|
|
@ -397,7 +397,7 @@ void ObjectActionTractor::deserialize(QByteArray serializedArguments) {
|
|||
|
||||
EntityDynamicType type;
|
||||
dataStream >> type;
|
||||
assert(type == getType());
|
||||
assert(type == getType() || type == DYNAMIC_TYPE_SPRING);
|
||||
|
||||
QUuid id;
|
||||
dataStream >> id;
|
||||
|
|
|
@ -328,10 +328,18 @@ void PhysicalEntitySimulation::handleChangedMotionStates(const VectorOfMotionSta
|
|||
}
|
||||
|
||||
void PhysicalEntitySimulation::addOwnershipBid(EntityMotionState* motionState) {
|
||||
motionState->initForBid();
|
||||
motionState->sendBid(_entityPacketSender, _physicsEngine->getNumSubsteps());
|
||||
_bids.push_back(motionState);
|
||||
_nextBidExpiry = glm::min(_nextBidExpiry, motionState->getNextBidExpiry());
|
||||
if (getEntityTree()->isServerlessMode()) {
|
||||
EntityItemPointer entity = motionState->getEntity();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
auto sessionID = nodeList->getSessionUUID();
|
||||
entity->setSimulationOwner(SimulationOwner(sessionID, SCRIPT_GRAB_SIMULATION_PRIORITY));
|
||||
_owned.push_back(motionState);
|
||||
} else {
|
||||
motionState->initForBid();
|
||||
motionState->sendBid(_entityPacketSender, _physicsEngine->getNumSubsteps());
|
||||
_bids.push_back(motionState);
|
||||
_nextBidExpiry = glm::min(_nextBidExpiry, motionState->getNextBidExpiry());
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalEntitySimulation::addOwnership(EntityMotionState* motionState) {
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include <SharedUtil.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
#include <NetworkingConstants.h>
|
||||
#include "ProceduralCommon_frag.h"
|
||||
|
||||
#include "Logging.h"
|
||||
|
@ -178,6 +178,8 @@ void Procedural::setProceduralData(const ProceduralData& proceduralData) {
|
|||
return;
|
||||
}
|
||||
_shaderPath = shaderUrl.toLocalFile();
|
||||
} else if (shaderUrl.scheme() == URL_SCHEME_QRC) {
|
||||
_shaderPath = ":" + shaderUrl.path();
|
||||
} else {
|
||||
_networkShader = ShaderCache::instance().getShader(shaderUrl);
|
||||
}
|
||||
|
@ -270,18 +272,24 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm
|
|||
// Leave this here for debugging
|
||||
// qCDebug(procedural) << "FragmentShader:\n" << fragmentShaderSource.c_str();
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel0"), 0));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel1"), 1));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel2"), 2));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel3"), 3));
|
||||
|
||||
_opaqueFragmentShader = gpu::Shader::createPixel(opaqueShaderSource);
|
||||
_opaqueShader = gpu::Shader::createProgram(_vertexShader, _opaqueFragmentShader);
|
||||
_transparentFragmentShader = gpu::Shader::createPixel(transparentShaderSource);
|
||||
_transparentShader = gpu::Shader::createProgram(_vertexShader, _transparentFragmentShader);
|
||||
gpu::Shader::makeProgram(*_opaqueShader, slotBindings);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel0"), 0));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel1"), 1));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel2"), 2));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel3"), 3));
|
||||
gpu::Shader::makeProgram(*_opaqueShader, slotBindings);
|
||||
gpu::Shader::makeProgram(*_transparentShader, slotBindings);
|
||||
if (!transparentShaderSource.empty() && transparentShaderSource != opaqueShaderSource) {
|
||||
_transparentFragmentShader = gpu::Shader::createPixel(transparentShaderSource);
|
||||
_transparentShader = gpu::Shader::createProgram(_vertexShader, _transparentFragmentShader);
|
||||
gpu::Shader::makeProgram(*_transparentShader, slotBindings);
|
||||
} else {
|
||||
_transparentFragmentShader = _opaqueFragmentShader;
|
||||
_transparentShader = _opaqueShader;
|
||||
}
|
||||
|
||||
_opaquePipeline = gpu::Pipeline::create(_opaqueShader, _opaqueState);
|
||||
_transparentPipeline = gpu::Pipeline::create(_transparentShader, _transparentState);
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_Controllers_Logging_h
|
||||
#define hifi_Controllers_Logging_h
|
||||
#ifndef hifi_QML_Logging_h
|
||||
#define hifi_QML_Logging_h
|
||||
|
||||
#include <QLoggingCategory>
|
||||
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
<@func declareLightingModel()@>
|
||||
|
||||
struct LightingModel {
|
||||
PRECISIONQ vec4 _UnlitEmissiveLightmapBackground;
|
||||
PRECISIONQ vec4 _ScatteringDiffuseSpecularAlbedo;
|
||||
PRECISIONQ vec4 _AmbientDirectionalPointSpot;
|
||||
PRECISIONQ vec4 _ShowContourObscuranceWireframe;
|
||||
vec4 _UnlitEmissiveLightmapBackground;
|
||||
vec4 _ScatteringDiffuseSpecularAlbedo;
|
||||
vec4 _AmbientDirectionalPointSpot;
|
||||
vec4 _ShowContourObscuranceWireframe;
|
||||
};
|
||||
|
||||
uniform lightingModelBuffer{
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
#include <render/ShapePipeline.h>
|
||||
|
||||
#include <render/FilterTask.h>
|
||||
|
||||
#include "StencilMaskPass.h"
|
||||
#include "ZoneRenderer.h"
|
||||
#include "FadeEffect.h"
|
||||
|
@ -53,8 +55,9 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
|
|||
const auto& transparents = items.get0()[RenderFetchCullSortTask::TRANSPARENT_SHAPE];
|
||||
// const auto& lights = items.get0()[RenderFetchCullSortTask::LIGHT];
|
||||
const auto& metas = items.get0()[RenderFetchCullSortTask::META];
|
||||
// const auto& overlayOpaques = items.get0()[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE];
|
||||
// const auto& overlayTransparents = items.get0()[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE];
|
||||
const auto& overlayOpaques = items.get0()[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE];
|
||||
const auto& overlayTransparents = items.get0()[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE];
|
||||
|
||||
//const auto& background = items.get0()[RenderFetchCullSortTask::BACKGROUND];
|
||||
// const auto& spatialSelection = items[1];
|
||||
|
||||
|
@ -75,6 +78,17 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
|
|||
// draw a stencil mask in hidden regions of the framebuffer.
|
||||
task.addJob<PrepareStencil>("PrepareStencil", framebuffer);
|
||||
|
||||
// Layered Overlays
|
||||
const auto filteredOverlaysOpaque = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredOpaque", overlayOpaques, Item::LAYER_3D_FRONT);
|
||||
const auto filteredOverlaysTransparent = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredTransparent", overlayTransparents, Item::LAYER_3D_FRONT);
|
||||
const auto overlaysInFrontOpaque = filteredOverlaysOpaque.getN<FilterLayeredItems::Outputs>(0);
|
||||
const auto overlaysInFrontTransparent = filteredOverlaysTransparent.getN<FilterLayeredItems::Outputs>(0);
|
||||
|
||||
const auto overlayInFrontOpaquesInputs = DrawOverlay3D::Inputs(overlaysInFrontOpaque, lightingModel, nullptr).asVarying();
|
||||
const auto overlayInFrontTransparentsInputs = DrawOverlay3D::Inputs(overlaysInFrontTransparent, lightingModel, nullptr).asVarying();
|
||||
task.addJob<DrawOverlay3D>("DrawOverlayInFrontOpaque", overlayInFrontOpaquesInputs, true);
|
||||
task.addJob<DrawOverlay3D>("DrawOverlayInFrontTransparent", overlayInFrontTransparentsInputs, false);
|
||||
|
||||
// Draw opaques forward
|
||||
const auto opaqueInputs = DrawForward::Inputs(opaques, lightingModel).asVarying();
|
||||
task.addJob<DrawForward>("DrawOpaques", opaqueInputs, shapePlumber);
|
||||
|
|
|
@ -149,9 +149,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con
|
|||
batch.setStateScissorRect(viewport);
|
||||
|
||||
batch.setFramebuffer(fbo);
|
||||
batch.clearFramebuffer(
|
||||
gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH,
|
||||
vec4(vec3(1.0, 1.0, 1.0), 0.0), 1.0, 0, true);
|
||||
batch.clearDepthFramebuffer(1.0, false);
|
||||
|
||||
glm::mat4 projMat;
|
||||
Transform viewMat;
|
||||
|
@ -232,12 +230,11 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
|
|||
const auto queryResolution = setupOutput.getN<RenderShadowSetup::Outputs>(2);
|
||||
// Fetch and cull the items from the scene
|
||||
|
||||
// Enable models to not cast shadows (otherwise, models will always cast shadows)
|
||||
static const auto shadowCasterFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(tagBits, tagMask).withShadowCaster();
|
||||
static const auto shadowCasterReceiverFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(tagBits, tagMask);
|
||||
|
||||
const auto fetchInput = FetchSpatialTree::Inputs(shadowCasterFilter, queryResolution).asVarying();
|
||||
const auto fetchInput = FetchSpatialTree::Inputs(shadowCasterReceiverFilter, queryResolution).asVarying();
|
||||
const auto shadowSelection = task.addJob<FetchSpatialTree>("FetchShadowTree", fetchInput);
|
||||
const auto selectionInputs = FetchSpatialSelection::Inputs(shadowSelection, shadowCasterFilter).asVarying();
|
||||
const auto selectionInputs = FetchSpatialSelection::Inputs(shadowSelection, shadowCasterReceiverFilter).asVarying();
|
||||
const auto shadowItems = task.addJob<FetchSpatialSelection>("FetchShadowSelection", selectionInputs);
|
||||
|
||||
// Cull objects that are not visible in camera view. Hopefully the cull functor only performs LOD culling, not
|
||||
|
@ -261,21 +258,22 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
|
|||
char jobName[64];
|
||||
sprintf(jobName, "ShadowCascadeSetup%d", i);
|
||||
const auto cascadeSetupOutput = task.addJob<RenderShadowCascadeSetup>(jobName, i, _cullFunctor, tagBits, tagMask);
|
||||
const auto shadowFilter = cascadeSetupOutput.getN<RenderShadowCascadeSetup::Outputs>(0);
|
||||
const auto shadowRenderFilter = cascadeSetupOutput.getN<RenderShadowCascadeSetup::Outputs>(0);
|
||||
const auto shadowBoundsFilter = cascadeSetupOutput.getN<RenderShadowCascadeSetup::Outputs>(1);
|
||||
auto antiFrustum = render::Varying(ViewFrustumPointer());
|
||||
cascadeFrustums[i] = cascadeSetupOutput.getN<RenderShadowCascadeSetup::Outputs>(1);
|
||||
cascadeFrustums[i] = cascadeSetupOutput.getN<RenderShadowCascadeSetup::Outputs>(2);
|
||||
if (i > 1) {
|
||||
antiFrustum = cascadeFrustums[i - 2];
|
||||
}
|
||||
|
||||
// CPU jobs: finer grained culling
|
||||
const auto cullInputs = CullShapeBounds::Inputs(sortedShapes, shadowFilter, antiFrustum).asVarying();
|
||||
const auto cullInputs = CullShapeBounds::Inputs(sortedShapes, shadowRenderFilter, shadowBoundsFilter, antiFrustum).asVarying();
|
||||
const auto culledShadowItemsAndBounds = task.addJob<CullShapeBounds>("CullShadowCascade", cullInputs, shadowCullFunctor, RenderDetails::SHADOW);
|
||||
|
||||
// GPU jobs: Render to shadow map
|
||||
sprintf(jobName, "RenderShadowMap%d", i);
|
||||
task.addJob<RenderShadowMap>(jobName, culledShadowItemsAndBounds, shapePlumber, i);
|
||||
task.addJob<RenderShadowCascadeTeardown>("ShadowCascadeTeardown", shadowFilter);
|
||||
task.addJob<RenderShadowCascadeTeardown>("ShadowCascadeTeardown", shadowRenderFilter);
|
||||
}
|
||||
|
||||
task.addJob<RenderShadowTeardown>("ShadowTeardown", setupOutput);
|
||||
|
@ -406,7 +404,11 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon
|
|||
|
||||
const auto globalShadow = lightStage->getCurrentKeyShadow();
|
||||
if (globalShadow && _cascadeIndex<globalShadow->getCascadeCount()) {
|
||||
output.edit0() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(_tagBits, _tagMask).withShadowCaster();
|
||||
auto baseFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(_tagBits, _tagMask);
|
||||
// Second item filter is to filter items to keep in shadow frustum computation (here we need to keep shadow receivers)
|
||||
output.edit1() = baseFilter;
|
||||
// First item filter is to filter items to render in shadow map (so only keep casters)
|
||||
output.edit0() = baseFilter.withShadowCaster();
|
||||
|
||||
// Set the keylight render args
|
||||
auto& cascade = globalShadow->getCascade(_cascadeIndex);
|
||||
|
@ -419,10 +421,11 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon
|
|||
texelSize *= minTexelCount;
|
||||
_cullFunctor._minSquareSize = texelSize * texelSize;
|
||||
|
||||
output.edit1() = cascadeFrustum;
|
||||
output.edit2() = cascadeFrustum;
|
||||
} else {
|
||||
output.edit0() = ItemFilter::Builder::nothing();
|
||||
output.edit1() = ViewFrustumPointer();
|
||||
output.edit1() = ItemFilter::Builder::nothing();
|
||||
output.edit2() = ViewFrustumPointer();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ private:
|
|||
|
||||
class RenderShadowCascadeSetup {
|
||||
public:
|
||||
using Outputs = render::VaryingSet2<render::ItemFilter, ViewFrustumPointer>;
|
||||
using Outputs = render::VaryingSet3<render::ItemFilter, render::ItemFilter, ViewFrustumPointer>;
|
||||
using JobModel = render::Job::ModelO<RenderShadowCascadeSetup, Outputs>;
|
||||
|
||||
RenderShadowCascadeSetup(unsigned int cascadeIndex, RenderShadowTask::CullFunctor& cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00) :
|
||||
|
|
|
@ -368,17 +368,19 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input
|
|||
RenderArgs* args = renderContext->args;
|
||||
|
||||
const auto& inShapes = inputs.get0();
|
||||
const auto& filter = inputs.get1();
|
||||
const auto& antiFrustum = inputs.get2();
|
||||
const auto& cullFilter = inputs.get1();
|
||||
const auto& boundsFilter = inputs.get2();
|
||||
const auto& antiFrustum = inputs.get3();
|
||||
auto& outShapes = outputs.edit0();
|
||||
auto& outBounds = outputs.edit1();
|
||||
|
||||
outShapes.clear();
|
||||
outBounds = AABox();
|
||||
|
||||
if (!filter.selectsNothing()) {
|
||||
if (!cullFilter.selectsNothing() || !boundsFilter.selectsNothing()) {
|
||||
auto& details = args->_details.edit(_detailType);
|
||||
Test test(_cullFunctor, args, details, antiFrustum);
|
||||
auto scene = args->_scene;
|
||||
|
||||
for (auto& inItems : inShapes) {
|
||||
auto key = inItems.first;
|
||||
|
@ -393,16 +395,26 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input
|
|||
if (antiFrustum == nullptr) {
|
||||
for (auto& item : inItems.second) {
|
||||
if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound)) {
|
||||
outItems->second.emplace_back(item);
|
||||
outBounds += item.bound;
|
||||
const auto shapeKey = scene->getItem(item.id).getKey();
|
||||
if (cullFilter.test(shapeKey)) {
|
||||
outItems->second.emplace_back(item);
|
||||
}
|
||||
if (boundsFilter.test(shapeKey)) {
|
||||
outBounds += item.bound;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto& item : inItems.second) {
|
||||
if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound) && test.antiFrustumTest(item.bound)) {
|
||||
outItems->second.emplace_back(item);
|
||||
outBounds += item.bound;
|
||||
}
|
||||
const auto shapeKey = scene->getItem(item.id).getKey();
|
||||
if (cullFilter.test(shapeKey)) {
|
||||
outItems->second.emplace_back(item);
|
||||
}
|
||||
if (boundsFilter.test(shapeKey)) {
|
||||
outBounds += item.bound;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
details._rendered += (int)outItems->second.size();
|
||||
|
|
|
@ -110,7 +110,7 @@ namespace render {
|
|||
|
||||
class CullShapeBounds {
|
||||
public:
|
||||
using Inputs = render::VaryingSet3<ShapeBounds, ItemFilter, ViewFrustumPointer>;
|
||||
using Inputs = render::VaryingSet4<ShapeBounds, ItemFilter, ItemFilter, ViewFrustumPointer>;
|
||||
using Outputs = render::VaryingSet2<ShapeBounds, AABox>;
|
||||
using JobModel = Job::ModelIO<CullShapeBounds, Inputs, Outputs>;
|
||||
|
||||
|
|
|
@ -186,36 +186,36 @@ public:
|
|||
|
||||
/**jsdoc
|
||||
* @function Assets.deleteAsset
|
||||
* @property {} options
|
||||
* @property {} scope
|
||||
* @property {} [callback = ""]
|
||||
* @param {} options
|
||||
* @param {} scope
|
||||
* @param {} [callback = ""]
|
||||
*/
|
||||
|
||||
Q_INVOKABLE void deleteAsset(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue());
|
||||
|
||||
/**jsdoc
|
||||
* @function Assets.resolveAsset
|
||||
* @property {} options
|
||||
* @property {} scope
|
||||
* @property {} [callback = ""]
|
||||
* @param {} options
|
||||
* @param {} scope
|
||||
* @param {} [callback = ""]
|
||||
*/
|
||||
|
||||
Q_INVOKABLE void resolveAsset(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue());
|
||||
|
||||
/**jsdoc
|
||||
* @function Assets.decompressData
|
||||
* @property {} options
|
||||
* @property {} scope
|
||||
* @property {} [callback = ""]
|
||||
* @param {} options
|
||||
* @param {} scope
|
||||
* @param {} [callback = ""]
|
||||
*/
|
||||
|
||||
Q_INVOKABLE void decompressData(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue());
|
||||
|
||||
/**jsdoc
|
||||
* @function Assets.compressData
|
||||
* @property {} options
|
||||
* @property {} scope
|
||||
* @property {} [callback = ""]
|
||||
* @param {} options
|
||||
* @param {} scope
|
||||
* @param {} [callback = ""]
|
||||
*/
|
||||
|
||||
Q_INVOKABLE void compressData(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue());
|
||||
|
@ -229,7 +229,7 @@ public:
|
|||
|
||||
/**jsdoc
|
||||
* @function Assets.canWriteCacheValue
|
||||
* @property {string} url
|
||||
* @param {string} url
|
||||
* @returns {boolean}
|
||||
*/
|
||||
|
||||
|
@ -237,8 +237,8 @@ public:
|
|||
|
||||
/**jsdoc
|
||||
* @function Assets.getCacheStatus
|
||||
* @property {} scope
|
||||
* @property {} [callback=undefined]
|
||||
* @param {} scope
|
||||
* @param {} [callback=undefined]
|
||||
*/
|
||||
|
||||
Q_INVOKABLE void getCacheStatus(QScriptValue scope, QScriptValue callback = QScriptValue()) {
|
||||
|
@ -247,38 +247,38 @@ public:
|
|||
|
||||
/**jsdoc
|
||||
* @function Assets.queryCacheMeta
|
||||
* @property {} options
|
||||
* @property {} scope
|
||||
* @property {} [callback=undefined]
|
||||
* @param {} options
|
||||
* @param {} scope
|
||||
* @param {} [callback=undefined]
|
||||
*/
|
||||
|
||||
Q_INVOKABLE void queryCacheMeta(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue());
|
||||
|
||||
/**jsdoc
|
||||
* @function Assets.loadFromCache
|
||||
* @property {} options
|
||||
* @property {} scope
|
||||
* @property {} [callback=undefined]
|
||||
* @param {} options
|
||||
* @param {} scope
|
||||
* @param {} [callback=undefined]
|
||||
*/
|
||||
|
||||
Q_INVOKABLE void loadFromCache(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue());
|
||||
|
||||
/**jsdoc
|
||||
* @function Assets.saveToCache
|
||||
* @property {} options
|
||||
* @property {} scope
|
||||
* @property {} [callback=undefined]
|
||||
* @param {} options
|
||||
* @param {} scope
|
||||
* @param {} [callback=undefined]
|
||||
*/
|
||||
|
||||
Q_INVOKABLE void saveToCache(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue());
|
||||
|
||||
/**jsdoc
|
||||
* @function Assets.saveToCache
|
||||
* @property {} url
|
||||
* @property {} data
|
||||
* @property {} metadata
|
||||
* @property {} scope
|
||||
* @property {} [callback=undefined]
|
||||
* @param {} url
|
||||
* @param {} data
|
||||
* @param {} metadata
|
||||
* @param {} scope
|
||||
* @param {} [callback=undefined]
|
||||
*/
|
||||
|
||||
Q_INVOKABLE void saveToCache(const QUrl& url, const QByteArray& data, const QVariantMap& metadata,
|
||||
|
|
|
@ -101,8 +101,6 @@ int functionSignatureMetaID = qRegisterMetaType<QScriptEngine::FunctionSignature
|
|||
|
||||
int scriptEnginePointerMetaID = qRegisterMetaType<ScriptEnginePointer>();
|
||||
|
||||
Q_LOGGING_CATEGORY(scriptengineScript, "hifi.scriptengine.script")
|
||||
|
||||
static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) {
|
||||
QString message = "";
|
||||
for (int i = 0; i < context->argumentCount(); i++) {
|
||||
|
@ -115,9 +113,9 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) {
|
|||
if (ScriptEngine *scriptEngine = qobject_cast<ScriptEngine*>(engine)) {
|
||||
scriptEngine->print(message);
|
||||
// prefix the script engine name to help disambiguate messages in the main debug log
|
||||
qCDebug(scriptengineScript, "[%s] %s", qUtf8Printable(scriptEngine->getFilename()), qUtf8Printable(message));
|
||||
qCDebug(scriptengine_script, "[%s] %s", qUtf8Printable(scriptEngine->getFilename()), qUtf8Printable(message));
|
||||
} else {
|
||||
qCDebug(scriptengineScript, "%s", qUtf8Printable(message));
|
||||
qCDebug(scriptengine_script, "%s", qUtf8Printable(message));
|
||||
}
|
||||
|
||||
return QScriptValue();
|
||||
|
|
|
@ -526,6 +526,9 @@ public:
|
|||
void setUserLoaded(bool isUserLoaded) { _isUserLoaded = isUserLoaded; }
|
||||
bool isUserLoaded() const { return _isUserLoaded; }
|
||||
|
||||
void setQuitWhenFinished(const bool quitWhenFinished) { _quitWhenFinished = quitWhenFinished; }
|
||||
bool isQuitWhenFinished() const { return _quitWhenFinished; }
|
||||
|
||||
// NOTE - this is used by the TypedArray implementation. we need to review this for thread safety
|
||||
ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; }
|
||||
|
||||
|
@ -768,6 +771,8 @@ protected:
|
|||
std::atomic<bool> _isUserLoaded { false };
|
||||
bool _isReloading { false };
|
||||
|
||||
std::atomic<bool> _quitWhenFinished;
|
||||
|
||||
ArrayBufferClass* _arrayBufferClass;
|
||||
|
||||
AssetScriptingInterface* _assetScriptingInterface;
|
||||
|
|
|
@ -13,3 +13,4 @@
|
|||
|
||||
Q_LOGGING_CATEGORY(scriptengine, "hifi.scriptengine")
|
||||
Q_LOGGING_CATEGORY(scriptengine_module, "hifi.scriptengine.module")
|
||||
Q_LOGGING_CATEGORY(scriptengine_script, "hifi.scriptengine.script")
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
Q_DECLARE_LOGGING_CATEGORY(scriptengine)
|
||||
Q_DECLARE_LOGGING_CATEGORY(scriptengine_module)
|
||||
Q_DECLARE_LOGGING_CATEGORY(scriptengine_script)
|
||||
|
||||
#endif // hifi_ScriptEngineLogging_h
|
||||
|
||||
|
|
|
@ -347,7 +347,8 @@ void ScriptEngines::saveScripts() {
|
|||
{
|
||||
QReadLocker lock(&_scriptEnginesHashLock);
|
||||
for (auto it = _scriptEnginesHash.begin(); it != _scriptEnginesHash.end(); ++it) {
|
||||
if (it.value() && it.value()->isUserLoaded()) {
|
||||
// Save user-loaded scripts, only if they are set to quit when finished
|
||||
if (it.value() && it.value()->isUserLoaded() && !it.value()->isQuitWhenFinished()) {
|
||||
auto normalizedUrl = normalizeScriptURL(it.key());
|
||||
list.append(normalizedUrl.toString());
|
||||
}
|
||||
|
@ -456,7 +457,7 @@ void ScriptEngines::reloadAllScripts() {
|
|||
}
|
||||
|
||||
ScriptEnginePointer ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor,
|
||||
bool activateMainWindow, bool reload) {
|
||||
bool activateMainWindow, bool reload, bool quitWhenFinished) {
|
||||
if (thread() != QThread::currentThread()) {
|
||||
ScriptEnginePointer result { nullptr };
|
||||
BLOCKING_INVOKE_METHOD(this, "loadScript", Q_RETURN_ARG(ScriptEnginePointer, result),
|
||||
|
@ -488,6 +489,7 @@ ScriptEnginePointer ScriptEngines::loadScript(const QUrl& scriptFilename, bool i
|
|||
scriptEngine = ScriptEnginePointer(new ScriptEngine(_context, NO_SCRIPT, "about:" + scriptFilename.fileName()));
|
||||
addScriptEngine(scriptEngine);
|
||||
scriptEngine->setUserLoaded(isUserLoaded);
|
||||
scriptEngine->setQuitWhenFinished(quitWhenFinished);
|
||||
|
||||
if (scriptFilename.isEmpty() || !scriptUrl.isValid()) {
|
||||
launchScriptEngine(scriptEngine);
|
||||
|
@ -496,6 +498,11 @@ ScriptEnginePointer ScriptEngines::loadScript(const QUrl& scriptFilename, bool i
|
|||
connect(scriptEngine.data(), &ScriptEngine::scriptLoaded, this, &ScriptEngines::onScriptEngineLoaded);
|
||||
connect(scriptEngine.data(), &ScriptEngine::errorLoadingScript, this, &ScriptEngines::onScriptEngineError);
|
||||
|
||||
// Shutdown Interface when script finishes, if requested
|
||||
if (quitWhenFinished) {
|
||||
connect(scriptEngine.data(), &ScriptEngine::finished, this, &ScriptEngines::quitWhenFinished);
|
||||
}
|
||||
|
||||
// get the script engine object to load the script at the designated script URL
|
||||
scriptEngine->loadURL(scriptUrl, reload);
|
||||
}
|
||||
|
@ -536,6 +543,10 @@ void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) {
|
|||
emit scriptCountChanged();
|
||||
}
|
||||
|
||||
void ScriptEngines::quitWhenFinished() {
|
||||
qApp->quit();
|
||||
}
|
||||
|
||||
int ScriptEngines::runScriptInitializers(ScriptEnginePointer scriptEngine) {
|
||||
int ii=0;
|
||||
for (auto initializer : _scriptInitializers) {
|
||||
|
|
|
@ -88,10 +88,11 @@ public:
|
|||
* @param {boolean} [loadScriptFromEditor=false]
|
||||
* @param {boolean} [activateMainWindow=false]
|
||||
* @param {boolean} [reload=false]
|
||||
* @param {boolean} [quitWhenFinished=false]
|
||||
* @returns {boolean}
|
||||
*/
|
||||
Q_INVOKABLE ScriptEnginePointer loadScript(const QUrl& scriptFilename = QString(),
|
||||
bool isUserLoaded = true, bool loadScriptFromEditor = false, bool activateMainWindow = false, bool reload = false);
|
||||
bool isUserLoaded = true, bool loadScriptFromEditor = false, bool activateMainWindow = false, bool reload = false, bool quitWhenFinished = false);
|
||||
|
||||
/**jsdoc
|
||||
* @function ScriptDiscoveryService.stopScript
|
||||
|
@ -266,6 +267,7 @@ protected:
|
|||
ScriptEnginePointer reloadScript(const QString& scriptName, bool isUserLoaded = true) { return loadScript(scriptName, isUserLoaded, false, false, true); }
|
||||
void removeScriptEngine(ScriptEnginePointer);
|
||||
void onScriptEngineLoaded(const QString& scriptFilename);
|
||||
void quitWhenFinished();
|
||||
void onScriptEngineError(const QString& scriptFilename);
|
||||
void launchScriptEngine(ScriptEnginePointer);
|
||||
|
||||
|
|
|
@ -106,10 +106,11 @@ public slots:
|
|||
void mute(const QUuid& nodeID);
|
||||
|
||||
/**jsdoc
|
||||
* Get the user name and machine fingerprint associated with the given UUID. This will only do anything if you're an admin
|
||||
* of the domain you're in.
|
||||
* @function Users.getUsernameFromID
|
||||
* @param {Uuid} nodeID The node or session ID of the user whose username you want.
|
||||
* Request the user name and machine fingerprint associated with the given UUID. The user name will be returned in a
|
||||
* {@link Users.usernameFromIDReply|usernameFromIDReply} signal. This will only do anything if you're an admin of the domain
|
||||
* you're in.
|
||||
* @function Users.requestUsernameFromID
|
||||
* @param {Uuid} nodeID The node or session ID of the user whose user name you want.
|
||||
*/
|
||||
void requestUsernameFromID(const QUuid& nodeID);
|
||||
|
||||
|
@ -170,7 +171,8 @@ signals:
|
|||
void enteredIgnoreRadius();
|
||||
|
||||
/**jsdoc
|
||||
* Notifies scripts of the user name and machine fingerprint associated with a UUID.
|
||||
* Triggered in response to a {@link Users.requestUsernameFromID|requestUsernameFromID} call. Provides the user name and
|
||||
* machine fingerprint associated with a UUID.
|
||||
* Username and machineFingerprint will be their default constructor output if the requesting user isn't an admin.
|
||||
* @function Users.usernameFromIDReply
|
||||
* @param {Uuid} nodeID
|
||||
|
|
3
libraries/test-utils/CMakeLists.txt
Normal file
3
libraries/test-utils/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
set(TARGET_NAME test-utils)
|
||||
setup_hifi_library(Network Gui)
|
||||
|
21
libraries/test-utils/src/test-utils/FileDownloader.cpp
Normal file
21
libraries/test-utils/src/test-utils/FileDownloader.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include "FileDownloader.h"
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
FileDownloader::FileDownloader(QUrl url, const Handler& handler, QObject* parent) : QObject(parent), _handler(handler) {
|
||||
connect(&_accessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(fileDownloaded(QNetworkReply*)));
|
||||
_accessManager.get(QNetworkRequest(url));
|
||||
}
|
||||
|
||||
void FileDownloader::waitForDownload() {
|
||||
while (!_complete) {
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
}
|
||||
|
||||
void FileDownloader::fileDownloaded(QNetworkReply* pReply) {
|
||||
_handler(pReply->readAll());
|
||||
pReply->deleteLater();
|
||||
_complete = true;
|
||||
}
|
23
libraries/test-utils/src/test-utils/FileDownloader.h
Normal file
23
libraries/test-utils/src/test-utils/FileDownloader.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
|
||||
class FileDownloader : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using Handler = std::function<void(const QByteArray& data)>;
|
||||
|
||||
FileDownloader(QUrl url, const Handler& handler, QObject* parent = 0);
|
||||
|
||||
void waitForDownload();
|
||||
|
||||
private slots:
|
||||
void fileDownloaded(QNetworkReply* pReply);
|
||||
|
||||
private:
|
||||
QNetworkAccessManager _accessManager;
|
||||
Handler _handler;
|
||||
bool _complete { false };
|
||||
};
|
|
@ -54,6 +54,12 @@ public:
|
|||
void setFullscreen(const QScreen* targetScreen, bool hideMenu = false);
|
||||
void unsetFullscreen(const QScreen* avoidScreen = nullptr);
|
||||
|
||||
// FIXME remove access tot he menu from the plugin container
|
||||
// Instead let display plugins expose a structure about the kinds
|
||||
// of actions and menu items they want to have appear when they are
|
||||
// active and allow the application to act on that when the display
|
||||
// plugin becomes active (or when the UI is initialized, and a
|
||||
// display plugin is already active)
|
||||
virtual ui::Menu* getPrimaryMenu() = 0;
|
||||
virtual void showDisplayPluginsTools(bool show = true) = 0;
|
||||
virtual void requestReset() = 0;
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace VirtualPad {
|
|||
|
||||
private:
|
||||
Instance _leftVPadInstance;
|
||||
bool _enabled;
|
||||
bool _enabled {true};
|
||||
bool _hidden;
|
||||
glm::vec2 _jumpButtonPosition;
|
||||
int _extraBottomMargin {0};
|
||||
|
|
|
@ -166,12 +166,11 @@ void OculusBaseDisplayPlugin::deactivateSession() {
|
|||
//_session = nullptr;
|
||||
}
|
||||
void OculusBaseDisplayPlugin::updatePresentPose() {
|
||||
//mat4 sensorResetMat;
|
||||
//_currentPresentFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds();
|
||||
//_currentPresentFrameInfo.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, _currentFrame->frameIndex);
|
||||
//auto trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrFalse);
|
||||
//_currentPresentFrameInfo.presentPose = toGlm(trackingState.HeadPose.ThePose);
|
||||
_currentPresentFrameInfo.presentPose = _currentPresentFrameInfo.renderPose;
|
||||
_currentPresentFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds();
|
||||
_currentPresentFrameInfo.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, 0);
|
||||
auto trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrFalse);
|
||||
_currentPresentFrameInfo.presentPose = toGlm(trackingState.HeadPose.ThePose);
|
||||
_currentPresentFrameInfo.renderPose = _currentPresentFrameInfo.presentPose;
|
||||
}
|
||||
|
||||
OculusBaseDisplayPlugin::~OculusBaseDisplayPlugin() {
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
|
||||
Q_DECLARE_LOGGING_CATEGORY(displayplugins)
|
||||
|
||||
const char* StandingHMDSensorMode { "Standing HMD Sensor Mode" }; // this probably shouldn't be hardcoded here
|
||||
const char* OpenVrThreadedSubmit { "OpenVR Threaded Submit" }; // this probably shouldn't be hardcoded here
|
||||
|
||||
PoseData _nextRenderPoseData;
|
||||
|
@ -451,7 +450,6 @@ bool OpenVrDisplayPlugin::internalActivate() {
|
|||
qDebug() << "OpenVR Threaded submit enabled: " << _threadedSubmit;
|
||||
|
||||
_openVrDisplayActive = true;
|
||||
_container->setIsOptionChecked(StandingHMDSensorMode, true);
|
||||
_system->GetRecommendedRenderTargetSize(&_renderTargetSize.x, &_renderTargetSize.y);
|
||||
// Recommended render target size is per-eye, so double the X size for
|
||||
// left + right eyes
|
||||
|
@ -507,7 +505,6 @@ void OpenVrDisplayPlugin::internalDeactivate() {
|
|||
Parent::internalDeactivate();
|
||||
|
||||
_openVrDisplayActive = false;
|
||||
_container->setIsOptionChecked(StandingHMDSensorMode, false);
|
||||
if (_system) {
|
||||
// TODO: Invalidate poses. It's fine if someone else sets these shared values, but we're about to stop updating them, and
|
||||
// we don't want ViveControllerManager to consider old values to be valid.
|
||||
|
|
167
scripts/system/+android/displayNames.js
Normal file
167
scripts/system/+android/displayNames.js
Normal file
|
@ -0,0 +1,167 @@
|
|||
"use strict";
|
||||
//
|
||||
// displayNames.js
|
||||
// scripts/system/
|
||||
//
|
||||
// Created by Cristian Duarte & Gabriel Calero on May 3, 2018
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
||||
var MAX_DISTANCE_PX = 20; // Should we use dp instead?
|
||||
var UNKNOWN_NAME = "Unknown";
|
||||
var METERS_ABOVE_HEAD = 0.4;
|
||||
|
||||
var TEXT_LINE_HEIGHT = .1;
|
||||
var TEXT_MARGIN = 0.025;
|
||||
|
||||
var HIDE_MS = 10000;
|
||||
|
||||
var currentTouchToAnalyze = null;
|
||||
|
||||
var currentlyShownAvatar = {
|
||||
avatarID: null,
|
||||
avatar: null,
|
||||
overlay: null
|
||||
};
|
||||
|
||||
var logEnabled = false;
|
||||
|
||||
var hideTimer = null;
|
||||
|
||||
function printd(str) {
|
||||
if (logEnabled) {
|
||||
print("[displayNames.js] " + str);
|
||||
}
|
||||
}
|
||||
|
||||
function clearOverlay() {
|
||||
currentlyShownAvatar.avatar = null;
|
||||
if (currentlyShownAvatar.overlay) {
|
||||
Overlays.editOverlay(currentlyShownAvatar.overlay, {visible: false});
|
||||
}
|
||||
}
|
||||
|
||||
function touchedAvatar(avatarID, avatarData) {
|
||||
printd("[AVATARNAME] touchEnd FOUND " + JSON.stringify(avatarData));
|
||||
|
||||
if (hideTimer) {
|
||||
Script.clearTimeout(hideTimer);
|
||||
}
|
||||
|
||||
// Case: touching an already selected avatar
|
||||
if (currentlyShownAvatar.avatar && currentlyShownAvatar.avatarID == avatarID) {
|
||||
clearOverlay();
|
||||
return;
|
||||
}
|
||||
|
||||
// Save currently selected avatar
|
||||
currentlyShownAvatar.avatarID = avatarID;
|
||||
currentlyShownAvatar.avatar = avatarData;
|
||||
|
||||
if (currentlyShownAvatar.overlay == null) {
|
||||
var over = Overlays.addOverlay("text3d", {
|
||||
lineHeight: TEXT_LINE_HEIGHT,
|
||||
color: { red: 255, green: 255, blue: 255},
|
||||
backgroundColor: {red: 0, green: 0, blue: 0},
|
||||
leftMargin: TEXT_MARGIN,
|
||||
topMargin: TEXT_MARGIN,
|
||||
rightMargin: TEXT_MARGIN,
|
||||
bottomMargin: TEXT_MARGIN,
|
||||
alpha: 0.6,
|
||||
solid: true,
|
||||
isFacingAvatar: true,
|
||||
visible: false
|
||||
});
|
||||
currentlyShownAvatar.overlay = over;
|
||||
}
|
||||
|
||||
var nameToShow = avatarData.displayName ? avatarData.displayName :
|
||||
(avatarData.sessionDisplayName ? avatarData.sessionDisplayName : UNKNOWN_NAME);
|
||||
var textSize = Overlays.textSize(currentlyShownAvatar.overlay, nameToShow);
|
||||
|
||||
Overlays.editOverlay(currentlyShownAvatar.overlay, {
|
||||
dimensions: {
|
||||
x: textSize.width + 2 * TEXT_MARGIN,
|
||||
y: TEXT_LINE_HEIGHT + 2 * TEXT_MARGIN
|
||||
},
|
||||
localPosition: { x: 0, y: METERS_ABOVE_HEAD, z: 0 },
|
||||
text: nameToShow,
|
||||
parentID: avatarData.sessionUUID,
|
||||
parentJointIndex: avatarData.getJointIndex("Head"),
|
||||
visible: true
|
||||
});
|
||||
|
||||
hideTimer = Script.setTimeout(function() {
|
||||
clearOverlay();
|
||||
}, HIDE_MS);
|
||||
}
|
||||
|
||||
function touchBegin(event) {
|
||||
currentTouchToAnalyze = event;
|
||||
}
|
||||
|
||||
function touchEnd(event) {
|
||||
if (Vec3.distance({x: event.x, y: event.y }, {x: currentTouchToAnalyze.x, y: currentTouchToAnalyze.y}) > MAX_DISTANCE_PX) {
|
||||
printd("[AVATARNAME] touchEnd moved too much");
|
||||
currentTouchToAnalyze = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var avatarRay = AvatarManager.findRayIntersection(pickRay, [], [MyAvatar.sessionUUID])
|
||||
|
||||
if (avatarRay.intersects) {
|
||||
touchedAvatar(avatarRay.avatarID, AvatarManager.getAvatar(avatarRay.avatarID));
|
||||
} else {
|
||||
printd("[AVATARNAME] touchEnd released outside the avatar");
|
||||
}
|
||||
|
||||
currentTouchToAnalyze = null;
|
||||
}
|
||||
|
||||
var runAtLeastOnce = false;
|
||||
|
||||
function ending() {
|
||||
if (!runAtLeastOnce) {
|
||||
return;
|
||||
}
|
||||
|
||||
Controller.touchBeginEvent.disconnect(touchBegin);
|
||||
Controller.touchEndEvent.disconnect(touchEnd);
|
||||
Controller.mousePressEvent.disconnect(touchBegin);
|
||||
Controller.mouseReleaseEvent.disconnect(touchEnd);
|
||||
|
||||
if (currentlyShownAvatar.overlay) {
|
||||
Overlays.deleteOverlay(currentlyShownAvatar.overlay);
|
||||
currentlyShownAvatar.overlay = null;
|
||||
}
|
||||
if (currentlyShownAvatar.avatar) {
|
||||
currentlyShownAvatar.avatar = null;
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
Controller.touchBeginEvent.connect(touchBegin);
|
||||
Controller.touchEndEvent.connect(touchEnd);
|
||||
Controller.mousePressEvent.connect(touchBegin);
|
||||
Controller.mouseReleaseEvent.connect(touchEnd);
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
ending();
|
||||
});
|
||||
|
||||
runAtLeastOnce = true;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: init,
|
||||
ending: ending
|
||||
}
|
||||
|
||||
//init(); // Enable to use in desktop as a standalone
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
|
@ -28,6 +28,7 @@ modeLabel[MODE_MY_VIEW]="MY VIEW";
|
|||
var logEnabled = false;
|
||||
var radar = Script.require('./radar.js');
|
||||
var uniqueColor = Script.require('./uniqueColor.js');
|
||||
var displayNames = Script.require('./displayNames.js');
|
||||
|
||||
function printd(str) {
|
||||
if (logEnabled) {
|
||||
|
@ -95,8 +96,10 @@ function switchToMode(newMode) {
|
|||
|
||||
if (currentMode == MODE_RADAR) {
|
||||
radar.startRadarMode();
|
||||
displayNames.ending();
|
||||
} else if (currentMode == MODE_MY_VIEW) {
|
||||
// nothing to do yet
|
||||
displayNames.init();
|
||||
} else {
|
||||
printd("Unknown view mode " + currentMode);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ function printd(str) {
|
|||
}
|
||||
|
||||
var radar = false;
|
||||
var radarHeight = 10; // camera position meters above the avatar
|
||||
var RADAR_HEIGHT_INIT_DELTA = 10;
|
||||
var radarHeight = MyAvatar.position.y + RADAR_HEIGHT_INIT_DELTA; // camera position (absolute y)
|
||||
var tablet;
|
||||
|
||||
var RADAR_CAMERA_OFFSET = -1; // 1 meter below the avatar
|
||||
|
@ -45,12 +46,12 @@ var uniqueColor;
|
|||
|
||||
function moveTo(position) {
|
||||
if (radar) {
|
||||
MyAvatar.position = position;
|
||||
Camera.position = Vec3.sum(MyAvatar.position, {
|
||||
x : 0,
|
||||
MyAvatar.goToLocation(position, false);
|
||||
Camera.position = {
|
||||
x : position.x,
|
||||
y : radarHeight,
|
||||
z : 0
|
||||
});
|
||||
z : position.z
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,46 +90,6 @@ function keyPressEvent(event) {
|
|||
}
|
||||
}
|
||||
|
||||
function actionOnObjectFromEvent(event) {
|
||||
var rayIntersection = findRayIntersection(Camera.computePickRay(event.x,
|
||||
event.y));
|
||||
if (rayIntersection && rayIntersection.intersects
|
||||
&& rayIntersection.overlayID) {
|
||||
printd("found overlayID touched " + rayIntersection.overlayID);
|
||||
if (entitiesByOverlayID[rayIntersection.overlayID]) {
|
||||
var entity = Entities.getEntityProperties(
|
||||
entitiesByOverlayID[rayIntersection.overlayID],
|
||||
[ "sourceUrl" ]);
|
||||
Window.openUrl(entity.sourceUrl);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (rayIntersection && rayIntersection.intersects
|
||||
&& rayIntersection.entityID && rayIntersection.properties) {
|
||||
printd("found " + rayIntersection.entityID + " of type "
|
||||
+ rayIntersection.properties.type);
|
||||
if (rayIntersection.properties.type == "Web") {
|
||||
printd("found web element to "
|
||||
+ rayIntersection.properties.sourceUrl);
|
||||
Window.openUrl(rayIntersection.properties.sourceUrl);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function mousePress(event) {
|
||||
mousePressOrTouchEnd(event);
|
||||
}
|
||||
|
||||
function mousePressOrTouchEnd(event) {
|
||||
if (radar) {
|
||||
if (actionOnObjectFromEvent(event)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toggleRadarMode() {
|
||||
if (radar) {
|
||||
endRadar();
|
||||
|
@ -229,9 +190,6 @@ function touchEnd(event) {
|
|||
if (analyzeDoubleTap(event))
|
||||
return; // double tap detected, finish
|
||||
|
||||
if (radar) {
|
||||
mousePressOrTouchEnd(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -386,12 +344,13 @@ function pinchUpdate(event) {
|
|||
radarHeight -= pinchIncrement;
|
||||
}
|
||||
}
|
||||
var deltaHeight = avatarY + radarHeight - Camera.position.y;
|
||||
Camera.position = Vec3.sum(Camera.position, {
|
||||
x : 0,
|
||||
y : deltaHeight,
|
||||
z : 0
|
||||
});
|
||||
|
||||
Camera.position = {
|
||||
x : Camera.position.x,
|
||||
y : radarHeight,
|
||||
z : Camera.position.z
|
||||
};
|
||||
|
||||
if (!draggingCamera) {
|
||||
startedDraggingCamera = true;
|
||||
draggingCamera = true;
|
||||
|
@ -401,7 +360,8 @@ function pinchUpdate(event) {
|
|||
}
|
||||
|
||||
function isInsideSquare(coords0, coords1, halfside) {
|
||||
return Math.abs(coords0.x - coords1.x) <= halfside
|
||||
return coords0 != undefined && coords1 != undefined &&
|
||||
Math.abs(coords0.x - coords1.x) <= halfside
|
||||
&& Math.abs(coords0.y - coords1.y) <= halfside;
|
||||
}
|
||||
|
||||
|
@ -412,7 +372,7 @@ function dragScrollUpdate(event) {
|
|||
// drag management
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var dragAt = Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction,
|
||||
radarHeight));
|
||||
radarHeight - MyAvatar.position.y));
|
||||
|
||||
if (lastDragAt === undefined || lastDragAt === null) {
|
||||
lastDragAt = dragAt;
|
||||
|
@ -654,6 +614,7 @@ function Teleporter() {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
Camera.position = Vec3.sum(Camera.position, {
|
||||
x : xDelta,
|
||||
y : 0,
|
||||
|
@ -722,7 +683,7 @@ function Teleporter() {
|
|||
return {
|
||||
dragTeleportBegin : function(event) {
|
||||
printd("[newTeleport] TELEPORT began");
|
||||
var overlayDimensions = entityIconModelDimensions();
|
||||
var overlayDimensions = teleportIconModelDimensions(MyAvatar.position.y);
|
||||
// var destination = computeDestination(event, MyAvatar.position,
|
||||
// Camera.position, radarHeight);
|
||||
// Dimension teleport and cancel overlays (not show them yet)
|
||||
|
@ -843,7 +804,7 @@ var avatarIconDimensionsVal = {
|
|||
};
|
||||
function avatarIconPlaneDimensions() {
|
||||
// given the current height, give a size
|
||||
var xy = -0.003531 * radarHeight + 0.1;
|
||||
var xy = -0.003531 * (radarHeight - MyAvatar.position.y) + 0.1;
|
||||
avatarIconDimensionsVal.x = Math.abs(xy);
|
||||
avatarIconDimensionsVal.y = Math.abs(xy);
|
||||
// reuse object
|
||||
|
@ -1121,172 +1082,20 @@ function renderAllOthersAvatarIcons() {
|
|||
}
|
||||
}
|
||||
|
||||
function entityAdded(entityID) {
|
||||
printd("Entity added " + entityID);
|
||||
var props = Entities.getEntityProperties(entityID, [ "type" ]);
|
||||
printd("Entity added " + entityID + " PROPS " + JSON.stringify(props));
|
||||
if (props && props.type == "Web") {
|
||||
printd("Entity Web added " + entityID);
|
||||
saveEntityData(entityID, true);
|
||||
}
|
||||
}
|
||||
|
||||
function entityRemoved(entityID) {
|
||||
printd("Entity removed " + entityID);
|
||||
var props = Entities.getEntityProperties(entityID, [ "type" ]);
|
||||
if (props && props.type == "Web") {
|
||||
print("Entity Web removed " + entityID);
|
||||
removeEntityData(entityID);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Entities (to remark) cache structure for showing entities markers
|
||||
******************************************************************************/
|
||||
|
||||
var entitiesData = {}; // by entityID
|
||||
var entitiesByOverlayID = {}; // by overlayID
|
||||
var entitiesIcons = []; // a parallel list of icons (overlays) to easily run
|
||||
// through
|
||||
|
||||
var ICON_ENTITY_WEB_MODEL_URL = Script.resolvePath("../assets/images/web.svg");
|
||||
var ICON_ENTITY_IMG_MODEL_URL = Script
|
||||
.resolvePath("../assets/models/teleport-cancel.fbx"); // FIXME - use
|
||||
// correct
|
||||
// model&texture
|
||||
var ICON_ENTITY_DEFAULT_DIMENSIONS = {
|
||||
x : 0.10,
|
||||
y : 0.00001,
|
||||
z : 0.10
|
||||
};
|
||||
|
||||
var entityIconModelDimensionsVal = {
|
||||
x : 0,
|
||||
y : 0.00001,
|
||||
z : 0
|
||||
};
|
||||
function entityIconModelDimensions() {
|
||||
// given the current height, give a size
|
||||
var xz = -0.002831 * radarHeight + 0.1;
|
||||
entityIconModelDimensionsVal.x = xz;
|
||||
entityIconModelDimensionsVal.z = xz;
|
||||
|
||||
function teleportIconModelDimensions(y) {
|
||||
var teleportModelDimensions = ICON_ENTITY_DEFAULT_DIMENSIONS;
|
||||
var xz = -0.002831 * (radarHeight - y) + 0.1;
|
||||
teleportModelDimensions.x = xz;
|
||||
teleportModelDimensions.z = xz;
|
||||
// reuse object
|
||||
return entityIconModelDimensionsVal;
|
||||
}
|
||||
/*
|
||||
* entityIconPlaneDimensions: similar to entityIconModelDimensions but using xy
|
||||
* plane
|
||||
*/
|
||||
function entityIconPlaneDimensions() {
|
||||
var dim = entityIconModelDimensions();
|
||||
var z = dim.z;
|
||||
dim.z = dim.y;
|
||||
dim.y = z;
|
||||
return dim;
|
||||
}
|
||||
|
||||
function currentOverlayForEntity(QUuid) {
|
||||
if (entitiesData[QUuid] != undefined) {
|
||||
return entitiesData[QUuid].icon;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function saveEntityData(QUuid, planar) {
|
||||
if (QUuid == null)
|
||||
return;
|
||||
var entity = Entities.getEntityProperties(QUuid, [ "position" ]);
|
||||
printd("entity added save entity " + QUuid);
|
||||
if (entitiesData[QUuid] != undefined) {
|
||||
entitiesData[QUuid].position = entity.position;
|
||||
} else {
|
||||
var entityIcon = Overlays.addOverlay("image3d", {
|
||||
subImage : {
|
||||
x : 0,
|
||||
y : 0,
|
||||
width : 150,
|
||||
height : 150
|
||||
},
|
||||
url : ICON_ENTITY_WEB_MODEL_URL,
|
||||
dimensions : ICON_ENTITY_DEFAULT_DIMENSIONS,
|
||||
visible : false,
|
||||
ignoreRayIntersection : false,
|
||||
orientation : Quat.fromPitchYawRollDegrees(-90, 0, 0)
|
||||
});
|
||||
|
||||
entitiesIcons.push(entityIcon);
|
||||
entitiesData[QUuid] = {
|
||||
position : entity.position,
|
||||
icon : entityIcon
|
||||
};
|
||||
entitiesByOverlayID[entityIcon] = QUuid;
|
||||
}
|
||||
}
|
||||
|
||||
function removeEntityData(QUuid) {
|
||||
if (QUuid == null)
|
||||
return;
|
||||
|
||||
var itsOverlay = currentOverlayForEntity(QUuid);
|
||||
if (itsOverlay != null) {
|
||||
Overlays.deleteOverlay(itsOverlay);
|
||||
delete entitiesByOverlayID[itsOverlay];
|
||||
}
|
||||
var idx = entitiesIcons.indexOf(itsOverlay);
|
||||
entitiesIcons.splice(idx, 1);
|
||||
|
||||
delete entitiesData[QUuid];
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Entities to remark Icon/Markers rendering
|
||||
******************************************************************************/
|
||||
|
||||
function hideAllEntitiesIcons() {
|
||||
var len = entitiesIcons.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
Overlays.editOverlay(entitiesIcons[i], {
|
||||
visible : false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function renderAllEntitiesIcons() {
|
||||
var entityPos;
|
||||
var entityProps;
|
||||
var iconDimensions = entityIconModelDimensions();
|
||||
var planeDimensions = entityIconPlaneDimensions(); // plane overlays uses
|
||||
// xy instead of xz
|
||||
for ( var QUuid in entitiesData) {
|
||||
if (entitiesData.hasOwnProperty(QUuid)) {
|
||||
entityProps = Entities.getEntityProperties(QUuid, [ "position",
|
||||
"visible" ]);
|
||||
if (entityProps != null) {
|
||||
entityPos = entityProps.position;
|
||||
if (entitiesData[QUuid].icon != undefined && entityPos) {
|
||||
var iconPos = findLineToHeightIntersectionCoords(
|
||||
entityPos.x,
|
||||
entityPos.y
|
||||
+ RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE,
|
||||
entityPos.z, Camera.position.x, Camera.position.y,
|
||||
Camera.position.z, Camera.position.y
|
||||
- RADAR_CAMERA_DISTANCE_TO_ICONS);
|
||||
if (!iconPos) {
|
||||
printd("entity icon pos bad for " + QUuid);
|
||||
continue;
|
||||
}
|
||||
var dimensions = entitiesData[QUuid].planar ? planeDimensions
|
||||
: iconDimensions;
|
||||
Overlays.editOverlay(entitiesData[QUuid].icon, {
|
||||
visible : entityProps.visible,
|
||||
dimensions : dimensions,
|
||||
position : iconPos
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return teleportModelDimensions;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -1298,11 +1107,8 @@ function startRadar() {
|
|||
saveAllOthersAvatarsData();
|
||||
Camera.mode = "independent";
|
||||
|
||||
Camera.position = Vec3.sum(MyAvatar.position, {
|
||||
x : 0,
|
||||
y : radarHeight,
|
||||
z : 0
|
||||
});
|
||||
initCameraOverMyAvatar();
|
||||
|
||||
Camera.orientation = Quat.fromPitchYawRollDegrees(-90, 0, 0);
|
||||
radar = true;
|
||||
|
||||
|
@ -1319,7 +1125,6 @@ function endRadar() {
|
|||
Controller.setVPadEnabled(true);
|
||||
|
||||
disconnectRadarModeEvents();
|
||||
hideAllEntitiesIcons();
|
||||
hideAllAvatarIcons();
|
||||
}
|
||||
|
||||
|
@ -1353,12 +1158,10 @@ function updateRadar() {
|
|||
// Update avatar icons
|
||||
if (startedDraggingCamera) {
|
||||
hideAllAvatarIcons();
|
||||
hideAllEntitiesIcons();
|
||||
startedDraggingCamera = false;
|
||||
} else if (!draggingCamera) {
|
||||
renderMyAvatarIcon();
|
||||
renderAllOthersAvatarIcons();
|
||||
renderAllEntitiesIcons();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1366,48 +1169,41 @@ function valueIfDefined(value) {
|
|||
return value !== undefined ? value : "";
|
||||
}
|
||||
|
||||
function entitiesAnalysis() {
|
||||
var ids = Entities.findEntitiesInFrustum(Camera.frustum);
|
||||
var entities = [];
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
var id = ids[i];
|
||||
var properties = Entities.getEntityProperties(id);
|
||||
entities.push({
|
||||
id : id,
|
||||
name : properties.name,
|
||||
type : properties.type,
|
||||
url : properties.type == "Model" ? properties.modelURL : "",
|
||||
sourceUrl : properties.sourceUrl,
|
||||
locked : properties.locked,
|
||||
visible : properties.visible,
|
||||
drawCalls : valueIfDefined(properties.renderInfo.drawCalls),
|
||||
hasScript : properties.script !== ""
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function connectRadarModeEvents() {
|
||||
Script.update.connect(updateRadar); // 60Hz loop
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
Controller.mousePressEvent.connect(mousePress); // single click/touch
|
||||
Controller.touchUpdateEvent.connect(touchUpdate);
|
||||
Window.domainChanged.connect(domainChanged);
|
||||
MyAvatar.positionGoneTo.connect(positionGoneTo);
|
||||
}
|
||||
|
||||
function positionGoneTo() {
|
||||
Camera.position = Vec3.sum(MyAvatar.position, {
|
||||
x : 0,
|
||||
function initCameraOverMyAvatar() {
|
||||
radarHeight = MyAvatar.position.y + RADAR_HEIGHT_INIT_DELTA;
|
||||
Camera.position = {
|
||||
x : MyAvatar.position.x,
|
||||
y : radarHeight,
|
||||
z : 0
|
||||
});
|
||||
z : MyAvatar.position.z
|
||||
};
|
||||
}
|
||||
|
||||
function domainChanged() {
|
||||
initCameraOverMyAvatar();
|
||||
}
|
||||
|
||||
function positionGoneTo() {
|
||||
Camera.position = {
|
||||
x : MyAvatar.position.x,
|
||||
y : radarHeight,
|
||||
z : MyAvatar.position.z
|
||||
};
|
||||
}
|
||||
|
||||
function disconnectRadarModeEvents() {
|
||||
Script.update.disconnect(updateRadar);
|
||||
Controller.keyPressEvent.disconnect(keyPressEvent);
|
||||
Controller.mousePressEvent.disconnect(mousePress);
|
||||
Controller.touchUpdateEvent.disconnect(touchUpdate);
|
||||
MyAvatar.positionGoneTo.disconnect(positionGoneTo);
|
||||
Window.domainChanged.disconnect(domainChanged);
|
||||
}
|
||||
|
||||
function init() {
|
||||
|
@ -1418,7 +1214,4 @@ function init() {
|
|||
|
||||
AvatarList.avatarAddedEvent.connect(avatarAdded);
|
||||
AvatarList.avatarRemovedEvent.connect(avatarRemoved);
|
||||
|
||||
Entities.addingEntity.connect(entityAdded);
|
||||
Entities.deletingEntity.connect(entityRemoved);
|
||||
}
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
||||
/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND,
|
||||
getControllerJointIndex, enableDispatcherModule, disableDispatcherModule,
|
||||
/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, Camera,
|
||||
getControllerJointIndex, enableDispatcherModule, disableDispatcherModule, entityIsFarGrabbedByOther,
|
||||
Messages, makeDispatcherModuleParameters, makeRunningValues, Settings, entityHasActions,
|
||||
Vec3, Overlays, flatten, Xform, getControllerWorldLocation, ensureDynamic, entityIsCloneable,
|
||||
cloneEntity, DISPATCHER_PROPERTIES, TEAR_AWAY_DISTANCE, Uuid, unhighlightTargetEntity
|
||||
cloneEntity, DISPATCHER_PROPERTIES, Uuid, unhighlightTargetEntity, isInEditMode
|
||||
*/
|
||||
|
||||
Script.include("/~/system/libraries/Xform.js");
|
||||
|
@ -781,7 +781,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var clearGrabActions = function(entityID) {
|
||||
var actionIDs = Entities.getActionIDs(entityID);
|
||||
var myGrabTag = "grab-" + MyAvatar.sessionUUID;
|
||||
|
@ -794,7 +794,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var onMousePress = function(event) {
|
||||
if (isInEditMode() || !event.isLeftButton) { // don't consider any left clicks on the entity while in edit
|
||||
return;
|
||||
|
@ -808,7 +808,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
|||
if (hasEquipData && entityProperties.parentID === EMPTY_PARENT_ID && !entityIsFarGrabbedByOther(entityID)) {
|
||||
entityProperties.id = entityID;
|
||||
var rightHandPosition = MyAvatar.getJointPosition("RightHand");
|
||||
var leftHandPosition = MyAvatar.getJointPosition("LeftHand");
|
||||
var leftHandPosition = MyAvatar.getJointPosition("LeftHand");
|
||||
var distanceToRightHand = Vec3.distance(entityProperties.position, rightHandPosition);
|
||||
var distanceToLeftHand = Vec3.distance(entityProperties.position, leftHandPosition);
|
||||
var leftHandAvailable = leftEquipEntity.targetEntityID === null;
|
||||
|
@ -828,7 +828,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
|||
};
|
||||
|
||||
var onKeyPress = function(event) {
|
||||
if (event.text === UNEQUIP_KEY) {
|
||||
if (event.text.toLowerCase() === UNEQUIP_KEY) {
|
||||
if (rightEquipEntity.targetEntityID) {
|
||||
rightEquipEntity.endEquipEntity();
|
||||
}
|
||||
|
|
|
@ -564,6 +564,9 @@ Script.include("/~/system/libraries/Xform.js");
|
|||
}
|
||||
} else if (this.distanceRotating) {
|
||||
this.distanceRotate(otherFarGrabModule);
|
||||
} else if (this.highlightedEntity) {
|
||||
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity);
|
||||
this.highlightedEntity = null;
|
||||
}
|
||||
}
|
||||
return this.exitIfDisabled(controllerData);
|
||||
|
|
|
@ -63,6 +63,9 @@
|
|||
this.highlightedEntity = targetEntityID;
|
||||
}
|
||||
}
|
||||
} else if (this.highlightedEntity) {
|
||||
dispatcherUtils.unhighlightTargetEntity(this.highlightedEntity);
|
||||
this.highlightedEntity = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
propsArePhysical, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, entityIsGrabbable,
|
||||
Quat, Vec3, MSECS_PER_SEC, getControllerWorldLocation, makeDispatcherModuleParameters, makeRunningValues,
|
||||
TRIGGER_OFF_VALUE, NEAR_GRAB_RADIUS, findGroupParent, entityIsCloneable, propsAreCloneDynamic, cloneEntity,
|
||||
HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, unhighlightTargetEntity
|
||||
HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, unhighlightTargetEntity, Uuid
|
||||
*/
|
||||
|
||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||
|
|
|
@ -7,12 +7,8 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND,
|
||||
getControllerJointIndex, getGrabbableData, enableDispatcherModule, disableDispatcherModule,
|
||||
propsArePhysical, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, entityIsGrabbable,
|
||||
Quat, Vec3, MSECS_PER_SEC, getControllerWorldLocation, makeDispatcherModuleParameters, makeRunningValues,
|
||||
TRIGGER_OFF_VALUE, NEAR_GRAB_RADIUS, findGroupParent, entityIsCloneable, propsAreCloneDynamic, cloneEntity,
|
||||
HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, AddressManager
|
||||
/* global Script, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule,
|
||||
makeDispatcherModuleParameters, makeRunningValues, TRIGGER_OFF_VALUE, NEAR_GRAB_RADIUS, BUMPER_ON_VALUE, AddressManager
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue