mirror of
https://github.com/overte-org/overte.git
synced 2025-04-23 06:13:33 +02:00
Merged from master and disable scissor testing with define macro until I figure out how to make it work in stereo
This commit is contained in:
commit
bced566510
116 changed files with 1640 additions and 1736 deletions
assignment-client/src/scripts
interface
libraries
audio/src
baking/src
display-plugins/src/display-plugins
entities-renderer/src
EntityTreeRenderer.cppEntityTreeRenderer.hRenderableEntityItem.cppRenderableEntityItem.hRenderableLineEntityItem.cppRenderableModelEntityItem.cppRenderableModelEntityItem.hRenderableParticleEffectEntityItem.cppRenderableShapeEntityItem.cppRenderableShapeEntityItem.hRenderableTextEntityItem.cppRenderableWebEntityItem.cppRenderableWebEntityItem.hRenderableZoneEntityItem.cppRenderableZoneEntityItem.h
entities/src
EntityItem.cppEntityItem.hEntityItemProperties.cppEntityScriptingInterface.cppEntityScriptingInterface.hEntityTree.cppEntityTree.hEntityTypes.cppLightEntityItem.cppModelEntityItem.cppParticleEffectEntityItem.cppShapeEntityItem.cppShapeEntityItem.hSimpleEntitySimulation.cpp
gpu/src/gpu
networking/src
octree/src
physics/src
plugins/src/plugins
render-utils/src
DebugDeferredBuffer.cppDeferredLightingEffect.cppGeometryCache.cppGeometryCache.hHaze.slfLightStage.cppLightStage.hModel.cppOutlineEffect.cppRenderDeferredTask.cppRenderShadowTask.cpp
render/src/render
script-engine/src
shared/src
ui/src/ui
|
@ -30,6 +30,8 @@
|
|||
#include <UUID.h>
|
||||
#include <WebSocketServerClass.h>
|
||||
|
||||
#include <EntityScriptClient.h> // for EntityScriptServerServices
|
||||
|
||||
#include "EntityScriptServerLogging.h"
|
||||
#include "../entities/AssignmentParentFinder.h"
|
||||
|
||||
|
@ -68,6 +70,9 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig
|
|||
DependencyManager::set<ScriptCache>();
|
||||
DependencyManager::set<ScriptEngines>(ScriptEngine::ENTITY_SERVER_SCRIPT);
|
||||
|
||||
DependencyManager::set<EntityScriptServerServices>();
|
||||
|
||||
|
||||
// Needed to ensure the creation of the DebugDraw instance on the main thread
|
||||
DebugDraw::getInstance();
|
||||
|
||||
|
@ -583,6 +588,7 @@ void EntityScriptServer::aboutToFinish() {
|
|||
// cleanup the AudioInjectorManager (and any still running injectors)
|
||||
DependencyManager::destroy<AudioInjectorManager>();
|
||||
DependencyManager::destroy<ScriptEngines>();
|
||||
DependencyManager::destroy<EntityScriptServerServices>();
|
||||
|
||||
// cleanup codec & encoder
|
||||
if (_codec && _encoder) {
|
||||
|
|
|
@ -14,6 +14,12 @@
|
|||
var isWindowFocused = true;
|
||||
var isKeyboardRaised = false;
|
||||
var isNumericKeyboard = false;
|
||||
var isPasswordField = false;
|
||||
|
||||
function shouldSetPasswordField() {
|
||||
var nodeType = document.activeElement.type;
|
||||
return nodeType === "password";
|
||||
}
|
||||
|
||||
function shouldRaiseKeyboard() {
|
||||
var nodeName = document.activeElement.nodeName;
|
||||
|
@ -53,12 +59,14 @@
|
|||
setInterval(function () {
|
||||
var keyboardRaised = shouldRaiseKeyboard();
|
||||
var numericKeyboard = shouldSetNumeric();
|
||||
var passwordField = shouldSetPasswordField();
|
||||
|
||||
if (isWindowFocused && (keyboardRaised !== isKeyboardRaised || numericKeyboard !== isNumericKeyboard)) {
|
||||
if (isWindowFocused &&
|
||||
(keyboardRaised !== isKeyboardRaised || numericKeyboard !== isNumericKeyboard || passwordField !== isPasswordField)) {
|
||||
|
||||
if (typeof EventBridge !== "undefined" && EventBridge !== null) {
|
||||
EventBridge.emitWebEvent(
|
||||
keyboardRaised ? ("_RAISE_KEYBOARD" + (numericKeyboard ? "_NUMERIC" : "")) : "_LOWER_KEYBOARD"
|
||||
keyboardRaised ? ("_RAISE_KEYBOARD" + (numericKeyboard ? "_NUMERIC" : "") + (passwordField ? "_PASSWORD" : "")) : "_LOWER_KEYBOARD"
|
||||
);
|
||||
} else {
|
||||
if (numWarnings < MAX_WARNINGS) {
|
||||
|
@ -74,6 +82,7 @@
|
|||
|
||||
isKeyboardRaised = keyboardRaised;
|
||||
isNumericKeyboard = numericKeyboard;
|
||||
isPasswordField = passwordField;
|
||||
}
|
||||
}, POLL_FREQUENCY);
|
||||
|
||||
|
|
|
@ -119,6 +119,7 @@ Item {
|
|||
width: parent.width
|
||||
focus: true
|
||||
label: "Username or Email"
|
||||
activeFocusOnPress: true
|
||||
|
||||
ShortcutText {
|
||||
anchors {
|
||||
|
@ -135,6 +136,9 @@ Item {
|
|||
|
||||
onLinkActivated: loginDialog.openUrl(link)
|
||||
}
|
||||
onFocusChanged: {
|
||||
root.text = "";
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
|
@ -143,6 +147,7 @@ Item {
|
|||
|
||||
label: "Password"
|
||||
echoMode: showPassword.checked ? TextInput.Normal : TextInput.Password
|
||||
activeFocusOnPress: true
|
||||
|
||||
ShortcutText {
|
||||
anchors {
|
||||
|
@ -159,6 +164,10 @@ Item {
|
|||
|
||||
onLinkActivated: loginDialog.openUrl(link)
|
||||
}
|
||||
onFocusChanged: {
|
||||
root.text = "";
|
||||
root.isPassword = true;
|
||||
}
|
||||
}
|
||||
|
||||
CheckBoxQQC2 {
|
||||
|
@ -233,18 +242,6 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
// Override ScrollingWindow's keyboard that would be at very bottom of dialog.
|
||||
Keyboard {
|
||||
raised: keyboardEnabled && keyboardRaised
|
||||
numeric: punctuationMode
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.title = qsTr("Sign Into High Fidelity")
|
||||
root.iconText = "<"
|
||||
|
|
|
@ -108,12 +108,17 @@ Item {
|
|||
id: emailField
|
||||
width: parent.width
|
||||
label: "Email"
|
||||
activeFocusOnPress: true
|
||||
onFocusChanged: {
|
||||
root.text = "";
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: usernameField
|
||||
width: parent.width
|
||||
label: "Username"
|
||||
activeFocusOnPress: true
|
||||
|
||||
ShortcutText {
|
||||
anchors {
|
||||
|
@ -128,6 +133,9 @@ Item {
|
|||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
color: hifi.colors.blueAccent
|
||||
onFocusChanged: {
|
||||
root.text = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,6 +144,7 @@ Item {
|
|||
width: parent.width
|
||||
label: "Password"
|
||||
echoMode: TextInput.Password
|
||||
activeFocusOnPress: true
|
||||
|
||||
ShortcutText {
|
||||
anchors {
|
||||
|
@ -151,6 +160,11 @@ Item {
|
|||
|
||||
color: hifi.colors.blueAccent
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
root.text = "";
|
||||
root.isPassword = focus
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
|
@ -202,18 +216,6 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
// Override ScrollingWindow's keyboard that would be at very bottom of dialog.
|
||||
Keyboard {
|
||||
raised: keyboardEnabled && keyboardRaised
|
||||
numeric: punctuationMode
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.title = qsTr("Create an Account")
|
||||
root.iconText = "<"
|
||||
|
|
|
@ -39,6 +39,10 @@ Rectangle {
|
|||
property bool shiftMode: false
|
||||
property bool numericShiftMode: false
|
||||
|
||||
onRaisedChanged: {
|
||||
mirroredText = "";
|
||||
}
|
||||
|
||||
function resetShiftMode(mode) {
|
||||
shiftMode = mode;
|
||||
shiftKey.resetToggledMode(mode);
|
||||
|
|
|
@ -16,6 +16,7 @@ Item {
|
|||
property bool keyboardEnabled: false
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
property bool passwordField: false
|
||||
property bool isDesktop: false
|
||||
property alias webView: web.webViewCore
|
||||
property alias profile: web.webViewCoreProfile
|
||||
|
@ -41,7 +42,7 @@ Item {
|
|||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
spacing: 120
|
||||
|
||||
|
||||
TabletWebButton {
|
||||
id: back
|
||||
enabledColor: hifi.colors.darkGray
|
||||
|
@ -165,6 +166,11 @@ Item {
|
|||
id: keyboard
|
||||
raised: parent.keyboardEnabled && parent.keyboardRaised
|
||||
numeric: parent.punctuationMode
|
||||
password: parent.passwordField
|
||||
|
||||
onPasswordChanged: {
|
||||
keyboard.mirroredText = "";
|
||||
}
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
|
@ -172,7 +178,7 @@ Item {
|
|||
bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
root.isDesktop = (typeof desktop !== "undefined");
|
||||
keyboardEnabled = HMD.active;
|
||||
|
|
|
@ -13,6 +13,7 @@ Item {
|
|||
property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
property bool passwordField: false
|
||||
property alias flickable: webroot.interactive
|
||||
|
||||
// FIXME - Keyboard HMD only: Make Interface either set keyboardRaised property directly in OffscreenQmlSurface
|
||||
|
@ -50,6 +51,7 @@ Item {
|
|||
id: keyboard
|
||||
raised: parent.keyboardEnabled && parent.keyboardRaised
|
||||
numeric: parent.punctuationMode
|
||||
password: parent.passwordField
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
|
|
|
@ -37,6 +37,8 @@ TabletModalWindow {
|
|||
property bool keyboardEnabled: false
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
property bool isPassword: false
|
||||
property alias text: loginKeyboard.mirroredText
|
||||
|
||||
readonly property bool isTablet: true
|
||||
|
||||
|
@ -130,6 +132,7 @@ TabletModalWindow {
|
|||
id: loginKeyboard
|
||||
raised: root.keyboardEnabled && root.keyboardRaised
|
||||
numeric: root.punctuationMode
|
||||
password: root.isPassword
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// skyboxchanger.qml
|
||||
//
|
||||
// SkyboxChanger.qml
|
||||
// qml/hifi
|
||||
//
|
||||
// Created by Cain Kilgore on 9th August 2017
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
|
@ -9,33 +9,73 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick 2.5
|
||||
import "../styles-uit"
|
||||
import "../controls-uit" as HifiControls
|
||||
import QtQuick.Controls 2.2
|
||||
|
||||
Rectangle {
|
||||
Item {
|
||||
id: root;
|
||||
|
||||
color: hifi.colors.baseGray;
|
||||
|
||||
HifiConstants { id: hifi; }
|
||||
|
||||
property var defaultThumbnails: [];
|
||||
property var defaultFulls: [];
|
||||
|
||||
ListModel {
|
||||
id: skyboxModel;
|
||||
}
|
||||
|
||||
function getSkyboxes() {
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
var url = "http://mpassets.highfidelity.com/5fbdbeef-1cf8-4954-811d-3d4acbba4dc9-v1/skyboxes.json";
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if (xmlhttp.readyState === XMLHttpRequest.DONE && xmlhttp.status === 200) {
|
||||
sortSkyboxes(xmlhttp.responseText);
|
||||
}
|
||||
}
|
||||
xmlhttp.open("GET", url, true);
|
||||
xmlhttp.send();
|
||||
}
|
||||
|
||||
function sortSkyboxes(response) {
|
||||
var arr = JSON.parse(response);
|
||||
var arrLength = arr.length;
|
||||
for (var i = 0; i < arrLength; i++) {
|
||||
defaultThumbnails.push(arr[i].thumb);
|
||||
defaultFulls.push(arr[i].full);
|
||||
skyboxModel.append({});
|
||||
}
|
||||
setSkyboxes();
|
||||
}
|
||||
|
||||
function setSkyboxes() {
|
||||
for (var i = 0; i < skyboxModel.count; i++) {
|
||||
skyboxModel.setProperty(i, "thumbnailPath", defaultThumbnails[i]);
|
||||
skyboxModel.setProperty(i, "fullSkyboxPath", defaultFulls[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
getSkyboxes();
|
||||
}
|
||||
|
||||
Item {
|
||||
id: titleBarContainer;
|
||||
// Size
|
||||
width: parent.width;
|
||||
height: 50;
|
||||
// Anchors
|
||||
height: childrenRect.height;
|
||||
anchors.left: parent.left;
|
||||
anchors.top: parent.top;
|
||||
|
||||
RalewaySemiBold {
|
||||
anchors.right: parent.right;
|
||||
anchors.topMargin: 20;
|
||||
RalewayBold {
|
||||
id: titleBarText;
|
||||
text: "Skybox Changer";
|
||||
// Text size
|
||||
size: hifi.fontSizes.overlayTitle;
|
||||
// Anchors
|
||||
anchors.fill: parent;
|
||||
anchors.leftMargin: 16;
|
||||
// Style
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 40
|
||||
height: paintedHeight;
|
||||
color: hifi.colors.lightGrayText;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
@ -43,131 +83,61 @@ Rectangle {
|
|||
id: titleBarDesc;
|
||||
text: "Click an image to choose a new Skybox.";
|
||||
wrapMode: Text.Wrap
|
||||
// Text size
|
||||
size: 14;
|
||||
// Anchors
|
||||
anchors.fill: parent;
|
||||
anchors.top: titleBarText.bottom
|
||||
anchors.leftMargin: 16;
|
||||
anchors.rightMargin: 16;
|
||||
// Style
|
||||
anchors.top: titleBarText.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 40
|
||||
height: paintedHeight;
|
||||
color: hifi.colors.lightGrayText;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This RowLayout could be a GridLayout instead for further expandability.
|
||||
// As this SkyboxChanger task only required 6 images, implementing GridLayout wasn't necessary.
|
||||
// In the future if this is to be expanded to add more Skyboxes, it might be worth changing this.
|
||||
RowLayout {
|
||||
id: row1
|
||||
GridView {
|
||||
id: gridView
|
||||
interactive: true
|
||||
clip: true
|
||||
anchors.top: titleBarContainer.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 30
|
||||
Layout.fillWidth: true
|
||||
anchors.topMargin: 30
|
||||
spacing: 10
|
||||
Image {
|
||||
width: 200; height: 200
|
||||
fillMode: Image.Stretch
|
||||
source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_1.jpg"
|
||||
clip: true
|
||||
id: preview1
|
||||
MouseArea {
|
||||
anchors.topMargin: 20
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: 400
|
||||
anchors.bottom: parent.bottom
|
||||
currentIndex: -1
|
||||
cellWidth: 200
|
||||
cellHeight: 200
|
||||
model: skyboxModel
|
||||
delegate: Item {
|
||||
width: gridView.cellWidth
|
||||
height: gridView.cellHeight
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/1.jpg'});
|
||||
Image {
|
||||
source: thumbnailPath
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
fillMode: Image.Stretch
|
||||
sourceSize.width: parent.width
|
||||
sourceSize.height: parent.height
|
||||
mipmap: true
|
||||
}
|
||||
}
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Image {
|
||||
width: 200; height: 200
|
||||
fillMode: Image.Stretch
|
||||
source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_2.jpg"
|
||||
clip: true
|
||||
id: preview2
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/2.png'});
|
||||
sendToScript({method: 'changeSkybox', url: fullSkyboxPath});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
id: row2
|
||||
anchors.top: row1.bottom
|
||||
anchors.topMargin: 10
|
||||
anchors.left: parent.left
|
||||
Layout.fillWidth: true
|
||||
anchors.leftMargin: 30
|
||||
spacing: 10
|
||||
Image {
|
||||
width: 200; height: 200
|
||||
fillMode: Image.Stretch
|
||||
source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_3.jpg"
|
||||
clip: true
|
||||
id: preview3
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/3.jpg'});
|
||||
}
|
||||
}
|
||||
}
|
||||
Image {
|
||||
width: 200; height: 200
|
||||
fillMode: Image.Stretch
|
||||
source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_4.jpg"
|
||||
clip: true
|
||||
id: preview4
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/4.jpg'});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
id: row3
|
||||
anchors.top: row2.bottom
|
||||
anchors.topMargin: 10
|
||||
anchors.left: parent.left
|
||||
Layout.fillWidth: true
|
||||
anchors.leftMargin: 30
|
||||
spacing: 10
|
||||
Image {
|
||||
width: 200; height: 200
|
||||
fillMode: Image.Stretch
|
||||
source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_5.jpg"
|
||||
clip: true
|
||||
id: preview5
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/5.png'});
|
||||
}
|
||||
}
|
||||
}
|
||||
Image {
|
||||
width: 200; height: 200
|
||||
fillMode: Image.Stretch
|
||||
source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_6.jpg"
|
||||
clip: true
|
||||
id: preview6
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/6.jpg'});
|
||||
}
|
||||
}
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
parent: gridView.parent
|
||||
anchors.top: gridView.top
|
||||
anchors.left: gridView.right
|
||||
anchors.bottom: gridView.bottom
|
||||
anchors.leftMargin: 10
|
||||
width: 19
|
||||
}
|
||||
}
|
||||
|
||||
signal sendToScript(var message);
|
||||
|
||||
}
|
||||
}
|
|
@ -22,8 +22,7 @@ RowLayout {
|
|||
property var sample: null;
|
||||
property bool isPlaying: false;
|
||||
function createSampleSound() {
|
||||
var SOUND = Qt.resolvedUrl("../../../sounds/sample.wav");
|
||||
sound = SoundCache.getSound(SOUND);
|
||||
sound = ApplicationInterface.getSampleSound();
|
||||
sample = null;
|
||||
}
|
||||
function playSound() {
|
||||
|
|
|
@ -39,7 +39,8 @@ Rectangle {
|
|||
property bool itemIsJson: true;
|
||||
property bool shouldBuyWithControlledFailure: false;
|
||||
property bool debugCheckoutSuccess: false;
|
||||
property bool canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified;
|
||||
property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified();
|
||||
property bool isWearable;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
Hifi.QmlCommerce {
|
||||
|
@ -80,6 +81,7 @@ Rectangle {
|
|||
root.activeView = "checkoutFailure";
|
||||
} else {
|
||||
root.itemHref = result.data.download_url;
|
||||
root.isWearable = result.data.categories.indexOf("Wearables") > -1;
|
||||
root.activeView = "checkoutSuccess";
|
||||
}
|
||||
}
|
||||
|
@ -592,7 +594,7 @@ Rectangle {
|
|||
height: 50;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
text: "Rez It"
|
||||
text: root.isWearable ? "Wear It" : "Rez It"
|
||||
onClicked: {
|
||||
if (urlHandler.canHandleUrl(root.itemHref)) {
|
||||
urlHandler.handleUrl(root.itemHref);
|
||||
|
@ -603,7 +605,7 @@ Rectangle {
|
|||
}
|
||||
RalewaySemiBold {
|
||||
id: noPermissionText;
|
||||
visible: !root.canRezCertifiedItems;
|
||||
visible: !root.canRezCertifiedItems && !root.isWearable;
|
||||
text: '<font color="' + hifi.colors.redAccent + '"><a href="#">You do not have Certified Rez permissions in this domain.</a></font>'
|
||||
// Text size
|
||||
size: 16;
|
||||
|
|
|
@ -39,6 +39,7 @@ Item {
|
|||
property int itemEdition;
|
||||
property int numberSold;
|
||||
property int limitedRun;
|
||||
property bool isWearable;
|
||||
|
||||
property string originalStatusText;
|
||||
property string originalStatusColor;
|
||||
|
@ -342,7 +343,7 @@ Item {
|
|||
anchors.bottom: parent.bottom;
|
||||
anchors.right: parent.right;
|
||||
width: height;
|
||||
enabled: root.canRezCertifiedItems && root.purchaseStatus !== "invalidated";
|
||||
enabled: (root.canRezCertifiedItems || root.isWearable) && root.purchaseStatus !== "invalidated";
|
||||
|
||||
onClicked: {
|
||||
if (urlHandler.canHandleUrl(root.itemHref)) {
|
||||
|
@ -415,7 +416,7 @@ Item {
|
|||
size: 16;
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: "Rez It"
|
||||
text: root.isWearable ? "Wear It" : "Rez It"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ Rectangle {
|
|||
property bool securityImageResultReceived: false;
|
||||
property bool purchasesReceived: false;
|
||||
property bool punctuationMode: false;
|
||||
property bool canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified;
|
||||
property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified();
|
||||
property bool pendingInventoryReply: true;
|
||||
property bool isShowingMyItems: false;
|
||||
property bool isDebuggingFirstUseTutorial: false;
|
||||
|
@ -434,6 +434,7 @@ Rectangle {
|
|||
numberSold: model.number_sold;
|
||||
limitedRun: model.limited_run;
|
||||
displayedItemCount: model.displayedItemCount;
|
||||
isWearable: model.categories.indexOf("Wearables") > -1;
|
||||
anchors.topMargin: 12;
|
||||
anchors.bottomMargin: 12;
|
||||
|
||||
|
@ -582,9 +583,11 @@ Rectangle {
|
|||
|
||||
Timer {
|
||||
id: inventoryTimer;
|
||||
interval: 90000;
|
||||
interval: 4000; // Change this back to 90000 after demo
|
||||
//interval: 90000;
|
||||
onTriggered: {
|
||||
if (root.activeView === "purchasesMain" && !root.pendingInventoryReply) {
|
||||
console.log("Refreshing Purchases...");
|
||||
root.pendingInventoryReply = true;
|
||||
commerce.inventory();
|
||||
}
|
||||
|
@ -660,6 +663,8 @@ Rectangle {
|
|||
currentPurchasesModelStatus !== previousPurchasesModelStatus) {
|
||||
|
||||
purchasesModel.setProperty(i, "statusChanged", true);
|
||||
} else {
|
||||
purchasesModel.setProperty(i, "statusChanged", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ Item {
|
|||
id: root;
|
||||
z: 997;
|
||||
property bool keyboardRaised: false;
|
||||
property bool isPasswordField: false;
|
||||
property string titleBarIcon: "";
|
||||
property string titleBarText: "";
|
||||
|
||||
|
@ -202,6 +203,7 @@ Item {
|
|||
|
||||
onFocusChanged: {
|
||||
root.keyboardRaised = focus;
|
||||
root.isPasswordField = (focus && passphraseField.echoMode === TextInput.Password);
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
|
@ -209,6 +211,7 @@ Item {
|
|||
|
||||
onClicked: {
|
||||
root.keyboardRaised = true;
|
||||
root.isPasswordField = (passphraseField.echoMode === TextInput.Password);
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
|
@ -382,6 +385,7 @@ Item {
|
|||
id: keyboard;
|
||||
raised: HMD.mounted && root.keyboardRaised;
|
||||
numeric: parent.punctuationMode;
|
||||
password: root.isPasswordField;
|
||||
anchors {
|
||||
bottom: parent.bottom;
|
||||
left: parent.left;
|
||||
|
|
|
@ -80,16 +80,18 @@ Item {
|
|||
|
||||
onFocusChanged: {
|
||||
if (focus) {
|
||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard'});
|
||||
var hidePassword = (currentPassphraseField.echoMode === TextInput.Password);
|
||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
||||
} else if (!passphraseFieldAgain.focus) {
|
||||
sendSignalToWallet({method: 'walletSetup_lowerKeyboard'});
|
||||
sendSignalToWallet({method: 'walletSetup_lowerKeyboard', isPasswordField: false});
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
onPressed: {
|
||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard'});
|
||||
var hidePassword = (currentPassphraseField.echoMode === TextInput.Password);
|
||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
|
@ -116,16 +118,18 @@ Item {
|
|||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
onPressed: {
|
||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard'});
|
||||
var hidePassword = (passphraseField.echoMode === TextInput.Password);
|
||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
if (focus) {
|
||||
sendMessageToLightbox({method: 'walletSetup_raiseKeyboard'});
|
||||
var hidePassword = (passphraseField.echoMode === TextInput.Password);
|
||||
sendMessageToLightbox({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
||||
} else if (!passphraseFieldAgain.focus) {
|
||||
sendMessageToLightbox({method: 'walletSetup_lowerKeyboard'});
|
||||
sendMessageToLightbox({method: 'walletSetup_lowerKeyboard', isPasswordField: false});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,16 +154,18 @@ Item {
|
|||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
onPressed: {
|
||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard'});
|
||||
var hidePassword = (passphraseFieldAgain.echoMode === TextInput.Password);
|
||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
if (focus) {
|
||||
sendMessageToLightbox({method: 'walletSetup_raiseKeyboard'});
|
||||
var hidePassword = (passphraseFieldAgain.echoMode === TextInput.Password);
|
||||
sendMessageToLightbox({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
||||
} else if (!passphraseField.focus) {
|
||||
sendMessageToLightbox({method: 'walletSetup_lowerKeyboard'});
|
||||
sendMessageToLightbox({method: 'walletSetup_lowerKeyboard', isPasswordField: false});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ Rectangle {
|
|||
|
||||
property string activeView: "initialize";
|
||||
property bool keyboardRaised: false;
|
||||
property bool isPassword: false;
|
||||
|
||||
Image {
|
||||
anchors.fill: parent;
|
||||
|
@ -181,8 +182,10 @@ Rectangle {
|
|||
}
|
||||
} else if (msg.method === 'walletSetup_raiseKeyboard') {
|
||||
root.keyboardRaised = true;
|
||||
root.isPassword = msg.isPasswordField;
|
||||
} else if (msg.method === 'walletSetup_lowerKeyboard') {
|
||||
root.keyboardRaised = false;
|
||||
root.isPassword = msg.isPasswordField;
|
||||
} else {
|
||||
sendToScript(msg);
|
||||
}
|
||||
|
@ -202,6 +205,7 @@ Rectangle {
|
|||
onSendSignalToWallet: {
|
||||
if (msg.method === 'walletSetup_raiseKeyboard') {
|
||||
root.keyboardRaised = true;
|
||||
root.isPassword = msg.isPasswordField;
|
||||
} else if (msg.method === 'walletSetup_lowerKeyboard') {
|
||||
root.keyboardRaised = false;
|
||||
} else if (msg.method === 'walletSecurity_changePassphraseCancelled') {
|
||||
|
@ -685,6 +689,7 @@ Rectangle {
|
|||
id: keyboard;
|
||||
raised: HMD.mounted && root.keyboardRaised;
|
||||
numeric: parent.punctuationMode;
|
||||
password: root.isPassword;
|
||||
anchors {
|
||||
bottom: parent.bottom;
|
||||
left: parent.left;
|
||||
|
|
|
@ -43,6 +43,7 @@ Item {
|
|||
|
||||
calculatePendingAndInvalidated();
|
||||
}
|
||||
refreshTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,6 +118,8 @@ Item {
|
|||
historyReceived = false;
|
||||
commerce.balance();
|
||||
commerce.history();
|
||||
} else {
|
||||
refreshTimer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -138,6 +141,17 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: refreshTimer;
|
||||
interval: 4000; // Remove this after demo?
|
||||
onTriggered: {
|
||||
console.log("Refreshing Wallet Home...");
|
||||
historyReceived = false;
|
||||
commerce.balance();
|
||||
commerce.history();
|
||||
}
|
||||
}
|
||||
|
||||
// Recent Activity
|
||||
Rectangle {
|
||||
id: recentActivityContainer;
|
||||
|
|
Binary file not shown.
|
@ -120,6 +120,7 @@
|
|||
#include <SceneScriptingInterface.h>
|
||||
#include <ScriptEngines.h>
|
||||
#include <ScriptCache.h>
|
||||
#include <ShapeEntityItem.h>
|
||||
#include <SoundCache.h>
|
||||
#include <ui/TabletScriptingInterface.h>
|
||||
#include <ui/ToolbarScriptingInterface.h>
|
||||
|
@ -691,7 +692,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
DependencyManager::set<CloseEventSender>();
|
||||
DependencyManager::set<ResourceManager>();
|
||||
DependencyManager::set<SelectionScriptingInterface>();
|
||||
DependencyManager::set<ContextOverlayInterface>();
|
||||
DependencyManager::set<Ledger>();
|
||||
DependencyManager::set<Wallet>();
|
||||
DependencyManager::set<WalletScriptingInterface>();
|
||||
|
@ -759,7 +759,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
_notifiedPacketVersionMismatchThisDomain(false),
|
||||
_maxOctreePPS(maxOctreePacketsPerSecond.get()),
|
||||
_lastFaceTrackerUpdate(0),
|
||||
_snapshotSound(nullptr)
|
||||
_snapshotSound(nullptr),
|
||||
_sampleSound(nullptr)
|
||||
|
||||
{
|
||||
auto steamClient = PluginManager::getInstance()->getSteamClientPlugin();
|
||||
setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning()));
|
||||
|
@ -804,7 +806,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
installNativeEventFilter(&MyNativeEventFilter::getInstance());
|
||||
#endif
|
||||
|
||||
|
||||
_logger = new FileLogger(this);
|
||||
qInstallMessageHandler(messageHandler);
|
||||
|
||||
|
@ -981,6 +982,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
connect(myAvatar.get(), &MyAvatar::positionGoneTo,
|
||||
DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
|
||||
|
||||
// Inititalize sample before registering
|
||||
QFileInfo infSample = QFileInfo(PathUtils::resourcesPath() + "sounds/sample.wav");
|
||||
_sampleSound = DependencyManager::get<SoundCache>()->getSound(QUrl::fromLocalFile(infSample.absoluteFilePath()));
|
||||
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
|
||||
scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine){
|
||||
registerScriptEngineWithApplicationServices(engine);
|
||||
|
@ -1182,7 +1187,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
// allow you to move an entity around in your hand
|
||||
_entityEditSender.setPacketsPerSecond(3000); // super high!!
|
||||
|
||||
// Overlays need to exist before we set the ContextOverlayInterface dependency
|
||||
_overlays.init(); // do this before scripts load
|
||||
DependencyManager::set<ContextOverlayInterface>();
|
||||
|
||||
// Make sure we don't time out during slow operations at startup
|
||||
updateHeartbeat();
|
||||
|
||||
|
@ -1472,53 +1480,19 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
}
|
||||
});
|
||||
|
||||
// If the user clicks somewhere where there is NO entity at all, we will release focus
|
||||
connect(getEntities().data(), &EntityTreeRenderer::mousePressOffEntity, [=]() {
|
||||
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
|
||||
});
|
||||
|
||||
// Keyboard focus handling for Web overlays.
|
||||
auto overlays = &(qApp->getOverlays());
|
||||
|
||||
connect(overlays, &Overlays::mousePressOnOverlay, [=](const OverlayID& overlayID, const PointerEvent& event) {
|
||||
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlays->getOverlay(overlayID));
|
||||
// Only Web overlays can have keyboard focus.
|
||||
if (thisOverlay) {
|
||||
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
|
||||
setKeyboardFocusOverlay(overlayID);
|
||||
}
|
||||
});
|
||||
|
||||
connect(overlays, &Overlays::overlayDeleted, [=](const OverlayID& overlayID) {
|
||||
if (overlayID == _keyboardFocusedOverlay.get()) {
|
||||
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
|
||||
}
|
||||
});
|
||||
|
||||
connect(overlays, &Overlays::mousePressOffOverlay, [=]() {
|
||||
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
|
||||
});
|
||||
|
||||
connect(this, &Application::aboutToQuit, [=]() {
|
||||
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
|
||||
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
|
||||
});
|
||||
|
||||
connect(overlays,
|
||||
SIGNAL(mousePressOnOverlay(const OverlayID&, const PointerEvent&)),
|
||||
DependencyManager::get<ContextOverlayInterface>().data(),
|
||||
SLOT(contextOverlays_mousePressOnOverlay(const OverlayID&, const PointerEvent&)));
|
||||
|
||||
connect(overlays,
|
||||
SIGNAL(hoverEnterOverlay(const OverlayID&, const PointerEvent&)),
|
||||
DependencyManager::get<ContextOverlayInterface>().data(),
|
||||
SLOT(contextOverlays_hoverEnterOverlay(const OverlayID&, const PointerEvent&)));
|
||||
|
||||
connect(overlays,
|
||||
SIGNAL(hoverLeaveOverlay(const OverlayID&, const PointerEvent&)),
|
||||
DependencyManager::get<ContextOverlayInterface>().data(),
|
||||
SLOT(contextOverlays_hoverLeaveOverlay(const OverlayID&, const PointerEvent&)));
|
||||
|
||||
// Add periodic checks to send user activity data
|
||||
static int CHECK_NEARBY_AVATARS_INTERVAL_MS = 10000;
|
||||
static int NEARBY_AVATAR_RADIUS_METERS = 10;
|
||||
|
@ -1787,9 +1761,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
return entityServerNode && !isPhysicsEnabled();
|
||||
});
|
||||
|
||||
QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav");
|
||||
_snapshotSound = DependencyManager::get<SoundCache>()->getSound(QUrl::fromLocalFile(inf.absoluteFilePath()));
|
||||
|
||||
QFileInfo infSnap = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav");
|
||||
_snapshotSound = DependencyManager::get<SoundCache>()->getSound(QUrl::fromLocalFile(infSnap.absoluteFilePath()));
|
||||
|
||||
QVariant testProperty = property(hifi::properties::TEST);
|
||||
qDebug() << testProperty;
|
||||
if (testProperty.isValid()) {
|
||||
|
@ -4202,6 +4176,7 @@ void Application::initDisplay() {
|
|||
}
|
||||
|
||||
void Application::init() {
|
||||
|
||||
// Make sure Login state is up to date
|
||||
DependencyManager::get<DialogsManager>()->toggleLoginDialog();
|
||||
|
||||
|
@ -4228,6 +4203,10 @@ void Application::init() {
|
|||
// fire off an immediate domain-server check in now that settings are loaded
|
||||
DependencyManager::get<NodeList>()->sendDomainServerCheckIn();
|
||||
|
||||
// This allows collision to be set up properly for shape entities supported by GeometryCache.
|
||||
// This is before entity setup to ensure that it's ready for whenever instance collision is initialized.
|
||||
ShapeEntityItem::setShapeInfoCalulator(ShapeEntityItem::ShapeInfoCalculator(&shapeInfoCalculator));
|
||||
|
||||
getEntities()->init();
|
||||
getEntities()->setEntityLoadingPriorityFunction([this](const EntityItem& item) {
|
||||
auto dims = item.getDimensions();
|
||||
|
@ -4550,14 +4529,9 @@ QUuid Application::getKeyboardFocusEntity() const {
|
|||
return _keyboardFocusedEntity.get();
|
||||
}
|
||||
|
||||
void Application::setKeyboardFocusEntity(QUuid id) {
|
||||
EntityItemID entityItemID(id);
|
||||
setKeyboardFocusEntity(entityItemID);
|
||||
}
|
||||
|
||||
static const float FOCUS_HIGHLIGHT_EXPANSION_FACTOR = 1.05f;
|
||||
|
||||
void Application::setKeyboardFocusEntity(EntityItemID entityItemID) {
|
||||
void Application::setKeyboardFocusEntity(const EntityItemID& entityItemID) {
|
||||
if (_keyboardFocusedEntity.get() != entityItemID) {
|
||||
_keyboardFocusedEntity.set(entityItemID);
|
||||
|
||||
|
@ -4594,7 +4568,7 @@ OverlayID Application::getKeyboardFocusOverlay() {
|
|||
return _keyboardFocusedOverlay.get();
|
||||
}
|
||||
|
||||
void Application::setKeyboardFocusOverlay(OverlayID overlayID) {
|
||||
void Application::setKeyboardFocusOverlay(const OverlayID& overlayID) {
|
||||
if (overlayID != _keyboardFocusedOverlay.get()) {
|
||||
_keyboardFocusedOverlay.set(overlayID);
|
||||
|
||||
|
@ -5090,6 +5064,7 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
|
||||
this->updateCamera(appRenderArgs._renderArgs);
|
||||
appRenderArgs._eyeToWorld = _myCamera.getTransform();
|
||||
appRenderArgs._isStereo = false;
|
||||
|
||||
{
|
||||
|
@ -6805,6 +6780,10 @@ void Application::loadScriptURLDialog() const {
|
|||
});
|
||||
}
|
||||
|
||||
SharedSoundPointer Application::getSampleSound() const {
|
||||
return _sampleSound;
|
||||
}
|
||||
|
||||
void Application::loadLODToolsDialog() {
|
||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet(SYSTEM_TABLET));
|
||||
|
@ -7427,51 +7406,6 @@ bool Application::isForeground() const {
|
|||
return _isForeground && !_window->isMinimized();
|
||||
}
|
||||
|
||||
void Application::sendMousePressOnEntity(QUuid id, PointerEvent event) {
|
||||
EntityItemID entityItemID(id);
|
||||
emit getEntities()->mousePressOnEntity(entityItemID, event);
|
||||
}
|
||||
|
||||
void Application::sendMouseMoveOnEntity(QUuid id, PointerEvent event) {
|
||||
EntityItemID entityItemID(id);
|
||||
emit getEntities()->mouseMoveOnEntity(entityItemID, event);
|
||||
}
|
||||
|
||||
void Application::sendMouseReleaseOnEntity(QUuid id, PointerEvent event) {
|
||||
EntityItemID entityItemID(id);
|
||||
emit getEntities()->mouseReleaseOnEntity(entityItemID, event);
|
||||
}
|
||||
|
||||
void Application::sendClickDownOnEntity(QUuid id, PointerEvent event) {
|
||||
EntityItemID entityItemID(id);
|
||||
emit getEntities()->clickDownOnEntity(entityItemID, event);
|
||||
}
|
||||
|
||||
void Application::sendHoldingClickOnEntity(QUuid id, PointerEvent event) {
|
||||
EntityItemID entityItemID(id);
|
||||
emit getEntities()->holdingClickOnEntity(entityItemID, event);
|
||||
}
|
||||
|
||||
void Application::sendClickReleaseOnEntity(QUuid id, PointerEvent event) {
|
||||
EntityItemID entityItemID(id);
|
||||
emit getEntities()->clickReleaseOnEntity(entityItemID, event);
|
||||
}
|
||||
|
||||
void Application::sendHoverEnterEntity(QUuid id, PointerEvent event) {
|
||||
EntityItemID entityItemID(id);
|
||||
emit getEntities()->hoverEnterEntity(entityItemID, event);
|
||||
}
|
||||
|
||||
void Application::sendHoverOverEntity(QUuid id, PointerEvent event) {
|
||||
EntityItemID entityItemID(id);
|
||||
emit getEntities()->hoverOverEntity(entityItemID, event);
|
||||
}
|
||||
|
||||
void Application::sendHoverLeaveEntity(QUuid id, PointerEvent event) {
|
||||
EntityItemID entityItemID(id);
|
||||
emit getEntities()->hoverLeaveEntity(entityItemID, event);
|
||||
}
|
||||
|
||||
// FIXME? perhaps two, one for the main thread and one for the offscreen UI rendering thread?
|
||||
static const int UI_RESERVED_THREADS = 1;
|
||||
// Windows won't let you have all the cores
|
||||
|
|
|
@ -277,18 +277,6 @@ public:
|
|||
gpu::TexturePointer getDefaultSkyboxTexture() const { return _defaultSkyboxTexture; }
|
||||
gpu::TexturePointer getDefaultSkyboxAmbientTexture() const { return _defaultSkyboxAmbientTexture; }
|
||||
|
||||
Q_INVOKABLE void sendMousePressOnEntity(QUuid id, PointerEvent event);
|
||||
Q_INVOKABLE void sendMouseMoveOnEntity(QUuid id, PointerEvent event);
|
||||
Q_INVOKABLE void sendMouseReleaseOnEntity(QUuid id, PointerEvent event);
|
||||
|
||||
Q_INVOKABLE void sendClickDownOnEntity(QUuid id, PointerEvent event);
|
||||
Q_INVOKABLE void sendHoldingClickOnEntity(QUuid id, PointerEvent event);
|
||||
Q_INVOKABLE void sendClickReleaseOnEntity(QUuid id, PointerEvent event);
|
||||
|
||||
Q_INVOKABLE void sendHoverEnterEntity(QUuid id, PointerEvent event);
|
||||
Q_INVOKABLE void sendHoverOverEntity(QUuid id, PointerEvent event);
|
||||
Q_INVOKABLE void sendHoverLeaveEntity(QUuid id, PointerEvent event);
|
||||
|
||||
OverlayID getTabletScreenID() const;
|
||||
OverlayID getTabletHomeButtonID() const;
|
||||
QUuid getTabletFrameID() const; // may be an entity or an overlay
|
||||
|
@ -326,6 +314,7 @@ public slots:
|
|||
void toggleEntityScriptServerLogDialog();
|
||||
Q_INVOKABLE void showAssetServerWidget(QString filePath = "");
|
||||
Q_INVOKABLE void loadAddAvatarBookmarkDialog() const;
|
||||
Q_INVOKABLE SharedSoundPointer getSampleSound() const;
|
||||
|
||||
void showDialog(const QUrl& widgetUrl, const QUrl& tabletUrl, const QString& name) const;
|
||||
|
||||
|
@ -388,11 +377,10 @@ public slots:
|
|||
void setKeyboardFocusHighlight(const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions);
|
||||
|
||||
QUuid getKeyboardFocusEntity() const; // thread-safe
|
||||
void setKeyboardFocusEntity(QUuid id);
|
||||
void setKeyboardFocusEntity(EntityItemID entityItemID);
|
||||
void setKeyboardFocusEntity(const EntityItemID& entityItemID);
|
||||
|
||||
OverlayID getKeyboardFocusOverlay();
|
||||
void setKeyboardFocusOverlay(OverlayID overlayID);
|
||||
void setKeyboardFocusOverlay(const OverlayID& overlayID);
|
||||
|
||||
void addAssetToWorldMessageClose();
|
||||
|
||||
|
@ -702,6 +690,7 @@ private:
|
|||
FileScriptingInterface* _fileDownload;
|
||||
AudioInjectorPointer _snapshotSoundInjector;
|
||||
SharedSoundPointer _snapshotSound;
|
||||
SharedSoundPointer _sampleSound;
|
||||
|
||||
DisplayPluginPointer _autoSwitchDisplayModeSupportedHMDPlugin;
|
||||
QString _autoSwitchDisplayModeSupportedHMDPluginName;
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include <GeometryCache.h>
|
||||
#include <OctreeConstants.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <ShapeEntityItem.h>
|
||||
#include <ShapeInfo.h>
|
||||
|
||||
#include "InterfaceLogging.h"
|
||||
#include "world.h"
|
||||
|
@ -393,4 +395,20 @@ void runUnitTests() {
|
|||
}
|
||||
}
|
||||
|
||||
void shapeInfoCalculator(const ShapeEntityItem * const shapeEntity, ShapeInfo &shapeInfo) {
|
||||
|
||||
if (shapeEntity == nullptr) {
|
||||
|
||||
//--EARLY EXIT--
|
||||
return;
|
||||
}
|
||||
|
||||
ShapeInfo::PointCollection pointCollection;
|
||||
ShapeInfo::PointList points;
|
||||
pointCollection.push_back(points);
|
||||
|
||||
GeometryCache::computeSimpleHullPointListForShape((int)shapeEntity->getShape(), shapeEntity->getDimensions(), pointCollection.back());
|
||||
shapeInfo.setPointCollection(pointCollection);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
#include <gpu/Batch.h>
|
||||
#include <render/Forward.h>
|
||||
|
||||
class ShapeEntityItem;
|
||||
class ShapeInfo;
|
||||
|
||||
void renderWorldBox(RenderArgs* args, gpu::Batch& batch);
|
||||
|
||||
void runTimingTests();
|
||||
|
@ -28,4 +31,6 @@ bool rayIntersectsSphere(const glm::vec3& rayStarting, const glm::vec3& rayNorma
|
|||
|
||||
bool pointInSphere(glm::vec3& point, glm::vec3& sphereCenter, double sphereRadius);
|
||||
|
||||
void shapeInfoCalculator(const ShapeEntityItem * const shapeEntity, ShapeInfo &shapeInfo);
|
||||
|
||||
#endif // hifi_Util_h
|
||||
|
|
|
@ -587,14 +587,16 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
MovingEntitiesOperator moveOperator;
|
||||
forEachDescendant([&](SpatiallyNestablePointer object) {
|
||||
// if the queryBox has changed, tell the entity-server
|
||||
if (object->getNestableType() == NestableType::Entity && object->checkAndMaybeUpdateQueryAACube()) {
|
||||
if (object->getNestableType() == NestableType::Entity && object->updateQueryAACube()) {
|
||||
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
|
||||
bool success;
|
||||
AACube newCube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
moveOperator.addEntityToMoveList(entity, newCube);
|
||||
}
|
||||
if (packetSender) {
|
||||
// send an edit packet to update the entity-server about the queryAABox. If it's an
|
||||
// avatar-entity, don't.
|
||||
if (packetSender && !entity->getClientOnly()) {
|
||||
EntityItemProperties properties = entity->getProperties();
|
||||
properties.setQueryAACubeDirty();
|
||||
properties.setLastEdited(now);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// interface/src/ui/overlays
|
||||
//
|
||||
// Created by Zander Otavka on 8/7/15.
|
||||
// Modified by Daniela Fontes on 24/10/17.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
|
@ -13,6 +14,7 @@
|
|||
|
||||
#include <Application.h>
|
||||
#include <Transform.h>
|
||||
#include "avatar/AvatarManager.h"
|
||||
|
||||
void Billboardable::setProperties(const QVariantMap& properties) {
|
||||
auto isFacingAvatar = properties["isFacingAvatar"];
|
||||
|
@ -32,10 +34,11 @@ bool Billboardable::pointTransformAtCamera(Transform& transform, glm::quat offse
|
|||
if (isFacingAvatar()) {
|
||||
glm::vec3 billboardPos = transform.getTranslation();
|
||||
glm::vec3 cameraPos = qApp->getCamera().getPosition();
|
||||
glm::vec3 look = cameraPos - billboardPos;
|
||||
float elevation = -asinf(look.y / glm::length(look));
|
||||
float azimuth = atan2f(look.x, look.z);
|
||||
glm::quat rotation(glm::vec3(elevation, azimuth, 0));
|
||||
// use the referencial from the avatar, y isn't always up
|
||||
glm::vec3 avatarUP = DependencyManager::get<AvatarManager>()->getMyAvatar()->getOrientation()*Vectors::UP;
|
||||
|
||||
glm::quat rotation(conjugate(toQuat(glm::lookAt(cameraPos, billboardPos, avatarUP))));
|
||||
|
||||
transform.setRotation(rotation);
|
||||
transform.postRotate(offsetRotation);
|
||||
return true;
|
||||
|
|
|
@ -34,13 +34,6 @@ ContextOverlayInterface::ContextOverlayInterface() {
|
|||
_tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
_selectionScriptingInterface = DependencyManager::get<SelectionScriptingInterface>();
|
||||
|
||||
_selectionToSceneHandlers[0].initialize("contextOverlayHighlightList");
|
||||
connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[0], &SelectionToSceneHandler::selectedItemsListChanged);
|
||||
for (auto i = 1; i < render::Scene::MAX_OUTLINE_COUNT ; i++) {
|
||||
_selectionToSceneHandlers[i].initialize(QString("contextOverlayHighlightList")+QString::number(i));
|
||||
connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[i], &SelectionToSceneHandler::selectedItemsListChanged);
|
||||
}
|
||||
|
||||
_entityPropertyFlags += PROP_POSITION;
|
||||
_entityPropertyFlags += PROP_ROTATION;
|
||||
_entityPropertyFlags += PROP_MARKETPLACE_ID;
|
||||
|
@ -48,10 +41,10 @@ ContextOverlayInterface::ContextOverlayInterface() {
|
|||
_entityPropertyFlags += PROP_REGISTRATION_POINT;
|
||||
_entityPropertyFlags += PROP_CERTIFICATE_ID;
|
||||
|
||||
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>().data();
|
||||
connect(entityTreeRenderer, SIGNAL(mousePressOnEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(createOrDestroyContextOverlay(const EntityItemID&, const PointerEvent&)));
|
||||
connect(entityTreeRenderer, SIGNAL(hoverEnterEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(contextOverlays_hoverEnterEntity(const EntityItemID&, const PointerEvent&)));
|
||||
connect(entityTreeRenderer, SIGNAL(hoverLeaveEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(contextOverlays_hoverLeaveEntity(const EntityItemID&, const PointerEvent&)));
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>().data();
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity, this, &ContextOverlayInterface::createOrDestroyContextOverlay);
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity, this, &ContextOverlayInterface::contextOverlays_hoverEnterEntity);
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity, this, &ContextOverlayInterface::contextOverlays_hoverLeaveEntity);
|
||||
connect(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"), &TabletProxy::tabletShownChanged, this, [&]() {
|
||||
if (_contextOverlayJustClicked && _hmdScriptingInterface->isMounted()) {
|
||||
QUuid tabletFrameID = _hmdScriptingInterface->getCurrentTabletFrameID();
|
||||
|
@ -64,8 +57,17 @@ ContextOverlayInterface::ContextOverlayInterface() {
|
|||
_contextOverlayJustClicked = false;
|
||||
}
|
||||
});
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>().data();
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::deletingEntity, this, &ContextOverlayInterface::deletingEntity);
|
||||
connect(&qApp->getOverlays(), &Overlays::mousePressOnOverlay, this, &ContextOverlayInterface::contextOverlays_mousePressOnOverlay);
|
||||
connect(&qApp->getOverlays(), &Overlays::hoverEnterOverlay, this, &ContextOverlayInterface::contextOverlays_hoverEnterOverlay);
|
||||
connect(&qApp->getOverlays(), &Overlays::hoverLeaveOverlay, this, &ContextOverlayInterface::contextOverlays_hoverLeaveOverlay);
|
||||
|
||||
_selectionToSceneHandlers[0].initialize("contextOverlayHighlightList");
|
||||
connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[0], &SelectionToSceneHandler::selectedItemsListChanged);
|
||||
for (auto i = 1; i < render::Scene::MAX_OUTLINE_COUNT; i++) {
|
||||
_selectionToSceneHandlers[i].initialize(QString("contextOverlayHighlightList") + QString::number(i));
|
||||
connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[i], &SelectionToSceneHandler::selectedItemsListChanged);
|
||||
}
|
||||
}
|
||||
|
||||
static const uint32_t MOUSE_HW_ID = 0;
|
||||
|
@ -143,8 +145,8 @@ bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID&
|
|||
if (event.getID() == LEFT_HAND_HW_ID) {
|
||||
offsetAngle *= -1.0f;
|
||||
}
|
||||
contextOverlayPosition = (glm::quat(glm::radians(glm::vec3(0.0f, offsetAngle, 0.0f)))) *
|
||||
((cameraPosition + direction * (distance - CONTEXT_OVERLAY_OFFSET_DISTANCE)));
|
||||
contextOverlayPosition = cameraPosition +
|
||||
(glm::quat(glm::radians(glm::vec3(0.0f, offsetAngle, 0.0f)))) * (direction * (distance - CONTEXT_OVERLAY_OFFSET_DISTANCE));
|
||||
contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_SIZE, CONTEXT_OVERLAY_SIZE) * glm::distance(contextOverlayPosition, cameraPosition);
|
||||
}
|
||||
|
||||
|
|
|
@ -96,6 +96,7 @@ void Line3DOverlay::setEnd(const glm::vec3& end) {
|
|||
} else {
|
||||
_direction = glm::vec3(0.0f);
|
||||
}
|
||||
notifyRenderTransformChange();
|
||||
}
|
||||
|
||||
void Line3DOverlay::setLocalEnd(const glm::vec3& localEnd) {
|
||||
|
|
|
@ -717,39 +717,34 @@ bool Overlays::isAddedOverlay(OverlayID id) {
|
|||
}
|
||||
|
||||
void Overlays::sendMousePressOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
|
||||
QMetaObject::invokeMethod(this, "mousePressOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event));
|
||||
mousePressEvent(overlayID, event);
|
||||
}
|
||||
|
||||
void Overlays::sendMouseReleaseOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
|
||||
QMetaObject::invokeMethod(this, "mouseReleaseOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event));
|
||||
mouseReleaseEvent(overlayID, event);
|
||||
}
|
||||
|
||||
void Overlays::sendMouseMoveOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
|
||||
QMetaObject::invokeMethod(this, "mouseMoveOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event));
|
||||
mouseMoveEvent(overlayID, event);
|
||||
}
|
||||
|
||||
void Overlays::sendHoverEnterOverlay(const OverlayID& id, const PointerEvent& event) {
|
||||
QMetaObject::invokeMethod(this, "hoverEnterOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event));
|
||||
void Overlays::sendHoverEnterOverlay(const OverlayID& overlayID, const PointerEvent& event) {
|
||||
emit hoverEnterOverlay(overlayID, event);
|
||||
}
|
||||
|
||||
void Overlays::sendHoverOverOverlay(const OverlayID& id, const PointerEvent& event) {
|
||||
QMetaObject::invokeMethod(this, "hoverOverOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event));
|
||||
void Overlays::sendHoverOverOverlay(const OverlayID& overlayID, const PointerEvent& event) {
|
||||
emit hoverOverOverlay(overlayID, event);
|
||||
}
|
||||
|
||||
void Overlays::sendHoverLeaveOverlay(const OverlayID& id, const PointerEvent& event) {
|
||||
QMetaObject::invokeMethod(this, "hoverLeaveOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event));
|
||||
void Overlays::sendHoverLeaveOverlay(const OverlayID& overlayID, const PointerEvent& event) {
|
||||
hoverLeaveEvent(overlayID, event);
|
||||
}
|
||||
|
||||
OverlayID Overlays::getKeyboardFocusOverlay() {
|
||||
return qApp->getKeyboardFocusOverlay();
|
||||
}
|
||||
|
||||
void Overlays::setKeyboardFocusOverlay(OverlayID id) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setKeyboardFocusOverlay", Q_ARG(OverlayID, id));
|
||||
return;
|
||||
}
|
||||
|
||||
void Overlays::setKeyboardFocusOverlay(const OverlayID& id) {
|
||||
qApp->setKeyboardFocusOverlay(id);
|
||||
}
|
||||
|
||||
|
@ -884,13 +879,35 @@ bool Overlays::mousePressEvent(QMouseEvent* event) {
|
|||
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
||||
|
||||
PointerEvent pointerEvent = calculateOverlayPointerEvent(_currentClickingOnOverlayID, ray, rayPickResult, event, PointerEvent::Press);
|
||||
emit mousePressOnOverlay(_currentClickingOnOverlayID, pointerEvent);
|
||||
mousePressEvent(_currentClickingOnOverlayID, pointerEvent);
|
||||
return true;
|
||||
}
|
||||
// if we didn't press on an overlay, disable overlay keyboard focus
|
||||
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
|
||||
// emit to scripts
|
||||
emit mousePressOffOverlay();
|
||||
return false;
|
||||
}
|
||||
|
||||
void Overlays::mousePressEvent(const OverlayID& overlayID, const PointerEvent& event) {
|
||||
// TODO: generalize this to allow any overlay to recieve events
|
||||
std::shared_ptr<Web3DOverlay> thisOverlay;
|
||||
if (getOverlayType(overlayID) == "web3d") {
|
||||
thisOverlay = std::static_pointer_cast<Web3DOverlay>(getOverlay(overlayID));
|
||||
}
|
||||
if (thisOverlay) {
|
||||
// Focus keyboard on web overlays
|
||||
DependencyManager::get<EntityScriptingInterface>()->setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
|
||||
setKeyboardFocusOverlay(overlayID);
|
||||
|
||||
// Send to web overlay
|
||||
QMetaObject::invokeMethod(thisOverlay.get(), "handlePointerEvent", Q_ARG(PointerEvent, event));
|
||||
}
|
||||
|
||||
// emit to scripts
|
||||
emit mousePressOnOverlay(overlayID, event);
|
||||
}
|
||||
|
||||
bool Overlays::mouseDoublePressEvent(QMouseEvent* event) {
|
||||
PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent");
|
||||
|
||||
|
@ -900,13 +917,30 @@ bool Overlays::mouseDoublePressEvent(QMouseEvent* event) {
|
|||
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
||||
|
||||
auto pointerEvent = calculateOverlayPointerEvent(_currentClickingOnOverlayID, ray, rayPickResult, event, PointerEvent::Press);
|
||||
// emit to scripts
|
||||
emit mouseDoublePressOnOverlay(_currentClickingOnOverlayID, pointerEvent);
|
||||
return true;
|
||||
}
|
||||
// emit to scripts
|
||||
emit mouseDoublePressOffOverlay();
|
||||
return false;
|
||||
}
|
||||
|
||||
void Overlays::hoverLeaveEvent(const OverlayID& overlayID, const PointerEvent& event) {
|
||||
// TODO: generalize this to allow any overlay to recieve events
|
||||
std::shared_ptr<Web3DOverlay> thisOverlay;
|
||||
if (getOverlayType(overlayID) == "web3d") {
|
||||
thisOverlay = std::static_pointer_cast<Web3DOverlay>(getOverlay(overlayID));
|
||||
}
|
||||
if (thisOverlay) {
|
||||
// Send to web overlay
|
||||
QMetaObject::invokeMethod(thisOverlay.get(), "hoverLeaveOverlay", Q_ARG(PointerEvent, event));
|
||||
}
|
||||
|
||||
// emit to scripts
|
||||
emit hoverLeaveOverlay(overlayID, event);
|
||||
}
|
||||
|
||||
bool Overlays::mouseReleaseEvent(QMouseEvent* event) {
|
||||
PerformanceTimer perfTimer("Overlays::mouseReleaseEvent");
|
||||
|
||||
|
@ -914,13 +948,28 @@ bool Overlays::mouseReleaseEvent(QMouseEvent* event) {
|
|||
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray);
|
||||
if (rayPickResult.intersects) {
|
||||
auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Release);
|
||||
emit mouseReleaseOnOverlay(rayPickResult.overlayID, pointerEvent);
|
||||
mouseReleaseEvent(rayPickResult.overlayID, pointerEvent);
|
||||
}
|
||||
|
||||
_currentClickingOnOverlayID = UNKNOWN_OVERLAY_ID;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Overlays::mouseReleaseEvent(const OverlayID& overlayID, const PointerEvent& event) {
|
||||
// TODO: generalize this to allow any overlay to recieve events
|
||||
std::shared_ptr<Web3DOverlay> thisOverlay;
|
||||
if (getOverlayType(overlayID) == "web3d") {
|
||||
thisOverlay = std::static_pointer_cast<Web3DOverlay>(getOverlay(overlayID));
|
||||
}
|
||||
if (thisOverlay) {
|
||||
// Send to web overlay
|
||||
QMetaObject::invokeMethod(thisOverlay.get(), "handlePointerEvent", Q_ARG(PointerEvent, event));
|
||||
}
|
||||
|
||||
// emit to scripts
|
||||
emit mouseReleaseOnOverlay(overlayID, event);
|
||||
}
|
||||
|
||||
bool Overlays::mouseMoveEvent(QMouseEvent* event) {
|
||||
PerformanceTimer perfTimer("Overlays::mouseMoveEvent");
|
||||
|
||||
|
@ -928,12 +977,12 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) {
|
|||
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray);
|
||||
if (rayPickResult.intersects) {
|
||||
auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Move);
|
||||
emit mouseMoveOnOverlay(rayPickResult.overlayID, pointerEvent);
|
||||
mouseMoveEvent(rayPickResult.overlayID, pointerEvent);
|
||||
|
||||
// If previously hovering over a different overlay then leave hover on that overlay.
|
||||
if (_currentHoverOverOverlayID != UNKNOWN_OVERLAY_ID && rayPickResult.overlayID != _currentHoverOverOverlayID) {
|
||||
auto pointerEvent = calculateOverlayPointerEvent(_currentHoverOverOverlayID, ray, rayPickResult, event, PointerEvent::Move);
|
||||
emit hoverLeaveOverlay(_currentHoverOverOverlayID, pointerEvent);
|
||||
hoverLeaveEvent(_currentHoverOverOverlayID, pointerEvent);
|
||||
}
|
||||
|
||||
// If hovering over a new overlay then enter hover on that overlay.
|
||||
|
@ -949,7 +998,7 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) {
|
|||
// If previously hovering an overlay then leave hover.
|
||||
if (_currentHoverOverOverlayID != UNKNOWN_OVERLAY_ID) {
|
||||
auto pointerEvent = calculateOverlayPointerEvent(_currentHoverOverOverlayID, ray, rayPickResult, event, PointerEvent::Move);
|
||||
emit hoverLeaveOverlay(_currentHoverOverOverlayID, pointerEvent);
|
||||
hoverLeaveEvent(_currentHoverOverOverlayID, pointerEvent);
|
||||
|
||||
_currentHoverOverOverlayID = UNKNOWN_OVERLAY_ID;
|
||||
}
|
||||
|
@ -957,6 +1006,21 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void Overlays::mouseMoveEvent(const OverlayID& overlayID, const PointerEvent& event) {
|
||||
// TODO: generalize this to allow any overlay to recieve events
|
||||
std::shared_ptr<Web3DOverlay> thisOverlay;
|
||||
if (getOverlayType(overlayID) == "web3d") {
|
||||
thisOverlay = std::static_pointer_cast<Web3DOverlay>(getOverlay(overlayID));
|
||||
}
|
||||
if (thisOverlay) {
|
||||
// Send to web overlay
|
||||
QMetaObject::invokeMethod(thisOverlay.get(), "handlePointerEvent", Q_ARG(PointerEvent, event));
|
||||
}
|
||||
|
||||
// emit to scripts
|
||||
emit mouseMoveOnOverlay(overlayID, event);
|
||||
}
|
||||
|
||||
QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
|
||||
QVector<QUuid> result;
|
||||
//if (QThread::currentThread() != thread()) {
|
||||
|
|
|
@ -107,6 +107,11 @@ public:
|
|||
bool mouseReleaseEvent(QMouseEvent* event);
|
||||
bool mouseMoveEvent(QMouseEvent* event);
|
||||
|
||||
void mousePressEvent(const OverlayID& overlayID, const PointerEvent& event);
|
||||
void mouseMoveEvent(const OverlayID& overlayID, const PointerEvent& event);
|
||||
void mouseReleaseEvent(const OverlayID& overlayID, const PointerEvent& event);
|
||||
void hoverLeaveEvent(const OverlayID& overlayID, const PointerEvent& event);
|
||||
|
||||
void cleanupAllOverlays();
|
||||
|
||||
public slots:
|
||||
|
@ -298,12 +303,12 @@ public slots:
|
|||
void sendMouseReleaseOnOverlay(const OverlayID& overlayID, const PointerEvent& event);
|
||||
void sendMouseMoveOnOverlay(const OverlayID& overlayID, const PointerEvent& event);
|
||||
|
||||
void sendHoverEnterOverlay(const OverlayID& id, const PointerEvent& event);
|
||||
void sendHoverOverOverlay(const OverlayID& id, const PointerEvent& event);
|
||||
void sendHoverLeaveOverlay(const OverlayID& id, const PointerEvent& event);
|
||||
void sendHoverEnterOverlay(const OverlayID& overlayID, const PointerEvent& event);
|
||||
void sendHoverOverOverlay(const OverlayID& overlayID, const PointerEvent& event);
|
||||
void sendHoverLeaveOverlay(const OverlayID& overlayID, const PointerEvent& event);
|
||||
|
||||
OverlayID getKeyboardFocusOverlay();
|
||||
void setKeyboardFocusOverlay(OverlayID id);
|
||||
void setKeyboardFocusOverlay(const OverlayID& id);
|
||||
|
||||
signals:
|
||||
/**jsdoc
|
||||
|
|
|
@ -125,11 +125,7 @@ void Web3DOverlay::destroyWebSurface() {
|
|||
}
|
||||
|
||||
_webSurface->pause();
|
||||
auto overlays = &(qApp->getOverlays());
|
||||
QObject::disconnect(overlays, &Overlays::mousePressOnOverlay, this, nullptr);
|
||||
QObject::disconnect(overlays, &Overlays::mouseReleaseOnOverlay, this, nullptr);
|
||||
QObject::disconnect(overlays, &Overlays::mouseMoveOnOverlay, this, nullptr);
|
||||
QObject::disconnect(overlays, &Overlays::hoverLeaveOverlay, this, nullptr);
|
||||
|
||||
QObject::disconnect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent);
|
||||
QObject::disconnect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived);
|
||||
DependencyManager::get<OffscreenQmlSurfaceCache>()->release(QML, _webSurface);
|
||||
|
@ -160,35 +156,17 @@ void Web3DOverlay::buildWebSurface() {
|
|||
_webSurface->resume();
|
||||
});
|
||||
|
||||
auto selfOverlayID = getOverlayID();
|
||||
std::weak_ptr<Web3DOverlay> weakSelf = std::dynamic_pointer_cast<Web3DOverlay>(qApp->getOverlays().getOverlay(selfOverlayID));
|
||||
auto forwardPointerEvent = [=](OverlayID overlayID, const PointerEvent& event) {
|
||||
auto self = weakSelf.lock();
|
||||
if (self && overlayID == selfOverlayID) {
|
||||
self->handlePointerEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
auto overlays = &(qApp->getOverlays());
|
||||
QObject::connect(overlays, &Overlays::mousePressOnOverlay, this, forwardPointerEvent);
|
||||
QObject::connect(overlays, &Overlays::mouseReleaseOnOverlay, this, forwardPointerEvent);
|
||||
QObject::connect(overlays, &Overlays::mouseMoveOnOverlay, this, forwardPointerEvent);
|
||||
QObject::connect(overlays, &Overlays::hoverLeaveOverlay, this, [=](OverlayID overlayID, const PointerEvent& event) {
|
||||
auto self = weakSelf.lock();
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
if (overlayID == selfOverlayID && (self->_pressed || (!self->_activeTouchPoints.empty() && self->_touchBeginAccepted))) {
|
||||
PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(),
|
||||
event.getButton(), event.getButtons(), event.getKeyboardModifiers());
|
||||
forwardPointerEvent(overlayID, endEvent);
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent);
|
||||
QObject::connect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived);
|
||||
}
|
||||
|
||||
void Web3DOverlay::hoverLeaveOverlay(const PointerEvent& event) {
|
||||
if ((_pressed || (!_activeTouchPoints.empty() && _touchBeginAccepted))) {
|
||||
PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(),
|
||||
event.getButton(), event.getButtons(), event.getKeyboardModifiers());
|
||||
handlePointerEvent(endEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void Web3DOverlay::update(float deltatime) {
|
||||
if (_webSurface) {
|
||||
|
|
|
@ -39,7 +39,8 @@ public:
|
|||
|
||||
QObject* getEventHandler();
|
||||
void setProxyWindow(QWindow* proxyWindow);
|
||||
void handlePointerEvent(const PointerEvent& event);
|
||||
Q_INVOKABLE void hoverLeaveOverlay(const PointerEvent& event);
|
||||
Q_INVOKABLE void handlePointerEvent(const PointerEvent& event);
|
||||
void handlePointerEventAsTouch(const PointerEvent& event);
|
||||
void handlePointerEventAsMouse(const PointerEvent& event);
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ class SoundCache : public ResourceCache, public Dependency {
|
|||
|
||||
public:
|
||||
Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url);
|
||||
|
||||
protected:
|
||||
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
|
||||
const void* extra) override;
|
||||
|
|
|
@ -72,7 +72,7 @@ void JSBaker::bake() {
|
|||
bool JSBaker::bakeJS(const QByteArray& inputFile, QByteArray& outputFile) {
|
||||
// Read from inputFile and write to outputFile per character
|
||||
QTextStream in(inputFile, QIODevice::ReadOnly);
|
||||
QTextStream out(outputFile, QIODevice::WriteOnly);
|
||||
QTextStream out(&outputFile, QIODevice::WriteOnly);
|
||||
|
||||
// Algorithm requires the knowledge of previous and next character for each character read
|
||||
QChar currentCharacter;
|
||||
|
|
|
@ -234,7 +234,8 @@ void CompositorHelper::handleLeaveEvent() {
|
|||
|
||||
bool CompositorHelper::handleRealMouseMoveEvent(bool sendFakeEvent) {
|
||||
// If the mouse move came from a capture mouse related move, we completely ignore it.
|
||||
if (_ignoreMouseMove) {
|
||||
// Note: if not going to synthesize event - do not touch _ignoreMouseMove flag
|
||||
if (_ignoreMouseMove && sendFakeEvent) {
|
||||
_ignoreMouseMove = false;
|
||||
return true; // swallow the event
|
||||
}
|
||||
|
@ -246,7 +247,12 @@ bool CompositorHelper::handleRealMouseMoveEvent(bool sendFakeEvent) {
|
|||
auto changeInRealMouse = newPosition - _lastKnownRealMouse;
|
||||
auto newReticlePosition = _reticlePositionInHMD + toGlm(changeInRealMouse);
|
||||
setReticlePosition(newReticlePosition, sendFakeEvent);
|
||||
_ignoreMouseMove = true;
|
||||
|
||||
// Note: if not going to synthesize event - do not touch _ignoreMouseMove flag
|
||||
if (sendFakeEvent) {
|
||||
_ignoreMouseMove = true;
|
||||
}
|
||||
|
||||
QCursor::setPos(QPoint(_lastKnownRealMouse.x(), _lastKnownRealMouse.y())); // move cursor back to where it was
|
||||
return true; // swallow the event
|
||||
} else {
|
||||
|
|
|
@ -418,6 +418,19 @@ void OpenGLDisplayPlugin::customizeContext() {
|
|||
_hudPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
{
|
||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
||||
auto ps = gpu::StandardShaderLib::getDrawTextureMirroredXPS();
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::Shader::makeProgram(*program);
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
state->setBlendFunction(true,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
_mirrorHUDPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
{
|
||||
auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
|
||||
auto ps = gpu::StandardShaderLib::getDrawTexturePS();
|
||||
|
@ -438,6 +451,7 @@ void OpenGLDisplayPlugin::uncustomizeContext() {
|
|||
_presentPipeline.reset();
|
||||
_cursorPipeline.reset();
|
||||
_hudPipeline.reset();
|
||||
_mirrorHUDPipeline.reset();
|
||||
_compositeFramebuffer.reset();
|
||||
withPresentThreadLock([&] {
|
||||
_currentFrame.reset();
|
||||
|
@ -562,11 +576,11 @@ void OpenGLDisplayPlugin::updateFrameData() {
|
|||
});
|
||||
}
|
||||
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> OpenGLDisplayPlugin::getHUDOperator() {
|
||||
return [this](gpu::Batch& batch, const gpu::TexturePointer& hudTexture) {
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> OpenGLDisplayPlugin::getHUDOperator() {
|
||||
return [this](gpu::Batch& batch, const gpu::TexturePointer& hudTexture, bool mirror) {
|
||||
if (_hudPipeline) {
|
||||
batch.enableStereo(false);
|
||||
batch.setPipeline(_hudPipeline);
|
||||
batch.setPipeline(mirror ? _mirrorHUDPipeline : _hudPipeline);
|
||||
batch.setResourceTexture(0, hudTexture);
|
||||
if (isStereo()) {
|
||||
for_each_eye([&](Eye eye) {
|
||||
|
|
|
@ -95,7 +95,7 @@ protected:
|
|||
virtual QThread::Priority getPresentPriority() { return QThread::HighPriority; }
|
||||
virtual void compositeLayers();
|
||||
virtual void compositeScene();
|
||||
virtual std::function<void(gpu::Batch&, const gpu::TexturePointer&)> getHUDOperator();
|
||||
virtual std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> getHUDOperator();
|
||||
virtual void compositePointer();
|
||||
virtual void compositeExtra() {};
|
||||
|
||||
|
@ -140,6 +140,8 @@ protected:
|
|||
gpu::Frame* _lastFrame { nullptr };
|
||||
gpu::FramebufferPointer _compositeFramebuffer;
|
||||
gpu::PipelinePointer _hudPipeline;
|
||||
gpu::PipelinePointer _mirrorHUDPipeline;
|
||||
gpu::ShaderPointer _mirrorHUDPS;
|
||||
gpu::PipelinePointer _simplePipeline;
|
||||
gpu::PipelinePointer _presentPipeline;
|
||||
gpu::PipelinePointer _cursorPipeline;
|
||||
|
|
|
@ -419,9 +419,9 @@ void HmdDisplayPlugin::HUDRenderer::updatePipeline() {
|
|||
}
|
||||
}
|
||||
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> HmdDisplayPlugin::HUDRenderer::render(HmdDisplayPlugin& plugin) {
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> HmdDisplayPlugin::HUDRenderer::render(HmdDisplayPlugin& plugin) {
|
||||
updatePipeline();
|
||||
return [this](gpu::Batch& batch, const gpu::TexturePointer& hudTexture) {
|
||||
return [this](gpu::Batch& batch, const gpu::TexturePointer& hudTexture, bool mirror) {
|
||||
if (pipeline) {
|
||||
batch.setPipeline(pipeline);
|
||||
|
||||
|
@ -436,7 +436,11 @@ std::function<void(gpu::Batch&, const gpu::TexturePointer&)> HmdDisplayPlugin::H
|
|||
batch.setUniformBuffer(uniformsLocation, uniformsBuffer);
|
||||
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
batch.setModelTransform(compositorHelper->getUiTransform());
|
||||
glm::mat4 modelTransform = compositorHelper->getUiTransform();
|
||||
if (mirror) {
|
||||
modelTransform = glm::scale(modelTransform, glm::vec3(-1, 1, 1));
|
||||
}
|
||||
batch.setModelTransform(modelTransform);
|
||||
batch.setResourceTexture(0, hudTexture);
|
||||
|
||||
batch.drawIndexed(gpu::TRIANGLES, indexCount);
|
||||
|
@ -468,7 +472,7 @@ void HmdDisplayPlugin::compositePointer() {
|
|||
});
|
||||
}
|
||||
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> HmdDisplayPlugin::getHUDOperator() {
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> HmdDisplayPlugin::getHUDOperator() {
|
||||
return _hudRenderer.render(*this);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ protected:
|
|||
|
||||
bool internalActivate() override;
|
||||
void internalDeactivate() override;
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> getHUDOperator() override;
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> getHUDOperator() override;
|
||||
void compositePointer() override;
|
||||
void internalPresent() override;
|
||||
void customizeContext() override;
|
||||
|
@ -116,6 +116,6 @@ private:
|
|||
|
||||
void build();
|
||||
void updatePipeline();
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> render(HmdDisplayPlugin& plugin);
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> render(HmdDisplayPlugin& plugin);
|
||||
} _hudRenderer;
|
||||
};
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include "EntitiesRendererLogging.h"
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
#include "RenderableWebEntityItem.h"
|
||||
|
||||
size_t std::hash<EntityItemID>::operator()(const EntityItemID& id) const { return qHash(id); }
|
||||
std::function<bool()> EntityTreeRenderer::_entitiesShouldFadeFunction;
|
||||
|
||||
|
@ -55,6 +57,32 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
|||
EntityRenderer::initEntityRenderers();
|
||||
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID;
|
||||
_currentClickingOnEntityID = UNKNOWN_ENTITY_ID;
|
||||
|
||||
// Forward mouse events to web entities
|
||||
auto handlePointerEvent = [&](const EntityItemID& entityID, const PointerEvent& event) {
|
||||
std::shared_ptr<render::entities::WebEntityRenderer> thisEntity;
|
||||
auto entity = getEntity(entityID);
|
||||
if (entity && entity->getType() == EntityTypes::Web) {
|
||||
thisEntity = std::static_pointer_cast<render::entities::WebEntityRenderer>(renderableForEntityId(entityID));
|
||||
}
|
||||
if (thisEntity) {
|
||||
QMetaObject::invokeMethod(thisEntity.get(), "handlePointerEvent", Q_ARG(PointerEvent, event));
|
||||
}
|
||||
};
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, this, handlePointerEvent);
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, handlePointerEvent);
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, handlePointerEvent);
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, this, [&](const EntityItemID& entityID, const PointerEvent& event) {
|
||||
std::shared_ptr<render::entities::WebEntityRenderer> thisEntity;
|
||||
auto entity = getEntity(entityID);
|
||||
if (entity && entity->getType() == EntityTypes::Web) {
|
||||
thisEntity = std::static_pointer_cast<render::entities::WebEntityRenderer>(renderableForEntityId(entityID));
|
||||
}
|
||||
if (thisEntity) {
|
||||
QMetaObject::invokeMethod(thisEntity.get(), "hoverLeaveEntity", Q_ARG(PointerEvent, event));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
EntityTreeRenderer::~EntityTreeRenderer() {
|
||||
|
@ -78,13 +106,49 @@ render::ItemID EntityTreeRenderer::renderableIdForEntityId(const EntityItemID& i
|
|||
int EntityTreeRenderer::_entitiesScriptEngineCount = 0;
|
||||
|
||||
void EntityTreeRenderer::resetEntitiesScriptEngine() {
|
||||
auto oldEngine = _entitiesScriptEngine;
|
||||
_entitiesScriptEngine = scriptEngineFactory(ScriptEngine::ENTITY_CLIENT_SCRIPT, NO_SCRIPT,
|
||||
QString("about:Entities %1").arg(++_entitiesScriptEngineCount));
|
||||
_scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine);
|
||||
_entitiesScriptEngine->runInThread();
|
||||
auto entitiesScriptEngineProvider = qSharedPointerCast<EntitiesScriptEngineProvider>(_entitiesScriptEngine);
|
||||
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(entitiesScriptEngineProvider);
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
entityScriptingInterface->setEntitiesScriptEngine(entitiesScriptEngineProvider);
|
||||
|
||||
// Connect mouse events to entity script callbacks
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "mousePressOnEntity", event);
|
||||
});
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseDoublePressOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "mouseDoublePressOnEntity", event);
|
||||
});
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "mouseMoveOnEntity", event);
|
||||
// FIXME: this is a duplicate of mouseMoveOnEntity, but it seems like some scripts might use this naming
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "mouseMoveEvent", event);
|
||||
});
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "mouseReleaseOnEntity", event);
|
||||
});
|
||||
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "clickDownOnEntity", event);
|
||||
});
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::holdingClickOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "holdingClickOnEntity", event);
|
||||
});
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickReleaseOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "clickReleaseOnEntity", event);
|
||||
});
|
||||
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "hoverEnterEntity", event);
|
||||
});
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverOverEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "hoverOverEntity", event);
|
||||
});
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "hoverLeaveEntity", event);
|
||||
});
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::clear() {
|
||||
|
@ -264,8 +328,7 @@ void EntityTreeRenderer::update(bool simulate) {
|
|||
// not yet released the hold then this is still considered a holdingClickOnEntity event
|
||||
// and we want to simulate this message here as well as in mouse move
|
||||
if (_lastPointerEventValid && !_currentClickingOnEntityID.isInvalidID()) {
|
||||
emit holdingClickOnEntity(_currentClickingOnEntityID, _lastPointerEvent);
|
||||
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "holdingClickOnEntity", _lastPointerEvent);
|
||||
emit DependencyManager::get<EntityScriptingInterface>()->holdingClickOnEntity(_currentClickingOnEntityID, _lastPointerEvent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -435,19 +498,6 @@ void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const Sha
|
|||
}
|
||||
|
||||
void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityScriptingInterface) {
|
||||
|
||||
connect(this, &EntityTreeRenderer::mousePressOnEntity, entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity);
|
||||
connect(this, &EntityTreeRenderer::mouseMoveOnEntity, entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity);
|
||||
connect(this, &EntityTreeRenderer::mouseReleaseOnEntity, entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity);
|
||||
|
||||
connect(this, &EntityTreeRenderer::clickDownOnEntity, entityScriptingInterface, &EntityScriptingInterface::clickDownOnEntity);
|
||||
connect(this, &EntityTreeRenderer::holdingClickOnEntity, entityScriptingInterface, &EntityScriptingInterface::holdingClickOnEntity);
|
||||
connect(this, &EntityTreeRenderer::clickReleaseOnEntity, entityScriptingInterface, &EntityScriptingInterface::clickReleaseOnEntity);
|
||||
|
||||
connect(this, &EntityTreeRenderer::hoverEnterEntity, entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity);
|
||||
connect(this, &EntityTreeRenderer::hoverOverEntity, entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity);
|
||||
connect(this, &EntityTreeRenderer::hoverLeaveEntity, entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity);
|
||||
|
||||
connect(this, &EntityTreeRenderer::enterEntity, entityScriptingInterface, &EntityScriptingInterface::enterEntity);
|
||||
connect(this, &EntityTreeRenderer::leaveEntity, entityScriptingInterface, &EntityScriptingInterface::leaveEntity);
|
||||
connect(this, &EntityTreeRenderer::collisionWithEntity, entityScriptingInterface, &EntityScriptingInterface::collisionWithEntity);
|
||||
|
@ -516,13 +566,11 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
|
|||
}
|
||||
|
||||
PerformanceTimer perfTimer("EntityTreeRenderer::mousePressEvent");
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
PickRay ray = _viewState->computePickRay(event->x(), event->y());
|
||||
RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID);
|
||||
if (rayPickResult.intersects) {
|
||||
//qCDebug(entitiesrenderer) << "mousePressEvent over entity:" << rayPickResult.entityID;
|
||||
|
||||
auto entity = getTree()->findEntityByEntityItemID(rayPickResult.entityID);
|
||||
auto properties = entity->getProperties();
|
||||
if (rayPickResult.intersects && rayPickResult.entity) {
|
||||
auto properties = rayPickResult.entity->getProperties();
|
||||
QString urlString = properties.getHref();
|
||||
QUrl url = QUrl(urlString, QUrl::StrictMode);
|
||||
if (url.isValid() && !url.isEmpty()){
|
||||
|
@ -536,23 +584,16 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
|
|||
toPointerButton(*event), toPointerButtons(*event),
|
||||
Qt::NoModifier); // TODO -- check for modifier keys?
|
||||
|
||||
emit mousePressOnEntity(rayPickResult.entityID, pointerEvent);
|
||||
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mousePressOnEntity", pointerEvent);
|
||||
}
|
||||
emit entityScriptingInterface->mousePressOnEntity(rayPickResult.entityID, pointerEvent);
|
||||
|
||||
_currentClickingOnEntityID = rayPickResult.entityID;
|
||||
emit clickDownOnEntity(_currentClickingOnEntityID, pointerEvent);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "clickDownOnEntity", pointerEvent);
|
||||
}
|
||||
emit entityScriptingInterface->clickDownOnEntity(_currentClickingOnEntityID, pointerEvent);
|
||||
|
||||
_lastPointerEvent = pointerEvent;
|
||||
_lastPointerEventValid = true;
|
||||
|
||||
} else {
|
||||
emit mousePressOffEntity();
|
||||
emit entityScriptingInterface->mousePressOffEntity();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -564,34 +605,25 @@ void EntityTreeRenderer::mouseDoublePressEvent(QMouseEvent* event) {
|
|||
}
|
||||
|
||||
PerformanceTimer perfTimer("EntityTreeRenderer::mouseDoublePressEvent");
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
PickRay ray = _viewState->computePickRay(event->x(), event->y());
|
||||
RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID);
|
||||
if (rayPickResult.intersects) {
|
||||
//qCDebug(entitiesrenderer) << "mouseDoublePressEvent over entity:" << rayPickResult.entityID;
|
||||
|
||||
if (rayPickResult.intersects && rayPickResult.entity) {
|
||||
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
|
||||
PointerEvent pointerEvent(PointerEvent::Press, MOUSE_POINTER_ID,
|
||||
pos2D, rayPickResult.intersection,
|
||||
rayPickResult.surfaceNormal, ray.direction,
|
||||
toPointerButton(*event), toPointerButtons(*event), Qt::NoModifier);
|
||||
|
||||
emit mouseDoublePressOnEntity(rayPickResult.entityID, pointerEvent);
|
||||
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseDoublePressOnEntity", pointerEvent);
|
||||
}
|
||||
emit entityScriptingInterface->mouseDoublePressOnEntity(rayPickResult.entityID, pointerEvent);
|
||||
|
||||
_currentClickingOnEntityID = rayPickResult.entityID;
|
||||
emit clickDownOnEntity(_currentClickingOnEntityID, pointerEvent);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "doubleclickOnEntity", pointerEvent);
|
||||
}
|
||||
emit entityScriptingInterface->clickDownOnEntity(_currentClickingOnEntityID, pointerEvent);
|
||||
|
||||
_lastPointerEvent = pointerEvent;
|
||||
_lastPointerEventValid = true;
|
||||
|
||||
} else {
|
||||
emit mouseDoublePressOffEntity();
|
||||
emit entityScriptingInterface->mouseDoublePressOffEntity();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -603,9 +635,10 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
|
|||
}
|
||||
|
||||
PerformanceTimer perfTimer("EntityTreeRenderer::mouseReleaseEvent");
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
PickRay ray = _viewState->computePickRay(event->x(), event->y());
|
||||
RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID);
|
||||
if (rayPickResult.intersects) {
|
||||
if (rayPickResult.intersects && rayPickResult.entity) {
|
||||
//qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
|
||||
|
||||
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
|
||||
|
@ -615,31 +648,23 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
|
|||
toPointerButton(*event), toPointerButtons(*event),
|
||||
Qt::NoModifier); // TODO -- check for modifier keys?
|
||||
|
||||
emit mouseReleaseOnEntity(rayPickResult.entityID, pointerEvent);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseReleaseOnEntity", pointerEvent);
|
||||
}
|
||||
emit entityScriptingInterface->mouseReleaseOnEntity(rayPickResult.entityID, pointerEvent);
|
||||
|
||||
_lastPointerEvent = pointerEvent;
|
||||
_lastPointerEventValid = true;
|
||||
}
|
||||
|
||||
// Even if we're no longer intersecting with an entity, if we started clicking on it, and now
|
||||
// we're releasing the button, then this is considered a clickOn event
|
||||
// we're releasing the button, then this is considered a clickReleaseOn event
|
||||
if (!_currentClickingOnEntityID.isInvalidID()) {
|
||||
|
||||
auto entity = getTree()->findEntityByID(_currentClickingOnEntityID);
|
||||
glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult);
|
||||
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
|
||||
PointerEvent pointerEvent(PointerEvent::Release, MOUSE_POINTER_ID,
|
||||
pos2D, rayPickResult.intersection,
|
||||
rayPickResult.surfaceNormal, ray.direction,
|
||||
toPointerButton(*event), toPointerButtons(*event),
|
||||
Qt::NoModifier); // TODO -- check for modifier keys?
|
||||
|
||||
emit clickReleaseOnEntity(_currentClickingOnEntityID, pointerEvent);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "clickReleaseOnEntity", pointerEvent);
|
||||
}
|
||||
emit entityScriptingInterface->clickReleaseOnEntity(_currentClickingOnEntityID, pointerEvent);
|
||||
}
|
||||
|
||||
// makes it the unknown ID, we just released so we can't be clicking on anything
|
||||
|
@ -654,9 +679,10 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
|
|||
}
|
||||
|
||||
PerformanceTimer perfTimer("EntityTreeRenderer::mouseMoveEvent");
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
PickRay ray = _viewState->computePickRay(event->x(), event->y());
|
||||
RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID);
|
||||
if (rayPickResult.intersects) {
|
||||
if (rayPickResult.intersects && rayPickResult.entity) {
|
||||
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
|
||||
PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID,
|
||||
pos2D, rayPickResult.intersection,
|
||||
|
@ -664,48 +690,32 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
|
|||
toPointerButton(*event), toPointerButtons(*event),
|
||||
Qt::NoModifier); // TODO -- check for modifier keys?
|
||||
|
||||
emit mouseMoveOnEntity(rayPickResult.entityID, pointerEvent);
|
||||
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveEvent", pointerEvent);
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveOnEntity", pointerEvent);
|
||||
}
|
||||
emit entityScriptingInterface->mouseMoveOnEntity(rayPickResult.entityID, pointerEvent);
|
||||
|
||||
// handle the hover logic...
|
||||
|
||||
// if we were previously hovering over an entity, and this new entity is not the same as our previous entity
|
||||
// then we need to send the hover leave.
|
||||
if (!_currentHoverOverEntityID.isInvalidID() && rayPickResult.entityID != _currentHoverOverEntityID) {
|
||||
|
||||
auto entity = getTree()->findEntityByID(_currentHoverOverEntityID);
|
||||
glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult);
|
||||
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
|
||||
PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID,
|
||||
pos2D, rayPickResult.intersection,
|
||||
rayPickResult.surfaceNormal, ray.direction,
|
||||
toPointerButton(*event), toPointerButtons(*event),
|
||||
Qt::NoModifier); // TODO -- check for modifier keys?
|
||||
|
||||
emit hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", pointerEvent);
|
||||
}
|
||||
emit entityScriptingInterface->hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent);
|
||||
}
|
||||
|
||||
// If the new hover entity does not match the previous hover entity then we are entering the new one
|
||||
// this is true if the _currentHoverOverEntityID is known or unknown
|
||||
if (rayPickResult.entityID != _currentHoverOverEntityID) {
|
||||
emit hoverEnterEntity(rayPickResult.entityID, pointerEvent);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverEnterEntity", pointerEvent);
|
||||
}
|
||||
emit entityScriptingInterface->hoverEnterEntity(rayPickResult.entityID, pointerEvent);
|
||||
}
|
||||
|
||||
// and finally, no matter what, if we're intersecting an entity then we're definitely hovering over it, and
|
||||
// we should send our hover over event
|
||||
emit hoverOverEntity(rayPickResult.entityID, pointerEvent);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverOverEntity", pointerEvent);
|
||||
}
|
||||
emit entityScriptingInterface->hoverOverEntity(rayPickResult.entityID, pointerEvent);
|
||||
|
||||
// remember what we're hovering over
|
||||
_currentHoverOverEntityID = rayPickResult.entityID;
|
||||
|
@ -718,38 +728,18 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
|
|||
// if we were previously hovering over an entity, and we're no longer hovering over any entity then we need to
|
||||
// send the hover leave for our previous entity
|
||||
if (!_currentHoverOverEntityID.isInvalidID()) {
|
||||
|
||||
auto entity = getTree()->findEntityByID(_currentHoverOverEntityID);
|
||||
glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult);
|
||||
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
|
||||
PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID,
|
||||
pos2D, rayPickResult.intersection,
|
||||
rayPickResult.surfaceNormal, ray.direction,
|
||||
toPointerButton(*event), toPointerButtons(*event),
|
||||
Qt::NoModifier); // TODO -- check for modifier keys?
|
||||
|
||||
emit hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", pointerEvent);
|
||||
}
|
||||
emit entityScriptingInterface->hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent);
|
||||
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID; // makes it the unknown ID
|
||||
}
|
||||
}
|
||||
|
||||
// Even if we're no longer intersecting with an entity, if we started clicking on an entity and we have
|
||||
// not yet released the hold then this is still considered a holdingClickOnEntity event
|
||||
if (!_currentClickingOnEntityID.isInvalidID()) {
|
||||
|
||||
auto entity = getTree()->findEntityByID(_currentClickingOnEntityID);
|
||||
glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult);
|
||||
PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID,
|
||||
pos2D, rayPickResult.intersection,
|
||||
rayPickResult.surfaceNormal, ray.direction,
|
||||
toPointerButton(*event), toPointerButtons(*event),
|
||||
Qt::NoModifier); // TODO -- check for modifier keys?
|
||||
|
||||
emit holdingClickOnEntity(_currentClickingOnEntityID, pointerEvent);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "holdingClickOnEntity", pointerEvent);
|
||||
_lastPointerEvent = pointerEvent;
|
||||
_lastPointerEventValid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,21 +117,6 @@ public:
|
|||
void onEntityChanged(const EntityItemID& id);
|
||||
|
||||
signals:
|
||||
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
void mouseDoublePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
void mouseMoveOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
void mousePressOffEntity();
|
||||
void mouseDoublePressOffEntity();
|
||||
|
||||
void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
void holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
void clickReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
|
||||
void hoverEnterEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
void hoverOverEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
void hoverLeaveEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
|
||||
void enterEntity(const EntityItemID& entityItemID);
|
||||
void leaveEntity(const EntityItemID& entityItemID);
|
||||
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
||||
|
|
|
@ -50,7 +50,9 @@ void EntityRenderer::initEntityRenderers() {
|
|||
REGISTER_ENTITY_TYPE_WITH_FACTORY(PolyVox, RenderablePolyVoxEntityItem::factory)
|
||||
}
|
||||
|
||||
|
||||
const Transform& EntityRenderer::getModelTransform() const {
|
||||
return _modelTransform;
|
||||
}
|
||||
|
||||
void EntityRenderer::makeStatusGetters(const EntityItemPointer& entity, Item::Status::Getters& statusGetters) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
|
|
@ -105,8 +105,10 @@ protected:
|
|||
template<typename T>
|
||||
std::shared_ptr<T> asTypedEntity() { return std::static_pointer_cast<T>(_entity); }
|
||||
|
||||
|
||||
static void makeStatusGetters(const EntityItemPointer& entity, Item::Status::Getters& statusGetters);
|
||||
static std::function<bool()> _entitiesShouldFadeFunction;
|
||||
const Transform& getModelTransform() const;
|
||||
|
||||
SharedSoundPointer _collisionSound;
|
||||
QUuid _changeHandlerId;
|
||||
|
@ -114,7 +116,6 @@ protected:
|
|||
quint64 _fadeStartTime{ usecTimestampNow() };
|
||||
bool _isFading{ _entitiesShouldFadeFunction() };
|
||||
bool _prevIsTransparent { false };
|
||||
Transform _modelTransform;
|
||||
Item::Bound _bound;
|
||||
bool _visible { false };
|
||||
bool _moving { false };
|
||||
|
@ -123,6 +124,10 @@ protected:
|
|||
|
||||
|
||||
private:
|
||||
// The base class relies on comparing the model transform to the entity transform in order
|
||||
// to trigger an update, so the member must not be visible to derived classes as a modifiable
|
||||
// transform
|
||||
Transform _modelTransform;
|
||||
// The rendering code only gets access to the entity in very specific circumstances
|
||||
// i.e. to see if the rendering code needs to update because of a change in state of the
|
||||
// entity. This forces all the rendering code itself to be independent of the entity
|
||||
|
|
|
@ -49,9 +49,10 @@ void LineEntityRenderer::doRender(RenderArgs* args) {
|
|||
PerformanceTimer perfTimer("RenderableLineEntityItem::render");
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
const auto& modelTransform = getModelTransform();
|
||||
Transform transform = Transform();
|
||||
transform.setTranslation(_modelTransform.getTranslation());
|
||||
transform.setRotation(_modelTransform.getRotation());
|
||||
transform.setTranslation(modelTransform.getTranslation());
|
||||
transform.setRotation(modelTransform.getRotation());
|
||||
batch.setModelTransform(transform);
|
||||
if (_linePoints.size() > 1) {
|
||||
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch);
|
||||
|
|
|
@ -695,12 +695,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape) {
|
||||
const void* key = static_cast<const void*>(shape);
|
||||
if (_collisionMeshKey != key) {
|
||||
if (_collisionMeshKey) {
|
||||
collisionMeshCache.releaseMesh(_collisionMeshKey);
|
||||
}
|
||||
_collisionMeshKey = key;
|
||||
// toggle _showCollisionGeometry forces re-evaluation later
|
||||
_showCollisionGeometry = !_showCollisionGeometry;
|
||||
emit requestCollisionGeometryUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1103,6 +1099,10 @@ bool ModelEntityRenderer::needsRenderUpdate() const {
|
|||
if (model->getRenderItemsNeedUpdate()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_needsCollisionGeometryUpdate) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Parent::needsRenderUpdate();
|
||||
}
|
||||
|
@ -1169,6 +1169,15 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
|
|||
return false;
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::setCollisionMeshKey(const void*key) {
|
||||
if (key != _collisionMeshKey) {
|
||||
if (_collisionMeshKey) {
|
||||
collisionMeshCache.releaseMesh(_collisionMeshKey);
|
||||
}
|
||||
_collisionMeshKey = key;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
|
||||
if (_hasModel != entity->hasModel()) {
|
||||
|
@ -1201,6 +1210,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
model = std::make_shared<Model>(nullptr, entity.get());
|
||||
connect(model.get(), &Model::setURLFinished, this, &ModelEntityRenderer::requestRenderUpdate);
|
||||
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
|
||||
connect(entity.get(), &RenderableModelEntityItem::requestCollisionGeometryUpdate, this, &ModelEntityRenderer::flagForCollisionGeometryUpdate);
|
||||
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
|
||||
model->init();
|
||||
entity->setModel(model);
|
||||
|
@ -1259,6 +1269,26 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
}
|
||||
// TODO? early exit here when not visible?
|
||||
|
||||
if (_needsCollisionGeometryUpdate) {
|
||||
setCollisionMeshKey(entity->getCollisionMeshKey());
|
||||
_needsCollisionGeometryUpdate = false;
|
||||
ShapeType type = entity->getShapeType();
|
||||
if (_showCollisionGeometry && type != SHAPE_TYPE_STATIC_MESH && type != SHAPE_TYPE_NONE) {
|
||||
// NOTE: it is OK if _collisionMeshKey is nullptr
|
||||
model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey);
|
||||
// NOTE: the model will render the collisionGeometry if it has one
|
||||
_model->setCollisionMesh(mesh);
|
||||
} else {
|
||||
if (_collisionMeshKey) {
|
||||
// release mesh
|
||||
collisionMeshCache.releaseMesh(_collisionMeshKey);
|
||||
}
|
||||
// clear model's collision geometry
|
||||
model::MeshPointer mesh = nullptr;
|
||||
_model->setCollisionMesh(mesh);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, "Fixup");
|
||||
if (model->needsFixupInScene()) {
|
||||
|
@ -1297,6 +1327,11 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
}
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::flagForCollisionGeometryUpdate() {
|
||||
_needsCollisionGeometryUpdate = true;
|
||||
emit requestRenderUpdate();
|
||||
}
|
||||
|
||||
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items
|
||||
void ModelEntityRenderer::doRender(RenderArgs* args) {
|
||||
DETAILED_PROFILE_RANGE(render_detail, "MetaModelRender");
|
||||
|
@ -1311,7 +1346,7 @@ void ModelEntityRenderer::doRender(RenderArgs* args) {
|
|||
if (!model || (model && model->didVisualGeometryRequestFail())) {
|
||||
static glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
batch.setModelTransform(_modelTransform); // we want to include the scale as well
|
||||
batch.setModelTransform(getModelTransform()); // we want to include the scale as well
|
||||
DependencyManager::get<GeometryCache>()->renderWireCubeInstance(args, batch, greenColor);
|
||||
return;
|
||||
}
|
||||
|
@ -1327,28 +1362,11 @@ void ModelEntityRenderer::doRender(RenderArgs* args) {
|
|||
// Remap textures for the next frame to avoid flicker
|
||||
// remapTextures();
|
||||
|
||||
#if 0
|
||||
// update whether the model should be showing collision mesh (this may flag for fixupInScene)
|
||||
bool showingCollisionGeometry = (bool)(args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS);
|
||||
if (showingCollisionGeometry != _showCollisionGeometry) {
|
||||
ShapeType type = _entity->getShapeType();
|
||||
_showCollisionGeometry = showingCollisionGeometry;
|
||||
if (_showCollisionGeometry && type != SHAPE_TYPE_STATIC_MESH && type != SHAPE_TYPE_NONE) {
|
||||
// NOTE: it is OK if _collisionMeshKey is nullptr
|
||||
model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey);
|
||||
// NOTE: the model will render the collisionGeometry if it has one
|
||||
_model->setCollisionMesh(mesh);
|
||||
} else {
|
||||
// release mesh
|
||||
if (_collisionMeshKey) {
|
||||
collisionMeshCache.releaseMesh(_collisionMeshKey);
|
||||
}
|
||||
// clear model's collision geometry
|
||||
model::MeshPointer mesh = nullptr;
|
||||
_model->setCollisionMesh(mesh);
|
||||
}
|
||||
bool showCollisionGeometry = (bool)(args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS);
|
||||
if (showCollisionGeometry != _showCollisionGeometry) {
|
||||
_showCollisionGeometry = showCollisionGeometry;
|
||||
flagForCollisionGeometryUpdate();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::mapJoints(const TypedEntityPointer& entity, const QStringList& modelJointNames) {
|
||||
|
|
|
@ -50,6 +50,8 @@ private:
|
|||
};
|
||||
|
||||
class RenderableModelEntityItem : public ModelEntityWrapper {
|
||||
Q_OBJECT
|
||||
|
||||
friend class render::entities::ModelEntityRenderer;
|
||||
using Parent = ModelEntityWrapper;
|
||||
public:
|
||||
|
@ -105,6 +107,10 @@ public:
|
|||
virtual QStringList getJointNames() const override;
|
||||
|
||||
bool getMeshes(MeshProxyList& result) override;
|
||||
const void* getCollisionMeshKey() const { return _collisionMeshKey; }
|
||||
|
||||
signals:
|
||||
void requestCollisionGeometryUpdate();
|
||||
|
||||
private:
|
||||
bool needsUpdateModelBounds() const;
|
||||
|
@ -117,7 +123,6 @@ private:
|
|||
QVariantMap _originalTextures;
|
||||
bool _dimensionsInitialized { true };
|
||||
bool _needsJointSimulation { false };
|
||||
bool _showCollisionGeometry { false };
|
||||
const void* _collisionMeshKey { nullptr };
|
||||
};
|
||||
|
||||
|
@ -141,6 +146,8 @@ protected:
|
|||
virtual bool needsRenderUpdate() const override;
|
||||
virtual void doRender(RenderArgs* args) override;
|
||||
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
||||
void flagForCollisionGeometryUpdate();
|
||||
void setCollisionMeshKey(const void* key);
|
||||
|
||||
private:
|
||||
void animate(const TypedEntityPointer& entity);
|
||||
|
@ -163,6 +170,7 @@ private:
|
|||
|
||||
bool _needsJointSimulation{ false };
|
||||
bool _showCollisionGeometry{ false };
|
||||
bool _needsCollisionGeometryUpdate{ false };
|
||||
const void* _collisionMeshKey{ nullptr };
|
||||
|
||||
// used on client side
|
||||
|
|
|
@ -69,8 +69,8 @@ ParticleEffectEntityRenderer::ParticleEffectEntityRenderer(const EntityItemPoint
|
|||
}
|
||||
|
||||
bool ParticleEffectEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
|
||||
entity->checkAndMaybeUpdateQueryAACube();
|
||||
|
||||
entity->updateQueryAACube();
|
||||
|
||||
if (_emitting != entity->getIsEmitting()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -251,12 +251,13 @@ void ParticleEffectEntityRenderer::stepSimulation() {
|
|||
});
|
||||
|
||||
if (_emitting && particleProperties.emitting()) {
|
||||
const auto& modelTransform = getModelTransform();
|
||||
uint64_t emitInterval = particleProperties.emitIntervalUsecs();
|
||||
if (emitInterval > 0 && interval >= _timeUntilNextEmit) {
|
||||
auto timeRemaining = interval;
|
||||
while (timeRemaining > _timeUntilNextEmit) {
|
||||
// emit particle
|
||||
_cpuParticles.push_back(createParticle(now, _modelTransform, particleProperties));
|
||||
_cpuParticles.push_back(createParticle(now, modelTransform, particleProperties));
|
||||
_timeUntilNextEmit = emitInterval;
|
||||
if (emitInterval < timeRemaining) {
|
||||
timeRemaining -= emitInterval;
|
||||
|
@ -315,7 +316,7 @@ void ParticleEffectEntityRenderer::doRender(RenderArgs* args) {
|
|||
// In trail mode, the particles are created in world space.
|
||||
// so we only set a transform if they're not in trail mode
|
||||
if (!_particleProperties.emission.shouldTrail) {
|
||||
transform = _modelTransform;
|
||||
transform = getModelTransform();
|
||||
transform.setScale(vec3(1));
|
||||
}
|
||||
batch.setModelTransform(transform);
|
||||
|
|
|
@ -30,23 +30,6 @@ using namespace render::entities;
|
|||
// is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down.
|
||||
static const float SPHERE_ENTITY_SCALE = 0.5f;
|
||||
|
||||
static std::array<GeometryCache::Shape, entity::NUM_SHAPES> MAPPING { {
|
||||
GeometryCache::Triangle,
|
||||
GeometryCache::Quad,
|
||||
GeometryCache::Hexagon,
|
||||
GeometryCache::Octagon,
|
||||
GeometryCache::Circle,
|
||||
GeometryCache::Cube,
|
||||
GeometryCache::Sphere,
|
||||
GeometryCache::Tetrahedron,
|
||||
GeometryCache::Octahedron,
|
||||
GeometryCache::Dodecahedron,
|
||||
GeometryCache::Icosahedron,
|
||||
GeometryCache::Torus,
|
||||
GeometryCache::Cone,
|
||||
GeometryCache::Cylinder,
|
||||
} };
|
||||
|
||||
|
||||
ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {
|
||||
_procedural._vertexSource = simple_vert;
|
||||
|
@ -76,6 +59,14 @@ bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
|
|||
return true;
|
||||
}
|
||||
|
||||
if (_shape != entity->getShape()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_dimensions != entity->getDimensions()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -93,12 +84,13 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
_position = entity->getPosition();
|
||||
_dimensions = entity->getDimensions();
|
||||
_orientation = entity->getOrientation();
|
||||
_renderTransform = getModelTransform();
|
||||
|
||||
if (_shape == entity::Sphere) {
|
||||
_modelTransform.postScale(SPHERE_ENTITY_SCALE);
|
||||
_renderTransform.postScale(SPHERE_ENTITY_SCALE);
|
||||
}
|
||||
|
||||
_modelTransform.postScale(_dimensions);
|
||||
_renderTransform.postScale(_dimensions);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -128,12 +120,13 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
GeometryCache::Shape geometryShape;
|
||||
bool proceduralRender = false;
|
||||
glm::vec4 outColor;
|
||||
withReadLock([&] {
|
||||
geometryShape = MAPPING[_shape];
|
||||
batch.setModelTransform(_modelTransform); // use a transform with scale, rotation, registration point and translation
|
||||
geometryShape = geometryCache->getShapeForEntityShape(_shape);
|
||||
batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation
|
||||
outColor = _color;
|
||||
if (_procedural.isReady()) {
|
||||
_procedural.prepare(batch, _position, _dimensions, _orientation);
|
||||
|
@ -146,14 +139,13 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
if (proceduralRender) {
|
||||
batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a);
|
||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
|
||||
DependencyManager::get<GeometryCache>()->renderWireShape(batch, geometryShape);
|
||||
geometryCache->renderWireShape(batch, geometryShape);
|
||||
} else {
|
||||
DependencyManager::get<GeometryCache>()->renderShape(batch, geometryShape);
|
||||
geometryCache->renderShape(batch, geometryShape);
|
||||
}
|
||||
} else {
|
||||
// FIXME, support instanced multi-shape rendering using multidraw indirect
|
||||
outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
auto pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline();
|
||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
|
||||
geometryCache->renderWireShapeInstance(args, batch, geometryShape, outColor, pipeline);
|
||||
|
@ -162,6 +154,6 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
}
|
||||
}
|
||||
|
||||
static const auto triCount = DependencyManager::get<GeometryCache>()->getShapeTriangleCount(geometryShape);
|
||||
const auto triCount = geometryCache->getShapeTriangleCount(geometryShape);
|
||||
args->_details._trianglesRendered += (int)triCount;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ private:
|
|||
|
||||
Procedural _procedural;
|
||||
QString _lastUserData;
|
||||
Transform _renderTransform;
|
||||
entity::Shape _shape { entity::Sphere };
|
||||
glm::vec4 _color;
|
||||
glm::vec3 _position;
|
||||
|
|
|
@ -93,10 +93,11 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
|
|||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
|
||||
auto transformToTopLeft = _modelTransform;
|
||||
const auto& modelTransform = getModelTransform();
|
||||
auto transformToTopLeft = modelTransform;
|
||||
if (_faceCamera) {
|
||||
//rotate about vertical to face the camera
|
||||
glm::vec3 dPosition = args->getViewFrustum().getPosition() - _modelTransform.getTranslation();
|
||||
glm::vec3 dPosition = args->getViewFrustum().getPosition() - modelTransform.getTranslation();
|
||||
// If x and z are 0, atan(x, z) is undefined, so default to 0 degrees
|
||||
float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z);
|
||||
glm::quat orientation = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f));
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <ui/TabletScriptingInterface.h>
|
||||
#include <EntityScriptingInterface.h>
|
||||
|
||||
#include "EntityTreeRenderer.h"
|
||||
#include "EntitiesRendererLogging.h"
|
||||
|
||||
|
||||
|
@ -86,6 +85,10 @@ bool WebEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointe
|
|||
return true;
|
||||
}
|
||||
|
||||
if (_lastLocked != entity->getLocked()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -136,11 +139,12 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
|
|||
}
|
||||
|
||||
_lastDPI = entity->getDPI();
|
||||
_lastLocked = entity->getLocked();
|
||||
|
||||
glm::vec2 windowSize = getWindowSize(entity);
|
||||
_webSurface->resize(QSize(windowSize.x, windowSize.y));
|
||||
|
||||
_modelTransform.postScale(entity->getDimensions());
|
||||
_renderTransform = getModelTransform();
|
||||
_renderTransform.postScale(entity->getDimensions());
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -180,7 +184,7 @@ void WebEntityRenderer::doRender(RenderArgs* args) {
|
|||
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
withReadLock([&] {
|
||||
batch.setModelTransform(_modelTransform);
|
||||
batch.setModelTransform(_renderTransform);
|
||||
});
|
||||
batch.setResourceTexture(0, _texture);
|
||||
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||
|
@ -234,38 +238,6 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) {
|
|||
emit entities->webEventReceived(entityItemID, message);
|
||||
});
|
||||
|
||||
auto forwardPointerEvent = [=](const EntityItemID& entityItemID, const PointerEvent& event) {
|
||||
if (entityItemID == entity->getID()) {
|
||||
handlePointerEvent(entity, event);
|
||||
}
|
||||
};
|
||||
|
||||
auto renderer = DependencyManager::get<EntityTreeRenderer>();
|
||||
QObject::connect(renderer.data(), &EntityTreeRenderer::mousePressOnEntity, this, forwardPointerEvent);
|
||||
QObject::connect(renderer.data(), &EntityTreeRenderer::mouseReleaseOnEntity, this, forwardPointerEvent);
|
||||
QObject::connect(renderer.data(), &EntityTreeRenderer::mouseMoveOnEntity, this, forwardPointerEvent);
|
||||
QObject::connect(renderer.data(), &EntityTreeRenderer::hoverLeaveEntity, this,
|
||||
[=](const EntityItemID& entityItemID, const PointerEvent& event) {
|
||||
if (this->_pressed && entity->getID() == entityItemID) {
|
||||
// If the user mouses off the entity while the button is down, simulate a touch end.
|
||||
QTouchEvent::TouchPoint point;
|
||||
point.setId(event.getID());
|
||||
point.setState(Qt::TouchPointReleased);
|
||||
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _lastDPI);
|
||||
QPointF windowPoint(windowPos.x, windowPos.y);
|
||||
point.setScenePos(windowPoint);
|
||||
point.setPos(windowPoint);
|
||||
QList<QTouchEvent::TouchPoint> touchPoints;
|
||||
touchPoints.push_back(point);
|
||||
QTouchEvent* touchEvent = new QTouchEvent(QEvent::TouchEnd, nullptr,
|
||||
Qt::NoModifier, Qt::TouchPointReleased, touchPoints);
|
||||
touchEvent->setWindow(_webSurface->getWindow());
|
||||
touchEvent->setDevice(&_touchDevice);
|
||||
touchEvent->setTarget(_webSurface->getRootItem());
|
||||
QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -295,13 +267,6 @@ void WebEntityRenderer::destroyWebSurface() {
|
|||
}
|
||||
|
||||
webSurface->pause();
|
||||
auto renderer = DependencyManager::get<EntityTreeRenderer>();
|
||||
if (renderer) {
|
||||
QObject::disconnect(renderer.data(), &EntityTreeRenderer::mousePressOnEntity, this, nullptr);
|
||||
QObject::disconnect(renderer.data(), &EntityTreeRenderer::mouseReleaseOnEntity, this, nullptr);
|
||||
QObject::disconnect(renderer.data(), &EntityTreeRenderer::mouseMoveOnEntity, this, nullptr);
|
||||
QObject::disconnect(renderer.data(), &EntityTreeRenderer::hoverLeaveEntity, this, nullptr);
|
||||
}
|
||||
webSurface.reset();
|
||||
}
|
||||
}
|
||||
|
@ -347,13 +312,34 @@ void WebEntityRenderer::loadSourceURL() {
|
|||
}
|
||||
}
|
||||
|
||||
void WebEntityRenderer::handlePointerEvent(const TypedEntityPointer& entity, const PointerEvent& event) {
|
||||
void WebEntityRenderer::hoverLeaveEntity(const PointerEvent& event) {
|
||||
if (!_lastLocked && _webSurface && _pressed) {
|
||||
// If the user mouses off the entity while the button is down, simulate a touch end.
|
||||
QTouchEvent::TouchPoint point;
|
||||
point.setId(event.getID());
|
||||
point.setState(Qt::TouchPointReleased);
|
||||
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _lastDPI);
|
||||
QPointF windowPoint(windowPos.x, windowPos.y);
|
||||
point.setScenePos(windowPoint);
|
||||
point.setPos(windowPoint);
|
||||
QList<QTouchEvent::TouchPoint> touchPoints;
|
||||
touchPoints.push_back(point);
|
||||
QTouchEvent* touchEvent = new QTouchEvent(QEvent::TouchEnd, nullptr,
|
||||
Qt::NoModifier, Qt::TouchPointReleased, touchPoints);
|
||||
touchEvent->setWindow(_webSurface->getWindow());
|
||||
touchEvent->setDevice(&_touchDevice);
|
||||
touchEvent->setTarget(_webSurface->getRootItem());
|
||||
QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void WebEntityRenderer::handlePointerEvent(const PointerEvent& event) {
|
||||
// Ignore mouse interaction if we're locked
|
||||
if (entity->getLocked() || !_webSurface) {
|
||||
if (_lastLocked || !_webSurface) {
|
||||
return;
|
||||
}
|
||||
|
||||
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * entity->getDPI());
|
||||
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _lastDPI);
|
||||
QPointF windowPoint(windowPos.x, windowPos.y);
|
||||
if (event.getType() == PointerEvent::Move) {
|
||||
// Forward a mouse move event to webSurface
|
||||
|
|
|
@ -18,12 +18,16 @@ class PointerEvent;
|
|||
namespace render { namespace entities {
|
||||
|
||||
class WebEntityRenderer : public TypedEntityRenderer<WebEntityItem> {
|
||||
Q_OBJECT
|
||||
using Parent = TypedEntityRenderer<WebEntityItem>;
|
||||
friend class EntityRenderer;
|
||||
|
||||
public:
|
||||
WebEntityRenderer(const EntityItemPointer& entity);
|
||||
|
||||
Q_INVOKABLE void hoverLeaveEntity(const PointerEvent& event);
|
||||
Q_INVOKABLE void handlePointerEvent(const PointerEvent& event);
|
||||
|
||||
protected:
|
||||
virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
|
||||
virtual bool needsRenderUpdate() const override;
|
||||
|
@ -44,9 +48,6 @@ private:
|
|||
bool hasWebSurface();
|
||||
void loadSourceURL();
|
||||
glm::vec2 getWindowSize(const TypedEntityPointer& entity) const;
|
||||
void handlePointerEvent(const TypedEntityPointer& entity, const PointerEvent& event);
|
||||
|
||||
private:
|
||||
|
||||
int _geometryId{ 0 };
|
||||
enum contentType {
|
||||
|
@ -60,8 +61,10 @@ private:
|
|||
bool _pressed{ false };
|
||||
QString _lastSourceUrl;
|
||||
uint16_t _lastDPI;
|
||||
bool _lastLocked;
|
||||
QTimer _timer;
|
||||
uint64_t _lastRenderTime { 0 };
|
||||
Transform _renderTransform;
|
||||
};
|
||||
|
||||
} } // namespace
|
||||
|
|
|
@ -112,6 +112,7 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) {
|
|||
// Do we need to allocate the light in the stage ?
|
||||
if (LightStage::isIndexInvalid(_sunIndex)) {
|
||||
_sunIndex = _stage->addLight(_sunLight);
|
||||
_shadowIndex = _stage->addShadow(_sunIndex);
|
||||
} else {
|
||||
_stage->updateLightArrayBuffer(_sunIndex);
|
||||
}
|
||||
|
@ -248,7 +249,8 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
|
|||
|
||||
void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
|
||||
if (entity->getShapeType() == SHAPE_TYPE_SPHERE) {
|
||||
_modelTransform.postScale(SPHERE_ENTITY_SCALE);
|
||||
_renderTransform = getModelTransform();
|
||||
_renderTransform.postScale(SPHERE_ENTITY_SCALE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -88,6 +88,7 @@ private:
|
|||
ComponentMode _hazeMode{ COMPONENT_MODE_INHERIT };
|
||||
|
||||
indexed_container::Index _sunIndex{ LightStage::INVALID_INDEX };
|
||||
indexed_container::Index _shadowIndex{ LightStage::INVALID_INDEX };
|
||||
indexed_container::Index _ambientIndex{ LightStage::INVALID_INDEX };
|
||||
|
||||
BackgroundStagePointer _backgroundStage;
|
||||
|
@ -119,6 +120,7 @@ private:
|
|||
bool _validSkyboxTexture{ false };
|
||||
|
||||
QString _proceduralUserData;
|
||||
Transform _renderTransform;
|
||||
};
|
||||
|
||||
} } // namespace
|
||||
|
|
|
@ -43,7 +43,7 @@ int EntityItem::_maxActionsDataSize = 800;
|
|||
quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND;
|
||||
|
||||
EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
||||
SpatiallyNestable(NestableType::Entity, entityItemID)
|
||||
SpatiallyNestable(NestableType::Entity, entityItemID)
|
||||
{
|
||||
setLocalVelocity(ENTITY_ITEM_DEFAULT_VELOCITY);
|
||||
setLocalAngularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY);
|
||||
|
@ -355,14 +355,6 @@ int EntityItem::expectedBytes() {
|
|||
|
||||
// clients use this method to unpack FULL updates from entity-server
|
||||
int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) {
|
||||
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) {
|
||||
|
||||
// NOTE: This shouldn't happen. The only versions of the bit stream that didn't support split mtu buffers should
|
||||
// be handled by the model subclass and shouldn't call this routine.
|
||||
qCDebug(entities) << "EntityItem::readEntityDataFromBuffer()... "
|
||||
"ERROR CASE...args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU";
|
||||
return 0;
|
||||
}
|
||||
setSourceUUID(args.sourceUUID);
|
||||
|
||||
args.entitiesPerPacket++;
|
||||
|
@ -588,34 +580,32 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
|
||||
// Newer bitstreams will have a last simulated and a last updated value
|
||||
quint64 lastSimulatedFromBufferAdjusted = now;
|
||||
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME) {
|
||||
// last simulated is stored as ByteCountCoded delta from lastEdited
|
||||
quint64 simulatedDelta;
|
||||
parser.readCompressedCount(simulatedDelta);
|
||||
// last simulated is stored as ByteCountCoded delta from lastEdited
|
||||
quint64 simulatedDelta;
|
||||
parser.readCompressedCount(simulatedDelta);
|
||||
#ifdef VALIDATE_ENTITY_ITEM_PARSER
|
||||
{
|
||||
QByteArray encodedSimulatedDelta = originalDataBuffer.mid(bytesRead); // maximum possible size
|
||||
ByteCountCoded<quint64> simulatedDeltaCoder = encodedSimulatedDelta;
|
||||
quint64 simulatedDelta2 = simulatedDeltaCoder;
|
||||
Q_ASSERT(simulatedDelta2 == simulatedDelta);
|
||||
encodedSimulatedDelta = simulatedDeltaCoder; // determine true length
|
||||
dataAt += encodedSimulatedDelta.size();
|
||||
bytesRead += encodedSimulatedDelta.size();
|
||||
Q_ASSERT(parser.offset() == (unsigned int) bytesRead);
|
||||
}
|
||||
{
|
||||
QByteArray encodedSimulatedDelta = originalDataBuffer.mid(bytesRead); // maximum possible size
|
||||
ByteCountCoded<quint64> simulatedDeltaCoder = encodedSimulatedDelta;
|
||||
quint64 simulatedDelta2 = simulatedDeltaCoder;
|
||||
Q_ASSERT(simulatedDelta2 == simulatedDelta);
|
||||
encodedSimulatedDelta = simulatedDeltaCoder; // determine true length
|
||||
dataAt += encodedSimulatedDelta.size();
|
||||
bytesRead += encodedSimulatedDelta.size();
|
||||
Q_ASSERT(parser.offset() == (unsigned int) bytesRead);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (overwriteLocalData) {
|
||||
lastSimulatedFromBufferAdjusted = lastEditedFromBufferAdjusted + simulatedDelta; // don't adjust for clock skew since we already did that
|
||||
if (lastSimulatedFromBufferAdjusted > now) {
|
||||
lastSimulatedFromBufferAdjusted = now;
|
||||
}
|
||||
#ifdef WANT_DEBUG
|
||||
qCDebug(entities) << " _lastEdited:" << debugTime(_lastEdited, now);
|
||||
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
|
||||
qCDebug(entities) << " lastSimulatedFromBufferAdjusted:" << debugTime(lastSimulatedFromBufferAdjusted, now);
|
||||
#endif
|
||||
if (overwriteLocalData) {
|
||||
lastSimulatedFromBufferAdjusted = lastEditedFromBufferAdjusted + simulatedDelta; // don't adjust for clock skew since we already did that
|
||||
if (lastSimulatedFromBufferAdjusted > now) {
|
||||
lastSimulatedFromBufferAdjusted = now;
|
||||
}
|
||||
#ifdef WANT_DEBUG
|
||||
qCDebug(entities) << " _lastEdited:" << debugTime(_lastEdited, now);
|
||||
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
|
||||
qCDebug(entities) << " lastSimulatedFromBufferAdjusted:" << debugTime(lastSimulatedFromBufferAdjusted, now);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WANT_DEBUG
|
||||
|
@ -717,9 +707,17 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
|
||||
}
|
||||
}
|
||||
|
||||
auto lastEdited = lastEditedFromBufferAdjusted;
|
||||
bool otherOverwrites = overwriteLocalData && !weOwnSimulation;
|
||||
auto shouldUpdate = [lastEdited, otherOverwrites, filterRejection](quint64 updatedTimestamp, bool valueChanged) {
|
||||
bool simulationChanged = lastEdited > updatedTimestamp;
|
||||
return otherOverwrites && simulationChanged && (valueChanged || filterRejection);
|
||||
};
|
||||
|
||||
{ // When we own the simulation we don't accept updates to the entity's transform/velocities
|
||||
// we also want to ignore any duplicate packets that have the same "recently updated" values
|
||||
// as a packet we've already recieved. This is because we want multiple edits of the same
|
||||
// as a packet we've already recieved. This is because we want multiple edits of the same
|
||||
// information to be idempotent, but if we applied new physics properties we'd resimulation
|
||||
// with small differences in results.
|
||||
|
||||
|
@ -727,17 +725,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
// made these lambdas that can access other details about the previous updates to suppress
|
||||
// any duplicates.
|
||||
|
||||
// Note: duplicate packets are expected and not wrong. They may be sent for any number of
|
||||
// Note: duplicate packets are expected and not wrong. They may be sent for any number of
|
||||
// reasons and the contract is that the client handles them in an idempotent manner.
|
||||
auto lastEdited = lastEditedFromBufferAdjusted;
|
||||
bool otherOverwrites = overwriteLocalData && !weOwnSimulation;
|
||||
auto shouldUpdate = [lastEdited, otherOverwrites, filterRejection](quint64 updatedTimestamp, bool valueChanged) {
|
||||
bool simulationChanged = lastEdited > updatedTimestamp;
|
||||
return otherOverwrites && simulationChanged && (valueChanged || filterRejection);
|
||||
};
|
||||
auto customUpdatePositionFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){
|
||||
if (shouldUpdate(_lastUpdatedPositionTimestamp, value != _lastUpdatedPositionValue)) {
|
||||
updatePositionFromNetwork(value);
|
||||
updatePosition(value);
|
||||
_lastUpdatedPositionTimestamp = lastEdited;
|
||||
_lastUpdatedPositionValue = value;
|
||||
}
|
||||
|
@ -745,7 +737,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
|
||||
auto customUpdateRotationFromNetwork = [this, shouldUpdate, lastEdited](glm::quat value){
|
||||
if (shouldUpdate(_lastUpdatedRotationTimestamp, value != _lastUpdatedRotationValue)) {
|
||||
updateRotationFromNetwork(value);
|
||||
updateRotation(value);
|
||||
_lastUpdatedRotationTimestamp = lastEdited;
|
||||
_lastUpdatedRotationValue = value;
|
||||
}
|
||||
|
@ -753,7 +745,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
|
||||
auto customUpdateVelocityFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){
|
||||
if (shouldUpdate(_lastUpdatedVelocityTimestamp, value != _lastUpdatedVelocityValue)) {
|
||||
updateVelocityFromNetwork(value);
|
||||
updateVelocity(value);
|
||||
_lastUpdatedVelocityTimestamp = lastEdited;
|
||||
_lastUpdatedVelocityValue = value;
|
||||
}
|
||||
|
@ -761,7 +753,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
|
||||
auto customUpdateAngularVelocityFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){
|
||||
if (shouldUpdate(_lastUpdatedAngularVelocityTimestamp, value != _lastUpdatedAngularVelocityValue)) {
|
||||
updateAngularVelocityFromNetwork(value);
|
||||
updateAngularVelocity(value);
|
||||
_lastUpdatedAngularVelocityTimestamp = lastEdited;
|
||||
_lastUpdatedAngularVelocityValue = value;
|
||||
}
|
||||
|
@ -780,8 +772,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, customUpdateVelocityFromNetwork);
|
||||
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, customUpdateAngularVelocityFromNetwork);
|
||||
READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, customSetAcceleration);
|
||||
|
||||
|
||||
}
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions);
|
||||
|
@ -817,20 +807,16 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
READ_ENTITY_PROPERTY(PROP_LOCKED, bool, updateLocked);
|
||||
READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData);
|
||||
|
||||
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_MARKETPLACE_ID) {
|
||||
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
|
||||
}
|
||||
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_CERTIFICATE_PROPERTIES) {
|
||||
READ_ENTITY_PROPERTY(PROP_ITEM_NAME, QString, setItemName);
|
||||
READ_ENTITY_PROPERTY(PROP_ITEM_DESCRIPTION, QString, setItemDescription);
|
||||
READ_ENTITY_PROPERTY(PROP_ITEM_CATEGORIES, QString, setItemCategories);
|
||||
READ_ENTITY_PROPERTY(PROP_ITEM_ARTIST, QString, setItemArtist);
|
||||
READ_ENTITY_PROPERTY(PROP_ITEM_LICENSE, QString, setItemLicense);
|
||||
READ_ENTITY_PROPERTY(PROP_LIMITED_RUN, quint32, setLimitedRun);
|
||||
READ_ENTITY_PROPERTY(PROP_EDITION_NUMBER, quint32, setEditionNumber);
|
||||
READ_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, quint32, setEntityInstanceNumber);
|
||||
READ_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, QString, setCertificateID);
|
||||
}
|
||||
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
|
||||
READ_ENTITY_PROPERTY(PROP_ITEM_NAME, QString, setItemName);
|
||||
READ_ENTITY_PROPERTY(PROP_ITEM_DESCRIPTION, QString, setItemDescription);
|
||||
READ_ENTITY_PROPERTY(PROP_ITEM_CATEGORIES, QString, setItemCategories);
|
||||
READ_ENTITY_PROPERTY(PROP_ITEM_ARTIST, QString, setItemArtist);
|
||||
READ_ENTITY_PROPERTY(PROP_ITEM_LICENSE, QString, setItemLicense);
|
||||
READ_ENTITY_PROPERTY(PROP_LIMITED_RUN, quint32, setLimitedRun);
|
||||
READ_ENTITY_PROPERTY(PROP_EDITION_NUMBER, quint32, setEditionNumber);
|
||||
READ_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, quint32, setEntityInstanceNumber);
|
||||
READ_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, QString, setCertificateID);
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_NAME, QString, setName);
|
||||
READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
||||
|
@ -846,7 +832,18 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
overwriteLocalData = oldOverwrite;
|
||||
}
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, AACube, setQueryAACube);
|
||||
|
||||
{
|
||||
auto customUpdateQueryAACubeFromNetwork = [this, shouldUpdate, lastEdited](AACube value){
|
||||
if (shouldUpdate(_lastUpdatedQueryAACubeTimestamp, value != _lastUpdatedQueryAACubeValue)) {
|
||||
setQueryAACube(value);
|
||||
_lastUpdatedQueryAACubeTimestamp = lastEdited;
|
||||
_lastUpdatedQueryAACubeValue = value;
|
||||
}
|
||||
};
|
||||
READ_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, AACube, customUpdateQueryAACubeFromNetwork);
|
||||
}
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_LAST_EDITED_BY, QUuid, setLastEditedBy);
|
||||
|
||||
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||
|
@ -858,10 +855,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
// NOTE: we had a bad version of the stream that we added stream data after the subclass. We can attempt to recover
|
||||
// by doing this parsing here... but it's not likely going to fully recover the content.
|
||||
//
|
||||
// TODO: Remove this code once we've sufficiently migrated content past this damaged version
|
||||
if (args.bitstreamVersion == VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED) {
|
||||
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
|
||||
}
|
||||
|
||||
if (overwriteLocalData && (getDirtyFlags() & (Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES))) {
|
||||
// NOTE: This code is attempting to "repair" the old data we just got from the server to make it more
|
||||
|
@ -1381,8 +1374,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lastEditedBy, setLastEditedBy);
|
||||
|
||||
AACube saveQueryAACube = _queryAACube;
|
||||
if (checkAndMaybeUpdateQueryAACube() && saveQueryAACube != _queryAACube) {
|
||||
if (updateQueryAACube()) {
|
||||
somethingChanged = true;
|
||||
}
|
||||
|
||||
|
@ -1546,6 +1538,9 @@ AACube EntityItem::getQueryAACube(bool& success) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
bool EntityItem::shouldPuffQueryAACube() const {
|
||||
return hasActions() || isChildOfMyAvatar() || isMovingRelativeToParent();
|
||||
}
|
||||
|
||||
// NOTE: This should only be used in cases of old bitstreams which only contain radius data
|
||||
// 0,0,0 --> maxDimension,maxDimension,maxDimension
|
||||
|
@ -1659,7 +1654,7 @@ bool EntityItem::verifyStaticCertificateProperties() {
|
|||
const auto hash = getStaticCertificateHash();
|
||||
const auto text = reinterpret_cast<const unsigned char*>(hash.constData());
|
||||
const unsigned int textLength = hash.length();
|
||||
|
||||
|
||||
// After DEBUG_CERT ends, we will get/cache this once from the marketplace when needed, and it likely won't be RSA.
|
||||
const char publicKey[] = "-----BEGIN PUBLIC KEY-----\n\
|
||||
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALCoBiDAZOClO26tC5pd7JikBL61WIgp\n\
|
||||
|
@ -1750,16 +1745,10 @@ void EntityItem::updateParentID(const QUuid& value) {
|
|||
if (tree) {
|
||||
tree->addToNeedsParentFixupList(getThisPointer());
|
||||
}
|
||||
updateQueryAACube();
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItem::updatePositionFromNetwork(const glm::vec3& value) {
|
||||
if (shouldSuppressLocationEdits()) {
|
||||
return;
|
||||
}
|
||||
updatePosition(value);
|
||||
}
|
||||
|
||||
void EntityItem::updateDimensions(const glm::vec3& value) {
|
||||
if (getDimensions() != value) {
|
||||
setDimensions(value);
|
||||
|
@ -1782,13 +1771,6 @@ void EntityItem::updateRotation(const glm::quat& rotation) {
|
|||
}
|
||||
}
|
||||
|
||||
void EntityItem::updateRotationFromNetwork(const glm::quat& rotation) {
|
||||
if (shouldSuppressLocationEdits()) {
|
||||
return;
|
||||
}
|
||||
updateRotation(rotation);
|
||||
}
|
||||
|
||||
void EntityItem::updateMass(float mass) {
|
||||
// Setting the mass actually changes the _density (at fixed volume), however
|
||||
// we must protect the density range to help maintain stability of physics simulation
|
||||
|
@ -1839,13 +1821,6 @@ void EntityItem::updateVelocity(const glm::vec3& value) {
|
|||
}
|
||||
}
|
||||
|
||||
void EntityItem::updateVelocityFromNetwork(const glm::vec3& value) {
|
||||
if (shouldSuppressLocationEdits()) {
|
||||
return;
|
||||
}
|
||||
updateVelocity(value);
|
||||
}
|
||||
|
||||
void EntityItem::updateDamping(float value) {
|
||||
auto clampedDamping = glm::clamp(value, 0.0f, 1.0f);
|
||||
if (_damping != clampedDamping) {
|
||||
|
@ -1897,13 +1872,6 @@ void EntityItem::updateAngularVelocity(const glm::vec3& value) {
|
|||
}
|
||||
}
|
||||
|
||||
void EntityItem::updateAngularVelocityFromNetwork(const glm::vec3& value) {
|
||||
if (shouldSuppressLocationEdits()) {
|
||||
return;
|
||||
}
|
||||
updateAngularVelocity(value);
|
||||
}
|
||||
|
||||
void EntityItem::updateAngularDamping(float value) {
|
||||
auto clampedDamping = glm::clamp(value, 0.0f, 1.0f);
|
||||
if (_angularDamping != clampedDamping) {
|
||||
|
@ -2016,9 +1984,7 @@ void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask
|
|||
// if this entity is a descendant of MyAvatar, don't collide with MyAvatar. This avoids the
|
||||
// "bootstrapping" problem where you can shoot yourself across the room by grabbing something
|
||||
// and holding it against your own avatar.
|
||||
QUuid ancestorID = findAncestorOfType(NestableType::Avatar);
|
||||
if (!ancestorID.isNull() &&
|
||||
(ancestorID == Physics::getSessionUUID() || ancestorID == AVATAR_SELF_ID)) {
|
||||
if (isChildOfMyAvatar()) {
|
||||
iAmHoldingThis = true;
|
||||
}
|
||||
// also, don't bootstrap our own avatar with a hold action
|
||||
|
@ -2125,6 +2091,7 @@ bool EntityItem::addAction(EntitySimulationPointer simulation, EntityDynamicPoin
|
|||
removeActionInternal(action->getID());
|
||||
}
|
||||
});
|
||||
updateQueryAACube();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -2183,6 +2150,8 @@ bool EntityItem::removeAction(EntitySimulationPointer simulation, const QUuid& a
|
|||
checkWaitingToRemove(simulation);
|
||||
success = removeActionInternal(actionID);
|
||||
});
|
||||
updateQueryAACube();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
@ -2425,6 +2394,7 @@ QVariantMap EntityItem::getActionArguments(const QUuid& actionID) const {
|
|||
}
|
||||
|
||||
bool EntityItem::shouldSuppressLocationEdits() const {
|
||||
// if any of the actions indicate they'd like suppression, suppress
|
||||
QHash<QUuid, EntityDynamicPointer>::const_iterator i = _objectActions.begin();
|
||||
while (i != _objectActions.end()) {
|
||||
if (i.value()->shouldSuppressLocationEdits()) {
|
||||
|
@ -2433,6 +2403,11 @@ bool EntityItem::shouldSuppressLocationEdits() const {
|
|||
i++;
|
||||
}
|
||||
|
||||
// if any of the ancestors are MyAvatar, suppress
|
||||
if (isChildOfMyAvatar()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2495,16 +2470,16 @@ void EntityItem::globalizeProperties(EntityItemProperties& properties, const QSt
|
|||
|
||||
|
||||
bool EntityItem::matchesJSONFilters(const QJsonObject& jsonFilters) const {
|
||||
|
||||
|
||||
// The intention for the query JSON filter and this method is to be flexible to handle a variety of filters for
|
||||
// ALL entity properties. Some work will need to be done to the property system so that it can be more flexible
|
||||
// (to grab the value and default value of a property given the string representation of that property, for example)
|
||||
|
||||
|
||||
// currently the only property filter we handle is '+' for serverScripts
|
||||
// which means that we only handle a filtered query asking for entities where the serverScripts property is non-default
|
||||
|
||||
|
||||
static const QString SERVER_SCRIPTS_PROPERTY = "serverScripts";
|
||||
|
||||
|
||||
foreach(const auto& property, jsonFilters.keys()) {
|
||||
if (property == SERVER_SCRIPTS_PROPERTY && jsonFilters[property] == EntityQueryFilterSymbol::NonDefault) {
|
||||
// check if this entity has a non-default value for serverScripts
|
||||
|
@ -2515,7 +2490,7 @@ bool EntityItem::matchesJSONFilters(const QJsonObject& jsonFilters) const {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// the json filter syntax did not match what we expected, return a match
|
||||
return true;
|
||||
}
|
||||
|
@ -2528,7 +2503,7 @@ quint64 EntityItem::getLastSimulated() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setLastSimulated(quint64 now) {
|
||||
void EntityItem::setLastSimulated(quint64 now) {
|
||||
withWriteLock([&] {
|
||||
_lastSimulated = now;
|
||||
});
|
||||
|
@ -2549,7 +2524,7 @@ void EntityItem::setLastEdited(quint64 lastEdited) {
|
|||
});
|
||||
}
|
||||
|
||||
quint64 EntityItem::getLastBroadcast() const {
|
||||
quint64 EntityItem::getLastBroadcast() const {
|
||||
quint64 result;
|
||||
withReadLock([&] {
|
||||
result = _lastBroadcast;
|
||||
|
@ -2557,19 +2532,19 @@ quint64 EntityItem::getLastBroadcast() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setLastBroadcast(quint64 lastBroadcast) {
|
||||
void EntityItem::setLastBroadcast(quint64 lastBroadcast) {
|
||||
withWriteLock([&] {
|
||||
_lastBroadcast = lastBroadcast;
|
||||
});
|
||||
}
|
||||
|
||||
void EntityItem::markAsChangedOnServer() {
|
||||
void EntityItem::markAsChangedOnServer() {
|
||||
withWriteLock([&] {
|
||||
_changedOnServer = usecTimestampNow();
|
||||
});
|
||||
}
|
||||
|
||||
quint64 EntityItem::getLastChangedOnServer() const {
|
||||
quint64 EntityItem::getLastChangedOnServer() const {
|
||||
quint64 result;
|
||||
withReadLock([&] {
|
||||
result = _changedOnServer;
|
||||
|
@ -2577,13 +2552,13 @@ quint64 EntityItem::getLastChangedOnServer() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::update(const quint64& now) {
|
||||
void EntityItem::update(const quint64& now) {
|
||||
withWriteLock([&] {
|
||||
_lastUpdated = now;
|
||||
_lastUpdated = now;
|
||||
});
|
||||
}
|
||||
|
||||
quint64 EntityItem::getLastUpdated() const {
|
||||
quint64 EntityItem::getLastUpdated() const {
|
||||
quint64 result;
|
||||
withReadLock([&] {
|
||||
result = _lastUpdated;
|
||||
|
@ -2591,10 +2566,10 @@ quint64 EntityItem::getLastUpdated() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::requiresRecalcBoxes() {
|
||||
void EntityItem::requiresRecalcBoxes() {
|
||||
withWriteLock([&] {
|
||||
_recalcAABox = true;
|
||||
_recalcMinAACube = true;
|
||||
_recalcAABox = true;
|
||||
_recalcMinAACube = true;
|
||||
_recalcMaxAACube = true;
|
||||
});
|
||||
}
|
||||
|
@ -2607,7 +2582,7 @@ QString EntityItem::getHref() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
QString EntityItem::getDescription() const {
|
||||
QString EntityItem::getDescription() const {
|
||||
QString result;
|
||||
withReadLock([&] {
|
||||
result = _description;
|
||||
|
@ -2629,54 +2604,54 @@ float EntityItem::getLocalRenderAlpha() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setLocalRenderAlpha(float localRenderAlpha) {
|
||||
void EntityItem::setLocalRenderAlpha(float localRenderAlpha) {
|
||||
withWriteLock([&] {
|
||||
_localRenderAlpha = localRenderAlpha;
|
||||
});
|
||||
}
|
||||
|
||||
glm::vec3 EntityItem::getGravity() const {
|
||||
glm::vec3 EntityItem::getGravity() const {
|
||||
glm::vec3 result;
|
||||
withReadLock([&] {
|
||||
result = _gravity;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItem::setGravity(const glm::vec3& value) {
|
||||
void EntityItem::setGravity(const glm::vec3& value) {
|
||||
withWriteLock([&] {
|
||||
_gravity = value;
|
||||
});
|
||||
}
|
||||
|
||||
glm::vec3 EntityItem::getAcceleration() const {
|
||||
glm::vec3 EntityItem::getAcceleration() const {
|
||||
glm::vec3 result;
|
||||
withReadLock([&] {
|
||||
result = _acceleration;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItem::setAcceleration(const glm::vec3& value) {
|
||||
void EntityItem::setAcceleration(const glm::vec3& value) {
|
||||
withWriteLock([&] {
|
||||
_acceleration = value;
|
||||
});
|
||||
}
|
||||
|
||||
float EntityItem::getDamping() const {
|
||||
float EntityItem::getDamping() const {
|
||||
float result;
|
||||
withReadLock([&] {
|
||||
result = _damping;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
void EntityItem::setDamping(float value) {
|
||||
void EntityItem::setDamping(float value) {
|
||||
withWriteLock([&] {
|
||||
_damping = value;
|
||||
});
|
||||
}
|
||||
|
||||
float EntityItem::getRestitution() const {
|
||||
float EntityItem::getRestitution() const {
|
||||
float result;
|
||||
withReadLock([&] {
|
||||
result = _restitution;
|
||||
|
@ -2684,7 +2659,7 @@ float EntityItem::getRestitution() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
float EntityItem::getFriction() const {
|
||||
float EntityItem::getFriction() const {
|
||||
float result;
|
||||
withReadLock([&] {
|
||||
result = _friction;
|
||||
|
@ -2693,35 +2668,35 @@ float EntityItem::getFriction() const {
|
|||
}
|
||||
|
||||
// lifetime related properties.
|
||||
float EntityItem::getLifetime() const {
|
||||
float EntityItem::getLifetime() const {
|
||||
float result;
|
||||
withReadLock([&] {
|
||||
result = _lifetime;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItem::setLifetime(float value) {
|
||||
void EntityItem::setLifetime(float value) {
|
||||
withWriteLock([&] {
|
||||
_lifetime = value;
|
||||
});
|
||||
}
|
||||
|
||||
quint64 EntityItem::getCreated() const {
|
||||
quint64 EntityItem::getCreated() const {
|
||||
quint64 result;
|
||||
withReadLock([&] {
|
||||
result = _created;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItem::setCreated(quint64 value) {
|
||||
void EntityItem::setCreated(quint64 value) {
|
||||
withWriteLock([&] {
|
||||
_created = value;
|
||||
});
|
||||
}
|
||||
|
||||
QString EntityItem::getScript() const {
|
||||
QString EntityItem::getScript() const {
|
||||
QString result;
|
||||
withReadLock([&] {
|
||||
result = _script;
|
||||
|
@ -2729,13 +2704,13 @@ QString EntityItem::getScript() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setScript(const QString& value) {
|
||||
void EntityItem::setScript(const QString& value) {
|
||||
withWriteLock([&] {
|
||||
_script = value;
|
||||
});
|
||||
}
|
||||
|
||||
quint64 EntityItem::getScriptTimestamp() const {
|
||||
quint64 EntityItem::getScriptTimestamp() const {
|
||||
quint64 result;
|
||||
withReadLock([&] {
|
||||
result = _scriptTimestamp;
|
||||
|
@ -2743,13 +2718,13 @@ quint64 EntityItem::getScriptTimestamp() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setScriptTimestamp(const quint64 value) {
|
||||
void EntityItem::setScriptTimestamp(const quint64 value) {
|
||||
withWriteLock([&] {
|
||||
_scriptTimestamp = value;
|
||||
});
|
||||
}
|
||||
|
||||
QString EntityItem::getServerScripts() const {
|
||||
QString EntityItem::getServerScripts() const {
|
||||
QString result;
|
||||
withReadLock([&] {
|
||||
result = _serverScripts;
|
||||
|
@ -2759,12 +2734,12 @@ QString EntityItem::getServerScripts() const {
|
|||
|
||||
void EntityItem::setServerScripts(const QString& serverScripts) {
|
||||
withWriteLock([&] {
|
||||
_serverScripts = serverScripts;
|
||||
_serverScripts = serverScripts;
|
||||
_serverScriptsChangedTimestamp = usecTimestampNow();
|
||||
});
|
||||
}
|
||||
|
||||
QString EntityItem::getCollisionSoundURL() const {
|
||||
QString EntityItem::getCollisionSoundURL() const {
|
||||
QString result;
|
||||
withReadLock([&] {
|
||||
result = _collisionSoundURL;
|
||||
|
@ -2772,22 +2747,22 @@ QString EntityItem::getCollisionSoundURL() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
glm::vec3 EntityItem::getRegistrationPoint() const {
|
||||
glm::vec3 EntityItem::getRegistrationPoint() const {
|
||||
glm::vec3 result;
|
||||
withReadLock([&] {
|
||||
result = _registrationPoint;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItem::setRegistrationPoint(const glm::vec3& value) {
|
||||
withWriteLock([&] {
|
||||
_registrationPoint = glm::clamp(value, 0.0f, 1.0f);
|
||||
_registrationPoint = glm::clamp(value, 0.0f, 1.0f);
|
||||
});
|
||||
dimensionsChanged(); // Registration Point affects the bounding box
|
||||
}
|
||||
|
||||
float EntityItem::getAngularDamping() const {
|
||||
float EntityItem::getAngularDamping() const {
|
||||
float result;
|
||||
withReadLock([&] {
|
||||
result = _angularDamping;
|
||||
|
@ -2795,13 +2770,13 @@ float EntityItem::getAngularDamping() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setAngularDamping(float value) {
|
||||
void EntityItem::setAngularDamping(float value) {
|
||||
withWriteLock([&] {
|
||||
_angularDamping = value;
|
||||
});
|
||||
}
|
||||
|
||||
QString EntityItem::getName() const {
|
||||
QString EntityItem::getName() const {
|
||||
QString result;
|
||||
withReadLock([&] {
|
||||
result = _name;
|
||||
|
@ -2809,13 +2784,13 @@ QString EntityItem::getName() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setName(const QString& value) {
|
||||
void EntityItem::setName(const QString& value) {
|
||||
withWriteLock([&] {
|
||||
_name = value;
|
||||
});
|
||||
}
|
||||
|
||||
QString EntityItem::getDebugName() {
|
||||
QString EntityItem::getDebugName() {
|
||||
QString result = getName();
|
||||
if (result.isEmpty()) {
|
||||
result = getID().toString();
|
||||
|
@ -2823,7 +2798,7 @@ QString EntityItem::getDebugName() {
|
|||
return result;
|
||||
}
|
||||
|
||||
bool EntityItem::getVisible() const {
|
||||
bool EntityItem::getVisible() const {
|
||||
bool result;
|
||||
withReadLock([&] {
|
||||
result = _visible;
|
||||
|
@ -2831,13 +2806,18 @@ bool EntityItem::getVisible() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setVisible(bool value) {
|
||||
void EntityItem::setVisible(bool value) {
|
||||
withWriteLock([&] {
|
||||
_visible = value;
|
||||
});
|
||||
}
|
||||
|
||||
bool EntityItem::getCollisionless() const {
|
||||
bool EntityItem::isChildOfMyAvatar() const {
|
||||
QUuid ancestorID = findAncestorOfType(NestableType::Avatar);
|
||||
return !ancestorID.isNull() && (ancestorID == Physics::getSessionUUID() || ancestorID == AVATAR_SELF_ID);
|
||||
}
|
||||
|
||||
bool EntityItem::getCollisionless() const {
|
||||
bool result;
|
||||
withReadLock([&] {
|
||||
result = _collisionless;
|
||||
|
@ -2845,13 +2825,13 @@ bool EntityItem::getCollisionless() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setCollisionless(bool value) {
|
||||
void EntityItem::setCollisionless(bool value) {
|
||||
withWriteLock([&] {
|
||||
_collisionless = value;
|
||||
});
|
||||
}
|
||||
|
||||
uint8_t EntityItem::getCollisionMask() const {
|
||||
uint8_t EntityItem::getCollisionMask() const {
|
||||
uint8_t result;
|
||||
withReadLock([&] {
|
||||
result = _collisionMask;
|
||||
|
@ -2859,13 +2839,13 @@ uint8_t EntityItem::getCollisionMask() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setCollisionMask(uint8_t value) {
|
||||
void EntityItem::setCollisionMask(uint8_t value) {
|
||||
withWriteLock([&] {
|
||||
_collisionMask = value;
|
||||
});
|
||||
}
|
||||
|
||||
bool EntityItem::getDynamic() const {
|
||||
bool EntityItem::getDynamic() const {
|
||||
if (SHAPE_TYPE_STATIC_MESH == getShapeType()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2876,13 +2856,13 @@ bool EntityItem::getDynamic() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setDynamic(bool value) {
|
||||
void EntityItem::setDynamic(bool value) {
|
||||
withWriteLock([&] {
|
||||
_dynamic = value;
|
||||
});
|
||||
}
|
||||
|
||||
bool EntityItem::getLocked() const {
|
||||
bool EntityItem::getLocked() const {
|
||||
bool result;
|
||||
withReadLock([&] {
|
||||
result = _locked;
|
||||
|
@ -2890,7 +2870,7 @@ bool EntityItem::getLocked() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setLocked(bool value) {
|
||||
void EntityItem::setLocked(bool value) {
|
||||
withWriteLock([&] {
|
||||
_locked = value;
|
||||
});
|
||||
|
@ -2913,7 +2893,7 @@ void EntityItem::updateLocked(bool value) {
|
|||
}
|
||||
}
|
||||
|
||||
QString EntityItem::getUserData() const {
|
||||
QString EntityItem::getUserData() const {
|
||||
QString result;
|
||||
withReadLock([&] {
|
||||
result = _userData;
|
||||
|
@ -2921,7 +2901,7 @@ QString EntityItem::getUserData() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setUserData(const QString& value) {
|
||||
void EntityItem::setUserData(const QString& value) {
|
||||
withWriteLock([&] {
|
||||
_userData = value;
|
||||
});
|
||||
|
@ -2955,7 +2935,7 @@ DEFINE_PROPERTY_ACCESSOR(quint32, EditionNumber, editionNumber)
|
|||
DEFINE_PROPERTY_ACCESSOR(quint32, EntityInstanceNumber, entityInstanceNumber)
|
||||
DEFINE_PROPERTY_ACCESSOR(QString, CertificateID, certificateID)
|
||||
|
||||
uint32_t EntityItem::getDirtyFlags() const {
|
||||
uint32_t EntityItem::getDirtyFlags() const {
|
||||
uint32_t result;
|
||||
withReadLock([&] {
|
||||
result = _dirtyFlags;
|
||||
|
@ -2970,7 +2950,7 @@ void EntityItem::markDirtyFlags(uint32_t mask) {
|
|||
});
|
||||
}
|
||||
|
||||
void EntityItem::clearDirtyFlags(uint32_t mask) {
|
||||
void EntityItem::clearDirtyFlags(uint32_t mask) {
|
||||
withWriteLock([&] {
|
||||
_dirtyFlags &= ~mask;
|
||||
});
|
||||
|
|
|
@ -240,6 +240,7 @@ public:
|
|||
|
||||
using SpatiallyNestable::getQueryAACube;
|
||||
virtual AACube getQueryAACube(bool& success) const override;
|
||||
virtual bool shouldPuffQueryAACube() const override;
|
||||
|
||||
QString getScript() const;
|
||||
void setScript(const QString& value);
|
||||
|
@ -273,6 +274,8 @@ public:
|
|||
inline bool isVisible() const { return getVisible(); }
|
||||
inline bool isInvisible() const { return !getVisible(); }
|
||||
|
||||
bool isChildOfMyAvatar() const;
|
||||
|
||||
bool getCollisionless() const;
|
||||
void setCollisionless(bool value);
|
||||
|
||||
|
@ -354,20 +357,16 @@ public:
|
|||
virtual void updateRegistrationPoint(const glm::vec3& value);
|
||||
void updatePosition(const glm::vec3& value);
|
||||
void updateParentID(const QUuid& value);
|
||||
void updatePositionFromNetwork(const glm::vec3& value);
|
||||
void updateDimensions(const glm::vec3& value);
|
||||
void updateRotation(const glm::quat& rotation);
|
||||
void updateRotationFromNetwork(const glm::quat& rotation);
|
||||
void updateDensity(float value);
|
||||
void updateMass(float value);
|
||||
void updateVelocity(const glm::vec3& value);
|
||||
void updateVelocityFromNetwork(const glm::vec3& value);
|
||||
void updateDamping(float value);
|
||||
void updateRestitution(float value);
|
||||
void updateFriction(float value);
|
||||
void updateGravity(const glm::vec3& value);
|
||||
void updateAngularVelocity(const glm::vec3& value);
|
||||
void updateAngularVelocityFromNetwork(const glm::vec3& value);
|
||||
void updateAngularDamping(float value);
|
||||
void updateCollisionless(bool value);
|
||||
void updateCollisionMask(uint8_t value);
|
||||
|
@ -629,12 +628,14 @@ protected:
|
|||
glm::vec3 _lastUpdatedVelocityValue;
|
||||
glm::vec3 _lastUpdatedAngularVelocityValue;
|
||||
glm::vec3 _lastUpdatedAccelerationValue;
|
||||
AACube _lastUpdatedQueryAACubeValue;
|
||||
|
||||
quint64 _lastUpdatedPositionTimestamp { 0 };
|
||||
quint64 _lastUpdatedRotationTimestamp { 0 };
|
||||
quint64 _lastUpdatedVelocityTimestamp { 0 };
|
||||
quint64 _lastUpdatedAngularVelocityTimestamp { 0 };
|
||||
quint64 _lastUpdatedAccelerationTimestamp { 0 };
|
||||
quint64 _lastUpdatedQueryAACubeTimestamp { 0 };
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -84,28 +84,11 @@ void EntityItemProperties::setLastEdited(quint64 usecTime) {
|
|||
_lastEdited = usecTime > _created ? usecTime : _created;
|
||||
}
|
||||
|
||||
const char* shapeTypeNames[] = {
|
||||
"none",
|
||||
"box",
|
||||
"sphere",
|
||||
"capsule-x",
|
||||
"capsule-y",
|
||||
"capsule-z",
|
||||
"cylinder-x",
|
||||
"cylinder-y",
|
||||
"cylinder-z",
|
||||
"hull",
|
||||
"plane",
|
||||
"compound",
|
||||
"simple-hull",
|
||||
"simple-compound",
|
||||
"static-mesh"
|
||||
};
|
||||
|
||||
QHash<QString, ShapeType> stringToShapeTypeLookup;
|
||||
|
||||
void addShapeType(ShapeType type) {
|
||||
stringToShapeTypeLookup[shapeTypeNames[type]] = type;
|
||||
stringToShapeTypeLookup[ShapeInfo::getNameForShapeType(type)] = type;
|
||||
}
|
||||
|
||||
void buildStringToShapeTypeLookup() {
|
||||
|
@ -180,9 +163,7 @@ void EntityItemProperties::setCollisionMaskFromString(const QString& maskString)
|
|||
}
|
||||
|
||||
QString EntityItemProperties::getShapeTypeAsString() const {
|
||||
if (_shapeType < sizeof(shapeTypeNames) / sizeof(char *))
|
||||
return QString(shapeTypeNames[_shapeType]);
|
||||
return QString(shapeTypeNames[SHAPE_TYPE_NONE]);
|
||||
return ShapeInfo::getNameForShapeType(_shapeType);
|
||||
}
|
||||
|
||||
void EntityItemProperties::setShapeTypeFromString(const QString& shapeName) {
|
||||
|
|
|
@ -50,6 +50,14 @@ EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership
|
|||
connect(nodeList.data(), &NodeList::canRezCertifiedChanged, this, &EntityScriptingInterface::canRezCertifiedChanged);
|
||||
connect(nodeList.data(), &NodeList::canRezTmpCertifiedChanged, this, &EntityScriptingInterface::canRezTmpCertifiedChanged);
|
||||
connect(nodeList.data(), &NodeList::canWriteAssetsChanged, this, &EntityScriptingInterface::canWriteAssetsChanged);
|
||||
|
||||
// If the user clicks somewhere where there is no entity at all, we will release focus
|
||||
connect(this, &EntityScriptingInterface::mousePressOffEntity, [=]() {
|
||||
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
|
||||
});
|
||||
|
||||
auto& packetReceiver = nodeList->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::EntityScriptCallMethod, this, "handleEntityScriptCallMethodPacket");
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::queueEntityMessage(PacketType packetType,
|
||||
|
@ -457,7 +465,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
|
|||
// if they've changed.
|
||||
entity->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
||||
if (descendant->getNestableType() == NestableType::Entity) {
|
||||
if (descendant->checkAndMaybeUpdateQueryAACube()) {
|
||||
if (descendant->updateQueryAACube()) {
|
||||
EntityItemPointer entityDescendant = std::static_pointer_cast<EntityItem>(descendant);
|
||||
EntityItemProperties newQueryCubeProperties;
|
||||
newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube());
|
||||
|
@ -571,6 +579,48 @@ void EntityScriptingInterface::callEntityServerMethod(QUuid id, const QString& m
|
|||
DependencyManager::get<EntityScriptClient>()->callEntityServerMethod(id, method, params);
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, const QStringList& params) {
|
||||
PROFILE_RANGE(script_entities, __FUNCTION__);
|
||||
auto scriptServerServices = DependencyManager::get<EntityScriptServerServices>();
|
||||
|
||||
// this won't be available on clients
|
||||
if (scriptServerServices) {
|
||||
scriptServerServices->callEntityClientMethod(clientSessionID, entityID, method, params);
|
||||
} else {
|
||||
qWarning() << "Entities.callEntityClientMethod() not allowed in client";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EntityScriptingInterface::handleEntityScriptCallMethodPacket(QSharedPointer<ReceivedMessage> receivedMessage, SharedNodePointer senderNode) {
|
||||
PROFILE_RANGE(script_entities, __FUNCTION__);
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
SharedNodePointer entityScriptServer = nodeList->soloNodeOfType(NodeType::EntityScriptServer);
|
||||
|
||||
if (entityScriptServer == senderNode) {
|
||||
auto entityID = QUuid::fromRfc4122(receivedMessage->read(NUM_BYTES_RFC4122_UUID));
|
||||
|
||||
auto method = receivedMessage->readString();
|
||||
|
||||
quint16 paramCount;
|
||||
receivedMessage->readPrimitive(¶mCount);
|
||||
|
||||
QStringList params;
|
||||
for (int param = 0; param < paramCount; param++) {
|
||||
auto paramString = receivedMessage->readString();
|
||||
params << paramString;
|
||||
}
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(_entitiesScriptEngineLock);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, method, params, senderNode->getUUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const {
|
||||
PROFILE_RANGE(script_entities, __FUNCTION__);
|
||||
|
||||
|
@ -1628,44 +1678,44 @@ QUuid EntityScriptingInterface::getKeyboardFocusEntity() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::setKeyboardFocusEntity(QUuid id) {
|
||||
QMetaObject::invokeMethod(qApp, "setKeyboardFocusEntity", Qt::QueuedConnection, Q_ARG(QUuid, id));
|
||||
void EntityScriptingInterface::setKeyboardFocusEntity(const EntityItemID& id) {
|
||||
QMetaObject::invokeMethod(qApp, "setKeyboardFocusEntity", Qt::DirectConnection, Q_ARG(EntityItemID, id));
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::sendMousePressOnEntity(QUuid id, PointerEvent event) {
|
||||
QMetaObject::invokeMethod(qApp, "sendMousePressOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
|
||||
void EntityScriptingInterface::sendMousePressOnEntity(const EntityItemID& id, const PointerEvent& event) {
|
||||
emit mousePressOnEntity(id, event);
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::sendMouseMoveOnEntity(QUuid id, PointerEvent event) {
|
||||
QMetaObject::invokeMethod(qApp, "sendMouseMoveOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
|
||||
void EntityScriptingInterface::sendMouseMoveOnEntity(const EntityItemID& id, const PointerEvent& event) {
|
||||
emit mouseMoveOnEntity(id, event);
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::sendMouseReleaseOnEntity(QUuid id, PointerEvent event) {
|
||||
QMetaObject::invokeMethod(qApp, "sendMouseReleaseOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
|
||||
void EntityScriptingInterface::sendMouseReleaseOnEntity(const EntityItemID& id, const PointerEvent& event) {
|
||||
emit mouseReleaseOnEntity(id, event);
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::sendClickDownOnEntity(QUuid id, PointerEvent event) {
|
||||
QMetaObject::invokeMethod(qApp, "sendClickDownOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
|
||||
void EntityScriptingInterface::sendClickDownOnEntity(const EntityItemID& id, const PointerEvent& event) {
|
||||
emit clickDownOnEntity(id, event);
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::sendHoldingClickOnEntity(QUuid id, PointerEvent event) {
|
||||
QMetaObject::invokeMethod(qApp, "sendHoldingClickOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
|
||||
void EntityScriptingInterface::sendHoldingClickOnEntity(const EntityItemID& id, const PointerEvent& event) {
|
||||
emit holdingClickOnEntity(id, event);
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::sendClickReleaseOnEntity(QUuid id, PointerEvent event) {
|
||||
QMetaObject::invokeMethod(qApp, "sendClickReleaseOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
|
||||
void EntityScriptingInterface::sendClickReleaseOnEntity(const EntityItemID& id, const PointerEvent& event) {
|
||||
emit clickReleaseOnEntity(id, event);
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::sendHoverEnterEntity(QUuid id, PointerEvent event) {
|
||||
QMetaObject::invokeMethod(qApp, "sendHoverEnterEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
|
||||
void EntityScriptingInterface::sendHoverEnterEntity(const EntityItemID& id, const PointerEvent& event) {
|
||||
emit hoverEnterEntity(id, event);
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::sendHoverOverEntity(QUuid id, PointerEvent event) {
|
||||
QMetaObject::invokeMethod(qApp, "sendHoverOverEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
|
||||
void EntityScriptingInterface::sendHoverOverEntity(const EntityItemID& id, const PointerEvent& event) {
|
||||
emit hoverOverEntity(id, event);
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::sendHoverLeaveEntity(QUuid id, PointerEvent event) {
|
||||
QMetaObject::invokeMethod(qApp, "sendHoverLeaveEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event));
|
||||
void EntityScriptingInterface::sendHoverLeaveEntity(const EntityItemID& id, const PointerEvent& event) {
|
||||
emit hoverLeaveEntity(id, event);
|
||||
}
|
||||
|
||||
bool EntityScriptingInterface::wantsHandControllerPointerEvents(QUuid id) {
|
||||
|
@ -1797,4 +1847,4 @@ QString EntityScriptingInterface::computeCertificateID(const QUuid& entityID) {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -189,12 +189,15 @@ public slots:
|
|||
Q_INVOKABLE void deleteEntity(QUuid entityID);
|
||||
|
||||
/**jsdoc
|
||||
* Call a method on an entity. Allows a script to call a method on an entity's script.
|
||||
* The method will execute in the entity script engine. If the entity does not have an
|
||||
* entity script or the method does not exist, this call will have no effect.
|
||||
* If it is running an entity script (specified by the `script` property)
|
||||
* Call a method on an entity in the same context as this function is called. Allows a script
|
||||
* to call a method on an entity's script. The method will execute in the entity script engine.
|
||||
* If the entity does not have an entity script or the method does not exist, this call will
|
||||
* have no effect. If it is running an entity script (specified by the `script` property)
|
||||
* and it exposes a property with the specified name `method`, it will be called
|
||||
* using `params` as the list of arguments.
|
||||
* using `params` as the list of arguments. If this is called within an entity script, the
|
||||
* method will be executed on the client in the entity script engine in which it was called. If
|
||||
* this is called in an entity server script, the method will be executed on the entity server
|
||||
* script engine.
|
||||
*
|
||||
* @function Entities.callEntityMethod
|
||||
* @param {EntityID} entityID The ID of the entity to call the method on.
|
||||
|
@ -218,6 +221,21 @@ public slots:
|
|||
*/
|
||||
Q_INVOKABLE void callEntityServerMethod(QUuid entityID, const QString& method, const QStringList& params = QStringList());
|
||||
|
||||
/**jsdoc
|
||||
* Call a client method on an entity on a specific client node. Allows a server entity script to call a
|
||||
* method on an entity's client script for a particular client. The method will execute in the entity script
|
||||
* engine on that single client. If the entity does not have an entity script or the method does not exist, or
|
||||
* the client is not connected to the domain, or you attempt to make this call outside of the entity server
|
||||
* script, this call will have no effect.
|
||||
*
|
||||
* @function Entities.callEntityClientMethod
|
||||
* @param {SessionID} clientSessionID The session ID of the client to call the method on.
|
||||
* @param {EntityID} entityID The ID of the entity to call the method on.
|
||||
* @param {string} method The name of the method to call.
|
||||
* @param {string[]} params The list of parameters to call the specified method with.
|
||||
*/
|
||||
Q_INVOKABLE void callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, const QStringList& params = QStringList());
|
||||
|
||||
/**jsdoc
|
||||
* finds the closest model to the center point, within the radius
|
||||
* will return a EntityItemID.isKnownID = false if no models are in the radius
|
||||
|
@ -362,19 +380,19 @@ public slots:
|
|||
Q_INVOKABLE QString getNestableType(QUuid id);
|
||||
|
||||
Q_INVOKABLE QUuid getKeyboardFocusEntity() const;
|
||||
Q_INVOKABLE void setKeyboardFocusEntity(QUuid id);
|
||||
Q_INVOKABLE void setKeyboardFocusEntity(const EntityItemID& id);
|
||||
|
||||
Q_INVOKABLE void sendMousePressOnEntity(QUuid id, PointerEvent event);
|
||||
Q_INVOKABLE void sendMouseMoveOnEntity(QUuid id, PointerEvent event);
|
||||
Q_INVOKABLE void sendMouseReleaseOnEntity(QUuid id, PointerEvent event);
|
||||
Q_INVOKABLE void sendMousePressOnEntity(const EntityItemID& id, const PointerEvent& event);
|
||||
Q_INVOKABLE void sendMouseMoveOnEntity(const EntityItemID& id, const PointerEvent& event);
|
||||
Q_INVOKABLE void sendMouseReleaseOnEntity(const EntityItemID& id, const PointerEvent& event);
|
||||
|
||||
Q_INVOKABLE void sendClickDownOnEntity(QUuid id, PointerEvent event);
|
||||
Q_INVOKABLE void sendHoldingClickOnEntity(QUuid id, PointerEvent event);
|
||||
Q_INVOKABLE void sendClickReleaseOnEntity(QUuid id, PointerEvent event);
|
||||
Q_INVOKABLE void sendClickDownOnEntity(const EntityItemID& id, const PointerEvent& event);
|
||||
Q_INVOKABLE void sendHoldingClickOnEntity(const EntityItemID& id, const PointerEvent& event);
|
||||
Q_INVOKABLE void sendClickReleaseOnEntity(const EntityItemID& id, const PointerEvent& event);
|
||||
|
||||
Q_INVOKABLE void sendHoverEnterEntity(QUuid id, PointerEvent event);
|
||||
Q_INVOKABLE void sendHoverOverEntity(QUuid id, PointerEvent event);
|
||||
Q_INVOKABLE void sendHoverLeaveEntity(QUuid id, PointerEvent event);
|
||||
Q_INVOKABLE void sendHoverEnterEntity(const EntityItemID& id, const PointerEvent& event);
|
||||
Q_INVOKABLE void sendHoverOverEntity(const EntityItemID& id, const PointerEvent& event);
|
||||
Q_INVOKABLE void sendHoverLeaveEntity(const EntityItemID& id, const PointerEvent& event);
|
||||
|
||||
Q_INVOKABLE bool wantsHandControllerPointerEvents(QUuid id);
|
||||
|
||||
|
@ -421,8 +439,11 @@ signals:
|
|||
void canWriteAssetsChanged(bool canWriteAssets);
|
||||
|
||||
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
void mouseDoublePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
void mouseMoveOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
void mousePressOffEntity();
|
||||
void mouseDoublePressOffEntity();
|
||||
|
||||
void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
void holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
|
@ -447,6 +468,10 @@ protected:
|
|||
std::lock_guard<std::recursive_mutex> lock(_entitiesScriptEngineLock);
|
||||
function(_entitiesScriptEngine);
|
||||
};
|
||||
|
||||
private slots:
|
||||
void handleEntityScriptCallMethodPacket(QSharedPointer<ReceivedMessage> receivedMessage, SharedNodePointer senderNode);
|
||||
|
||||
private:
|
||||
bool actionWorker(const QUuid& entityID, std::function<bool(EntitySimulationPointer, EntityItemPointer)> actor);
|
||||
bool polyVoxWorker(QUuid entityID, std::function<bool(PolyVoxEntityItem&)> actor);
|
||||
|
|
|
@ -1029,7 +1029,8 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList<Q
|
|||
changedProperties[index] = QString("queryAACube:") +
|
||||
QString::number((int)center.x) + "," +
|
||||
QString::number((int)center.y) + "," +
|
||||
QString::number((int)center.z);
|
||||
QString::number((int)center.z) + "/" +
|
||||
QString::number(properties.getQueryAACube().getDimensions().x);
|
||||
}
|
||||
if (properties.positionChanged()) {
|
||||
int index = changedProperties.indexOf("position");
|
||||
|
@ -1807,7 +1808,7 @@ QVector<EntityItemID> EntityTree::sendEntities(EntityEditPacketSender* packetSen
|
|||
addToNeedsParentFixupList(entity);
|
||||
}
|
||||
entity->forceQueryAACubeUpdate();
|
||||
entity->checkAndMaybeUpdateQueryAACube();
|
||||
entity->updateQueryAACube();
|
||||
moveOperator.addEntityToMoveList(entity, entity->getQueryAACube());
|
||||
i++;
|
||||
} else {
|
||||
|
|
|
@ -89,8 +89,6 @@ public:
|
|||
// own definition. Implement these to allow your octree based server to support editing
|
||||
virtual bool getWantSVOfileVersions() const override { return true; }
|
||||
virtual PacketType expectedDataPacketType() const override { return PacketType::EntityData; }
|
||||
virtual bool canProcessVersion(PacketVersion thisVersion) const override
|
||||
{ return thisVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS; }
|
||||
virtual bool handlesEditPacketType(PacketType packetType) const override;
|
||||
void fixupTerseEditLogging(EntityItemProperties& properties, QList<QString>& changedProperties);
|
||||
virtual int processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength,
|
||||
|
@ -111,9 +109,6 @@ public:
|
|||
virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const override;
|
||||
virtual bool mustIncludeAllChildData() const override { return false; }
|
||||
|
||||
virtual bool versionHasSVOfileBreaks(PacketVersion thisVersion) const override
|
||||
{ return thisVersion >= VERSION_ENTITIES_HAS_FILE_BREAKS; }
|
||||
|
||||
virtual void update() override { update(true); }
|
||||
|
||||
void update(bool simulate);
|
||||
|
|
|
@ -102,12 +102,6 @@ EntityItemPointer EntityTypes::constructEntityItem(EntityType entityType, const
|
|||
EntityItemPointer EntityTypes::constructEntityItem(const unsigned char* data, int bytesToRead,
|
||||
ReadBitstreamToTreeParams& args) {
|
||||
|
||||
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) {
|
||||
EntityItemID tempEntityID;
|
||||
EntityItemProperties tempProperties;
|
||||
return constructEntityItem(Model, tempEntityID, tempProperties);
|
||||
}
|
||||
|
||||
// Header bytes
|
||||
// object ID [16 bytes]
|
||||
// ByteCountCoded(type code) [~1 byte]
|
||||
|
|
|
@ -175,35 +175,12 @@ int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
int bytesRead = 0;
|
||||
const unsigned char* dataAt = data;
|
||||
|
||||
if (args.bitstreamVersion < VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES) {
|
||||
READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, setIsSpotlight);
|
||||
|
||||
// _diffuseColor has been renamed to _color
|
||||
READ_ENTITY_PROPERTY(PROP_DIFFUSE_COLOR, rgbColor, setColor);
|
||||
|
||||
// Ambient and specular color are from an older format and are no longer supported.
|
||||
// Their values will be ignored.
|
||||
READ_ENTITY_PROPERTY(PROP_AMBIENT_COLOR_UNUSED, rgbColor, setIgnoredColor);
|
||||
READ_ENTITY_PROPERTY(PROP_SPECULAR_COLOR_UNUSED, rgbColor, setIgnoredColor);
|
||||
|
||||
// _constantAttenuation has been renamed to _intensity
|
||||
READ_ENTITY_PROPERTY(PROP_INTENSITY, float, setIntensity);
|
||||
|
||||
// Linear and quadratic attenuation are from an older format and are no longer supported.
|
||||
// Their values will be ignored.
|
||||
READ_ENTITY_PROPERTY(PROP_LINEAR_ATTENUATION_UNUSED, float, setIgnoredAttenuation);
|
||||
READ_ENTITY_PROPERTY(PROP_QUADRATIC_ATTENUATION_UNUSED, float, setIgnoredAttenuation);
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_EXPONENT, float, setExponent);
|
||||
READ_ENTITY_PROPERTY(PROP_CUTOFF, float, setCutoff);
|
||||
} else {
|
||||
READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, setIsSpotlight);
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor);
|
||||
READ_ENTITY_PROPERTY(PROP_INTENSITY, float, setIntensity);
|
||||
READ_ENTITY_PROPERTY(PROP_EXPONENT, float, setExponent);
|
||||
READ_ENTITY_PROPERTY(PROP_CUTOFF, float, setCutoff);
|
||||
READ_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, float, setFalloffRadius);
|
||||
}
|
||||
READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, setIsSpotlight);
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor);
|
||||
READ_ENTITY_PROPERTY(PROP_INTENSITY, float, setIntensity);
|
||||
READ_ENTITY_PROPERTY(PROP_EXPONENT, float, setExponent);
|
||||
READ_ENTITY_PROPERTY(PROP_CUTOFF, float, setCutoff);
|
||||
READ_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, float, setFalloffRadius);
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
|
|
@ -111,38 +111,19 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor);
|
||||
READ_ENTITY_PROPERTY(PROP_MODEL_URL, QString, setModelURL);
|
||||
if (args.bitstreamVersion < VERSION_ENTITIES_HAS_COLLISION_MODEL) {
|
||||
setCompoundShapeURL("");
|
||||
} else {
|
||||
READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
|
||||
}
|
||||
|
||||
// Because we're using AnimationLoop which will reset the frame index if you change it's running state
|
||||
// we want to read these values in the order they appear in the buffer, but call our setters in an
|
||||
// order that allows AnimationLoop to preserve the correct frame rate.
|
||||
if (args.bitstreamVersion < VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP) {
|
||||
READ_ENTITY_PROPERTY(PROP_ANIMATION_URL, QString, setAnimationURL);
|
||||
READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setAnimationFPS);
|
||||
READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setAnimationCurrentFrame);
|
||||
READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying);
|
||||
}
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
|
||||
READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures);
|
||||
|
||||
if (args.bitstreamVersion < VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP) {
|
||||
READ_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, QString, setAnimationSettings);
|
||||
} else {
|
||||
int bytesFromAnimation;
|
||||
withWriteLock([&] {
|
||||
// Note: since we've associated our _animationProperties with our _animationLoop, the readEntitySubclassDataFromBuffer()
|
||||
// will automatically read into the animation loop
|
||||
bytesFromAnimation = _animationProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||
propertyFlags, overwriteLocalData, animationPropertiesChanged);
|
||||
});
|
||||
int bytesFromAnimation;
|
||||
withWriteLock([&] {
|
||||
// Note: since we've associated our _animationProperties with our _animationLoop, the readEntitySubclassDataFromBuffer()
|
||||
// will automatically read into the animation loop
|
||||
bytesFromAnimation = _animationProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||
propertyFlags, overwriteLocalData, animationPropertiesChanged);
|
||||
});
|
||||
|
||||
bytesRead += bytesFromAnimation;
|
||||
dataAt += bytesFromAnimation;
|
||||
}
|
||||
bytesRead += bytesFromAnimation;
|
||||
dataAt += bytesFromAnimation;
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType);
|
||||
|
||||
|
|
|
@ -464,76 +464,40 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
|
|||
const unsigned char* dataAt = data;
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor);
|
||||
// Because we're using AnimationLoop which will reset the frame index if you change it's running state
|
||||
// we want to read these values in the order they appear in the buffer, but call our setters in an
|
||||
// order that allows AnimationLoop to preserve the correct frame rate.
|
||||
if (args.bitstreamVersion < VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP) {
|
||||
SKIP_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float);
|
||||
SKIP_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float);
|
||||
SKIP_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool);
|
||||
SKIP_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, QString);
|
||||
} else {
|
||||
READ_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, bool, setIsEmitting);
|
||||
}
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, bool, setIsEmitting);
|
||||
READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType);
|
||||
READ_ENTITY_PROPERTY(PROP_MAX_PARTICLES, quint32, setMaxParticles);
|
||||
READ_ENTITY_PROPERTY(PROP_LIFESPAN, float, setLifespan);
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_RATE, float, setEmitRate);
|
||||
if (args.bitstreamVersion < VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER) {
|
||||
// OLD PROP_EMIT_VELOCITY FAKEOUT
|
||||
SKIP_ENTITY_PROPERTY(PROP_EMIT_SPEED, glm::vec3);
|
||||
}
|
||||
|
||||
if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_MODIFICATIONS) {
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration);
|
||||
READ_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, setParticleRadius);
|
||||
READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures);
|
||||
if (args.bitstreamVersion < VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER) {
|
||||
// OLD PROP_VELOCITY_SPREAD FAKEOUT
|
||||
SKIP_ENTITY_PROPERTY(PROP_SPEED_SPREAD, glm::vec3);
|
||||
}
|
||||
} else {
|
||||
// OLD PROP_EMIT_ACCELERATION FAKEOUT
|
||||
SKIP_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float);
|
||||
// OLD PROP_ACCELERATION_SPREAD FAKEOUT
|
||||
SKIP_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float);
|
||||
READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, setParticleRadius);
|
||||
READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures);
|
||||
}
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration);
|
||||
READ_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, setParticleRadius);
|
||||
READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures);
|
||||
|
||||
if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_RADIUS_PROPERTIES) {
|
||||
READ_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, float, setRadiusSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_RADIUS_START, float, setRadiusStart);
|
||||
READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish);
|
||||
}
|
||||
READ_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, float, setRadiusSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_RADIUS_START, float, setRadiusStart);
|
||||
READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish);
|
||||
|
||||
if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES) {
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_SPREAD, xColor, setColorSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_START, xColor, setColorStart);
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_FINISH, xColor, setColorFinish);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA_FINISH, float, setAlphaFinish);
|
||||
}
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_SPREAD, xColor, setColorSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_START, xColor, setColorStart);
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_FINISH, xColor, setColorFinish);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA_FINISH, float, setAlphaFinish);
|
||||
|
||||
if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER) {
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_SPEED, float, setEmitSpeed);
|
||||
READ_ENTITY_PROPERTY(PROP_SPEED_SPREAD, float, setSpeedSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, glm::quat, setEmitOrientation);
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, glm::vec3, setEmitDimensions);
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_RADIUS_START, float, setEmitRadiusStart);
|
||||
READ_ENTITY_PROPERTY(PROP_POLAR_START, float, setPolarStart);
|
||||
READ_ENTITY_PROPERTY(PROP_POLAR_FINISH, float, setPolarFinish);
|
||||
READ_ENTITY_PROPERTY(PROP_AZIMUTH_START, float, setAzimuthStart);
|
||||
READ_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, float, setAzimuthFinish);
|
||||
}
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_SPEED, float, setEmitSpeed);
|
||||
READ_ENTITY_PROPERTY(PROP_SPEED_SPREAD, float, setSpeedSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, glm::quat, setEmitOrientation);
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, glm::vec3, setEmitDimensions);
|
||||
READ_ENTITY_PROPERTY(PROP_EMIT_RADIUS_START, float, setEmitRadiusStart);
|
||||
READ_ENTITY_PROPERTY(PROP_POLAR_START, float, setPolarStart);
|
||||
READ_ENTITY_PROPERTY(PROP_POLAR_FINISH, float, setPolarFinish);
|
||||
READ_ENTITY_PROPERTY(PROP_AZIMUTH_START, float, setAzimuthStart);
|
||||
READ_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, float, setAzimuthFinish);
|
||||
|
||||
if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING) {
|
||||
READ_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail);
|
||||
}
|
||||
READ_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail);
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,14 @@ namespace entity {
|
|||
}
|
||||
}
|
||||
|
||||
// shapeCalculator is a hook for external code that knows how to configure a ShapeInfo
|
||||
// for given entity::Shape and dimensions
|
||||
ShapeEntityItem::ShapeInfoCalculator shapeCalculator = nullptr;
|
||||
|
||||
void ShapeEntityItem::setShapeInfoCalulator(ShapeEntityItem::ShapeInfoCalculator callback) {
|
||||
shapeCalculator = callback;
|
||||
}
|
||||
|
||||
ShapeEntityItem::Pointer ShapeEntityItem::baseFactory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
Pointer entity(new ShapeEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); });
|
||||
entity->setProperties(properties);
|
||||
|
@ -87,6 +95,7 @@ EntityItemProperties ShapeEntityItem::getProperties(EntityPropertyFlags desiredP
|
|||
}
|
||||
|
||||
void ShapeEntityItem::setShape(const entity::Shape& shape) {
|
||||
const entity::Shape prevShape = _shape;
|
||||
_shape = shape;
|
||||
switch (_shape) {
|
||||
case entity::Shape::Cube:
|
||||
|
@ -99,6 +108,11 @@ void ShapeEntityItem::setShape(const entity::Shape& shape) {
|
|||
_type = EntityTypes::Shape;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_shape != prevShape) {
|
||||
// Internally grabs writeLock
|
||||
markDirtyFlags(Simulation::DIRTY_SHAPE);
|
||||
}
|
||||
}
|
||||
|
||||
bool ShapeEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||
|
@ -219,6 +233,7 @@ void ShapeEntityItem::debugDump() const {
|
|||
qCDebug(entities) << "SHAPE EntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||
qCDebug(entities) << " name:" << _name;
|
||||
qCDebug(entities) << " shape:" << stringFromShape(_shape) << " (EnumId: " << _shape << " )";
|
||||
qCDebug(entities) << " collisionShapeType:" << ShapeInfo::getNameForShapeType(getShapeType());
|
||||
qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2];
|
||||
qCDebug(entities) << " position:" << debugTreeVector(getPosition());
|
||||
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
|
||||
|
@ -233,73 +248,101 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
|
||||
const glm::vec3 entityDimensions = getDimensions();
|
||||
|
||||
switch (_shape) {
|
||||
case entity::Shape::Quad:
|
||||
case entity::Shape::Cube:
|
||||
{
|
||||
_collisionShapeType = SHAPE_TYPE_BOX;
|
||||
switch (_shape){
|
||||
case entity::Shape::Quad: {
|
||||
// Not in GeometryCache::buildShapes, unsupported.
|
||||
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
|
||||
//TODO WL21389: Add a SHAPE_TYPE_QUAD ShapeType and treat
|
||||
// as a special box (later if desired support)
|
||||
}
|
||||
break;
|
||||
case entity::Shape::Cube: {
|
||||
_collisionShapeType = SHAPE_TYPE_BOX;
|
||||
}
|
||||
break;
|
||||
case entity::Shape::Sphere: {
|
||||
|
||||
float diameter = entityDimensions.x;
|
||||
const float MIN_DIAMETER = 0.001f;
|
||||
const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f;
|
||||
if (diameter > MIN_DIAMETER
|
||||
&& fabsf(diameter - entityDimensions.y) / diameter < MIN_RELATIVE_SPHERICAL_ERROR
|
||||
&& fabsf(diameter - entityDimensions.z) / diameter < MIN_RELATIVE_SPHERICAL_ERROR) {
|
||||
|
||||
_collisionShapeType = SHAPE_TYPE_SPHERE;
|
||||
} else {
|
||||
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
|
||||
}
|
||||
break;
|
||||
case entity::Shape::Sphere:
|
||||
{
|
||||
}
|
||||
break;
|
||||
case entity::Shape::Circle: {
|
||||
_collisionShapeType = SHAPE_TYPE_CIRCLE;
|
||||
}
|
||||
break;
|
||||
case entity::Shape::Cylinder: {
|
||||
_collisionShapeType = SHAPE_TYPE_CYLINDER_Y;
|
||||
// TODO WL21389: determine if rotation is axis-aligned
|
||||
//const Transform::Quat & rot = _transform.getRotation();
|
||||
|
||||
float diameter = entityDimensions.x;
|
||||
const float MIN_DIAMETER = 0.001f;
|
||||
const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f;
|
||||
if (diameter > MIN_DIAMETER
|
||||
&& fabsf(diameter - entityDimensions.y) / diameter < MIN_RELATIVE_SPHERICAL_ERROR
|
||||
&& fabsf(diameter - entityDimensions.z) / diameter < MIN_RELATIVE_SPHERICAL_ERROR) {
|
||||
// TODO WL21389: some way to tell apart SHAPE_TYPE_CYLINDER_Y, _X, _Z based on rotation and
|
||||
// hull ( or dimensions, need circular cross section)
|
||||
// Should allow for minor variance along axes?
|
||||
|
||||
_collisionShapeType = SHAPE_TYPE_SPHERE;
|
||||
} else {
|
||||
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case entity::Shape::Cone: {
|
||||
if (shapeCalculator) {
|
||||
shapeCalculator(this, info);
|
||||
// shapeCalculator only supports convex shapes (e.g. SHAPE_TYPE_HULL)
|
||||
_collisionShapeType = SHAPE_TYPE_SIMPLE_HULL;
|
||||
} else {
|
||||
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
|
||||
}
|
||||
break;
|
||||
case entity::Shape::Cylinder:
|
||||
{
|
||||
_collisionShapeType = SHAPE_TYPE_CYLINDER_Y;
|
||||
// TODO WL21389: determine if rotation is axis-aligned
|
||||
//const Transform::Quat & rot = _transform.getRotation();
|
||||
|
||||
// TODO WL21389: some way to tell apart SHAPE_TYPE_CYLINDER_Y, _X, _Z based on rotation and
|
||||
// hull ( or dimensions, need circular cross section)
|
||||
// Should allow for minor variance along axes?
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
// gons, ones, & angles built via GeometryCache::extrudePolygon
|
||||
case entity::Shape::Triangle:
|
||||
case entity::Shape::Hexagon:
|
||||
case entity::Shape::Octagon:
|
||||
case entity::Shape::Circle:
|
||||
case entity::Shape::Octagon: {
|
||||
if (shapeCalculator) {
|
||||
shapeCalculator(this, info);
|
||||
// shapeCalculator only supports convex shapes (e.g. SHAPE_TYPE_HULL)
|
||||
_collisionShapeType = SHAPE_TYPE_SIMPLE_HULL;
|
||||
} else {
|
||||
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// hedrons built via GeometryCache::setUpFlatShapes
|
||||
case entity::Shape::Tetrahedron:
|
||||
case entity::Shape::Octahedron:
|
||||
case entity::Shape::Dodecahedron:
|
||||
case entity::Shape::Icosahedron:
|
||||
case entity::Shape::Cone:
|
||||
{
|
||||
//TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later)
|
||||
case entity::Shape::Icosahedron: {
|
||||
if ( shapeCalculator ) {
|
||||
shapeCalculator(this, info);
|
||||
// shapeCalculator only supports convex shapes (e.g. SHAPE_TYPE_HULL)
|
||||
_collisionShapeType = SHAPE_TYPE_SIMPLE_HULL;
|
||||
} else {
|
||||
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
|
||||
}
|
||||
break;
|
||||
case entity::Shape::Torus:
|
||||
{
|
||||
// Not in GeometryCache::buildShapes, unsupported.
|
||||
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
|
||||
//TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later if desired support)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case entity::Shape::Torus: {
|
||||
// Not in GeometryCache::buildShapes, unsupported.
|
||||
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
|
||||
//TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later if desired support)
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
EntityItem::computeShapeInfo(info);
|
||||
}
|
||||
|
||||
// This value specifes how the shape should be treated by physics calculations.
|
||||
// This value specifies how the shape should be treated by physics calculations.
|
||||
ShapeType ShapeEntityItem::getShapeType() const {
|
||||
return _collisionShapeType;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ namespace entity {
|
|||
::QString stringFromShape(Shape shape);
|
||||
}
|
||||
|
||||
|
||||
class ShapeEntityItem : public EntityItem {
|
||||
using Pointer = std::shared_ptr<ShapeEntityItem>;
|
||||
static Pointer baseFactory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
@ -43,6 +42,9 @@ public:
|
|||
static EntityItemPointer sphereFactory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
static EntityItemPointer boxFactory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
using ShapeInfoCalculator = std::function<void( const ShapeEntityItem * const shapeEntity, ShapeInfo& info)>;
|
||||
static void setShapeInfoCalulator(ShapeInfoCalculator callback);
|
||||
|
||||
ShapeEntityItem(const EntityItemID& entityItemID);
|
||||
|
||||
void pureVirtualFunctionPlaceHolder() override { };
|
||||
|
|
|
@ -136,7 +136,7 @@ void SimpleEntitySimulation::sortEntitiesThatMoved() {
|
|||
SetOfEntities::iterator itemItr = _entitiesToSort.begin();
|
||||
while (itemItr != _entitiesToSort.end()) {
|
||||
EntityItemPointer entity = *itemItr;
|
||||
entity->checkAndMaybeUpdateQueryAACube();
|
||||
entity->updateQueryAACube();
|
||||
++itemItr;
|
||||
}
|
||||
EntitySimulation::sortEntitiesThatMoved();
|
||||
|
|
22
libraries/gpu/src/gpu/DrawTextureMirroredX.slf
Normal file
22
libraries/gpu/src/gpu/DrawTextureMirroredX.slf
Normal file
|
@ -0,0 +1,22 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// Draw texture 0 fetched at (1.0 - texcoord.x, texcoord.y)
|
||||
//
|
||||
// Created by Sam Gondelman on 10/24/2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
|
||||
uniform sampler2D colorMap;
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
outFragColor = texture(colorMap, vec2(1.0 - varTexCoord0.x, varTexCoord0.y));
|
||||
}
|
|
@ -23,6 +23,7 @@ const char DrawNada_frag[] = "void main(void) {}"; // DrawNada is really simple.
|
|||
|
||||
#include "DrawWhite_frag.h"
|
||||
#include "DrawTexture_frag.h"
|
||||
#include "DrawTextureMirroredX_frag.h"
|
||||
#include "DrawTextureOpaque_frag.h"
|
||||
#include "DrawColoredTexture_frag.h"
|
||||
|
||||
|
@ -37,6 +38,7 @@ ShaderPointer StandardShaderLib::_drawTransformVertexPositionVS;
|
|||
ShaderPointer StandardShaderLib::_drawNadaPS;
|
||||
ShaderPointer StandardShaderLib::_drawWhitePS;
|
||||
ShaderPointer StandardShaderLib::_drawTexturePS;
|
||||
ShaderPointer StandardShaderLib::_drawTextureMirroredXPS;
|
||||
ShaderPointer StandardShaderLib::_drawTextureOpaquePS;
|
||||
ShaderPointer StandardShaderLib::_drawColoredTexturePS;
|
||||
StandardShaderLib::ProgramMap StandardShaderLib::_programs;
|
||||
|
@ -130,6 +132,13 @@ ShaderPointer StandardShaderLib::getDrawTexturePS() {
|
|||
return _drawTexturePS;
|
||||
}
|
||||
|
||||
ShaderPointer StandardShaderLib::getDrawTextureMirroredXPS() {
|
||||
if (!_drawTextureMirroredXPS) {
|
||||
_drawTextureMirroredXPS = gpu::Shader::createPixel(std::string(DrawTextureMirroredX_frag));
|
||||
}
|
||||
return _drawTextureMirroredXPS;
|
||||
}
|
||||
|
||||
ShaderPointer StandardShaderLib::getDrawTextureOpaquePS() {
|
||||
if (!_drawTextureOpaquePS) {
|
||||
_drawTextureOpaquePS = gpu::Shader::createPixel(std::string(DrawTextureOpaque_frag));
|
||||
|
|
|
@ -47,6 +47,7 @@ public:
|
|||
|
||||
static ShaderPointer getDrawWhitePS();
|
||||
static ShaderPointer getDrawTexturePS();
|
||||
static ShaderPointer getDrawTextureMirroredXPS();
|
||||
static ShaderPointer getDrawTextureOpaquePS();
|
||||
static ShaderPointer getDrawColoredTexturePS();
|
||||
|
||||
|
@ -67,6 +68,7 @@ protected:
|
|||
static ShaderPointer _drawNadaPS;
|
||||
static ShaderPointer _drawWhitePS;
|
||||
static ShaderPointer _drawTexturePS;
|
||||
static ShaderPointer _drawTextureMirroredXPS;
|
||||
static ShaderPointer _drawTextureOpaquePS;
|
||||
static ShaderPointer _drawColoredTexturePS;
|
||||
|
||||
|
|
|
@ -92,6 +92,28 @@ void EntityScriptClient::callEntityServerMethod(QUuid entityID, const QString& m
|
|||
}
|
||||
}
|
||||
|
||||
void EntityScriptServerServices::callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, const QStringList& params) {
|
||||
// only valid to call this function if you are the entity script server
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
SharedNodePointer targetClient = nodeList->nodeWithUUID(clientSessionID);
|
||||
|
||||
if (nodeList->getOwnerType() == NodeType::EntityScriptServer && targetClient) {
|
||||
auto packetList = NLPacketList::create(PacketType::EntityScriptCallMethod, QByteArray(), true, true);
|
||||
|
||||
packetList->write(entityID.toRfc4122());
|
||||
|
||||
packetList->writeString(method);
|
||||
|
||||
quint16 paramCount = params.length();
|
||||
packetList->writePrimitive(paramCount);
|
||||
|
||||
foreach(const QString& param, params) {
|
||||
packetList->writeString(param);
|
||||
}
|
||||
|
||||
nodeList->sendPacketList(std::move(packetList), *targetClient);
|
||||
}
|
||||
}
|
||||
|
||||
MessageID EntityScriptClient::getEntityServerScriptStatus(QUuid entityID, GetScriptStatusCallback callback) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
|
|
@ -74,4 +74,11 @@ private:
|
|||
void forceFailureOfPendingRequests(SharedNodePointer node);
|
||||
};
|
||||
|
||||
|
||||
class EntityScriptServerServices : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
public:
|
||||
void callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, const QStringList& params);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,9 +29,9 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::EntityAdd:
|
||||
case PacketType::EntityEdit:
|
||||
case PacketType::EntityData:
|
||||
return VERSION_ENTITIES_STROKE_COLOR_PROPERTY;
|
||||
case PacketType::EntityPhysics:
|
||||
return VERSION_ENTITIES_HAZE;
|
||||
return static_cast<PacketVersion>(EntityVersion::StrokeColorProperty);
|
||||
|
||||
case PacketType::EntityQuery:
|
||||
return static_cast<PacketVersion>(EntityQueryPacketVersion::JSONFilterWithFamilyTree);
|
||||
case PacketType::AvatarIdentity:
|
||||
|
@ -62,6 +62,9 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::DomainServerAddedNode:
|
||||
return static_cast<PacketVersion>(DomainServerAddedNodeVersion::PermissionsGrid);
|
||||
|
||||
case PacketType::EntityScriptCallMethod:
|
||||
return static_cast<PacketVersion>(EntityScriptCallMethodVersion::ClientCallable);
|
||||
|
||||
case PacketType::MixedAudio:
|
||||
case PacketType::SilentAudioFrame:
|
||||
case PacketType::InjectAudio:
|
||||
|
|
|
@ -194,85 +194,14 @@ void sendWrongProtocolVersionsSignature(bool sendWrongVersion); /// for debuggin
|
|||
uint qHash(const PacketType& key, uint seed);
|
||||
QDebug operator<<(QDebug debug, const PacketType& type);
|
||||
|
||||
const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_ANIMATION = 1;
|
||||
const PacketVersion VERSION_ROOT_ELEMENT_HAS_DATA = 2;
|
||||
const PacketVersion VERSION_ENTITIES_SUPPORT_SPLIT_MTU = 3;
|
||||
const PacketVersion VERSION_ENTITIES_HAS_FILE_BREAKS = VERSION_ENTITIES_SUPPORT_SPLIT_MTU;
|
||||
const PacketVersion VERSION_ENTITIES_SUPPORT_DIMENSIONS = 4;
|
||||
const PacketVersion VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS = 5;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_USER_DATA = 6;
|
||||
const PacketVersion VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME = 7;
|
||||
const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE = 8;
|
||||
const PacketVersion VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES = 9;
|
||||
const PacketVersion VERSION_ENTITIES_HAS_PARTICLES = 10;
|
||||
const PacketVersion VERSION_ENTITIES_USE_METERS_AND_RADIANS = 11;
|
||||
const PacketVersion VERSION_ENTITIES_HAS_COLLISION_MODEL = 12;
|
||||
const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED = 13;
|
||||
const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID = 14;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_ACCELERATION = 15;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_UUIDS = 16;
|
||||
const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_EXIST = 17;
|
||||
const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_DYNAMIC_SHAPE = 18;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_NAMES = 19;
|
||||
const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_ATMOSPHERE = 20;
|
||||
const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_SKYBOX = 21;
|
||||
const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_STAGE_HAS_AUTOMATIC_HOURDAY = 22;
|
||||
const PacketVersion VERSION_ENTITIES_PARTICLE_ENTITIES_HAVE_TEXTURES = 23;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_LINE_TYPE = 24;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_COLLISION_SOUND_URL = 25;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_FRICTION = 26;
|
||||
const PacketVersion VERSION_NO_ENTITY_ID_SWAP = 27;
|
||||
const PacketVersion VERSION_ENTITIES_PARTICLE_FIX = 28;
|
||||
const PacketVersion VERSION_ENTITIES_LINE_POINTS = 29;
|
||||
const PacketVersion VERSION_ENTITIES_FACE_CAMERA = 30;
|
||||
const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP = 31;
|
||||
const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP_FIX = 32;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE = 33;
|
||||
const PacketVersion VERSION_ENTITIES_NEW_PROTOCOL_LAYER = 35;
|
||||
const PacketVersion VERSION_POLYVOX_TEXTURES = 36;
|
||||
const PacketVersion VERSION_ENTITIES_POLYLINE = 37;
|
||||
const PacketVersion VERSION_OCTREE_CENTERED_ORIGIN = 38;
|
||||
const PacketVersion VERSION_ENTITIES_PARTICLE_MODIFICATIONS = 39;
|
||||
const PacketVersion VERSION_ENTITIES_POLYVOX_NEIGHBORS = 40;
|
||||
const PacketVersion VERSION_ENTITIES_PARTICLE_RADIUS_PROPERTIES = 41;
|
||||
const PacketVersion VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES = 42;
|
||||
const PacketVersion VERSION_ENTITIES_PROTOCOL_HEADER_SWAP = 43;
|
||||
const PacketVersion VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER = 44;
|
||||
const PacketVersion VERSION_ENTITIES_PROTOCOL_CHANNELS = 45;
|
||||
const PacketVersion VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP = 46;
|
||||
const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP = 47;
|
||||
const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP_BIS = 48;
|
||||
const PacketVersion VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING = 49;
|
||||
const PacketVersion VERSION_ENTITIES_POLYLINE_TEXTURE = 50;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_PARENTS = 51;
|
||||
const PacketVersion VERSION_ENTITIES_REMOVED_START_AUTOMATICALLY_FROM_ANIMATION_PROPERTY_GROUP = 52;
|
||||
const PacketVersion VERSION_MODEL_ENTITIES_JOINTS_ON_WIRE = 53;
|
||||
const PacketVersion VERSION_ENTITITES_HAVE_QUERY_BOX = 54;
|
||||
const PacketVersion VERSION_ENTITITES_HAVE_COLLISION_MASK = 55;
|
||||
const PacketVersion VERSION_ATMOSPHERE_REMOVED = 56;
|
||||
const PacketVersion VERSION_LIGHT_HAS_FALLOFF_RADIUS = 57;
|
||||
const PacketVersion VERSION_ENTITIES_NO_FLY_ZONES = 58;
|
||||
const PacketVersion VERSION_ENTITIES_MORE_SHAPES = 59;
|
||||
const PacketVersion VERSION_ENTITIES_PROPERLY_ENCODE_SHAPE_EDITS = 60;
|
||||
const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_STATIC_MESH = 61;
|
||||
const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SIMPLE_HULLS = 62;
|
||||
const PacketVersion VERSION_WEB_ENTITIES_SUPPORT_DPI = 63;
|
||||
const PacketVersion VERSION_ENTITIES_ARROW_ACTION = 64;
|
||||
const PacketVersion VERSION_ENTITIES_LAST_EDITED_BY = 65;
|
||||
const PacketVersion VERSION_ENTITIES_SERVER_SCRIPTS = 66;
|
||||
const PacketVersion VERSION_ENTITIES_PHYSICS_PACKET = 67;
|
||||
const PacketVersion VERSION_ENTITIES_ZONE_FILTERS = 68;
|
||||
const PacketVersion VERSION_ENTITIES_HINGE_CONSTRAINT = 69;
|
||||
const PacketVersion VERSION_ENTITIES_BULLET_DYNAMICS = 70;
|
||||
const PacketVersion VERSION_ENTITIES_HAS_SHOULD_HIGHLIGHT = 71;
|
||||
const PacketVersion VERSION_ENTITIES_HAS_HIGHLIGHT_SCRIPTING_INTERFACE = 72;
|
||||
const PacketVersion VERSION_ENTITIES_ANIMATION_ALLOW_TRANSLATION_PROPERTIES = 73;
|
||||
const PacketVersion VERSION_ENTITIES_HAS_CERTIFICATE_PROPERTIES = 74;
|
||||
const PacketVersion VERSION_ENTITIES_HAZE = 75;
|
||||
const PacketVersion VERSION_ENTITIES_UV_MODE_PROPERTY = 76;
|
||||
const PacketVersion VERSION_ENTITIES_STROKE_COLOR_PROPERTY = 77;
|
||||
enum class EntityVersion : PacketVersion {
|
||||
StrokeColorProperty = 77
|
||||
};
|
||||
|
||||
enum class EntityScriptCallMethodVersion : PacketVersion {
|
||||
ServerCallable = 18,
|
||||
ClientCallable = 19
|
||||
};
|
||||
|
||||
enum class EntityQueryPacketVersion: PacketVersion {
|
||||
JSONFilter = 18,
|
||||
|
|
|
@ -1721,8 +1721,8 @@ bool Octree::readFromStream(uint64_t streamLength, QDataStream& inputStream, con
|
|||
device->ungetChar(firstChar);
|
||||
|
||||
if (firstChar == (char) PacketType::EntityData) {
|
||||
qCDebug(octree) << "Reading from binary SVO Stream length:" << streamLength;
|
||||
return readSVOFromStream(streamLength, inputStream);
|
||||
qCWarning(octree) << "Reading from binary SVO no longer supported";
|
||||
return false;
|
||||
} else {
|
||||
qCDebug(octree) << "Reading from JSON SVO Stream length:" << streamLength;
|
||||
return readJSONFromStream(streamLength, inputStream, marketplaceID);
|
||||
|
@ -1730,137 +1730,6 @@ bool Octree::readFromStream(uint64_t streamLength, QDataStream& inputStream, con
|
|||
}
|
||||
|
||||
|
||||
bool Octree::readSVOFromStream(uint64_t streamLength, QDataStream& inputStream) {
|
||||
qWarning() << "SVO file format depricated. Support for reading SVO files is no longer support and will be removed soon.";
|
||||
|
||||
bool fileOk = false;
|
||||
|
||||
PacketVersion gotVersion = 0;
|
||||
|
||||
uint64_t headerLength = 0; // bytes in the header
|
||||
|
||||
bool wantImportProgress = true;
|
||||
|
||||
PacketType expectedType = expectedDataPacketType();
|
||||
PacketVersion expectedVersion = versionForPacketType(expectedType);
|
||||
bool hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion);
|
||||
|
||||
// before reading the file, check to see if this version of the Octree supports file versions
|
||||
if (getWantSVOfileVersions()) {
|
||||
|
||||
// read just enough of the file to parse the header...
|
||||
const uint64_t HEADER_LENGTH = sizeof(int) + sizeof(PacketVersion);
|
||||
unsigned char fileHeader[HEADER_LENGTH];
|
||||
inputStream.readRawData((char*)&fileHeader, HEADER_LENGTH);
|
||||
|
||||
headerLength = HEADER_LENGTH; // we need this later to skip to the data
|
||||
|
||||
unsigned char* dataAt = (unsigned char*)&fileHeader;
|
||||
uint64_t dataLength = HEADER_LENGTH;
|
||||
|
||||
// if so, read the first byte of the file and see if it matches the expected version code
|
||||
int intPacketType;
|
||||
memcpy(&intPacketType, dataAt, sizeof(intPacketType));
|
||||
PacketType gotType = (PacketType) intPacketType;
|
||||
|
||||
dataAt += sizeof(expectedType);
|
||||
dataLength -= sizeof(expectedType);
|
||||
gotVersion = *dataAt;
|
||||
|
||||
if (gotType == expectedType) {
|
||||
if (canProcessVersion(gotVersion)) {
|
||||
dataAt += sizeof(gotVersion);
|
||||
dataLength -= sizeof(gotVersion);
|
||||
fileOk = true;
|
||||
qCDebug(octree, "SVO file version match. Expected: %d Got: %d",
|
||||
versionForPacketType(expectedDataPacketType()), gotVersion);
|
||||
|
||||
hasBufferBreaks = versionHasSVOfileBreaks(gotVersion);
|
||||
} else {
|
||||
qCDebug(octree, "SVO file version mismatch. Expected: %d Got: %d",
|
||||
versionForPacketType(expectedDataPacketType()), gotVersion);
|
||||
}
|
||||
} else {
|
||||
qCDebug(octree) << "SVO file type mismatch. Expected: " << expectedType
|
||||
<< " Got: " << gotType;
|
||||
}
|
||||
|
||||
} else {
|
||||
qCDebug(octree) << " NOTE: this file type does not include type and version information.";
|
||||
fileOk = true; // assume the file is ok
|
||||
}
|
||||
|
||||
if (hasBufferBreaks) {
|
||||
qCDebug(octree) << " this version includes buffer breaks";
|
||||
} else {
|
||||
qCDebug(octree) << " this version does not include buffer breaks";
|
||||
}
|
||||
|
||||
if (fileOk) {
|
||||
|
||||
// if this version of the file does not include buffer breaks, then we need to load the entire file at once
|
||||
if (!hasBufferBreaks) {
|
||||
|
||||
// read the entire file into a buffer, WHAT!? Why not.
|
||||
uint64_t dataLength = streamLength - headerLength;
|
||||
unsigned char* entireFileDataSection = new unsigned char[dataLength];
|
||||
inputStream.readRawData((char*)entireFileDataSection, dataLength);
|
||||
|
||||
unsigned char* dataAt = entireFileDataSection;
|
||||
|
||||
ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0,
|
||||
SharedNodePointer(), wantImportProgress, gotVersion);
|
||||
|
||||
readBitstreamToTree(dataAt, dataLength, args);
|
||||
delete[] entireFileDataSection;
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
uint64_t dataLength = streamLength - headerLength;
|
||||
uint64_t remainingLength = dataLength;
|
||||
const uint64_t MAX_CHUNK_LENGTH = MAX_OCTREE_PACKET_SIZE * 2;
|
||||
unsigned char* fileChunk = new unsigned char[MAX_CHUNK_LENGTH];
|
||||
|
||||
while (remainingLength > 0) {
|
||||
quint16 chunkLength = 0;
|
||||
|
||||
inputStream.readRawData((char*)&chunkLength, sizeof(chunkLength));
|
||||
remainingLength -= sizeof(chunkLength);
|
||||
|
||||
if (chunkLength > remainingLength) {
|
||||
qCDebug(octree) << "UNEXPECTED chunk size of:" << chunkLength
|
||||
<< "greater than remaining length:" << remainingLength;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chunkLength > MAX_CHUNK_LENGTH) {
|
||||
qCDebug(octree) << "UNEXPECTED chunk size of:" << chunkLength
|
||||
<< "greater than MAX_CHUNK_LENGTH:" << MAX_CHUNK_LENGTH;
|
||||
break;
|
||||
}
|
||||
|
||||
inputStream.readRawData((char*)fileChunk, chunkLength);
|
||||
|
||||
remainingLength -= chunkLength;
|
||||
|
||||
unsigned char* dataAt = fileChunk;
|
||||
uint64_t dataLength = chunkLength;
|
||||
|
||||
ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0,
|
||||
SharedNodePointer(), wantImportProgress, gotVersion);
|
||||
|
||||
readBitstreamToTree(dataAt, dataLength, args);
|
||||
}
|
||||
|
||||
delete[] fileChunk;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return fileOk;
|
||||
}
|
||||
|
||||
// hack to get the marketplace id into the entities. We will create a way to get this from a hash of
|
||||
// the entity later, but this helps us move things along for now
|
||||
QJsonDocument addMarketplaceIDToDocumentEntities(QJsonDocument& doc, const QString& marketplaceID) {
|
||||
|
|
|
@ -208,8 +208,6 @@ public:
|
|||
// own definition. Implement these to allow your octree based server to support editing
|
||||
virtual bool getWantSVOfileVersions() const { return false; }
|
||||
virtual PacketType expectedDataPacketType() const { return PacketType::Unknown; }
|
||||
virtual bool canProcessVersion(PacketVersion thisVersion) const {
|
||||
return thisVersion == versionForPacketType(expectedDataPacketType()); }
|
||||
virtual PacketVersion expectedVersion() const { return versionForPacketType(expectedDataPacketType()); }
|
||||
virtual bool handlesEditPacketType(PacketType packetType) const { return false; }
|
||||
virtual int processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength,
|
||||
|
@ -222,11 +220,6 @@ public:
|
|||
virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const { }
|
||||
virtual bool mustIncludeAllChildData() const { return true; }
|
||||
|
||||
/// some versions of the SVO file will include breaks with buffer lengths between each buffer chunk in the SVO
|
||||
/// file. If the Octree subclass expects this for this particular version of the file, it should override this
|
||||
/// method and return true.
|
||||
virtual bool versionHasSVOfileBreaks(PacketVersion thisVersion) const { return false; }
|
||||
|
||||
virtual void update() { } // nothing to do by default
|
||||
|
||||
OctreeElementPointer getRoot() { return _rootElement; }
|
||||
|
|
|
@ -491,6 +491,10 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (_entity->shouldSuppressLocationEdits()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isLocallyOwned()) {
|
||||
// we don't own the simulation
|
||||
|
||||
|
@ -577,7 +581,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
|
|||
}
|
||||
|
||||
if (properties.transformChanged()) {
|
||||
if (_entity->checkAndMaybeUpdateQueryAACube()) {
|
||||
if (_entity->updateQueryAACube()) {
|
||||
// due to parenting, the server may not know where something is in world-space, so include the bounding cube.
|
||||
properties.setQueryAACube(_entity->getQueryAACube());
|
||||
}
|
||||
|
@ -644,7 +648,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
|
|||
_entity->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
||||
if (descendant->getNestableType() == NestableType::Entity) {
|
||||
EntityItemPointer entityDescendant = std::static_pointer_cast<EntityItem>(descendant);
|
||||
if (descendant->checkAndMaybeUpdateQueryAACube()) {
|
||||
if (descendant->updateQueryAACube()) {
|
||||
EntityItemProperties newQueryCubeProperties;
|
||||
newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube());
|
||||
newQueryCubeProperties.setLastEdited(properties.getLastEdited());
|
||||
|
|
|
@ -66,7 +66,7 @@ class PhysicsEngine;
|
|||
|
||||
class ObjectMotionState : public btMotionState {
|
||||
public:
|
||||
// These poroperties of the PhysicsEngine are "global" within the context of all ObjectMotionStates
|
||||
// These properties of the PhysicsEngine are "global" within the context of all ObjectMotionStates
|
||||
// (assuming just one PhysicsEngine). They are cached as statics for fast calculations in the
|
||||
// ObjectMotionState context.
|
||||
static void setWorldOffset(const glm::vec3& offset);
|
||||
|
|
|
@ -314,6 +314,7 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info)
|
|||
shape = new btCylinderShapeZ(btHalfExtents);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CIRCLE:
|
||||
case SHAPE_TYPE_CYLINDER_Y: {
|
||||
const glm::vec3 halfExtents = info.getHalfExtents();
|
||||
const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z);
|
||||
|
|
|
@ -35,8 +35,8 @@ void DisplayPlugin::waitForPresent() {
|
|||
}
|
||||
}
|
||||
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> DisplayPlugin::getHUDOperator() {
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> hudOperator;
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> DisplayPlugin::getHUDOperator() {
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> hudOperator;
|
||||
{
|
||||
QMutexLocker locker(&_presentMutex);
|
||||
hudOperator = _hudOperator;
|
||||
|
|
|
@ -204,7 +204,7 @@ public:
|
|||
|
||||
void waitForPresent();
|
||||
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> getHUDOperator();
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> getHUDOperator();
|
||||
|
||||
static const QString& MENU_PATH();
|
||||
|
||||
|
@ -218,7 +218,7 @@ protected:
|
|||
|
||||
gpu::ContextPointer _gpuContext;
|
||||
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> _hudOperator { std::function<void(gpu::Batch&, const gpu::TexturePointer&)>() };
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> _hudOperator { std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)>() };
|
||||
|
||||
private:
|
||||
QMutex _presentMutex;
|
||||
|
|
|
@ -435,7 +435,7 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I
|
|||
auto lightStage = renderContext->_scene->getStage<LightStage>();
|
||||
assert(lightStage);
|
||||
assert(lightStage->getNumLights() > 0);
|
||||
auto lightAndShadow = lightStage->getLightAndShadow(0);
|
||||
auto lightAndShadow = lightStage->getCurrentKeyLightAndShadow();
|
||||
const auto& globalShadow = lightAndShadow.second;
|
||||
if (globalShadow) {
|
||||
batch.setResourceTexture(Shadow, globalShadow->map);
|
||||
|
|
|
@ -498,7 +498,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
|
|||
auto lightStage = renderContext->_scene->getStage<LightStage>();
|
||||
assert(lightStage);
|
||||
assert(lightStage->getNumLights() > 0);
|
||||
auto lightAndShadow = lightStage->getLightAndShadow(0);
|
||||
auto lightAndShadow = lightStage->getCurrentKeyLightAndShadow();
|
||||
const auto& globalShadow = lightAndShadow.second;
|
||||
|
||||
// Bind the shadow buffer
|
||||
|
@ -509,14 +509,21 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
|
|||
auto& program = deferredLightingEffect->_directionalSkyboxLight;
|
||||
LightLocationsPtr locations = deferredLightingEffect->_directionalSkyboxLightLocations;
|
||||
|
||||
auto keyLight = lightStage->getLight(0);
|
||||
auto keyLight = lightAndShadow.first;
|
||||
|
||||
model::LightPointer keyAmbientLight;
|
||||
if (lightStage && lightStage->_currentFrame._ambientLights.size()) {
|
||||
keyAmbientLight = lightStage->getLight(lightStage->_currentFrame._ambientLights.front());
|
||||
}
|
||||
bool hasAmbientMap = (keyAmbientLight != nullptr);
|
||||
|
||||
// Setup the global directional pass pipeline
|
||||
{
|
||||
if (deferredLightingEffect->_shadowMapEnabled) {
|
||||
|
||||
// If the keylight has an ambient Map then use the Skybox version of the pass
|
||||
// otherwise use the ambient sphere version
|
||||
if (keyLight->getAmbientMap()) {
|
||||
if (hasAmbientMap) {
|
||||
program = deferredLightingEffect->_directionalSkyboxLightShadow;
|
||||
locations = deferredLightingEffect->_directionalSkyboxLightShadowLocations;
|
||||
} else {
|
||||
|
@ -526,7 +533,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
|
|||
} else {
|
||||
// If the keylight has an ambient Map then use the Skybox version of the pass
|
||||
// otherwise use the ambient sphere version
|
||||
if (keyLight->getAmbientMap()) {
|
||||
if (hasAmbientMap) {
|
||||
program = deferredLightingEffect->_directionalSkyboxLight;
|
||||
locations = deferredLightingEffect->_directionalSkyboxLightLocations;
|
||||
} else {
|
||||
|
|
|
@ -52,6 +52,46 @@
|
|||
|
||||
//#define WANT_DEBUG
|
||||
|
||||
// @note: Originally size entity::NUM_SHAPES
|
||||
// As of Commit b93e91b9, render-utils no longer retains knowledge of
|
||||
// entity lib, and thus doesn't know about entity::NUM_SHAPES. Should
|
||||
// the enumerations be altered, this will need to be updated.
|
||||
// @see ShapeEntityItem.h
|
||||
static std::array<GeometryCache::Shape, (GeometryCache::NUM_SHAPES - 1)> MAPPING{ {
|
||||
GeometryCache::Triangle,
|
||||
GeometryCache::Quad,
|
||||
GeometryCache::Hexagon,
|
||||
GeometryCache::Octagon,
|
||||
GeometryCache::Circle,
|
||||
GeometryCache::Cube,
|
||||
GeometryCache::Sphere,
|
||||
GeometryCache::Tetrahedron,
|
||||
GeometryCache::Octahedron,
|
||||
GeometryCache::Dodecahedron,
|
||||
GeometryCache::Icosahedron,
|
||||
GeometryCache::Torus,
|
||||
GeometryCache::Cone,
|
||||
GeometryCache::Cylinder,
|
||||
} };
|
||||
|
||||
static const std::array<const char * const, GeometryCache::NUM_SHAPES> GEOCACHE_SHAPE_STRINGS{ {
|
||||
"Line",
|
||||
"Triangle",
|
||||
"Quad",
|
||||
"Hexagon",
|
||||
"Octagon",
|
||||
"Circle",
|
||||
"Cube",
|
||||
"Sphere",
|
||||
"Tetrahedron",
|
||||
"Octahedron",
|
||||
"Dodecahedron",
|
||||
"Icosahedron",
|
||||
"Torus",
|
||||
"Cone",
|
||||
"Cylinder"
|
||||
} };
|
||||
|
||||
const int GeometryCache::UNKNOWN_ID = -1;
|
||||
|
||||
|
||||
|
@ -69,6 +109,51 @@ static gpu::Stream::FormatPointer INSTANCED_SOLID_FADE_STREAM_FORMAT;
|
|||
static const uint SHAPE_VERTEX_STRIDE = sizeof(glm::vec3) * 2; // vertices and normals
|
||||
static const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3);
|
||||
|
||||
void GeometryCache::computeSimpleHullPointListForShape(const int entityShape, const glm::vec3 &entityExtents, QVector<glm::vec3> &outPointList) {
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
const GeometryCache::Shape geometryShape = GeometryCache::getShapeForEntityShape( entityShape );
|
||||
const GeometryCache::ShapeData * shapeData = geometryCache->getShapeData( geometryShape );
|
||||
if (!shapeData){
|
||||
//--EARLY EXIT--( data isn't ready for some reason... )
|
||||
return;
|
||||
}
|
||||
|
||||
const gpu::BufferView & shapeVerts = shapeData->_positionView;
|
||||
const gpu::BufferView::Size numItems = shapeVerts.getNumElements();
|
||||
|
||||
outPointList.reserve((int)numItems);
|
||||
QVector<glm::vec3> uniqueVerts;
|
||||
uniqueVerts.reserve((int)numItems);
|
||||
|
||||
const float MAX_INCLUSIVE_FILTER_DISTANCE_SQUARED = 1.0e-6f; //< 1mm^2
|
||||
for (gpu::BufferView::Index i = 0; i < (gpu::BufferView::Index)numItems; ++i) {
|
||||
const int numUniquePoints = (int)uniqueVerts.size();
|
||||
const geometry::Vec &curVert = shapeVerts.get<geometry::Vec>(i);
|
||||
bool isUniquePoint = true;
|
||||
|
||||
for (int uniqueIndex = 0; uniqueIndex < numUniquePoints; ++uniqueIndex) {
|
||||
const geometry::Vec knownVert = uniqueVerts[uniqueIndex];
|
||||
const float distToKnownPoint = glm::length2(knownVert - curVert);
|
||||
|
||||
if (distToKnownPoint <= MAX_INCLUSIVE_FILTER_DISTANCE_SQUARED) {
|
||||
isUniquePoint = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isUniquePoint) {
|
||||
|
||||
//--EARLY ITERATION EXIT--
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
uniqueVerts.push_back(curVert);
|
||||
outPointList.push_back(curVert * entityExtents);
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t SIDES>
|
||||
std::vector<vec3> polygon() {
|
||||
std::vector<vec3> result;
|
||||
|
@ -85,7 +170,7 @@ void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, c
|
|||
gpu::Buffer::Size offset = vertexBuffer->getSize();
|
||||
vertexBuffer->append(vertices);
|
||||
|
||||
gpu::Buffer::Size viewSize = vertices.size() * 2 * sizeof(glm::vec3);
|
||||
gpu::Buffer::Size viewSize = vertices.size() * sizeof(glm::vec3);
|
||||
|
||||
_positionView = gpu::BufferView(vertexBuffer, offset,
|
||||
viewSize, SHAPE_VERTEX_STRIDE, POSITION_ELEMENT);
|
||||
|
@ -441,12 +526,46 @@ void GeometryCache::buildShapes() {
|
|||
extrudePolygon<64>(_shapes[Cone], _shapeVertices, _shapeIndices, true);
|
||||
//Circle
|
||||
drawCircle(_shapes[Circle], _shapeVertices, _shapeIndices);
|
||||
// Not implememented yet:
|
||||
// Not implemented yet:
|
||||
//Quad,
|
||||
//Torus,
|
||||
|
||||
}
|
||||
|
||||
const GeometryCache::ShapeData * GeometryCache::getShapeData(const Shape shape) const {
|
||||
if (((int)shape < 0) || ((int)shape >= (int)_shapes.size())) {
|
||||
qCWarning(renderutils) << "GeometryCache::getShapeData - Invalid shape " << shape << " specified. Returning default fallback.";
|
||||
|
||||
//--EARLY EXIT--( No valid shape data for shape )
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &_shapes[shape];
|
||||
}
|
||||
|
||||
GeometryCache::Shape GeometryCache::getShapeForEntityShape(int entityShape) {
|
||||
if ((entityShape < 0) || (entityShape >= (int)MAPPING.size())) {
|
||||
qCWarning(renderutils) << "GeometryCache::getShapeForEntityShape - Invalid shape " << entityShape << " specified. Returning default fallback.";
|
||||
|
||||
//--EARLY EXIT--( fall back to default assumption )
|
||||
return GeometryCache::Sphere;
|
||||
}
|
||||
|
||||
return MAPPING[entityShape];
|
||||
}
|
||||
|
||||
QString GeometryCache::stringFromShape(GeometryCache::Shape geoShape)
|
||||
{
|
||||
if (((int)geoShape < 0) || ((int)geoShape >= (int)GeometryCache::NUM_SHAPES)) {
|
||||
qCWarning(renderutils) << "GeometryCache::stringFromShape - Invalid shape " << geoShape << " specified.";
|
||||
|
||||
//--EARLY EXIT--
|
||||
return "INVALID_GEOCACHE_SHAPE";
|
||||
}
|
||||
|
||||
return GEOCACHE_SHAPE_STRINGS[geoShape];
|
||||
}
|
||||
|
||||
gpu::Stream::FormatPointer& getSolidStreamFormat() {
|
||||
if (!SOLID_STREAM_FORMAT) {
|
||||
SOLID_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
|
||||
|
|
|
@ -147,6 +147,16 @@ public:
|
|||
NUM_SHAPES,
|
||||
};
|
||||
|
||||
/// @param entityShapeEnum: The entity::Shape enumeration for the shape
|
||||
/// whose GeometryCache::Shape is desired.
|
||||
/// @return GeometryCache::NUM_SHAPES in the event of an error; otherwise,
|
||||
/// the GeometryCache::Shape enum which aligns with the
|
||||
/// specified entityShapeEnum
|
||||
static GeometryCache::Shape getShapeForEntityShape(int entityShapeEnum);
|
||||
static QString stringFromShape(GeometryCache::Shape geoShape);
|
||||
|
||||
static void computeSimpleHullPointListForShape(int entityShape, const glm::vec3 &entityExtents, QVector<glm::vec3> &outPointList);
|
||||
|
||||
static uint8_t CUSTOM_PIPELINE_NUMBER;
|
||||
static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key);
|
||||
static void registerShapePipeline() {
|
||||
|
@ -355,15 +365,21 @@ public:
|
|||
|
||||
using VShape = std::array<ShapeData, NUM_SHAPES>;
|
||||
|
||||
VShape _shapes;
|
||||
/// returns ShapeData associated with the specified shape,
|
||||
/// otherwise nullptr in the event of an error.
|
||||
const ShapeData * getShapeData(Shape shape) const;
|
||||
|
||||
private:
|
||||
|
||||
GeometryCache();
|
||||
virtual ~GeometryCache();
|
||||
void buildShapes();
|
||||
|
||||
typedef QPair<int, int> IntPair;
|
||||
typedef QPair<unsigned int, unsigned int> VerticesIndices;
|
||||
|
||||
|
||||
VShape _shapes;
|
||||
|
||||
gpu::PipelinePointer _standardDrawPipeline;
|
||||
gpu::PipelinePointer _standardDrawPipelineNoBlend;
|
||||
|
|
|
@ -138,7 +138,8 @@ void main(void) {
|
|||
}
|
||||
|
||||
// Mix with background at far range
|
||||
if (distance > 32000.0) {
|
||||
const float BLEND_DISTANCE = 27000.0;
|
||||
if (distance > BLEND_DISTANCE) {
|
||||
outFragColor = mix(potentialFragColor, fragColor, hazeParams.backgroundBlendValue);
|
||||
} else {
|
||||
outFragColor = potentialFragColor;
|
||||
|
|
|
@ -142,6 +142,11 @@ LightStage::LightPointer LightStage::removeLight(Index index) {
|
|||
LightPointer removed = _lights.freeElement(index);
|
||||
|
||||
if (removed) {
|
||||
auto shadowId = _descs[index].shadowId;
|
||||
// Remove shadow if one exists for this light
|
||||
if (shadowId != INVALID_INDEX) {
|
||||
_shadows.freeElement(shadowId);
|
||||
}
|
||||
_lightMap.erase(removed);
|
||||
_descs[index] = Desc();
|
||||
}
|
||||
|
|
|
@ -116,6 +116,30 @@ public:
|
|||
return LightAndShadow(getLight(lightId), getShadow(lightId));
|
||||
}
|
||||
|
||||
LightPointer getCurrentKeyLight() const {
|
||||
Index keyLightId{ 0 };
|
||||
if (!_currentFrame._sunLights.empty()) {
|
||||
keyLightId = _currentFrame._sunLights.front();
|
||||
}
|
||||
return _lights.get(keyLightId);
|
||||
}
|
||||
|
||||
ShadowPointer getCurrentKeyShadow() const {
|
||||
Index keyLightId{ 0 };
|
||||
if (!_currentFrame._sunLights.empty()) {
|
||||
keyLightId = _currentFrame._sunLights.front();
|
||||
}
|
||||
return getShadow(keyLightId);
|
||||
}
|
||||
|
||||
LightAndShadow getCurrentKeyLightAndShadow() const {
|
||||
Index keyLightId{ 0 };
|
||||
if (!_currentFrame._sunLights.empty()) {
|
||||
keyLightId = _currentFrame._sunLights.front();
|
||||
}
|
||||
return LightAndShadow(getLight(keyLightId), getShadow(keyLightId));
|
||||
}
|
||||
|
||||
LightStage();
|
||||
Lights _lights;
|
||||
LightMap _lightMap;
|
||||
|
|
|
@ -235,7 +235,6 @@ void Model::updateRenderItems() {
|
|||
self->updateClusterMatrices();
|
||||
|
||||
Transform modelTransform = self->getTransform();
|
||||
Transform physicsTransform = modelTransform;
|
||||
modelTransform.setScale(glm::vec3(1.0f));
|
||||
|
||||
uint32_t deleteGeometryCounter = self->_deleteGeometryCounter;
|
||||
|
@ -259,13 +258,12 @@ void Model::updateRenderItems() {
|
|||
});
|
||||
}
|
||||
|
||||
// collision mesh does not share the same unit scale as the FBX file's mesh: only apply offset
|
||||
Transform collisionMeshOffset;
|
||||
collisionMeshOffset.setIdentity();
|
||||
foreach(auto itemID, self->_collisionRenderItemsMap.keys()) {
|
||||
transaction.updateItem<MeshPartPayload>(itemID, [physicsTransform, collisionMeshOffset](MeshPartPayload& data) {
|
||||
transaction.updateItem<MeshPartPayload>(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) {
|
||||
// update the model transform for this render item.
|
||||
data.updateTransform(physicsTransform, collisionMeshOffset);
|
||||
data.updateTransform(modelTransform, collisionMeshOffset);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
|
||||
using namespace render;
|
||||
|
||||
#define OUTLINE_USE_SCISSOR false
|
||||
|
||||
OutlineRessources::OutlineRessources() {
|
||||
}
|
||||
|
||||
|
@ -122,6 +124,15 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con
|
|||
outputs = expandRect(outlinedRect, blurPixelWidth+1, framebufferSize);
|
||||
outlinedRect = expandRect(outputs, blurPixelWidth+1, framebufferSize);
|
||||
|
||||
// Clear the framebuffer without stereo
|
||||
// Needs to be distinct from the other batch because using the clear call
|
||||
// while stereo is enabled triggers a warning
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(ressources->getDepthFramebuffer());
|
||||
batch.clearDepthFramebuffer(1.0f);
|
||||
});
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
args->_batch = &batch;
|
||||
|
||||
|
@ -133,9 +144,10 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con
|
|||
args->getViewFrustum().evalProjectionMatrix(projMat);
|
||||
args->getViewFrustum().evalViewTransform(viewMat);
|
||||
|
||||
#if OUTLINE_USE_SCISSOR
|
||||
batch.setStateScissorRect(outlinedRect);
|
||||
#endif
|
||||
batch.setFramebuffer(ressources->getDepthFramebuffer());
|
||||
batch.clearDepthFramebuffer(1.0f, true);
|
||||
|
||||
// Setup camera, projection and viewport for all items
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
|
@ -282,7 +294,6 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I
|
|||
}
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(destinationFrameBuffer);
|
||||
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
|
@ -290,7 +301,9 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I
|
|||
batch.resetViewTransform();
|
||||
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport));
|
||||
batch.setPipeline(pipeline);
|
||||
#if OUTLINE_USE_SCISSOR
|
||||
batch.setStateScissorRect(outlineRect);
|
||||
#endif
|
||||
|
||||
batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration);
|
||||
batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer());
|
||||
|
@ -307,7 +320,7 @@ const gpu::PipelinePointer& DrawOutline::getPipeline() {
|
|||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false, false));
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
state->setScissorEnable(true);
|
||||
state->setScissorEnable(OUTLINE_USE_SCISSOR);
|
||||
|
||||
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(Outline_frag));
|
||||
|
@ -355,9 +368,10 @@ void DebugOutline::run(const render::RenderContextPointer& renderContext, const
|
|||
RenderArgs* args = renderContext->args;
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
#if OUTLINE_USE_SCISSOR
|
||||
batch.setStateScissorRect(outlineRect);
|
||||
#endif
|
||||
|
||||
const auto geometryBuffer = DependencyManager::get<GeometryCache>();
|
||||
|
||||
|
@ -392,7 +406,7 @@ void DebugOutline::initializePipelines() {
|
|||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
state->setScissorEnable(true);
|
||||
state->setScissorEnable(OUTLINE_USE_SCISSOR);
|
||||
|
||||
const auto vs = gpu::Shader::createVertex(VERTEX_SHADER);
|
||||
|
||||
|
@ -448,7 +462,7 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende
|
|||
auto state = std::make_shared<gpu::State>();
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
state->setColorWriteMask(false, false, false, false);
|
||||
state->setScissorEnable(true);
|
||||
state->setScissorEnable(OUTLINE_USE_SCISSOR);
|
||||
initMaskPipelines(*shapePlumber, state);
|
||||
}
|
||||
auto sharedParameters = std::make_shared<OutlineSharedParameters>();
|
||||
|
|
|
@ -458,7 +458,7 @@ void CompositeHUD::run(const RenderContextPointer& renderContext) {
|
|||
// Grab the HUD texture
|
||||
gpu::doInBatch(renderContext->args->_context, [&](gpu::Batch& batch) {
|
||||
if (renderContext->args->_hudOperator) {
|
||||
renderContext->args->_hudOperator(batch, renderContext->args->_hudTexture);
|
||||
renderContext->args->_hudOperator(batch, renderContext->args->_hudTexture, renderContext->args->_renderMode == RenderArgs::RenderMode::MIRROR_RENDER_MODE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -33,10 +33,8 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext,
|
|||
|
||||
auto lightStage = renderContext->_scene->getStage<LightStage>();
|
||||
assert(lightStage);
|
||||
LightStage::Index globalLightIndex { 0 };
|
||||
|
||||
const auto globalLight = lightStage->getLight(globalLightIndex);
|
||||
const auto shadow = lightStage->getShadow(globalLightIndex);
|
||||
const auto shadow = lightStage->getCurrentKeyShadow();
|
||||
if (!shadow) return;
|
||||
|
||||
const auto& fbo = shadow->framebuffer;
|
||||
|
@ -128,20 +126,22 @@ void RenderShadowTask::configure(const Config& configuration) {
|
|||
void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, Output& output) {
|
||||
auto lightStage = renderContext->_scene->getStage<LightStage>();
|
||||
assert(lightStage);
|
||||
const auto globalShadow = lightStage->getShadow(0);
|
||||
|
||||
// Cache old render args
|
||||
RenderArgs* args = renderContext->args;
|
||||
output = args->_renderMode;
|
||||
const auto globalShadow = lightStage->getCurrentKeyShadow();
|
||||
if (globalShadow) {
|
||||
// Cache old render args
|
||||
RenderArgs* args = renderContext->args;
|
||||
output = args->_renderMode;
|
||||
|
||||
auto nearClip = args->getViewFrustum().getNearClip();
|
||||
float nearDepth = -args->_boomOffset.z;
|
||||
const int SHADOW_FAR_DEPTH = 20;
|
||||
globalShadow->setKeylightFrustum(args->getViewFrustum(), nearDepth, nearClip + SHADOW_FAR_DEPTH);
|
||||
auto nearClip = args->getViewFrustum().getNearClip();
|
||||
float nearDepth = -args->_boomOffset.z;
|
||||
const int SHADOW_FAR_DEPTH = 20;
|
||||
globalShadow->setKeylightFrustum(args->getViewFrustum(), nearDepth, nearClip + SHADOW_FAR_DEPTH);
|
||||
|
||||
// Set the keylight render args
|
||||
args->pushViewFrustum(*(globalShadow->getFrustum()));
|
||||
args->_renderMode = RenderArgs::SHADOW_RENDER_MODE;
|
||||
// Set the keylight render args
|
||||
args->pushViewFrustum(*(globalShadow->getFrustum()));
|
||||
args->_renderMode = RenderArgs::SHADOW_RENDER_MODE;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderShadowTeardown::run(const render::RenderContextPointer& renderContext, const Input& input) {
|
||||
|
|
|
@ -122,7 +122,7 @@ namespace render {
|
|||
render::ScenePointer _scene;
|
||||
int8_t _cameraMode { -1 };
|
||||
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> _hudOperator;
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> _hudOperator;
|
||||
gpu::TexturePointer _hudTexture;
|
||||
};
|
||||
|
||||
|
|
|
@ -97,7 +97,6 @@ static const bool HIFI_AUTOREFRESH_FILE_SCRIPTS { true };
|
|||
Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature)
|
||||
int functionSignatureMetaID = qRegisterMetaType<QScriptEngine::FunctionSignature>();
|
||||
|
||||
Q_DECLARE_METATYPE(ScriptEnginePointer)
|
||||
int scriptEnginePointerMetaID = qRegisterMetaType<ScriptEnginePointer>();
|
||||
|
||||
Q_LOGGING_CATEGORY(scriptengineScript, "hifi.scriptengine.script")
|
||||
|
|
|
@ -55,6 +55,8 @@ static const int DEFAULT_ENTITY_PPS_PER_SCRIPT = 900;
|
|||
|
||||
class ScriptEngines;
|
||||
|
||||
Q_DECLARE_METATYPE(ScriptEnginePointer)
|
||||
|
||||
class CallbackData {
|
||||
public:
|
||||
QScriptValue function;
|
||||
|
|
|
@ -15,9 +15,38 @@
|
|||
|
||||
#include "NumericalConstants.h" // for MILLIMETERS_PER_METER
|
||||
|
||||
// Originally within EntityItemProperties.cpp
|
||||
const char* shapeTypeNames[] = {
|
||||
"none",
|
||||
"box",
|
||||
"sphere",
|
||||
"capsule-x",
|
||||
"capsule-y",
|
||||
"capsule-z",
|
||||
"cylinder-x",
|
||||
"cylinder-y",
|
||||
"cylinder-z",
|
||||
"hull",
|
||||
"plane",
|
||||
"compound",
|
||||
"simple-hull",
|
||||
"simple-compound",
|
||||
"static-mesh"
|
||||
};
|
||||
|
||||
static const size_t SHAPETYPE_NAME_COUNT = (sizeof(shapeTypeNames) / sizeof((shapeTypeNames)[0]));
|
||||
|
||||
// Bullet doesn't support arbitrarily small shapes
|
||||
const float MIN_HALF_EXTENT = 0.005f; // 0.5 cm
|
||||
|
||||
QString ShapeInfo::getNameForShapeType(ShapeType type) {
|
||||
if (((int)type <= 0) || ((int)type >= (int)SHAPETYPE_NAME_COUNT)) {
|
||||
type = (ShapeType)0;
|
||||
}
|
||||
|
||||
return shapeTypeNames[(int)type];
|
||||
}
|
||||
|
||||
void ShapeInfo::clear() {
|
||||
_url.clear();
|
||||
_pointCollection.clear();
|
||||
|
@ -29,7 +58,6 @@ void ShapeInfo::clear() {
|
|||
}
|
||||
|
||||
void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) {
|
||||
//TODO WL21389: Does this need additional cases and handling added?
|
||||
_url = "";
|
||||
_type = type;
|
||||
setHalfExtents(halfExtents);
|
||||
|
@ -38,6 +66,7 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
|
|||
_halfExtents = glm::vec3(0.0f);
|
||||
break;
|
||||
case SHAPE_TYPE_BOX:
|
||||
case SHAPE_TYPE_HULL:
|
||||
break;
|
||||
case SHAPE_TYPE_SPHERE: {
|
||||
float radius = glm::length(halfExtents) / SQUARE_ROOT_OF_3;
|
||||
|
@ -45,7 +74,13 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
|
|||
_halfExtents = glm::vec3(radius);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CIRCLE: {
|
||||
_halfExtents = glm::vec3(_halfExtents.x, MIN_HALF_EXTENT, _halfExtents.z);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_COMPOUND:
|
||||
case SHAPE_TYPE_SIMPLE_HULL:
|
||||
case SHAPE_TYPE_SIMPLE_COMPOUND:
|
||||
case SHAPE_TYPE_STATIC_MESH:
|
||||
_url = QUrl(url);
|
||||
break;
|
||||
|
@ -56,9 +91,6 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
|
|||
}
|
||||
|
||||
void ShapeInfo::setBox(const glm::vec3& halfExtents) {
|
||||
//TODO WL21389: Should this pointlist clearance added in case
|
||||
// this is a re-purposed instance?
|
||||
// See https://github.com/highfidelity/hifi/pull/11024#discussion_r128885491
|
||||
_url = "";
|
||||
_type = SHAPE_TYPE_BOX;
|
||||
setHalfExtents(halfExtents);
|
||||
|
@ -66,7 +98,6 @@ void ShapeInfo::setBox(const glm::vec3& halfExtents) {
|
|||
}
|
||||
|
||||
void ShapeInfo::setSphere(float radius) {
|
||||
//TODO WL21389: See comment in setBox regarding clearance
|
||||
_url = "";
|
||||
_type = SHAPE_TYPE_SPHERE;
|
||||
radius = glm::max(radius, MIN_HALF_EXTENT);
|
||||
|
@ -75,14 +106,11 @@ void ShapeInfo::setSphere(float radius) {
|
|||
}
|
||||
|
||||
void ShapeInfo::setPointCollection(const ShapeInfo::PointCollection& pointCollection) {
|
||||
//TODO WL21389: May need to skip resetting type here.
|
||||
_pointCollection = pointCollection;
|
||||
_type = (_pointCollection.size() > 0) ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE;
|
||||
_doubleHashKey.clear();
|
||||
}
|
||||
|
||||
void ShapeInfo::setCapsuleY(float radius, float halfHeight) {
|
||||
//TODO WL21389: See comment in setBox regarding clearance
|
||||
_url = "";
|
||||
_type = SHAPE_TYPE_CAPSULE_Y;
|
||||
radius = glm::max(radius, MIN_HALF_EXTENT);
|
||||
|
@ -123,8 +151,15 @@ int ShapeInfo::getLargestSubshapePointCount() const {
|
|||
return numPoints;
|
||||
}
|
||||
|
||||
float computeCylinderVolume(const float radius, const float height) {
|
||||
return PI * radius * radius * 2.0f * height;
|
||||
}
|
||||
|
||||
float computeCapsuleVolume(const float radius, const float cylinderHeight) {
|
||||
return PI * radius * radius * (cylinderHeight + 4.0f * radius / 3.0f);
|
||||
}
|
||||
|
||||
float ShapeInfo::computeVolume() const {
|
||||
//TODO WL21389: Add support for other ShapeTypes( CYLINDER_X, CYLINDER_Y, etc).
|
||||
const float DEFAULT_VOLUME = 1.0f;
|
||||
float volume = DEFAULT_VOLUME;
|
||||
switch(_type) {
|
||||
|
@ -137,17 +172,37 @@ float ShapeInfo::computeVolume() const {
|
|||
volume = 4.0f * PI * _halfExtents.x * _halfExtents.y * _halfExtents.z / 3.0f;
|
||||
break;
|
||||
}
|
||||
case SHAPE_TYPE_CYLINDER_X: {
|
||||
volume = computeCylinderVolume(_halfExtents.y, _halfExtents.x);
|
||||
break;
|
||||
}
|
||||
case SHAPE_TYPE_CYLINDER_Y: {
|
||||
float radius = _halfExtents.x;
|
||||
volume = PI * radius * radius * 2.0f * _halfExtents.y;
|
||||
volume = computeCylinderVolume(_halfExtents.x, _halfExtents.y);
|
||||
break;
|
||||
}
|
||||
case SHAPE_TYPE_CYLINDER_Z: {
|
||||
volume = computeCylinderVolume(_halfExtents.x, _halfExtents.z);
|
||||
break;
|
||||
}
|
||||
case SHAPE_TYPE_CAPSULE_X: {
|
||||
// Need to offset halfExtents.x by y to account for the system treating
|
||||
// the x extent of the capsule as the cylindrical height + spherical radius.
|
||||
const float cylinderHeight = 2.0f * (_halfExtents.x - _halfExtents.y);
|
||||
volume = computeCapsuleVolume(_halfExtents.y, cylinderHeight);
|
||||
break;
|
||||
}
|
||||
case SHAPE_TYPE_CAPSULE_Y: {
|
||||
float radius = _halfExtents.x;
|
||||
// Need to offset halfExtents.y by x to account for the system treating
|
||||
// the y extent of the capsule as the cylindrical height + spherical radius.
|
||||
float cylinderHeight = 2.0f * (_halfExtents.y - _halfExtents.x);
|
||||
volume = PI * radius * radius * (cylinderHeight + 4.0f * radius / 3.0f);
|
||||
const float cylinderHeight = 2.0f * (_halfExtents.y - _halfExtents.x);
|
||||
volume = computeCapsuleVolume(_halfExtents.x, cylinderHeight);
|
||||
break;
|
||||
}
|
||||
case SHAPE_TYPE_CAPSULE_Z: {
|
||||
// Need to offset halfExtents.z by x to account for the system treating
|
||||
// the z extent of the capsule as the cylindrical height + spherical radius.
|
||||
const float cylinderHeight = 2.0f * (_halfExtents.z - _halfExtents.x);
|
||||
volume = computeCapsuleVolume(_halfExtents.x, cylinderHeight);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -158,7 +213,6 @@ float ShapeInfo::computeVolume() const {
|
|||
}
|
||||
|
||||
bool ShapeInfo::contains(const glm::vec3& point) const {
|
||||
//TODO WL21389: Add support for other ShapeTypes like Ellipsoid/Compound.
|
||||
switch(_type) {
|
||||
case SHAPE_TYPE_SPHERE:
|
||||
return glm::length(point) <= _halfExtents.x;
|
||||
|
@ -203,7 +257,6 @@ bool ShapeInfo::contains(const glm::vec3& point) const {
|
|||
}
|
||||
|
||||
const DoubleHashKey& ShapeInfo::getHash() const {
|
||||
//TODO WL21389: Need to include the pointlist for SIMPLE_HULL in hash
|
||||
// NOTE: we cache the key so we only ever need to compute it once for any valid ShapeInfo instance.
|
||||
if (_doubleHashKey.isNull() && _type != SHAPE_TYPE_NONE) {
|
||||
bool useOffset = glm::length2(_offset) > MIN_SHAPE_OFFSET * MIN_SHAPE_OFFSET;
|
||||
|
@ -214,52 +267,103 @@ const DoubleHashKey& ShapeInfo::getHash() const {
|
|||
uint32_t primeIndex = 0;
|
||||
_doubleHashKey.computeHash((uint32_t)_type, primeIndex++);
|
||||
|
||||
// compute hash1
|
||||
uint32_t hash = _doubleHashKey.getHash();
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
// NOTE: 0.49f is used to bump the float up almost half a millimeter
|
||||
// so the cast to int produces a round() effect rather than a floor()
|
||||
hash ^= DoubleHashKey::hashFunction(
|
||||
if (_type != SHAPE_TYPE_SIMPLE_HULL) {
|
||||
// compute hash1
|
||||
uint32_t hash = _doubleHashKey.getHash();
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
// NOTE: 0.49f is used to bump the float up almost half a millimeter
|
||||
// so the cast to int produces a round() effect rather than a floor()
|
||||
hash ^= DoubleHashKey::hashFunction(
|
||||
(uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f),
|
||||
primeIndex++);
|
||||
if (useOffset) {
|
||||
hash ^= DoubleHashKey::hashFunction(
|
||||
if (useOffset) {
|
||||
hash ^= DoubleHashKey::hashFunction(
|
||||
(uint32_t)(_offset[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _offset[j]) * 0.49f),
|
||||
primeIndex++);
|
||||
}
|
||||
}
|
||||
}
|
||||
_doubleHashKey.setHash(hash);
|
||||
_doubleHashKey.setHash(hash);
|
||||
|
||||
// compute hash2
|
||||
hash = _doubleHashKey.getHash2();
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
// NOTE: 0.49f is used to bump the float up almost half a millimeter
|
||||
// so the cast to int produces a round() effect rather than a floor()
|
||||
uint32_t floatHash = DoubleHashKey::hashFunction2(
|
||||
// compute hash2
|
||||
hash = _doubleHashKey.getHash2();
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
// NOTE: 0.49f is used to bump the float up almost half a millimeter
|
||||
// so the cast to int produces a round() effect rather than a floor()
|
||||
uint32_t floatHash = DoubleHashKey::hashFunction2(
|
||||
(uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f));
|
||||
if (useOffset) {
|
||||
floatHash ^= DoubleHashKey::hashFunction2(
|
||||
if (useOffset) {
|
||||
floatHash ^= DoubleHashKey::hashFunction2(
|
||||
(uint32_t)(_offset[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _offset[j]) * 0.49f));
|
||||
}
|
||||
hash += ~(floatHash << 17);
|
||||
hash ^= (floatHash >> 11);
|
||||
hash += (floatHash << 4);
|
||||
hash ^= (floatHash >> 7);
|
||||
hash += ~(floatHash << 10);
|
||||
hash = (hash << 16) | (hash >> 16);
|
||||
}
|
||||
hash += ~(floatHash << 17);
|
||||
hash ^= (floatHash >> 11);
|
||||
hash += (floatHash << 4);
|
||||
hash ^= (floatHash >> 7);
|
||||
hash += ~(floatHash << 10);
|
||||
hash = (hash << 16) | (hash >> 16);
|
||||
}
|
||||
_doubleHashKey.setHash2(hash);
|
||||
_doubleHashKey.setHash2(hash);
|
||||
} else {
|
||||
|
||||
if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_STATIC_MESH) {
|
||||
QString url = _url.toString();
|
||||
if (!url.isEmpty()) {
|
||||
// fold the urlHash into both parts
|
||||
QByteArray baUrl = url.toLocal8Bit();
|
||||
const char *cUrl = baUrl.data();
|
||||
uint32_t urlHash = qChecksum(cUrl, baUrl.count());
|
||||
_doubleHashKey.setHash(_doubleHashKey.getHash() ^ urlHash);
|
||||
_doubleHashKey.setHash2(_doubleHashKey.getHash2() ^ urlHash);
|
||||
assert(_pointCollection.size() == (size_t)1);
|
||||
const PointList & points = _pointCollection.back();
|
||||
const int numPoints = (int)points.size();
|
||||
uint32_t hash = _doubleHashKey.getHash();
|
||||
uint32_t hash2 = _doubleHashKey.getHash2();
|
||||
|
||||
for (int pointIndex = 0; pointIndex < numPoints; ++pointIndex) {
|
||||
// compute hash1 & 2
|
||||
const glm::vec3 &curPoint = points[pointIndex];
|
||||
for (int vecCompIndex = 0; vecCompIndex < 3; ++vecCompIndex) {
|
||||
|
||||
// NOTE: 0.49f is used to bump the float up almost half a millimeter
|
||||
// so the cast to int produces a round() effect rather than a floor()
|
||||
uint32_t valueToHash = (uint32_t)(curPoint[vecCompIndex] * MILLIMETERS_PER_METER + copysignf(1.0f, curPoint[vecCompIndex]) * 0.49f);
|
||||
|
||||
hash ^= DoubleHashKey::hashFunction(valueToHash, primeIndex++);
|
||||
uint32_t floatHash = DoubleHashKey::hashFunction2(valueToHash);
|
||||
|
||||
if (useOffset) {
|
||||
|
||||
const uint32_t offsetValToHash = (uint32_t)(_offset[vecCompIndex] * MILLIMETERS_PER_METER + copysignf(1.0f, _offset[vecCompIndex])* 0.49f);
|
||||
|
||||
hash ^= DoubleHashKey::hashFunction(offsetValToHash, primeIndex++);
|
||||
floatHash ^= DoubleHashKey::hashFunction2(offsetValToHash);
|
||||
}
|
||||
|
||||
hash2 += ~(floatHash << 17);
|
||||
hash2 ^= (floatHash >> 11);
|
||||
hash2 += (floatHash << 4);
|
||||
hash2 ^= (floatHash >> 7);
|
||||
hash2 += ~(floatHash << 10);
|
||||
hash2 = (hash2 << 16) | (hash2 >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
_doubleHashKey.setHash(hash);
|
||||
_doubleHashKey.setHash2(hash2);
|
||||
}
|
||||
|
||||
QString url = _url.toString();
|
||||
if (!url.isEmpty()) {
|
||||
// fold the urlHash into both parts
|
||||
QByteArray baUrl = url.toLocal8Bit();
|
||||
uint32_t urlHash = qChecksum(baUrl.data(), baUrl.size());
|
||||
_doubleHashKey.setHash(_doubleHashKey.getHash() ^ urlHash);
|
||||
_doubleHashKey.setHash2(_doubleHashKey.getHash2() ^ urlHash);
|
||||
}
|
||||
|
||||
uint32_t numHulls = 0;
|
||||
if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
numHulls = (uint32_t)_pointCollection.size();
|
||||
} else if (_type == SHAPE_TYPE_SIMPLE_HULL) {
|
||||
numHulls = 1;
|
||||
}
|
||||
if (numHulls > 0) {
|
||||
uint32_t hash = DoubleHashKey::hashFunction(numHulls, primeIndex++);
|
||||
_doubleHashKey.setHash(_doubleHashKey.getHash() ^ hash);
|
||||
hash = DoubleHashKey::hashFunction2(numHulls);
|
||||
_doubleHashKey.setHash2(_doubleHashKey.getHash2() ^ hash);
|
||||
}
|
||||
}
|
||||
return _doubleHashKey;
|
||||
|
|
|
@ -46,7 +46,8 @@ enum ShapeType {
|
|||
SHAPE_TYPE_SIMPLE_HULL,
|
||||
SHAPE_TYPE_SIMPLE_COMPOUND,
|
||||
SHAPE_TYPE_STATIC_MESH,
|
||||
SHAPE_TYPE_ELLIPSOID
|
||||
SHAPE_TYPE_ELLIPSOID,
|
||||
SHAPE_TYPE_CIRCLE
|
||||
};
|
||||
|
||||
class ShapeInfo {
|
||||
|
@ -57,6 +58,8 @@ public:
|
|||
using PointCollection = QVector<PointList>;
|
||||
using TriangleIndices = QVector<int32_t>;
|
||||
|
||||
static QString getNameForShapeType(ShapeType type);
|
||||
|
||||
void clear();
|
||||
|
||||
void setParams(ShapeType type, const glm::vec3& halfExtents, QString url="");
|
||||
|
@ -66,7 +69,7 @@ public:
|
|||
void setCapsuleY(float radius, float halfHeight);
|
||||
void setOffset(const glm::vec3& offset);
|
||||
|
||||
int getType() const { return _type; }
|
||||
ShapeType getType() const { return _type; }
|
||||
|
||||
const glm::vec3& getHalfExtents() const { return _halfExtents; }
|
||||
const glm::vec3& getOffset() const { return _offset; }
|
||||
|
|
|
@ -963,35 +963,41 @@ AACube SpatiallyNestable::getMaximumAACube(bool& success) const {
|
|||
|
||||
const float PARENTED_EXPANSION_FACTOR = 3.0f;
|
||||
|
||||
bool SpatiallyNestable::checkAndMaybeUpdateQueryAACube() {
|
||||
bool success = false;
|
||||
AACube maxAACube = getMaximumAACube(success);
|
||||
if (success) {
|
||||
// maybe update _queryAACube
|
||||
if (!_queryAACubeSet || (_parentID.isNull() && _children.size() == 0) || !_queryAACube.contains(maxAACube)) {
|
||||
if (_parentJointIndex != INVALID_JOINT_INDEX || _children.size() > 0 ) {
|
||||
// make an expanded AACube centered on the object
|
||||
float scale = PARENTED_EXPANSION_FACTOR * maxAACube.getScale();
|
||||
_queryAACube = AACube(maxAACube.calcCenter() - glm::vec3(0.5f * scale), scale);
|
||||
} else {
|
||||
_queryAACube = maxAACube;
|
||||
}
|
||||
|
||||
forEachDescendant([&](const SpatiallyNestablePointer& descendant) {
|
||||
bool childSuccess;
|
||||
AACube descendantAACube = descendant->getQueryAACube(childSuccess);
|
||||
if (childSuccess) {
|
||||
if (_queryAACube.contains(descendantAACube)) {
|
||||
return ;
|
||||
}
|
||||
_queryAACube += descendantAACube.getMinimumPoint();
|
||||
_queryAACube += descendantAACube.getMaximumPoint();
|
||||
}
|
||||
});
|
||||
_queryAACubeSet = true;
|
||||
}
|
||||
bool SpatiallyNestable::updateQueryAACube() {
|
||||
if (!queryAACubeNeedsUpdate()) {
|
||||
return false;
|
||||
}
|
||||
return success;
|
||||
|
||||
bool success;
|
||||
AACube maxAACube = getMaximumAACube(success);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (shouldPuffQueryAACube()) {
|
||||
// make an expanded AACube centered on the object
|
||||
float scale = PARENTED_EXPANSION_FACTOR * maxAACube.getScale();
|
||||
_queryAACube = AACube(maxAACube.calcCenter() - glm::vec3(0.5f * scale), scale);
|
||||
_queryAACubeIsPuffed = true;
|
||||
} else {
|
||||
_queryAACube = maxAACube;
|
||||
_queryAACubeIsPuffed = false;
|
||||
}
|
||||
|
||||
forEachDescendant([&](const SpatiallyNestablePointer& descendant) {
|
||||
bool childSuccess;
|
||||
AACube descendantAACube = descendant->getQueryAACube(childSuccess);
|
||||
if (childSuccess) {
|
||||
if (_queryAACube.contains(descendantAACube)) {
|
||||
return; // from lambda
|
||||
}
|
||||
_queryAACube += descendantAACube.getMinimumPoint();
|
||||
_queryAACube += descendantAACube.getMaximumPoint();
|
||||
}
|
||||
});
|
||||
|
||||
_queryAACubeSet = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setQueryAACube(const AACube& queryAACube) {
|
||||
|
@ -1008,6 +1014,16 @@ bool SpatiallyNestable::queryAACubeNeedsUpdate() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool success;
|
||||
AACube maxAACube = getMaximumAACube(success);
|
||||
if (success && !_queryAACube.contains(maxAACube)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (shouldPuffQueryAACube() != _queryAACubeIsPuffed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// make sure children are still in their boxes, also.
|
||||
bool childNeedsUpdate = false;
|
||||
forEachDescendantTest([&](const SpatiallyNestablePointer& descendant) {
|
||||
|
@ -1021,31 +1037,6 @@ bool SpatiallyNestable::queryAACubeNeedsUpdate() const {
|
|||
return childNeedsUpdate;
|
||||
}
|
||||
|
||||
void SpatiallyNestable::updateQueryAACube() {
|
||||
bool success;
|
||||
AACube maxAACube = getMaximumAACube(success);
|
||||
if (_parentJointIndex != INVALID_JOINT_INDEX || _children.size() > 0 ) {
|
||||
// make an expanded AACube centered on the object
|
||||
float scale = PARENTED_EXPANSION_FACTOR * maxAACube.getScale();
|
||||
_queryAACube = AACube(maxAACube.calcCenter() - glm::vec3(0.5f * scale), scale);
|
||||
} else {
|
||||
_queryAACube = maxAACube;
|
||||
}
|
||||
|
||||
forEachDescendant([&](const SpatiallyNestablePointer& descendant) {
|
||||
bool success;
|
||||
AACube descendantAACube = descendant->getQueryAACube(success);
|
||||
if (success) {
|
||||
if (_queryAACube.contains(descendantAACube)) {
|
||||
return;
|
||||
}
|
||||
_queryAACube += descendantAACube.getMinimumPoint();
|
||||
_queryAACube += descendantAACube.getMaximumPoint();
|
||||
}
|
||||
});
|
||||
_queryAACubeSet = true;
|
||||
}
|
||||
|
||||
AACube SpatiallyNestable::getQueryAACube(bool& success) const {
|
||||
if (_queryAACubeSet) {
|
||||
success = true;
|
||||
|
|
|
@ -106,11 +106,11 @@ public:
|
|||
virtual glm::vec3 getParentAngularVelocity(bool& success) const;
|
||||
|
||||
virtual AACube getMaximumAACube(bool& success) const;
|
||||
bool checkAndMaybeUpdateQueryAACube();
|
||||
void updateQueryAACube();
|
||||
|
||||
virtual void setQueryAACube(const AACube& queryAACube);
|
||||
virtual bool queryAACubeNeedsUpdate() const;
|
||||
virtual bool shouldPuffQueryAACube() const { return false; }
|
||||
bool updateQueryAACube();
|
||||
void forceQueryAACubeUpdate() { _queryAACubeSet = false; }
|
||||
virtual AACube getQueryAACube(bool& success) const;
|
||||
virtual AACube getQueryAACube() const;
|
||||
|
@ -234,6 +234,7 @@ private:
|
|||
glm::vec3 _angularVelocity;
|
||||
mutable bool _parentKnowsMe { false };
|
||||
bool _isDead { false };
|
||||
bool _queryAACubeIsPuffed { false };
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -104,8 +104,9 @@ bool TriangleSet::TriangleOctreeCell::findRayIntersectionInternal(const glm::vec
|
|||
if (_bounds.findRayIntersection(origin, direction, boxDistance, face, surfaceNormal)) {
|
||||
|
||||
// if our bounding box intersects at a distance greater than the current known
|
||||
// best distance, than we can safely not check any of our triangles
|
||||
if (boxDistance > bestDistance) {
|
||||
// best distance, and our origin isn't inside the boounds, then we can safely
|
||||
// not check any of our triangles
|
||||
if (boxDistance > bestDistance && !_bounds.contains(origin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1082,37 +1082,7 @@ void OffscreenQmlSurface::synthesizeKeyPress(QString key, QObject* targetOverrid
|
|||
}
|
||||
}
|
||||
|
||||
static void forEachKeyboard(QQuickItem* parent, std::function<void(QQuickItem*)> function) {
|
||||
if (!function) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto keyboards = parent->findChildren<QObject*>("keyboard");
|
||||
|
||||
for (auto keyboardObject : keyboards) {
|
||||
auto keyboard = qobject_cast<QQuickItem*>(keyboardObject);
|
||||
if (keyboard) {
|
||||
function(keyboard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const int TEXTINPUT_PASSWORD = 2;
|
||||
|
||||
static QQuickItem* getTopmostParent(QQuickItem* item) {
|
||||
QObject* itemObject = item;
|
||||
while (itemObject) {
|
||||
if (itemObject->parent()) {
|
||||
itemObject = itemObject->parent();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return qobject_cast<QQuickItem*> (itemObject);
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool numeric) {
|
||||
void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool numeric, bool passwordField) {
|
||||
#if Q_OS_ANDROID
|
||||
return;
|
||||
#endif
|
||||
|
@ -1128,21 +1098,6 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n
|
|||
return;
|
||||
}
|
||||
|
||||
auto echoMode = item->property("echoMode");
|
||||
bool isPasswordField = echoMode.isValid() && echoMode.toInt() == TEXTINPUT_PASSWORD;
|
||||
|
||||
// we need to somehow pass 'isPasswordField' to visible keyboard so it will change its 'mirror text' to asterixes
|
||||
// the issue in some cases there might be more than one keyboard in object tree and it is hard to understand which one is being used at the moment
|
||||
// unfortunately attempts to check for visibility failed becuase visibility is not updated yet. So... I don't see other way than just update properties for all the keyboards
|
||||
|
||||
auto topmostParent = getTopmostParent(item);
|
||||
if (topmostParent) {
|
||||
forEachKeyboard(topmostParent, [&](QQuickItem* keyboard) {
|
||||
keyboard->setProperty("mirroredText", QVariant::fromValue(QString("")));
|
||||
keyboard->setProperty("password", isPasswordField);
|
||||
});
|
||||
}
|
||||
|
||||
// for future probably makes sense to consider one of the following:
|
||||
// 1. make keyboard a singleton, which will be dynamically re-parented before showing
|
||||
// 2. track currently visible keyboard somewhere, allow to subscribe for this signal
|
||||
|
@ -1153,15 +1108,15 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n
|
|||
numeric = numeric || QString(item->metaObject()->className()).left(7) == "SpinBox";
|
||||
|
||||
if (item->property("keyboardRaised").isValid()) {
|
||||
forEachKeyboard(item, [&](QQuickItem* keyboard) {
|
||||
keyboard->setProperty("mirroredText", QVariant::fromValue(QString("")));
|
||||
keyboard->setProperty("password", isPasswordField);
|
||||
});
|
||||
|
||||
// FIXME - HMD only: Possibly set value of "keyboardEnabled" per isHMDMode() for use in WebView.qml.
|
||||
if (item->property("punctuationMode").isValid()) {
|
||||
item->setProperty("punctuationMode", QVariant(numeric));
|
||||
}
|
||||
if (item->property("passwordField").isValid()) {
|
||||
item->setProperty("passwordField", QVariant(passwordField));
|
||||
}
|
||||
|
||||
item->setProperty("keyboardRaised", QVariant(raised));
|
||||
return;
|
||||
}
|
||||
|
@ -1186,9 +1141,13 @@ void OffscreenQmlSurface::emitWebEvent(const QVariant& message) {
|
|||
const QString RAISE_KEYBOARD = "_RAISE_KEYBOARD";
|
||||
const QString RAISE_KEYBOARD_NUMERIC = "_RAISE_KEYBOARD_NUMERIC";
|
||||
const QString LOWER_KEYBOARD = "_LOWER_KEYBOARD";
|
||||
const QString RAISE_KEYBOARD_NUMERIC_PASSWORD = "_RAISE_KEYBOARD_NUMERIC_PASSWORD";
|
||||
const QString RAISE_KEYBOARD_PASSWORD = "_RAISE_KEYBOARD_PASSWORD";
|
||||
QString messageString = message.type() == QVariant::String ? message.toString() : "";
|
||||
if (messageString.left(RAISE_KEYBOARD.length()) == RAISE_KEYBOARD) {
|
||||
setKeyboardRaised(_currentFocusItem, true, messageString == RAISE_KEYBOARD_NUMERIC);
|
||||
bool numeric = (messageString == RAISE_KEYBOARD_NUMERIC || messageString == RAISE_KEYBOARD_NUMERIC_PASSWORD);
|
||||
bool passwordField = (messageString == RAISE_KEYBOARD_PASSWORD || messageString == RAISE_KEYBOARD_NUMERIC_PASSWORD);
|
||||
setKeyboardRaised(_currentFocusItem, true, numeric, passwordField);
|
||||
} else if (messageString == LOWER_KEYBOARD) {
|
||||
setKeyboardRaised(_currentFocusItem, false);
|
||||
} else {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue