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

This commit is contained in:
Sam Gateau 2017-10-21 10:01:07 -07:00
commit 50a3ccdbca
104 changed files with 1309 additions and 719 deletions

View file

@ -25,7 +25,7 @@ The above dependencies will be downloaded, built, linked and included automatica
These are not placed in your normal build tree when doing an out of source build so that they do not need to be re-downloaded and re-compiled every time the CMake build folder is cleared. Should you want to force a re-download and re-compile of a specific external, you can simply remove that directory from the appropriate subfolder in `build/ext`. Should you want to force a re-download and re-compile of all externals, just remove the `build/ext` folder.
If you would like to use a specific install of a dependency instead of the version that would be grabbed as a CMake ExternalProject, you can pass -DUSE_LOCAL_$NAME=0 (where $NAME is the name of the subfolder in [cmake/externals](cmake/externals)) when you run CMake to tell it not to get that dependency as an external project.
If you would like to use a specific install of a dependency instead of the version that would be grabbed as a CMake ExternalProject, you can pass -DUSE\_LOCAL\_$NAME=0 (where $NAME is the name of the subfolder in [cmake/externals](cmake/externals)) when you run CMake to tell it not to get that dependency as an external project.
### OS Specific Build Guides

View file

@ -210,6 +210,7 @@ endif()
# link required hifi libraries
link_hifi_libraries(
shared octree ktx gpu gl gpu-gl procedural model render
pointers
recording fbx networking model-networking entities avatars trackers
audio audio-client animation script-engine physics
render-utils entities-renderer avatars-renderer ui auto-updater midi

View file

@ -11,6 +11,7 @@
import QtQuick 2.5
import QtQuick.Controls 1.4 as Original
import QtQuick.Controls.Styles 1.4
import TabletScriptingInterface 1.0
import "../styles-uit"
@ -26,6 +27,16 @@ Original.Button {
HifiConstants { id: hifi }
onHoveredChanged: {
if (hovered) {
tabletInterface.playSound(TabletEnums.ButtonHover);
}
}
onClicked: {
tabletInterface.playSound(TabletEnums.ButtonClick);
}
style: ButtonStyle {
background: Rectangle {

View file

@ -14,6 +14,8 @@ import QtQuick.Controls.Styles 1.4
import "../styles-uit"
import TabletScriptingInterface 1.0
Original.CheckBox {
id: checkBox
@ -28,6 +30,15 @@ Original.CheckBox {
readonly property int checkRadius: 2
activeFocusOnPress: true
onClicked: {
tabletInterface.playSound(TabletEnums.ButtonClick);
}
// TODO: doesnt works for QQC1. check with QQC2
// onHovered: {
// tabletInterface.playSound(TabletEnums.ButtonHover);
// }
style: CheckBoxStyle {
indicator: Rectangle {
id: box

View file

@ -13,6 +13,7 @@ import QtQuick.Controls 2.2
import "../styles-uit"
import "../controls-uit" as HiFiControls
import TabletScriptingInterface 1.0
CheckBox {
id: checkBox
@ -32,6 +33,17 @@ CheckBox {
readonly property int checkSize: Math.max(boxSize - 8, 10)
readonly property int checkRadius: isRound ? checkSize / 2 : 2
focusPolicy: Qt.ClickFocus
hoverEnabled: true
onClicked: {
tabletInterface.playSound(TabletEnums.ButtonClick);
}
onHoveredChanged: {
if (hovered) {
tabletInterface.playSound(TabletEnums.ButtonHover);
}
}
indicator: Rectangle {
id: box

View file

@ -12,6 +12,7 @@
import QtQuick 2.5
import QtQuick.Controls 1.4 as Original
import QtQuick.Controls.Styles 1.4
import TabletScriptingInterface 1.0
import "../styles-uit"
@ -24,6 +25,16 @@ Original.Button {
width: 120
height: 28
onHoveredChanged: {
if (hovered) {
tabletInterface.playSound(TabletEnums.ButtonHover);
}
}
onClicked: {
tabletInterface.playSound(TabletEnums.ButtonClick);
}
style: ButtonStyle {
background: Rectangle {

View file

@ -1,4 +1,5 @@
import QtQuick 2.0
import TabletScriptingInterface 1.0
Item {
id: keyItem
@ -32,8 +33,15 @@ Item {
}
}
onContainsMouseChanged: {
if (containsMouse) {
tabletInterface.playSound(TabletEnums.ButtonHover);
}
}
onClicked: {
mouse.accepted = true;
tabletInterface.playSound(TabletEnums.ButtonClick);
webEntity.synthesizeKeyPress(glyph);
webEntity.synthesizeKeyPress(glyph, mirrorText);

View file

@ -15,6 +15,8 @@ import QtQuick.Controls.Styles 1.4
import "../styles-uit"
import "../controls-uit" as HifiControls
import TabletScriptingInterface 1.0
Original.RadioButton {
id: radioButton
HifiConstants { id: hifi }
@ -27,6 +29,15 @@ Original.RadioButton {
readonly property int checkSize: 10
readonly property int checkRadius: 2
onClicked: {
tabletInterface.playSound(TabletEnums.ButtonClick);
}
// TODO: doesnt works for QQC1. check with QQC2
// onHovered: {
// tabletInterface.playSound(TabletEnums.ButtonHover);
// }
style: RadioButtonStyle {
indicator: Rectangle {
id: box

View file

@ -9,6 +9,7 @@
//
import QtQuick 2.5
import TabletScriptingInterface 1.0
import "../../controls-uit"
@ -22,7 +23,16 @@ Preference {
Button {
id: button
onClicked: preference.trigger()
onHoveredChanged: {
if (hovered) {
tabletInterface.playSound(TabletEnums.ButtonHover);
}
}
onClicked: {
preference.trigger();
tabletInterface.playSound(TabletEnums.ButtonClick);
}
width: 180
anchors.bottom: parent.bottom
}

View file

@ -9,6 +9,7 @@
//
import QtQuick 2.5
import TabletScriptingInterface 1.0
import "../../controls-uit"
@ -38,6 +39,16 @@ Preference {
CheckBox {
id: checkBox
onHoveredChanged: {
if (hovered) {
tabletInterface.playSound(TabletEnums.ButtonHover);
}
}
onClicked: {
tabletInterface.playSound(TabletEnums.ButtonClick);
}
anchors {
top: spacer.bottom
left: parent.left

View file

@ -14,6 +14,8 @@ import QtQuick.Controls 1.4
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0
import TabletScriptingInterface 1.0
Rectangle {
readonly property var level: Audio.inputLevel;
@ -57,8 +59,16 @@ Rectangle {
hoverEnabled: true;
scrollGestureEnabled: false;
onClicked: { Audio.muted = !Audio.muted; }
onClicked: {
Audio.muted = !Audio.muted;
tabletInterface.playSound(TabletEnums.ButtonClick);
}
drag.target: dragTarget;
onContainsMouseChanged: {
if (containsMouse) {
tabletInterface.playSound(TabletEnums.ButtonHover);
}
}
}
QtObject {

View file

@ -239,6 +239,25 @@ Rectangle {
}
}
}
}
HifiCommerceCommon.FirstUseTutorial {
id: firstUseTutorial;
z: 999;
visible: root.activeView === "firstUseTutorial";
anchors.fill: parent;
Connections {
onSendSignalToParent: {
switch (message.method) {
case 'tutorial_skipClicked':
case 'tutorial_finished':
Settings.setValue("isFirstUseOfPurchases", false);
root.activeView = "checkoutSuccess";
break;
}
}
}
}
//
@ -611,6 +630,28 @@ Rectangle {
lightboxPopup.visible = true;
}
}
RalewaySemiBold {
id: explainRezText;
//visible: !root.isWearable;
text: '<font color="' + hifi.colors.redAccent + '"><a href="#">What does "Rez" mean?</a></font>'
// Text size
size: 16;
// Anchors
anchors.top: noPermissionText.visible ? noPermissionText.bottom : rezNowButton.bottom;
anchors.topMargin: 6;
height: paintedHeight;
anchors.left: parent.left;
anchors.right: parent.right;
// Style
color: hifi.colors.redAccent;
wrapMode: Text.WordWrap;
// Alignment
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
onLinkActivated: {
root.activeView = "firstUseTutorial";
}
}
RalewaySemiBold {
id: myPurchasesLink;
@ -618,7 +659,7 @@ Rectangle {
// Text size
size: 20;
// Anchors
anchors.top: noPermissionText.visible ? noPermissionText.bottom : rezNowButton.bottom;
anchors.top: explainRezText.visible ? explainRezText.bottom : (noPermissionText.visible ? noPermissionText.bottom : rezNowButton.bottom);
anchors.topMargin: 40;
height: paintedHeight;
anchors.left: parent.left;

View file

@ -25,7 +25,13 @@ Rectangle {
HifiConstants { id: hifi; }
id: root;
property int activeView: 1;
property int activeView: 1;
onVisibleChanged: {
if (visible) {
root.activeView = 1;
}
}
Image {
anchors.fill: parent;

View file

@ -241,7 +241,7 @@ Rectangle {
}
}
FirstUseTutorial {
HifiCommerceCommon.FirstUseTutorial {
id: firstUseTutorial;
z: 999;
visible: root.activeView === "firstUseTutorial";

View file

@ -25,6 +25,7 @@ Item {
id: root;
property string keyFilePath;
property bool showDebugButtons: true;
Hifi.QmlCommerce {
id: commerce;
@ -56,6 +57,7 @@ Item {
}
HifiControlsUit.Button {
id: clearCachedPassphraseButton;
visible: root.showDebugButtons;
color: hifi.buttons.black;
colorScheme: hifi.colorSchemes.dark;
anchors.top: parent.top;
@ -71,6 +73,7 @@ Item {
}
HifiControlsUit.Button {
id: resetButton;
visible: root.showDebugButtons;
color: hifi.buttons.red;
colorScheme: hifi.colorSchemes.dark;
anchors.top: clearCachedPassphraseButton.top;
@ -95,12 +98,12 @@ Item {
ListElement {
isExpanded: false;
question: "Where are my private keys stored?"
answer: qsTr('By default, your private keys are <b>only stored on your hard drive</b> in High Fidelity Interface\'s AppData directory.<br><br><b><font color="#0093C5"><a href="#privateKeyPath">Tap here to open the file path of your hifikey in your file explorer.</a></font></b>');
answer: qsTr('By default, your private keys are <b>only stored on your hard drive</b> in High Fidelity Interface\'s AppData directory.<br><br><b><font color="#0093C5"><a href="#privateKeyPath">Tap here to open the folder where your HifiKeys are stored on your main display.</a></font></b>');
}
ListElement {
isExpanded: false;
question: "How can I backup my private keys?"
answer: qsTr('You may backup the file containing your private keys by copying it to a USB flash drive, or to a service like Dropbox or Google Drive.<br><br>Restore your backup by replacing the file in Interface\'s AppData directory with your backed-up copy.<br><br><b><font color="#0093C5"><a href="#privateKeyPath">Tap here to open the file path of your hifikey in your file explorer.</a></font></b>');
answer: qsTr('You may backup the file containing your private keys by copying it to a USB flash drive, or to a service like Dropbox or Google Drive.<br><br>Restore your backup by replacing the file in Interface\'s AppData directory with your backed-up copy.<br><br><b><font color="#0093C5"><a href="#privateKeyPath">Tap here to open the folder where your HifiKeys are stored on your main display.</a></font></b>');
}
ListElement {
isExpanded: false;

View file

@ -25,7 +25,7 @@ Item {
HifiConstants { id: hifi; }
id: root;
z: 998;
z: 997;
property bool keyboardRaised: false;
property string titleBarIcon: "";
property string titleBarText: "";
@ -350,7 +350,7 @@ Item {
Item {
id: keyboardContainer;
z: 999;
z: 998;
visible: keyboard.raised;
property bool punctuationMode: false;
anchors {
@ -361,11 +361,13 @@ Item {
Image {
id: lowerKeyboardButton;
z: 999;
source: "images/lowerKeyboard.png";
anchors.horizontalCenter: parent.horizontalCenter;
anchors.bottom: keyboard.top;
height: 30;
width: 120;
anchors.right: keyboard.right;
anchors.top: keyboard.showMirrorText ? keyboard.top : undefined;
anchors.bottom: keyboard.showMirrorText ? undefined : keyboard.bottom;
height: 50;
width: 60;
MouseArea {
anchors.fill: parent;

View file

@ -290,7 +290,17 @@ Item {
id: removeHmdContainer;
z: 998;
visible: false;
color: hifi.colors.blueHighlight;
gradient: Gradient {
GradientStop {
position: 0.2;
color: hifi.colors.baseGrayHighlight;
}
GradientStop {
position: 1.0;
color: hifi.colors.baseGrayShadow;
}
}
anchors.fill: backupInstructionsButton;
radius: 5;
MouseArea {

View file

@ -165,7 +165,7 @@ Rectangle {
WalletSetup {
id: walletSetup;
visible: root.activeView === "walletSetup";
z: 998;
z: 997;
anchors.fill: parent;
Connections {
@ -192,7 +192,7 @@ Rectangle {
PassphraseChange {
id: passphraseChange;
visible: root.activeView === "passphraseChange";
z: 998;
z: 997;
anchors.top: titleBarContainer.bottom;
anchors.left: parent.left;
anchors.right: parent.right;
@ -217,7 +217,7 @@ Rectangle {
SecurityImageChange {
id: securityImageChange;
visible: root.activeView === "securityImageChange";
z: 998;
z: 997;
anchors.top: titleBarContainer.bottom;
anchors.left: parent.left;
anchors.right: parent.right;
@ -653,7 +653,7 @@ Rectangle {
Item {
id: keyboardContainer;
z: 999;
z: 998;
visible: keyboard.raised;
property bool punctuationMode: false;
anchors {
@ -664,11 +664,13 @@ Rectangle {
Image {
id: lowerKeyboardButton;
z: 999;
source: "images/lowerKeyboard.png";
anchors.horizontalCenter: parent.horizontalCenter;
anchors.bottom: keyboard.top;
height: 30;
width: 120;
anchors.right: keyboard.right;
anchors.top: keyboard.showMirrorText ? keyboard.top : undefined;
anchors.bottom: keyboard.showMirrorText ? undefined : keyboard.bottom;
height: 50;
width: 60;
MouseArea {
anchors.fill: parent;

View file

@ -164,7 +164,7 @@ Item {
anchors.top: parent.top;
anchors.topMargin: 26;
anchors.left: parent.left;
anchors.leftMargin: 30;
anchors.leftMargin: 20;
anchors.right: parent.right;
anchors.rightMargin: 30;
height: 30;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -1,5 +1,6 @@
import QtQuick 2.0
import QtGraphicalEffects 1.0
import TabletScriptingInterface 1.0
Item {
id: tabletButton
@ -130,11 +131,13 @@ Item {
}
tabletButton.clicked();
if (tabletRoot) {
tabletRoot.playButtonClickSound();
tabletInterface.playSound(TabletEnums.ButtonClick);
}
}
onEntered: {
tabletButton.isEntered = true;
tabletInterface.playSound(TabletEnums.ButtonHover);
if (tabletButton.isActive) {
tabletButton.state = "hover active state";
} else {

View file

@ -9,9 +9,13 @@
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import TabletScriptingInterface 1.0
import "../../styles-uit"
import "."
FocusScope {
id: root
implicitHeight: background.height
@ -69,12 +73,17 @@ FocusScope {
onImplicitWidthChanged: listView !== null ? listView.recalcSize() : 0
MouseArea {
enabled: name !== "" && item.enabled
anchors.fill: parent
hoverEnabled: true
onEntered: listView.currentIndex = index
onEntered: {
tabletInterface.playSound(TabletEnums.ButtonHover);
listView.currentIndex = index
}
onClicked: {
root.selected(item)
tabletRoot.playButtonClickSound();
tabletInterface.playSound(TabletEnums.ButtonClick);
root.selected(item);
}
}
}

View file

@ -1,6 +1,7 @@
import QtQuick 2.0
import Hifi 1.0
import QtQuick.Controls 1.4
import "../../dialogs"
import "../../controls"

View file

@ -19,7 +19,6 @@ Window {
shown: true
width: content.width
height: content.height
disableFade: true
// Disable this window from being able to call 'desktop.raise() and desktop.showDesktop'
activator: Item {}
property bool horizontal: true
@ -127,7 +126,7 @@ Window {
sortButtons();
shown = true;
fadeIn(null);
return result;
}
@ -143,7 +142,7 @@ Window {
buttons.splice(index, 1);
if (buttons.length === 0) {
shown = false;
fadeOut(null);
}
}
}

View file

@ -36,9 +36,6 @@ FocusScope {
// Some dialogs should be destroyed when they become
// invisible, so handle that
onVisibleChanged: {
if (disableFade) {
return;
}
// If someone directly set the visibility to false
// toggle it back on and use the targetVisible flag to transition
// via fading.
@ -66,9 +63,7 @@ FocusScope {
}
onFadeTargetPropertyChanged: {
if (!disableFade) {
visible = (fadeTargetProperty != 0.0);
}
visible = (fadeTargetProperty != 0.0);
}
function fadeIn(callback) {

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1847,6 +1847,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_rayPickManager.setPrecisionPicking(rayPickID, value);
});
// Preload Tablet sounds
DependencyManager::get<TabletScriptingInterface>()->preloadSounds();
qCDebug(interfaceapp) << "Metaverse session ID is" << uuidStringWithoutCurlyBraces(accountManager->getSessionID());
}
@ -2324,6 +2327,8 @@ void Application::initializeUi() {
surfaceContext->setContextProperty("Account", AccountScriptingInterface::getInstance());
surfaceContext->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
// Tablet inteference with Tablet.qml. Need to avoid this in QML space
surfaceContext->setContextProperty("tabletInterface", DependencyManager::get<TabletScriptingInterface>().data());
surfaceContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface);
surfaceContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
surfaceContext->setContextProperty("FaceTracker", DependencyManager::get<DdeFaceTracker>().data());
@ -2392,8 +2397,8 @@ void Application::initializeUi() {
}
void Application::updateCamera(RenderArgs& renderArgs) {
PROFILE_RANGE(render, "/updateCamera");
PerformanceTimer perfTimer("CameraUpdates");
PROFILE_RANGE(render, __FUNCTION__);
PerformanceTimer perfTimer("updateCamera");
glm::vec3 boomOffset;
auto myAvatar = getMyAvatar();
@ -2609,7 +2614,7 @@ void Application::resizeGL() {
}
void Application::handleSandboxStatus(QNetworkReply* reply) {
PROFILE_RANGE(render, "HandleSandboxStatus");
PROFILE_RANGE(render, __FUNCTION__);
bool sandboxIsRunning = SandboxUtils::readStatus(reply->readAll());
qDebug() << "HandleSandboxStatus" << sandboxIsRunning;
@ -4638,7 +4643,6 @@ void Application::updateDialogs(float deltaTime) const {
static bool domainLoadingInProgress = false;
void Application::update(float deltaTime) {
PROFILE_RANGE_EX(app, __FUNCTION__, 0xffff0000, (uint64_t)_renderFrameCount + 1);
if (!_physicsEnabled) {
@ -4833,11 +4837,11 @@ void Application::update(float deltaTime) {
QSharedPointer<AvatarManager> avatarManager = DependencyManager::get<AvatarManager>();
{
PROFILE_RANGE_EX(simulation_physics, "Physics", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount());
PROFILE_RANGE(simulation_physics, "Physics");
PerformanceTimer perfTimer("physics");
if (_physicsEnabled) {
{
PROFILE_RANGE_EX(simulation_physics, "UpdateStates", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount());
PROFILE_RANGE(simulation_physics, "PreStep");
PerformanceTimer perfTimer("updateStates)");
static VectorOfMotionStates motionStates;
@ -4871,14 +4875,14 @@ void Application::update(float deltaTime) {
});
}
{
PROFILE_RANGE_EX(simulation_physics, "StepSimulation", 0xffff8000, (uint64_t)getActiveDisplayPlugin()->presentCount());
PROFILE_RANGE(simulation_physics, "Step");
PerformanceTimer perfTimer("stepSimulation");
getEntities()->getTree()->withWriteLock([&] {
_physicsEngine->stepSimulation();
});
}
{
PROFILE_RANGE_EX(simulation_physics, "HarvestChanges", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount());
PROFILE_RANGE(simulation_physics, "PostStep");
PerformanceTimer perfTimer("harvestChanges");
if (_physicsEngine->hasOutgoingChanges()) {
// grab the collision events BEFORE handleOutgoingChanges() because at this point
@ -4886,6 +4890,7 @@ void Application::update(float deltaTime) {
auto& collisionEvents = _physicsEngine->getCollisionEvents();
getEntities()->getTree()->withWriteLock([&] {
PROFILE_RANGE(simulation_physics, "Harvest");
PerformanceTimer perfTimer("handleOutgoingChanges");
const VectorOfMotionStates& outgoingChanges = _physicsEngine->getChangedMotionStates();
@ -4898,18 +4903,25 @@ void Application::update(float deltaTime) {
if (!_aboutToQuit) {
// handleCollisionEvents() AFTER handleOutgoinChanges()
PerformanceTimer perfTimer("entities");
avatarManager->handleCollisionEvents(collisionEvents);
// Collision events (and their scripts) must not be handled when we're locked, above. (That would risk
// deadlock.)
_entitySimulation->handleCollisionEvents(collisionEvents);
{
PROFILE_RANGE(simulation_physics, "CollisionEvents");
PerformanceTimer perfTimer("entities");
avatarManager->handleCollisionEvents(collisionEvents);
// Collision events (and their scripts) must not be handled when we're locked, above. (That would risk
// deadlock.)
_entitySimulation->handleCollisionEvents(collisionEvents);
}
PROFILE_RANGE(simulation_physics, "UpdateEntities");
// NOTE: the getEntities()->update() call below will wait for lock
// and will simulate entity motion (the EntityTree has been given an EntitySimulation).
getEntities()->update(true); // update the models...
}
myAvatar->harvestResultsFromPhysicsSimulation(deltaTime);
{
PROFILE_RANGE(simulation_physics, "MyAvatar");
myAvatar->harvestResultsFromPhysicsSimulation(deltaTime);
}
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) &&
Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsSimulationTiming)) {
@ -4928,13 +4940,13 @@ void Application::update(float deltaTime) {
// AvatarManager update
{
{
PROFILE_RANGE(simulation, "OtherAvatars");
PerformanceTimer perfTimer("otherAvatars");
PROFILE_RANGE_EX(simulation, "OtherAvatars", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount());
avatarManager->updateOtherAvatars(deltaTime);
}
{
PROFILE_RANGE_EX(simulation, "MyAvatar", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount());
PROFILE_RANGE(simulation, "MyAvatar");
PerformanceTimer perfTimer("MyAvatar");
qApp->updateMyAvatarLookAtPosition();
avatarManager->updateMyAvatar(deltaTime);
@ -5805,6 +5817,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue<TabletProxy>, wrapperFromScriptValue<TabletProxy>);
qScriptRegisterMetaType(scriptEngine.data(),
wrapperToScriptValue<TabletButtonProxy>, wrapperFromScriptValue<TabletButtonProxy>);
// Tablet inteference with Tablet.qml. Need to avoid this in QML space
scriptEngine->registerGlobalObject("tabletInterface", DependencyManager::get<TabletScriptingInterface>().data());
scriptEngine->registerGlobalObject("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
auto toolbarScriptingInterface = DependencyManager::get<ToolbarScriptingInterface>().data();

View file

@ -10,7 +10,6 @@
//
#include "JointRayPick.h"
#include "DependencyManager.h"
#include "avatar/AvatarManager.h"
JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled) :

View file

@ -11,7 +11,7 @@
#ifndef hifi_JointRayPick_h
#define hifi_JointRayPick_h
#include "RayPick.h"
#include <pointers/rays/RayPick.h>
class JointRayPick : public RayPick {

View file

@ -11,8 +11,8 @@
#include "LaserPointer.h"
#include "Application.h"
#include "ui/overlays/Overlay.h"
#include "avatar/AvatarManager.h"
#include "RayPickScriptingInterface.h"
LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates,
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) :
@ -22,9 +22,10 @@ LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& rende
_faceAvatar(faceAvatar),
_centerEndY(centerEndY),
_lockEnd(lockEnd),
_distanceScaleEnd(distanceScaleEnd)
_distanceScaleEnd(distanceScaleEnd),
_rayPickUID(DependencyManager::get<RayPickScriptingInterface>()->createRayPick(rayProps))
{
_rayPickUID = DependencyManager::get<RayPickScriptingInterface>()->createRayPick(rayProps);
for (auto& state : _renderStates) {
if (!enabled || state.first != _currentRenderState) {
@ -39,7 +40,7 @@ LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& rende
}
LaserPointer::~LaserPointer() {
DependencyManager::get<RayPickScriptingInterface>()->removeRayPick(_rayPickUID);
qApp->getRayPickManager().removeRayPick(_rayPickUID);
for (auto& renderState : _renderStates) {
renderState.second.deleteOverlays();
@ -50,47 +51,51 @@ LaserPointer::~LaserPointer() {
}
void LaserPointer::enable() {
QWriteLocker lock(getLock());
DependencyManager::get<RayPickScriptingInterface>()->enableRayPick(_rayPickUID);
_renderingEnabled = true;
qApp->getRayPickManager().enableRayPick(_rayPickUID);
withWriteLock([&] {
_renderingEnabled = true;
});
}
void LaserPointer::disable() {
QWriteLocker lock(getLock());
DependencyManager::get<RayPickScriptingInterface>()->disableRayPick(_rayPickUID);
_renderingEnabled = false;
if (!_currentRenderState.empty()) {
if (_renderStates.find(_currentRenderState) != _renderStates.end()) {
disableRenderState(_renderStates[_currentRenderState]);
qApp->getRayPickManager().disableRayPick(_rayPickUID);
withWriteLock([&] {
_renderingEnabled = false;
if (!_currentRenderState.empty()) {
if (_renderStates.find(_currentRenderState) != _renderStates.end()) {
disableRenderState(_renderStates[_currentRenderState]);
}
if (_defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) {
disableRenderState(_defaultRenderStates[_currentRenderState].second);
}
}
if (_defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) {
disableRenderState(_defaultRenderStates[_currentRenderState].second);
}
}
});
}
void LaserPointer::setRenderState(const std::string& state) {
QWriteLocker lock(getLock());
if (!_currentRenderState.empty() && state != _currentRenderState) {
if (_renderStates.find(_currentRenderState) != _renderStates.end()) {
disableRenderState(_renderStates[_currentRenderState]);
withWriteLock([&] {
if (!_currentRenderState.empty() && state != _currentRenderState) {
if (_renderStates.find(_currentRenderState) != _renderStates.end()) {
disableRenderState(_renderStates[_currentRenderState]);
}
if (_defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) {
disableRenderState(_defaultRenderStates[_currentRenderState].second);
}
}
if (_defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) {
disableRenderState(_defaultRenderStates[_currentRenderState].second);
}
}
_currentRenderState = state;
_currentRenderState = state;
});
}
void LaserPointer::editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) {
QWriteLocker lock(getLock());
updateRenderStateOverlay(_renderStates[state].getStartID(), startProps);
updateRenderStateOverlay(_renderStates[state].getPathID(), pathProps);
updateRenderStateOverlay(_renderStates[state].getEndID(), endProps);
QVariant endDim = endProps.toMap()["dimensions"];
if (endDim.isValid()) {
_renderStates[state].setEndDim(vec3FromVariant(endDim));
}
withWriteLock([&] {
updateRenderStateOverlay(_renderStates[state].getStartID(), startProps);
updateRenderStateOverlay(_renderStates[state].getPathID(), pathProps);
updateRenderStateOverlay(_renderStates[state].getEndID(), endProps);
QVariant endDim = endProps.toMap()["dimensions"];
if (endDim.isValid()) {
_renderStates[state].setEndDim(vec3FromVariant(endDim));
}
});
}
void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant& props) {
@ -102,8 +107,7 @@ void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant&
}
const RayPickResult LaserPointer::getPrevRayPickResult() {
QReadLocker lock(getLock());
return DependencyManager::get<RayPickScriptingInterface>()->getPrevRayPickResult(_rayPickUID);
return qApp->getRayPickManager().getPrevRayPickResult(_rayPickUID);
}
void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState) {
@ -202,65 +206,45 @@ void LaserPointer::disableRenderState(const RenderState& renderState) {
void LaserPointer::update() {
// This only needs to be a read lock because update won't change any of the properties that can be modified from scripts
QReadLocker lock(getLock());
RayPickResult prevRayPickResult = DependencyManager::get<RayPickScriptingInterface>()->getPrevRayPickResult(_rayPickUID);
if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() &&
withReadLock([&] {
RayPickResult prevRayPickResult = qApp->getRayPickManager().getPrevRayPickResult(_rayPickUID);
if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() &&
(prevRayPickResult.type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) {
float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult.distance;
updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, distance, prevRayPickResult.objectID, prevRayPickResult.searchRay, false);
disableRenderState(_defaultRenderStates[_currentRenderState].second);
} else if (_renderingEnabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) {
disableRenderState(_renderStates[_currentRenderState]);
updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), prevRayPickResult.searchRay, true);
} else if (!_currentRenderState.empty()) {
disableRenderState(_renderStates[_currentRenderState]);
disableRenderState(_defaultRenderStates[_currentRenderState].second);
}
float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult.distance;
updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, distance, prevRayPickResult.objectID, prevRayPickResult.searchRay, false);
disableRenderState(_defaultRenderStates[_currentRenderState].second);
} else if (_renderingEnabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) {
disableRenderState(_renderStates[_currentRenderState]);
updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), prevRayPickResult.searchRay, true);
} else if (!_currentRenderState.empty()) {
disableRenderState(_renderStates[_currentRenderState]);
disableRenderState(_defaultRenderStates[_currentRenderState].second);
}
});
}
void LaserPointer::setPrecisionPicking(const bool precisionPicking) {
QWriteLocker lock(getLock());
DependencyManager::get<RayPickScriptingInterface>()->setPrecisionPicking(_rayPickUID, precisionPicking);
qApp->getRayPickManager().setPrecisionPicking(_rayPickUID, precisionPicking);
}
void LaserPointer::setLaserLength(const float laserLength) {
QWriteLocker lock(getLock());
_laserLength = laserLength;
withWriteLock([&] {
_laserLength = laserLength;
});
}
void LaserPointer::setLockEndUUID(QUuid objectID, const bool isOverlay) {
QWriteLocker lock(getLock());
_objectLockEnd = std::pair<QUuid, bool>(objectID, isOverlay);
withWriteLock([&] {
_objectLockEnd = std::pair<QUuid, bool>(objectID, isOverlay);
});
}
void LaserPointer::setIgnoreEntities(const QScriptValue& ignoreEntities) {
QWriteLocker lock(getLock());
DependencyManager::get<RayPickScriptingInterface>()->setIgnoreEntities(_rayPickUID, ignoreEntities);
void LaserPointer::setIgnoreItems(const QVector<QUuid>& ignoreItems) const {
qApp->getRayPickManager().setIgnoreItems(_rayPickUID, ignoreItems);
}
void LaserPointer::setIncludeEntities(const QScriptValue& includeEntities) {
QWriteLocker lock(getLock());
DependencyManager::get<RayPickScriptingInterface>()->setIncludeEntities(_rayPickUID, includeEntities);
}
void LaserPointer::setIgnoreOverlays(const QScriptValue& ignoreOverlays) {
QWriteLocker lock(getLock());
DependencyManager::get<RayPickScriptingInterface>()->setIgnoreOverlays(_rayPickUID, ignoreOverlays);
}
void LaserPointer::setIncludeOverlays(const QScriptValue& includeOverlays) {
QWriteLocker lock(getLock());
DependencyManager::get<RayPickScriptingInterface>()->setIncludeOverlays(_rayPickUID, includeOverlays);
}
void LaserPointer::setIgnoreAvatars(const QScriptValue& ignoreAvatars) {
QWriteLocker lock(getLock());
DependencyManager::get<RayPickScriptingInterface>()->setIgnoreAvatars(_rayPickUID, ignoreAvatars);
}
void LaserPointer::setIncludeAvatars(const QScriptValue& includeAvatars) {
QWriteLocker lock(getLock());
DependencyManager::get<RayPickScriptingInterface>()->setIncludeAvatars(_rayPickUID, includeAvatars);
void LaserPointer::setIncludeItems(const QVector<QUuid>& includeItems) const {
qApp->getRayPickManager().setIncludeItems(_rayPickUID, includeItems);
}
RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, const OverlayID& endID) :
@ -288,4 +272,4 @@ void RenderState::deleteOverlays() {
if (!_endID.isNull()) {
qApp->getOverlays().deleteOverlay(_endID);
}
}
}

View file

@ -12,10 +12,12 @@
#define hifi_LaserPointer_h
#include <QString>
#include "glm/glm.hpp"
#include <glm/glm.hpp>
#include <DependencyManager.h>
#include "raypick/RayPickScriptingInterface.h"
#include <shared/ReadWriteLockable.h>
#include "ui/overlays/Overlay.h"
class RayPickResult;
@ -49,9 +51,10 @@ private:
};
class LaserPointer {
class LaserPointer : public ReadWriteLockable {
public:
using Pointer = std::shared_ptr<LaserPointer>;
typedef std::unordered_map<std::string, RenderState> RenderStateMap;
typedef std::unordered_map<std::string, std::pair<float, RenderState>> DefaultRenderStateMap;
@ -73,14 +76,8 @@ public:
void setLaserLength(const float laserLength);
void setLockEndUUID(QUuid objectID, const bool isOverlay);
void setIgnoreEntities(const QScriptValue& ignoreEntities);
void setIncludeEntities(const QScriptValue& includeEntities);
void setIgnoreOverlays(const QScriptValue& ignoreOverlays);
void setIncludeOverlays(const QScriptValue& includeOverlays);
void setIgnoreAvatars(const QScriptValue& ignoreAvatars);
void setIncludeAvatars(const QScriptValue& includeAvatars);
QReadWriteLock* getLock() { return &_lock; }
void setIgnoreItems(const QVector<QUuid>& ignoreItems) const;
void setIncludeItems(const QVector<QUuid>& includeItems) const;
void update();
@ -96,8 +93,7 @@ private:
bool _distanceScaleEnd;
std::pair<QUuid, bool> _objectLockEnd { std::pair<QUuid, bool>(QUuid(), false)};
QUuid _rayPickUID;
QReadWriteLock _lock;
const QUuid _rayPickUID;
void updateRenderStateOverlay(const OverlayID& id, const QVariant& props);
void updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState);

View file

@ -12,138 +12,110 @@
QUuid LaserPointerManager::createLaserPointer(const QVariant& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates,
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) {
QUuid result;
std::shared_ptr<LaserPointer> laserPointer = std::make_shared<LaserPointer>(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled);
if (!laserPointer->getRayUID().isNull()) {
QWriteLocker containsLock(&_containsLock);
QUuid id = QUuid::createUuid();
_laserPointers[id] = laserPointer;
return id;
result = QUuid::createUuid();
withWriteLock([&] { _laserPointers[result] = laserPointer; });
}
return QUuid();
return result;
}
void LaserPointerManager::removeLaserPointer(const QUuid uid) {
QWriteLocker lock(&_containsLock);
_laserPointers.remove(uid);
LaserPointer::Pointer LaserPointerManager::find(const QUuid& uid) const {
return resultWithReadLock<LaserPointer::Pointer>([&] {
auto itr = _laserPointers.find(uid);
if (itr != _laserPointers.end()) {
return *itr;
}
return LaserPointer::Pointer();
});
}
void LaserPointerManager::enableLaserPointer(const QUuid uid) {
QReadLocker lock(&_containsLock);
auto laserPointer = _laserPointers.find(uid);
if (laserPointer != _laserPointers.end()) {
laserPointer.value()->enable();
void LaserPointerManager::removeLaserPointer(const QUuid& uid) {
withWriteLock([&] {
_laserPointers.remove(uid);
});
}
void LaserPointerManager::enableLaserPointer(const QUuid& uid) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->enable();
}
}
void LaserPointerManager::disableLaserPointer(const QUuid uid) {
QReadLocker lock(&_containsLock);
auto laserPointer = _laserPointers.find(uid);
if (laserPointer != _laserPointers.end()) {
laserPointer.value()->disable();
void LaserPointerManager::disableLaserPointer(const QUuid& uid) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->disable();
}
}
void LaserPointerManager::setRenderState(QUuid uid, const std::string& renderState) {
QReadLocker lock(&_containsLock);
auto laserPointer = _laserPointers.find(uid);
if (laserPointer != _laserPointers.end()) {
laserPointer.value()->setRenderState(renderState);
void LaserPointerManager::setRenderState(const QUuid& uid, const std::string& renderState) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->setRenderState(renderState);
}
}
void LaserPointerManager::editRenderState(QUuid uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) {
QReadLocker lock(&_containsLock);
auto laserPointer = _laserPointers.find(uid);
if (laserPointer != _laserPointers.end()) {
laserPointer.value()->editRenderState(state, startProps, pathProps, endProps);
void LaserPointerManager::editRenderState(const QUuid& uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->editRenderState(state, startProps, pathProps, endProps);
}
}
const RayPickResult LaserPointerManager::getPrevRayPickResult(const QUuid uid) {
QReadLocker lock(&_containsLock);
auto laserPointer = _laserPointers.find(uid);
if (laserPointer != _laserPointers.end()) {
return laserPointer.value()->getPrevRayPickResult();
const RayPickResult LaserPointerManager::getPrevRayPickResult(const QUuid& uid) const {
auto laserPointer = find(uid);
if (laserPointer) {
return laserPointer->getPrevRayPickResult();
}
return RayPickResult();
}
void LaserPointerManager::update() {
QReadLocker lock(&_containsLock);
for (QUuid& uid : _laserPointers.keys()) {
auto laserPointer = _laserPointers.find(uid);
laserPointer.value()->update();
auto cachedLaserPointers = resultWithReadLock<QList<std::shared_ptr<LaserPointer>>>([&] {
return _laserPointers.values();
});
for (const auto& laserPointer : cachedLaserPointers) {
laserPointer->update();
}
}
void LaserPointerManager::setPrecisionPicking(QUuid uid, const bool precisionPicking) {
QReadLocker lock(&_containsLock);
auto laserPointer = _laserPointers.find(uid);
if (laserPointer != _laserPointers.end()) {
laserPointer.value()->setPrecisionPicking(precisionPicking);
void LaserPointerManager::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->setPrecisionPicking(precisionPicking);
}
}
void LaserPointerManager::setLaserLength(QUuid uid, const float laserLength) {
QReadLocker lock(&_containsLock);
auto laserPointer = _laserPointers.find(uid);
if (laserPointer != _laserPointers.end()) {
laserPointer.value()->setLaserLength(laserLength);
void LaserPointerManager::setLaserLength(const QUuid& uid, const float laserLength) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->setLaserLength(laserLength);
}
}
void LaserPointerManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) {
QReadLocker lock(&_containsLock);
auto laserPointer = _laserPointers.find(uid);
if (laserPointer != _laserPointers.end()) {
laserPointer.value()->setIgnoreEntities(ignoreEntities);
void LaserPointerManager::setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignoreEntities) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->setIgnoreItems(ignoreEntities);
}
}
void LaserPointerManager::setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) {
QReadLocker lock(&_containsLock);
auto laserPointer = _laserPointers.find(uid);
if (laserPointer != _laserPointers.end()) {
laserPointer.value()->setIncludeEntities(includeEntities);
void LaserPointerManager::setIncludeItems(const QUuid& uid, const QVector<QUuid>& includeEntities) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->setIncludeItems(includeEntities);
}
}
void LaserPointerManager::setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) {
QReadLocker lock(&_containsLock);
auto laserPointer = _laserPointers.find(uid);
if (laserPointer != _laserPointers.end()) {
laserPointer.value()->setIgnoreOverlays(ignoreOverlays);
}
}
void LaserPointerManager::setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) {
QReadLocker lock(&_containsLock);
auto laserPointer = _laserPointers.find(uid);
if (laserPointer != _laserPointers.end()) {
laserPointer.value()->setIncludeOverlays(includeOverlays);
}
}
void LaserPointerManager::setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) {
QReadLocker lock(&_containsLock);
auto laserPointer = _laserPointers.find(uid);
if (laserPointer != _laserPointers.end()) {
laserPointer.value()->setIgnoreAvatars(ignoreAvatars);
}
}
void LaserPointerManager::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) {
QReadLocker lock(&_containsLock);
auto laserPointer = _laserPointers.find(uid);
if (laserPointer != _laserPointers.end()) {
laserPointer.value()->setIncludeAvatars(includeAvatars);
}
}
void LaserPointerManager::setLockEndUUID(QUuid uid, QUuid objectID, const bool isOverlay) {
QReadLocker lock(&_containsLock);
auto laserPointer = _laserPointers.find(uid);
if (laserPointer != _laserPointers.end()) {
laserPointer.value()->setLockEndUUID(objectID, isOverlay);
void LaserPointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const {
auto laserPointer = find(uid);
if (laserPointer) {
laserPointer->setLockEndUUID(objectID, isOverlay);
}
}

View file

@ -14,39 +14,38 @@
#include <memory>
#include <glm/glm.hpp>
#include <shared/ReadWriteLockable.h>
#include "LaserPointer.h"
class RayPickResult;
class LaserPointerManager {
class LaserPointerManager : protected ReadWriteLockable {
public:
QUuid createLaserPointer(const QVariant& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates,
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled);
void removeLaserPointer(const QUuid uid);
void enableLaserPointer(const QUuid uid);
void disableLaserPointer(const QUuid uid);
void setRenderState(QUuid uid, const std::string& renderState);
void editRenderState(QUuid uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps);
const RayPickResult getPrevRayPickResult(const QUuid uid);
void setPrecisionPicking(QUuid uid, const bool precisionPicking);
void setLaserLength(QUuid uid, const float laserLength);
void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities);
void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities);
void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays);
void setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays);
void setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars);
void setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars);
void removeLaserPointer(const QUuid& uid);
void enableLaserPointer(const QUuid& uid) const;
void disableLaserPointer(const QUuid& uid) const;
void setRenderState(const QUuid& uid, const std::string& renderState) const;
void editRenderState(const QUuid& uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const;
const RayPickResult getPrevRayPickResult(const QUuid& uid) const;
void setLockEndUUID(QUuid uid, QUuid objectID, const bool isOverlay);
void setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const;
void setLaserLength(const QUuid& uid, const float laserLength) const;
void setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignoreEntities) const;
void setIncludeItems(const QUuid& uid, const QVector<QUuid>& includeEntities) const;
void setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const;
void update();
private:
LaserPointer::Pointer find(const QUuid& uid) const;
QHash<QUuid, std::shared_ptr<LaserPointer>> _laserPointers;
QReadWriteLock _containsLock;
};
#endif // hifi_LaserPointerManager_h

View file

@ -11,10 +11,19 @@
#include "LaserPointerScriptingInterface.h"
#include <QVariant>
#include "GLMHelpers.h"
#include <QtCore/QVariant>
QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& properties) {
#include <GLMHelpers.h>
#include <RegisteredMetaTypes.h>
void LaserPointerScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) const {
qApp->getLaserPointerManager().setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems));
}
void LaserPointerScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) const {
qApp->getLaserPointerManager().setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems));
}
QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& properties) const {
QVariantMap propertyMap = properties.toMap();
bool faceAvatar = false;
@ -74,7 +83,7 @@ QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& propert
return qApp->getLaserPointerManager().createLaserPointer(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled);
}
void LaserPointerScriptingInterface::editRenderState(QUuid uid, const QString& renderState, const QVariant& properties) {
void LaserPointerScriptingInterface::editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const {
QVariantMap propMap = properties.toMap();
QVariant startProps;
@ -95,7 +104,7 @@ void LaserPointerScriptingInterface::editRenderState(QUuid uid, const QString& r
qApp->getLaserPointerManager().editRenderState(uid, renderState.toStdString(), startProps, pathProps, endProps);
}
const RenderState LaserPointerScriptingInterface::buildRenderState(const QVariantMap& propMap) {
RenderState LaserPointerScriptingInterface::buildRenderState(const QVariantMap& propMap) {
QUuid startID;
if (propMap["start"].isValid()) {
QVariantMap startMap = propMap["start"].toMap();

View file

@ -22,27 +22,23 @@ class LaserPointerScriptingInterface : public QObject, public Dependency {
SINGLETON_DEPENDENCY
public slots:
Q_INVOKABLE QUuid createLaserPointer(const QVariant& properties);
Q_INVOKABLE void enableLaserPointer(QUuid uid) { qApp->getLaserPointerManager().enableLaserPointer(uid); }
Q_INVOKABLE void disableLaserPointer(QUuid uid) { qApp->getLaserPointerManager().disableLaserPointer(uid); }
Q_INVOKABLE void removeLaserPointer(QUuid uid) { qApp->getLaserPointerManager().removeLaserPointer(uid); }
Q_INVOKABLE void editRenderState(QUuid uid, const QString& renderState, const QVariant& properties);
Q_INVOKABLE void setRenderState(QUuid uid, const QString& renderState) { qApp->getLaserPointerManager().setRenderState(uid, renderState.toStdString()); }
Q_INVOKABLE RayPickResult getPrevRayPickResult(QUuid uid) { return qApp->getLaserPointerManager().getPrevRayPickResult(uid); }
Q_INVOKABLE QUuid createLaserPointer(const QVariant& properties) const;
Q_INVOKABLE void enableLaserPointer(const QUuid& uid) const { qApp->getLaserPointerManager().enableLaserPointer(uid); }
Q_INVOKABLE void disableLaserPointer(const QUuid& uid) const { qApp->getLaserPointerManager().disableLaserPointer(uid); }
Q_INVOKABLE void removeLaserPointer(const QUuid& uid) const { qApp->getLaserPointerManager().removeLaserPointer(uid); }
Q_INVOKABLE void editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const;
Q_INVOKABLE void setRenderState(const QUuid& uid, const QString& renderState) const { qApp->getLaserPointerManager().setRenderState(uid, renderState.toStdString()); }
Q_INVOKABLE RayPickResult getPrevRayPickResult(QUuid uid) const { return qApp->getLaserPointerManager().getPrevRayPickResult(uid); }
Q_INVOKABLE void setPrecisionPicking(QUuid uid, const bool precisionPicking) { qApp->getLaserPointerManager().setPrecisionPicking(uid, precisionPicking); }
Q_INVOKABLE void setLaserLength(QUuid uid, const float laserLength) { qApp->getLaserPointerManager().setLaserLength(uid, laserLength); }
Q_INVOKABLE void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { qApp->getLaserPointerManager().setIgnoreEntities(uid, ignoreEntities); }
Q_INVOKABLE void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) { qApp->getLaserPointerManager().setIncludeEntities(uid, includeEntities); }
Q_INVOKABLE void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) { qApp->getLaserPointerManager().setIgnoreOverlays(uid, ignoreOverlays); }
Q_INVOKABLE void setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) { qApp->getLaserPointerManager().setIncludeOverlays(uid, includeOverlays); }
Q_INVOKABLE void setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) { qApp->getLaserPointerManager().setIgnoreAvatars(uid, ignoreAvatars); }
Q_INVOKABLE void setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) { qApp->getLaserPointerManager().setIncludeAvatars(uid, includeAvatars); }
Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { qApp->getLaserPointerManager().setPrecisionPicking(uid, precisionPicking); }
Q_INVOKABLE void setLaserLength(const QUuid& uid, float laserLength) const { qApp->getLaserPointerManager().setLaserLength(uid, laserLength); }
Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities) const;
Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities) const;
Q_INVOKABLE void setLockEndUUID(QUuid uid, QUuid objectID, const bool isOverlay) { qApp->getLaserPointerManager().setLockEndUUID(uid, objectID, isOverlay); }
Q_INVOKABLE void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { qApp->getLaserPointerManager().setLockEndUUID(uid, objectID, isOverlay); }
private:
const RenderState buildRenderState(const QVariantMap& propMap);
static RenderState buildRenderState(const QVariantMap& propMap);
};

View file

@ -11,7 +11,7 @@
#ifndef hifi_MouseRayPick_h
#define hifi_MouseRayPick_h
#include "RayPick.h"
#include <pointers/rays/RayPick.h>
class MouseRayPick : public RayPick {

View file

@ -1,62 +0,0 @@
//
// RayPick.cpp
// interface/src/raypick
//
// Created by Sam Gondelman 7/11/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
//
#include "RayPick.h"
RayPick::RayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) :
_filter(filter),
_maxDistance(maxDistance),
_enabled(enabled)
{
}
void RayPick::enable() {
QWriteLocker lock(getLock());
_enabled = true;
}
void RayPick::disable() {
QWriteLocker lock(getLock());
_enabled = false;
}
const RayPickResult& RayPick::getPrevRayPickResult() {
QReadLocker lock(getLock());
return _prevResult;
}
void RayPick::setIgnoreEntities(const QScriptValue& ignoreEntities) {
QWriteLocker lock(getLock());
_ignoreEntities = qVectorEntityItemIDFromScriptValue(ignoreEntities);
}
void RayPick::setIncludeEntities(const QScriptValue& includeEntities) {
QWriteLocker lock(getLock());
_includeEntities = qVectorEntityItemIDFromScriptValue(includeEntities);
}
void RayPick::setIgnoreOverlays(const QScriptValue& ignoreOverlays) {
QWriteLocker lock(getLock());
_ignoreOverlays = qVectorOverlayIDFromScriptValue(ignoreOverlays);
}
void RayPick::setIncludeOverlays(const QScriptValue& includeOverlays) {
QWriteLocker lock(getLock());
_includeOverlays = qVectorOverlayIDFromScriptValue(includeOverlays);
}
void RayPick::setIgnoreAvatars(const QScriptValue& ignoreAvatars) {
QWriteLocker lock(getLock());
_ignoreAvatars = qVectorEntityItemIDFromScriptValue(ignoreAvatars);
}
void RayPick::setIncludeAvatars(const QScriptValue& includeAvatars) {
QWriteLocker lock(getLock());
_includeAvatars = qVectorEntityItemIDFromScriptValue(includeAvatars);
}

View file

@ -10,6 +10,8 @@
//
#include "RayPickManager.h"
#include <pointers/rays/StaticRayPick.h>
#include "Application.h"
#include "EntityScriptingInterface.h"
#include "ui/overlays/Overlays.h"
@ -18,45 +20,50 @@
#include "DependencyManager.h"
#include "JointRayPick.h"
#include "StaticRayPick.h"
#include "MouseRayPick.h"
bool RayPickManager::checkAndCompareCachedResults(QPair<glm::vec3, glm::vec3>& ray, RayPickCache& cache, RayPickResult& res, const RayPickFilter::Flags& mask) {
if (cache.contains(ray) && cache[ray].find(mask) != cache[ray].end()) {
if (cache[ray][mask].distance < res.distance) {
res = cache[ray][mask];
bool RayPickManager::checkAndCompareCachedResults(QPair<glm::vec3, glm::vec3>& ray, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key) {
if (cache.contains(ray) && cache[ray].find(key) != cache[ray].end()) {
if (cache[ray][key].distance < res.distance) {
res = cache[ray][key];
}
return true;
}
return false;
}
void RayPickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, const RayPickFilter::Flags& mask, RayPickResult& res, QPair<glm::vec3, glm::vec3>& ray, RayPickCache& cache) {
void RayPickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, QPair<glm::vec3, glm::vec3>& ray, RayPickCache& cache) {
if (intersects) {
cache[ray][mask] = resTemp;
cache[ray][key] = resTemp;
if (resTemp.distance < res.distance) {
res = resTemp;
}
} else {
cache[ray][mask] = RayPickResult(res.searchRay);
cache[ray][key] = RayPickResult(res.searchRay);
}
}
void RayPickManager::update() {
QReadLocker lock(&_containsLock);
RayPickCache results;
for (auto& uid : _rayPicks.keys()) {
std::shared_ptr<RayPick> rayPick = _rayPicks[uid];
QWriteLocker lock(rayPick->getLock());
QHash<QUuid, RayPick::Pointer> cachedRayPicks;
withReadLock([&] {
cachedRayPicks = _rayPicks;
});
for (const auto& uid : cachedRayPicks.keys()) {
std::shared_ptr<RayPick> rayPick = cachedRayPicks[uid];
if (!rayPick->isEnabled() || rayPick->getFilter().doesPickNothing() || rayPick->getMaxDistance() < 0.0f) {
continue;
}
bool valid;
PickRay ray = rayPick->getPickRay(valid);
PickRay ray;
if (!valid) {
continue;
{
bool valid;
ray = rayPick->getPickRay(valid);
if (!valid) {
continue;
}
}
QPair<glm::vec3, glm::vec3> rayKey = QPair<glm::vec3, glm::vec3>(ray.origin, ray.direction);
@ -67,16 +74,16 @@ void RayPickManager::update() {
bool fromCache = true;
bool invisible = rayPick->getFilter().doesPickInvisible();
bool nonCollidable = rayPick->getFilter().doesPickNonCollidable();
RayPickFilter::Flags entityMask = rayPick->getFilter().getEntityFlags();
if (!checkAndCompareCachedResults(rayKey, results, res, entityMask)) {
entityRes = DependencyManager::get<EntityScriptingInterface>()->findRayIntersectionVector(ray, !rayPick->getFilter().doesPickCourse(),
rayPick->getIncludeEntites(), rayPick->getIgnoreEntites(), !invisible, !nonCollidable);
RayCacheKey entityKey = { rayPick->getFilter().getEntityFlags(), rayPick->getIncludeItems(), rayPick->getIgnoreItems() };
if (!checkAndCompareCachedResults(rayKey, results, res, entityKey)) {
entityRes = DependencyManager::get<EntityScriptingInterface>()->findRayIntersectionVector(ray, !rayPick->getFilter().doesPickCoarse(),
rayPick->getIncludeItemsAs<EntityItemID>(), rayPick->getIgnoreItemsAs<EntityItemID>(), !invisible, !nonCollidable);
fromCache = false;
}
if (!fromCache) {
cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, ray, entityRes.surfaceNormal),
entityMask, res, rayKey, results);
entityKey, res, rayKey, results);
}
}
@ -85,33 +92,34 @@ void RayPickManager::update() {
bool fromCache = true;
bool invisible = rayPick->getFilter().doesPickInvisible();
bool nonCollidable = rayPick->getFilter().doesPickNonCollidable();
RayPickFilter::Flags overlayMask = rayPick->getFilter().getOverlayFlags();
if (!checkAndCompareCachedResults(rayKey, results, res, overlayMask)) {
overlayRes = qApp->getOverlays().findRayIntersectionVector(ray, !rayPick->getFilter().doesPickCourse(),
rayPick->getIncludeOverlays(), rayPick->getIgnoreOverlays(), !invisible, !nonCollidable);
RayCacheKey overlayKey = { rayPick->getFilter().getOverlayFlags(), rayPick->getIncludeItems(), rayPick->getIgnoreItems() };
if (!checkAndCompareCachedResults(rayKey, results, res, overlayKey)) {
overlayRes = qApp->getOverlays().findRayIntersectionVector(ray, !rayPick->getFilter().doesPickCoarse(),
rayPick->getIncludeItemsAs<OverlayID>(), rayPick->getIgnoreItemsAs<OverlayID>(), !invisible, !nonCollidable);
fromCache = false;
}
if (!fromCache) {
cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, ray, overlayRes.surfaceNormal),
overlayMask, res, rayKey, results);
overlayKey, res, rayKey, results);
}
}
if (rayPick->getFilter().doesPickAvatars()) {
RayPickFilter::Flags avatarMask = rayPick->getFilter().getAvatarFlags();
if (!checkAndCompareCachedResults(rayKey, results, res, avatarMask)) {
RayToAvatarIntersectionResult avatarRes = DependencyManager::get<AvatarManager>()->findRayIntersectionVector(ray, rayPick->getIncludeAvatars(), rayPick->getIgnoreAvatars());
cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, ray), avatarMask, res, rayKey, results);
RayCacheKey avatarKey = { rayPick->getFilter().getAvatarFlags(), rayPick->getIncludeItems(), rayPick->getIgnoreItems() };
if (!checkAndCompareCachedResults(rayKey, results, res, avatarKey)) {
RayToAvatarIntersectionResult avatarRes = DependencyManager::get<AvatarManager>()->findRayIntersectionVector(ray,
rayPick->getIncludeItemsAs<EntityItemID>(), rayPick->getIgnoreItemsAs<EntityItemID>());
cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, ray), avatarKey, res, rayKey, results);
}
}
// Can't intersect with HUD in desktop mode
if (rayPick->getFilter().doesPickHUD() && DependencyManager::get<HMDScriptingInterface>()->isHMDMode()) {
RayPickFilter::Flags hudMask = rayPick->getFilter().getHUDFlags();
if (!checkAndCompareCachedResults(rayKey, results, res, hudMask)) {
RayCacheKey hudKey = { rayPick->getFilter().getHUDFlags(), QVector<QUuid>(), QVector<QUuid>() };
if (!checkAndCompareCachedResults(rayKey, results, res, hudKey)) {
glm::vec3 hudRes = DependencyManager::get<HMDScriptingInterface>()->calculateRayUICollisionPoint(ray.origin, ray.direction);
cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(ray.origin, hudRes), hudRes, ray), hudMask, res, rayKey, results);
cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(ray.origin, hudRes), hudRes, ray), hudKey, res, rayKey, results);
}
}
@ -123,109 +131,87 @@ void RayPickManager::update() {
}
}
QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled) {
QWriteLocker lock(&_containsLock);
QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, float maxDistance, bool enabled) {
auto newRayPick = std::make_shared<JointRayPick>(jointName, posOffset, dirOffset, filter, maxDistance, enabled);
QUuid id = QUuid::createUuid();
_rayPicks[id] = std::make_shared<JointRayPick>(jointName, posOffset, dirOffset, filter, maxDistance, enabled);
withWriteLock([&] {
_rayPicks[id] = newRayPick;
});
return id;
}
QUuid RayPickManager::createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) {
QWriteLocker lock(&_containsLock);
QUuid RayPickManager::createRayPick(const RayPickFilter& filter, float maxDistance, bool enabled) {
QUuid id = QUuid::createUuid();
_rayPicks[id] = std::make_shared<MouseRayPick>(filter, maxDistance, enabled);
auto newRayPick = std::make_shared<MouseRayPick>(filter, maxDistance, enabled);
withWriteLock([&] {
_rayPicks[id] = newRayPick;
});
return id;
}
QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled) {
QWriteLocker lock(&_containsLock);
QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, float maxDistance, bool enabled) {
QUuid id = QUuid::createUuid();
_rayPicks[id] = std::make_shared<StaticRayPick>(position, direction, filter, maxDistance, enabled);
auto newRayPick = std::make_shared<StaticRayPick>(position, direction, filter, maxDistance, enabled);
withWriteLock([&] {
_rayPicks[id] = newRayPick;
});
return id;
}
void RayPickManager::removeRayPick(const QUuid uid) {
QWriteLocker lock(&_containsLock);
_rayPicks.remove(uid);
void RayPickManager::removeRayPick(const QUuid& uid) {
withWriteLock([&] {
_rayPicks.remove(uid);
});
}
void RayPickManager::enableRayPick(const QUuid uid) {
QReadLocker containsLock(&_containsLock);
auto rayPick = _rayPicks.find(uid);
if (rayPick != _rayPicks.end()) {
rayPick.value()->enable();
RayPick::Pointer RayPickManager::findRayPick(const QUuid& uid) const {
return resultWithReadLock<RayPick::Pointer>([&] {
if (_rayPicks.contains(uid)) {
return _rayPicks[uid];
}
return RayPick::Pointer();
});
}
void RayPickManager::enableRayPick(const QUuid& uid) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
rayPick->enable();
}
}
void RayPickManager::disableRayPick(const QUuid uid) {
QReadLocker containsLock(&_containsLock);
auto rayPick = _rayPicks.find(uid);
if (rayPick != _rayPicks.end()) {
rayPick.value()->disable();
void RayPickManager::disableRayPick(const QUuid& uid) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
rayPick->disable();
}
}
const RayPickResult RayPickManager::getPrevRayPickResult(const QUuid uid) {
QReadLocker containsLock(&_containsLock);
auto rayPick = _rayPicks.find(uid);
if (rayPick != _rayPicks.end()) {
return rayPick.value()->getPrevRayPickResult();
RayPickResult RayPickManager::getPrevRayPickResult(const QUuid& uid) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
return rayPick->getPrevRayPickResult();
}
return RayPickResult();
}
void RayPickManager::setPrecisionPicking(QUuid uid, const bool precisionPicking) {
QReadLocker containsLock(&_containsLock);
auto rayPick = _rayPicks.find(uid);
if (rayPick != _rayPicks.end()) {
rayPick.value()->setPrecisionPicking(precisionPicking);
void RayPickManager::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
rayPick->setPrecisionPicking(precisionPicking);
}
}
void RayPickManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) {
QReadLocker containsLock(&_containsLock);
auto rayPick = _rayPicks.find(uid);
if (rayPick != _rayPicks.end()) {
rayPick.value()->setIgnoreEntities(ignoreEntities);
void RayPickManager::setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignore) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
rayPick->setIgnoreItems(ignore);
}
}
void RayPickManager::setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) {
QReadLocker containsLock(&_containsLock);
auto rayPick = _rayPicks.find(uid);
if (rayPick != _rayPicks.end()) {
rayPick.value()->setIncludeEntities(includeEntities);
void RayPickManager::setIncludeItems(const QUuid& uid, const QVector<QUuid>& include) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
rayPick->setIncludeItems(include);
}
}
void RayPickManager::setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) {
QReadLocker containsLock(&_containsLock);
auto rayPick = _rayPicks.find(uid);
if (rayPick != _rayPicks.end()) {
rayPick.value()->setIgnoreOverlays(ignoreOverlays);
}
}
void RayPickManager::setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) {
QReadLocker containsLock(&_containsLock);
auto rayPick = _rayPicks.find(uid);
if (rayPick != _rayPicks.end()) {
rayPick.value()->setIncludeOverlays(includeOverlays);
}
}
void RayPickManager::setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) {
QReadLocker containsLock(&_containsLock);
auto rayPick = _rayPicks.find(uid);
if (rayPick != _rayPicks.end()) {
rayPick.value()->setIgnoreAvatars(ignoreAvatars);
}
}
void RayPickManager::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) {
QReadLocker containsLock(&_containsLock);
auto rayPick = _rayPicks.find(uid);
if (rayPick != _rayPicks.end()) {
rayPick.value()->setIncludeAvatars(includeAvatars);
}
}

View file

@ -11,19 +11,39 @@
#ifndef hifi_RayPickManager_h
#define hifi_RayPickManager_h
#include "RayPick.h"
#include <memory>
#include <QtCore/QObject>
#include "RegisteredMetaTypes.h"
#include <unordered_map>
#include <queue>
#include <QtCore/QObject>
#include <RegisteredMetaTypes.h>
#include <pointers/rays/RayPick.h>
class RayPickResult;
class RayPickManager {
typedef struct RayCacheKey {
RayPickFilter::Flags mask;
QVector<QUuid> include;
QVector<QUuid> ignore;
bool operator==(const RayCacheKey& other) const {
return (mask == other.mask && include == other.include && ignore == other.ignore);
}
} RayCacheKey;
namespace std {
template <>
struct hash<RayCacheKey> {
size_t operator()(const RayCacheKey& k) const {
return ((hash<RayPickFilter::Flags>()(k.mask) ^ (qHash(k.include) << 1)) >> 1) ^ (qHash(k.ignore) << 1);
}
};
}
class RayPickManager : protected ReadWriteLockable {
public:
void update();
@ -31,28 +51,24 @@ public:
QUuid createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled);
QUuid createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled);
QUuid createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled);
void removeRayPick(const QUuid uid);
void enableRayPick(const QUuid uid);
void disableRayPick(const QUuid uid);
const RayPickResult getPrevRayPickResult(const QUuid uid);
void removeRayPick(const QUuid& uid);
void enableRayPick(const QUuid& uid) const;
void disableRayPick(const QUuid& uid) const;
RayPickResult getPrevRayPickResult(const QUuid& uid) const;
void setPrecisionPicking(QUuid uid, const bool precisionPicking);
void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities);
void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities);
void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays);
void setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays);
void setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars);
void setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars);
void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const;
void setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignore) const;
void setIncludeItems(const QUuid& uid, const QVector<QUuid>& include) const;
private:
QHash<QUuid, std::shared_ptr<RayPick>> _rayPicks;
QReadWriteLock _containsLock;
RayPick::Pointer findRayPick(const QUuid& uid) const;
QHash<QUuid, RayPick::Pointer> _rayPicks;
typedef QHash<QPair<glm::vec3, glm::vec3>, std::unordered_map<RayPickFilter::Flags, RayPickResult>> RayPickCache;
typedef QHash<QPair<glm::vec3, glm::vec3>, std::unordered_map<RayCacheKey, RayPickResult>> RayPickCache;
// Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer
bool checkAndCompareCachedResults(QPair<glm::vec3, glm::vec3>& ray, RayPickCache& cache, RayPickResult& res, const RayPickFilter::Flags& mask);
void cacheResult(const bool intersects, const RayPickResult& resTemp, const RayPickFilter::Flags& mask, RayPickResult& res, QPair<glm::vec3, glm::vec3>& ray, RayPickCache& cache);
bool checkAndCompareCachedResults(QPair<glm::vec3, glm::vec3>& ray, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key);
void cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, QPair<glm::vec3, glm::vec3>& ray, RayPickCache& cache);
};
#endif // hifi_RayPickManager_h

View file

@ -66,46 +66,30 @@ QUuid RayPickScriptingInterface::createRayPick(const QVariant& properties) {
return QUuid();
}
void RayPickScriptingInterface::enableRayPick(QUuid uid) {
void RayPickScriptingInterface::enableRayPick(const QUuid& uid) {
qApp->getRayPickManager().enableRayPick(uid);
}
void RayPickScriptingInterface::disableRayPick(QUuid uid) {
void RayPickScriptingInterface::disableRayPick(const QUuid& uid) {
qApp->getRayPickManager().disableRayPick(uid);
}
void RayPickScriptingInterface::removeRayPick(QUuid uid) {
void RayPickScriptingInterface::removeRayPick(const QUuid& uid) {
qApp->getRayPickManager().removeRayPick(uid);
}
RayPickResult RayPickScriptingInterface::getPrevRayPickResult(QUuid uid) {
RayPickResult RayPickScriptingInterface::getPrevRayPickResult(const QUuid& uid) {
return qApp->getRayPickManager().getPrevRayPickResult(uid);
}
void RayPickScriptingInterface::setPrecisionPicking(QUuid uid, const bool precisionPicking) {
void RayPickScriptingInterface::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) {
qApp->getRayPickManager().setPrecisionPicking(uid, precisionPicking);
}
void RayPickScriptingInterface::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) {
qApp->getRayPickManager().setIgnoreEntities(uid, ignoreEntities);
void RayPickScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) {
qApp->getRayPickManager().setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems));
}
void RayPickScriptingInterface::setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) {
qApp->getRayPickManager().setIncludeEntities(uid, includeEntities);
}
void RayPickScriptingInterface::setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) {
qApp->getRayPickManager().setIgnoreOverlays(uid, ignoreOverlays);
}
void RayPickScriptingInterface::setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) {
qApp->getRayPickManager().setIncludeOverlays(uid, includeOverlays);
}
void RayPickScriptingInterface::setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) {
qApp->getRayPickManager().setIgnoreAvatars(uid, ignoreAvatars);
}
void RayPickScriptingInterface::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) {
qApp->getRayPickManager().setIncludeAvatars(uid, includeAvatars);
void RayPickScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) {
qApp->getRayPickManager().setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems));
}

View file

@ -13,10 +13,9 @@
#include <QtCore/QObject>
#include "RegisteredMetaTypes.h"
#include "DependencyManager.h"
#include "RayPick.h"
#include <RegisteredMetaTypes.h>
#include <DependencyManager.h>
#include <pointers/rays/RayPick.h>
class RayPickScriptingInterface : public QObject, public Dependency {
Q_OBJECT
@ -25,7 +24,7 @@ class RayPickScriptingInterface : public QObject, public Dependency {
Q_PROPERTY(unsigned int PICK_OVERLAYS READ PICK_OVERLAYS CONSTANT)
Q_PROPERTY(unsigned int PICK_AVATARS READ PICK_AVATARS CONSTANT)
Q_PROPERTY(unsigned int PICK_HUD READ PICK_HUD CONSTANT)
Q_PROPERTY(unsigned int PICK_COURSE READ PICK_COURSE CONSTANT)
Q_PROPERTY(unsigned int PICK_COARSE READ PICK_COARSE CONSTANT)
Q_PROPERTY(unsigned int PICK_INCLUDE_INVISIBLE READ PICK_INCLUDE_INVISIBLE CONSTANT)
Q_PROPERTY(unsigned int PICK_INCLUDE_NONCOLLIDABLE READ PICK_INCLUDE_NONCOLLIDABLE CONSTANT)
Q_PROPERTY(unsigned int PICK_ALL_INTERSECTIONS READ PICK_ALL_INTERSECTIONS CONSTANT)
@ -38,25 +37,21 @@ class RayPickScriptingInterface : public QObject, public Dependency {
public slots:
Q_INVOKABLE QUuid createRayPick(const QVariant& properties);
Q_INVOKABLE void enableRayPick(QUuid uid);
Q_INVOKABLE void disableRayPick(QUuid uid);
Q_INVOKABLE void removeRayPick(QUuid uid);
Q_INVOKABLE RayPickResult getPrevRayPickResult(QUuid uid);
Q_INVOKABLE void enableRayPick(const QUuid& uid);
Q_INVOKABLE void disableRayPick(const QUuid& uid);
Q_INVOKABLE void removeRayPick(const QUuid& uid);
Q_INVOKABLE RayPickResult getPrevRayPickResult(const QUuid& uid);
Q_INVOKABLE void setPrecisionPicking(QUuid uid, const bool precisionPicking);
Q_INVOKABLE void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities);
Q_INVOKABLE void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities);
Q_INVOKABLE void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays);
Q_INVOKABLE void setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays);
Q_INVOKABLE void setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars);
Q_INVOKABLE void setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars);
Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, const bool precisionPicking);
Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities);
Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities);
unsigned int PICK_NOTHING() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_NOTHING); }
unsigned int PICK_NOTHING() { return 0; }
unsigned int PICK_ENTITIES() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_ENTITIES); }
unsigned int PICK_OVERLAYS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_OVERLAYS); }
unsigned int PICK_AVATARS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_AVATARS); }
unsigned int PICK_HUD() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_HUD); }
unsigned int PICK_COURSE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_COURSE); }
unsigned int PICK_COARSE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_COARSE); }
unsigned int PICK_INCLUDE_INVISIBLE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_INCLUDE_INVISIBLE); }
unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_INCLUDE_NONCOLLIDABLE); }
unsigned int PICK_ALL_INTERSECTIONS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_ALL_INTERSECTIONS); }

View file

@ -51,13 +51,11 @@ void Image3DOverlay::update(float deltatime) {
_texture = DependencyManager::get<TextureCache>()->getTexture(_url);
_textureIsLoaded = false;
}
#if OVERLAY_PANELS
if (usecTimestampNow() > _transformExpiry) {
Transform transform = getTransform();
applyTransformTo(transform);
setTransform(transform);
}
#endif
Parent::update(deltatime);
}

View file

@ -257,7 +257,3 @@ bool Text3DOverlay::findRayIntersection(const glm::vec3 &origin, const glm::vec3
return Billboard3DOverlay::findRayIntersection(origin, direction, distance, face, surfaceNormal);
}
Transform Text3DOverlay::evalRenderTransform() {
return Parent::evalRenderTransform();
}

View file

@ -65,9 +65,6 @@ public:
virtual Text3DOverlay* createClone() const override;
protected:
Transform evalRenderTransform() override;
private:
TextRenderer3D* _textRenderer = nullptr;

View file

@ -63,7 +63,6 @@ static const float OPAQUE_ALPHA_THRESHOLD = 0.99f;
const QString Web3DOverlay::TYPE = "web3d";
const QString Web3DOverlay::QML = "Web3DOverlay.qml";
Web3DOverlay::Web3DOverlay() : _dpi(DPI) {
_touchDevice.setCapabilities(QTouchDevice::Position);
_touchDevice.setType(QTouchDevice::TouchScreen);
@ -249,6 +248,9 @@ void Web3DOverlay::setupQmlSurface() {
_webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../");
// Tablet inteference with Tablet.qml. Need to avoid this in QML space
_webSurface->getSurfaceContext()->setContextProperty("tabletInterface", DependencyManager::get<TabletScriptingInterface>().data());
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface.data());
// mark the TabletProxy object as cpp ownership.
QObject* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system");

View file

@ -32,6 +32,7 @@
#include "AnimUtil.h"
#include "IKTarget.h"
static int nextRigId = 1;
static std::map<int, Rig*> rigRegistry;
static std::mutex rigRegistryMutex;
@ -999,14 +1000,13 @@ void Rig::updateAnimationStateHandlers() { // called on avatar update thread (wh
}
void Rig::updateAnimations(float deltaTime, const glm::mat4& rootTransform, const glm::mat4& rigToWorldTransform) {
PROFILE_RANGE_EX(simulation_animation_detail, __FUNCTION__, 0xffff00ff, 0);
PerformanceTimer perfTimer("updateAnimations");
DETAILED_PROFILE_RANGE_EX(simulation_animation_detail, __FUNCTION__, 0xffff00ff, 0);
DETAILED_PERFORMANCE_TIMER("updateAnimations");
setModelOffset(rootTransform);
if (_animNode && _enabledAnimations) {
PerformanceTimer perfTimer("handleTriggers");
DETAILED_PERFORMANCE_TIMER("handleTriggers");
updateAnimationStateHandlers();
_animVars.setRigToGeometryTransform(_rigToGeometryTransform);
@ -1658,7 +1658,7 @@ bool Rig::getModelRegistrationPoint(glm::vec3& modelRegistrationPointOut) const
}
void Rig::applyOverridePoses() {
PerformanceTimer perfTimer("override");
DETAILED_PERFORMANCE_TIMER("override");
if (_numOverrides == 0 || !_animSkeleton) {
return;
}
@ -1675,7 +1675,7 @@ void Rig::applyOverridePoses() {
}
void Rig::buildAbsoluteRigPoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePosesOut) {
PerformanceTimer perfTimer("buildAbsolute");
DETAILED_PERFORMANCE_TIMER("buildAbsolute");
if (!_animSkeleton) {
return;
}
@ -1730,8 +1730,9 @@ void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const {
}
void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
PerformanceTimer perfTimer("copyJoints");
PROFILE_RANGE(simulation_animation_detail, "copyJoints");
DETAILED_PROFILE_RANGE(simulation_animation_detail, "copyJoints");
DETAILED_PERFORMANCE_TIMER("copyJoints");
if (!_animSkeleton) {
return;
}

View file

@ -377,7 +377,8 @@ void FBXBaker::rewriteAndBakeSceneModels() {
bool hasColors { mesh.colors.size() > 0 };
bool hasTexCoords { mesh.texCoords.size() > 0 };
bool hasTexCoords1 { mesh.texCoords1.size() > 0 };
bool hasPerFaceMaterials { mesh.parts.size() > 1 };
bool hasPerFaceMaterials { mesh.parts.size() > 1
|| extractedMesh.partMaterialTextures[0].first != 0 };
bool needsOriginalIndices { hasDeformers };
int normalsAttributeID { -1 };
@ -594,6 +595,10 @@ void FBXBaker::rewriteAndBakeSceneTextures() {
QString fbxTextureFileName { textureChild.properties.at(0).toByteArray() };
QFileInfo textureFileInfo { fbxTextureFileName.replace("\\", "/") };
if (hasErrors()) {
return;
}
if (textureFileInfo.suffix() == BAKED_TEXTURE_EXT.mid(1)) {
// re-baking an FBX that already references baked textures is a fail
// so we add an error and return from here
@ -602,6 +607,11 @@ void FBXBaker::rewriteAndBakeSceneTextures() {
return;
}
if (!TextureBaker::getSupportedFormats().contains(textureFileInfo.suffix())) {
// this is a texture format we don't bake, skip it
handleWarning(fbxTextureFileName + " is not a bakeable texture format");
continue;
}
// make sure this texture points to something and isn't one we've already re-mapped
if (!textureFileInfo.filePath().isEmpty()) {

View file

@ -164,6 +164,8 @@ void EntityTreeRenderer::shutdown() {
}
void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, render::Transaction& transaction) {
PROFILE_RANGE_EX(simulation_physics, "Add", 0xffff00ff, (uint64_t)_entitiesToAdd.size());
PerformanceTimer pt("add");
// Clear any expired entities
// FIXME should be able to use std::remove_if, but it fails due to some
// weird compilation error related to EntityItemID assignment operators
@ -207,6 +209,8 @@ void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, r
}
void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene, render::Transaction& transaction) {
PROFILE_RANGE_EX(simulation_physics, "Change", 0xffff00ff, (uint64_t)_changedEntities.size());
PerformanceTimer pt("change");
std::unordered_set<EntityItemID> changedEntities;
_changedEntitiesGuard.withWriteLock([&] {
#if 0
@ -227,6 +231,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
}
if (!_renderablesToUpdate.empty()) {
PROFILE_RANGE_EX(simulation_physics, "UpdateRenderables", 0xffff00ff, (uint64_t)_renderablesToUpdate.size());
for (const auto& entry : _renderablesToUpdate) {
const auto& renderable = entry.second;
renderable->updateInScene(scene, transaction);
@ -236,6 +241,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
}
void EntityTreeRenderer::update(bool simulate) {
PROFILE_RANGE(simulation_physics, "ETR::update");
PerformanceTimer perfTimer("ETRupdate");
if (_tree && !_shuttingDown) {
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
@ -243,22 +249,14 @@ void EntityTreeRenderer::update(bool simulate) {
// Update the rendereable entities as needed
{
PROFILE_RANGE(simulation_physics, "Scene");
PerformanceTimer sceneTimer("scene");
auto scene = _viewState->getMain3DScene();
if (scene) {
render::Transaction transaction;
{
PerformanceTimer pt("add");
addPendingEntities(scene, transaction);
}
{
PerformanceTimer pt("change");
updateChangedEntities(scene, transaction);
}
{
PerformanceTimer pt("enqueue");
scene->enqueueTransaction(transaction);
}
addPendingEntities(scene, transaction);
updateChangedEntities(scene, transaction);
scene->enqueueTransaction(transaction);
}
}
@ -340,7 +338,8 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector<EntityIt
}
bool EntityTreeRenderer::checkEnterLeaveEntities() {
PerformanceTimer perfTimer("checkEnterLeaveEntities");
PROFILE_RANGE(simulation_physics, "EnterLeave");
PerformanceTimer perfTimer("enterLeave");
auto now = usecTimestampNow();
bool didUpdate = false;

View file

@ -26,6 +26,7 @@
#include "RenderableWebEntityItem.h"
#include "RenderableZoneEntityItem.h"
using namespace render;
using namespace render::entities;
@ -271,6 +272,7 @@ void EntityRenderer::removeFromScene(const ScenePointer& scene, Transaction& tra
}
void EntityRenderer::updateInScene(const ScenePointer& scene, Transaction& transaction) {
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
if (!isValidRenderItem()) {
return;
}
@ -330,6 +332,7 @@ bool EntityRenderer::needsRenderUpdateFromEntity(const EntityItemPointer& entity
}
void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) {
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
withWriteLock([&] {
auto transparent = isTransparent();
if (_prevIsTransparent && !transparent) {

View file

@ -34,6 +34,7 @@
#include "EntityTreeRenderer.h"
#include "EntitiesRendererLogging.h"
static CollisionRenderMeshCache collisionMeshCache;
void ModelEntityWrapper::setModel(const ModelPointer& model) {
@ -107,6 +108,7 @@ QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextu
}
void RenderableModelEntityItem::doInitialModelSimulation() {
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
ModelPointer model = getModel();
if (!model) {
return;
@ -123,11 +125,11 @@ void RenderableModelEntityItem::doInitialModelSimulation() {
model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
model->setRotation(getRotation());
model->setTranslation(getPosition());
{
PerformanceTimer perfTimer("model->simulate");
if (_needsInitialSimulation) {
model->simulate(0.0f);
_needsInitialSimulation = false;
}
_needsInitialSimulation = false;
}
void RenderableModelEntityItem::autoResizeJointArrays() {
@ -138,6 +140,7 @@ void RenderableModelEntityItem::autoResizeJointArrays() {
}
bool RenderableModelEntityItem::needsUpdateModelBounds() const {
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
ModelPointer model = getModel();
if (!hasModel() || !model) {
return false;
@ -151,7 +154,7 @@ bool RenderableModelEntityItem::needsUpdateModelBounds() const {
return true;
}
if (isMovingRelativeToParent() || isAnimatingSomething()) {
if (isAnimatingSomething()) {
return true;
}
@ -178,13 +181,61 @@ bool RenderableModelEntityItem::needsUpdateModelBounds() const {
}
}
return false;
return model->needsReload();
}
void RenderableModelEntityItem::updateModelBounds() {
if (needsUpdateModelBounds()) {
doInitialModelSimulation();
DETAILED_PROFILE_RANGE(simulation_physics, "updateModelBounds");
if (!_dimensionsInitialized || !hasModel()) {
return;
}
ModelPointer model = getModel();
if (!model || !model->isLoaded()) {
return;
}
bool updateRenderItems = false;
if (model->needsReload()) {
model->updateGeometry();
updateRenderItems = true;
}
if (model->getScaleToFitDimensions() != getDimensions() ||
model->getRegistrationPoint() != getRegistrationPoint()) {
// The machinery for updateModelBounds will give existing models the opportunity to fix their
// translation/rotation/scale/registration. The first two are straightforward, but the latter two
// have guards to make sure they don't happen after they've already been set. Here we reset those guards.
// This doesn't cause the entity values to change -- it just allows the model to match once it comes in.
model->setScaleToFit(false, getDimensions());
model->setSnapModelToRegistrationPoint(false, getRegistrationPoint());
// now recalculate the bounds and registration
model->setScaleToFit(true, getDimensions());
model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
updateRenderItems = true;
}
bool success;
auto transform = getTransform(success);
if (success && (model->getTranslation() != transform.getTranslation() ||
model->getRotation() != transform.getRotation())) {
model->setTransformNoUpdateRenderItems(transform);
updateRenderItems = true;
}
if (_needsInitialSimulation || _needsJointSimulation || isAnimatingSomething()) {
// NOTE: on isAnimatingSomething() we need to call Model::simulate() which calls Rig::updateRig()
// TODO: there is opportunity to further optimize the isAnimatingSomething() case.
model->simulate(0.0f);
_needsInitialSimulation = false;
_needsJointSimulation = false;
updateRenderItems = true;
}
if (updateRenderItems) {
model->updateRenderItems();
}
}
@ -293,7 +344,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() const {
// we have both URLs AND both geometries AND they are both fully loaded.
if (_needsInitialSimulation) {
// the _model's offset will be wrong until _needsInitialSimulation is false
PerformanceTimer perfTimer("_model->simulate");
DETAILED_PERFORMANCE_TIMER("_model->simulate");
const_cast<RenderableModelEntityItem*>(this)->doInitialModelSimulation();
}
return true;
@ -839,7 +890,7 @@ void RenderableModelEntityItem::setJointTranslationsSet(const QVector<bool>& tra
}
void RenderableModelEntityItem::locationChanged(bool tellPhysics) {
PerformanceTimer pertTimer("locationChanged");
DETAILED_PERFORMANCE_TIMER("locationChanged");
EntityItem::locationChanged(tellPhysics);
auto model = getModel();
if (model && model->isLoaded()) {
@ -880,7 +931,6 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() {
return;
}
// relay any inbound joint changes from scripts/animation/network to the model/rig
_jointDataLock.withWriteLock([&] {
for (int index = 0; index < _localJointData.size(); ++index) {
@ -897,15 +947,11 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() {
});
}
bool RenderableModelEntityItem::isAnimatingSomething() const {
return !getAnimationURL().isEmpty() && getAnimationIsPlaying() && getAnimationFPS() != 0.0f;
}
using namespace render;
using namespace render::entities;
ItemKey ModelEntityRenderer::getKey() {
return ItemKey::Builder().withTypeMeta();
return ItemKey::Builder().withTypeMeta().withTypeShape();
}
uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) {
@ -1124,6 +1170,7 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
}
void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
if (_hasModel != entity->hasModel()) {
_hasModel = entity->hasModel();
}
@ -1202,9 +1249,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
}
}
if (entity->needsUpdateModelBounds()) {
entity->updateModelBounds();
}
entity->updateModelBounds();
if (model->isVisible() != _visible) {
// FIXME: this seems like it could be optimized if we tracked our last known visible state in
@ -1212,13 +1257,16 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
// so most of the time we don't do anything in this function.
model->setVisibleInScene(_visible, scene);
}
// TODO? early exit here when not visible?
//entity->doInitialModelSimulation();
if (model->needsFixupInScene()) {
model->removeFromScene(scene, transaction);
render::Item::Status::Getters statusGetters;
makeStatusGetters(entity, statusGetters);
model->addToScene(scene, transaction, statusGetters);
{
DETAILED_PROFILE_RANGE(simulation_physics, "Fixup");
if (model->needsFixupInScene()) {
model->removeFromScene(scene, transaction);
render::Item::Status::Getters statusGetters;
makeStatusGetters(entity, statusGetters);
model->addToScene(scene, transaction, statusGetters);
}
}
// When the individual mesh parts of a model finish fading, they will mark their Model as needing updating
@ -1227,16 +1275,20 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
model->updateRenderItems();
}
// make a copy of the animation properites
auto newAnimationProperties = entity->getAnimationProperties();
if (newAnimationProperties != _renderAnimationProperties) {
withWriteLock([&] {
_renderAnimationProperties = newAnimationProperties;
_currentFrame = _renderAnimationProperties.getCurrentFrame();
});
{
DETAILED_PROFILE_RANGE(simulation_physics, "CheckAnimation");
// make a copy of the animation properites
auto newAnimationProperties = entity->getAnimationProperties();
if (newAnimationProperties != _renderAnimationProperties) {
withWriteLock([&] {
_renderAnimationProperties = newAnimationProperties;
_currentFrame = _renderAnimationProperties.getCurrentFrame();
});
}
}
if (_animating) {
DETAILED_PROFILE_RANGE(simulation_physics, "Animate");
if (!jointsMapped()) {
mapJoints(entity, model->getJointNames());
}
@ -1247,15 +1299,16 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items
void ModelEntityRenderer::doRender(RenderArgs* args) {
PROFILE_RANGE(render_detail, "MetaModelRender");
PerformanceTimer perfTimer("RMEIrender");
DETAILED_PROFILE_RANGE(render_detail, "MetaModelRender");
DETAILED_PERFORMANCE_TIMER("RMEIrender");
ModelPointer model;
withReadLock([&]{
model = _model;
});
if (_model && _model->didVisualGeometryRequestFail()) {
// If we don't have a model, or the model doesn't have visual geometry, render our bounding box as green wireframe
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

View file

@ -108,7 +108,6 @@ public:
private:
bool needsUpdateModelBounds() const;
bool isAnimatingSomething() const;
void autoResizeJointArrays();
void copyAnimationJointDataToModel();

View file

@ -96,6 +96,7 @@ PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity)
polylineFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), offsetof(Vertex, position));
polylineFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), offsetof(Vertex, normal));
polylineFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), offsetof(Vertex, uv));
polylineFormat->setAttribute(gpu::Stream::COLOR, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB), offsetof(Vertex, color));
});
PolyLineUniforms uniforms;
@ -116,7 +117,8 @@ bool PolyLineEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP
entity->pointsChanged() ||
entity->strokeWidthsChanged() ||
entity->normalsChanged() ||
entity->texturesChanged()
entity->texturesChanged() ||
entity->strokeColorsChanged()
);
}
@ -129,9 +131,11 @@ void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer&
if (!textures.isEmpty()) {
entityTextures = QUrl(textures);
}
_texture = DependencyManager::get<TextureCache>()->getTexture(entityTextures);
}
if (!_texture || _texture->getURL() != entityTextures) {
if (!_texture) {
_texture = DependencyManager::get<TextureCache>()->getTexture(entityTextures);
}
}
@ -143,6 +147,10 @@ void PolyLineEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo
auto pointsChanged = entity->pointsChanged();
auto strokeWidthsChanged = entity->strokeWidthsChanged();
auto normalsChanged = entity->normalsChanged();
auto strokeColorsChanged = entity->strokeColorsChanged();
bool isUVModeStretch = entity->getIsUVModeStretch();
entity->resetPolyLineChanged();
_polylineTransform = Transform();
@ -158,10 +166,14 @@ void PolyLineEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo
if (normalsChanged) {
_lastNormals = entity->getNormals();
}
if (pointsChanged || strokeWidthsChanged || normalsChanged) {
if (strokeColorsChanged) {
_lastStrokeColors = entity->getStrokeColors();
_lastStrokeColors = _lastNormals.size() == _lastStrokeColors.size() ? _lastStrokeColors : QVector<glm::vec3>({ toGlm(entity->getXColor()) });
}
if (pointsChanged || strokeWidthsChanged || normalsChanged || strokeColorsChanged) {
_empty = std::min(_lastPoints.size(), std::min(_lastNormals.size(), _lastStrokeWidths.size())) < 2;
if (!_empty) {
updateGeometry(updateVertices(_lastPoints, _lastNormals, _lastStrokeWidths));
updateGeometry(updateVertices(_lastPoints, _lastNormals, _lastStrokeWidths, _lastStrokeColors, isUVModeStretch, _textureAspectRatio));
}
}
}
@ -175,7 +187,12 @@ void PolyLineEntityRenderer::updateGeometry(const std::vector<Vertex>& vertices)
_verticesBuffer->setSubData(0, vertices);
}
std::vector<PolyLineEntityRenderer::Vertex> PolyLineEntityRenderer::updateVertices(const QVector<glm::vec3>& points, const QVector<glm::vec3>& normals, const QVector<float>& strokeWidths) {
std::vector<PolyLineEntityRenderer::Vertex> PolyLineEntityRenderer::updateVertices(const QVector<glm::vec3>& points,
const QVector<glm::vec3>& normals,
const QVector<float>& strokeWidths,
const QVector<glm::vec3>& strokeColors,
const bool isUVModeStretch,
const float textureAspectRatio) {
// Calculate the minimum vector size out of normals, points, and stroke widths
int size = std::min(points.size(), std::min(normals.size(), strokeWidths.size()));
@ -190,10 +207,52 @@ std::vector<PolyLineEntityRenderer::Vertex> PolyLineEntityRenderer::updateVertic
float uCoord = 0.0f;
int finalIndex = size - 1;
glm::vec3 binormal;
float accumulatedDistance = 0.0f;
float distanceToLastPoint = 0.0f;
float accumulatedStrokeWidth = 0.0f;
float strokeWidth = 0.0f;
bool doesStrokeWidthVary = false;
for (int i = 1; i < strokeWidths.size(); i++) {
if (strokeWidths[i] != strokeWidths[i - 1]) {
doesStrokeWidthVary = true;
break;
}
}
for (int i = 0; i <= finalIndex; i++) {
const float& width = strokeWidths.at(i);
const auto& point = points.at(i);
const auto& normal = normals.at(i);
const auto& color = strokeColors.size() == normals.size() ? strokeColors.at(i) : strokeColors.at(0);
int vertexIndex = i * 2;
if (!isUVModeStretch && i >= 1) {
distanceToLastPoint = glm::distance(points.at(i), points.at(i - 1));
accumulatedDistance += distanceToLastPoint;
strokeWidth = 2 * strokeWidths[i];
if (doesStrokeWidthVary) {
//If the stroke varies along the line the texture will stretch more or less depending on the speed
//because it looks better than using the same method as below
accumulatedStrokeWidth += strokeWidth;
float increaseValue = 1;
if (accumulatedStrokeWidth != 0) {
float newUcoord = glm::ceil(((1.0f / textureAspectRatio) * accumulatedDistance) / (accumulatedStrokeWidth / i));
increaseValue = newUcoord - uCoord;
}
increaseValue = increaseValue > 0 ? increaseValue : 1;
uCoord += increaseValue;
} else {
//If the stroke width is constant then the textures should keep the aspect ratio along the line
uCoord = ((1.0f / textureAspectRatio) * accumulatedDistance) / strokeWidth;
}
} else if (vertexIndex >= 2) {
uCoord += uCoordInc;
}
// For last point we can assume binormals are the same since it represents the last two vertices of quad
if (i < finalIndex) {
@ -206,11 +265,10 @@ std::vector<PolyLineEntityRenderer::Vertex> PolyLineEntityRenderer::updateVertic
}
}
const auto v1 = point + binormal;
const auto v2 = point - binormal;
vertices.emplace_back(v1, normal, vec2(uCoord, 0.0f));
vertices.emplace_back(v2, normal, vec2(uCoord, 1.0f));
uCoord += uCoordInc;
const auto v1 = points.at(i) + binormal;
const auto v2 = points.at(i) - binormal;
vertices.emplace_back(v1, normal, vec2(uCoord, 0.0f), color);
vertices.emplace_back(v2, normal, vec2(uCoord, 1.0f), color);
}
return vertices;
@ -235,6 +293,12 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
batch.setResourceTexture(PAINTSTROKE_TEXTURE_SLOT, DependencyManager::get<TextureCache>()->getWhiteTexture());
}
float textureWidth = (float)_texture->getOriginalWidth();
float textureHeight = (float)_texture->getOriginalHeight();
if (textureWidth != 0 && textureHeight != 0) {
_textureAspectRatio = textureWidth / textureHeight;
}
batch.setInputFormat(polylineFormat);
batch.setInputBuffer(0, _verticesBuffer, 0, sizeof(Vertex));
@ -247,4 +311,4 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
#endif
batch.draw(gpu::TRIANGLE_STRIP, _numVertices, 0);
}
}

View file

@ -27,7 +27,9 @@ public:
protected:
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene,
Transaction& transaction,
const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual ItemKey getKey() override;
@ -38,24 +40,37 @@ protected:
struct Vertex {
Vertex() {}
Vertex(const vec3& position, const vec3& normal, const vec2& uv) : position(position), normal(normal), uv(uv) {}
Vertex(const vec3& position, const vec3& normal, const vec2& uv, const vec3& color) : position(position),
normal(normal),
uv(uv),
color(color) {}
vec3 position;
vec3 normal;
vec2 uv;
vec3 color;
};
void updateGeometry(const std::vector<Vertex>& vertices);
static std::vector<Vertex> updateVertices(const QVector<glm::vec3>& points, const QVector<glm::vec3>& normals, const QVector<float>& strokeWidths);
static std::vector<Vertex> updateVertices(const QVector<glm::vec3>& points,
const QVector<glm::vec3>& normals,
const QVector<float>& strokeWidths,
const QVector<glm::vec3>& strokeColors,
const bool isUVModeStretch,
const float textureAspectRatio);
Transform _polylineTransform;
QVector<glm::vec3> _lastPoints;
QVector<glm::vec3> _lastNormals;
QVector<glm::vec3> _lastStrokeColors;
QVector<float> _lastStrokeWidths;
gpu::BufferPointer _verticesBuffer;
gpu::BufferView _uniformBuffer;
uint32_t _numVertices { 0 };
bool _empty{ true };
NetworkTexturePointer _texture;
float _textureAspectRatio { 1.0f };
};
} } // namespace

View file

@ -40,7 +40,7 @@ void main(void) {
packDeferredFragmentTranslucent(
float(frontCondition) * interpolatedNormal,
texel.a * varColor.a,
polyline.color * texel.rgb,
color * texel.rgb,
vec3(0.01, 0.01, 0.01),
10.0);
}

View file

@ -228,11 +228,21 @@ const std::array<ComponentPair, COMPONENT_MODE_ITEM_COUNT> COMPONENT_MODES = { {
} };
QString EntityItemProperties::getHazeModeAsString() const {
return COMPONENT_MODES[_hazeMode].second;
// return "inherit" if _hazeMode is not valid
if (_hazeMode < COMPONENT_MODE_ITEM_COUNT) {
return COMPONENT_MODES[_hazeMode].second;
} else {
return COMPONENT_MODES[COMPONENT_MODE_INHERIT].second;
}
}
QString EntityItemProperties::getHazeModeString(uint32_t mode) {
return COMPONENT_MODES[mode].second;
// return "inherit" if mode is not valid
if (mode < COMPONENT_MODE_ITEM_COUNT) {
return COMPONENT_MODES[mode].second;
} else {
return COMPONENT_MODES[COMPONENT_MODE_INHERIT].second;
}
}
void EntityItemProperties::setHazeModeFromString(const QString& hazeMode) {
@ -345,7 +355,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_FACE_CAMERA, faceCamera);
CHECK_PROPERTY_CHANGE(PROP_ACTION_DATA, actionData);
CHECK_PROPERTY_CHANGE(PROP_NORMALS, normals);
CHECK_PROPERTY_CHANGE(PROP_STROKE_COLORS, strokeColors);
CHECK_PROPERTY_CHANGE(PROP_STROKE_WIDTHS, strokeWidths);
CHECK_PROPERTY_CHANGE(PROP_IS_UV_MODE_STRETCH, isUVModeStretch);
CHECK_PROPERTY_CHANGE(PROP_X_TEXTURE_URL, xTextureURL);
CHECK_PROPERTY_CHANGE(PROP_Y_TEXTURE_URL, yTextureURL);
CHECK_PROPERTY_CHANGE(PROP_Z_TEXTURE_URL, zTextureURL);
@ -595,8 +607,10 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_WIDTH, lineWidth);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_POINTS, linePoints);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NORMALS, normals);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_STROKE_COLORS, strokeColors);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_STROKE_WIDTHS, strokeWidths);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_UV_MODE_STRETCH, isUVModeStretch);
}
if (!skipDefaults && !strictSemantics) {
@ -761,7 +775,10 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(faceCamera, bool, setFaceCamera);
COPY_PROPERTY_FROM_QSCRIPTVALUE(actionData, QByteArray, setActionData);
COPY_PROPERTY_FROM_QSCRIPTVALUE(normals, qVectorVec3, setNormals);
COPY_PROPERTY_FROM_QSCRIPTVALUE(strokeColors, qVectorVec3, setStrokeColors);
COPY_PROPERTY_FROM_QSCRIPTVALUE(strokeWidths,qVectorFloat, setStrokeWidths);
COPY_PROPERTY_FROM_QSCRIPTVALUE(isUVModeStretch, bool, setIsUVModeStretch);
if (!honorReadOnly) {
// this is used by the json reader to set things that we don't want javascript to able to affect.
@ -915,7 +932,9 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
COPY_PROPERTY_IF_CHANGED(faceCamera);
COPY_PROPERTY_IF_CHANGED(actionData);
COPY_PROPERTY_IF_CHANGED(normals);
COPY_PROPERTY_IF_CHANGED(strokeColors);
COPY_PROPERTY_IF_CHANGED(strokeWidths);
COPY_PROPERTY_IF_CHANGED(isUVModeStretch);
COPY_PROPERTY_IF_CHANGED(created);
_animation.merge(other._animation);
@ -1102,7 +1121,9 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
ADD_PROPERTY_TO_MAP(PROP_FACE_CAMERA, FaceCamera, faceCamera, bool);
ADD_PROPERTY_TO_MAP(PROP_ACTION_DATA, ActionData, actionData, QByteArray);
ADD_PROPERTY_TO_MAP(PROP_NORMALS, Normals, normals, QVector<glm::vec3>);
ADD_PROPERTY_TO_MAP(PROP_STROKE_COLORS, StrokeColors, strokeColors, QVector<glm::vec3>);
ADD_PROPERTY_TO_MAP(PROP_STROKE_WIDTHS, StrokeWidths, strokeWidths, QVector<float>);
ADD_PROPERTY_TO_MAP(PROP_IS_UV_MODE_STRETCH, IsUVModeStretch, isUVModeStretch, QVector<float>);
ADD_PROPERTY_TO_MAP(PROP_X_TEXTURE_URL, XTextureURL, xTextureURL, QString);
ADD_PROPERTY_TO_MAP(PROP_Y_TEXTURE_URL, YTextureURL, yTextureURL, QString);
ADD_PROPERTY_TO_MAP(PROP_Z_TEXTURE_URL, ZTextureURL, zTextureURL, QString);
@ -1448,9 +1469,11 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
if (properties.getType() == EntityTypes::PolyLine) {
APPEND_ENTITY_PROPERTY(PROP_LINE_WIDTH, properties.getLineWidth());
APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, properties.getLinePoints());
APPEND_ENTITY_PROPERTY(PROP_NORMALS, properties.getNormals());
APPEND_ENTITY_PROPERTY(PROP_NORMALS, properties.getPackedNormals());
APPEND_ENTITY_PROPERTY(PROP_STROKE_COLORS, properties.getPackedStrokeColors());
APPEND_ENTITY_PROPERTY(PROP_STROKE_WIDTHS, properties.getStrokeWidths());
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, properties.getTextures());
APPEND_ENTITY_PROPERTY(PROP_IS_UV_MODE_STRETCH, properties.getIsUVModeStretch());
}
// NOTE: Spheres and Boxes are just special cases of Shape, and they need to include their PROP_SHAPE
// when encoding/decoding edits because otherwise they can't polymorph to other shape types
@ -1537,6 +1560,44 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
return success;
}
QByteArray EntityItemProperties::getPackedNormals() const {
return packNormals(getNormals());
}
QByteArray EntityItemProperties::packNormals(const QVector<glm::vec3>& normals) const {
int normalsSize = normals.size();
QByteArray packedNormals = QByteArray(normalsSize * 6 + 1, '0');
// add size of the array
packedNormals[0] = ((uint8_t)normalsSize);
int index = 1;
for (int i = 0; i < normalsSize; i++) {
int numBytes = packFloatVec3ToSignedTwoByteFixed((unsigned char*)packedNormals.data() + index, normals[i], 15);
index += numBytes;
}
return packedNormals;
}
QByteArray EntityItemProperties::getPackedStrokeColors() const {
return packStrokeColors(getStrokeColors());
}
QByteArray EntityItemProperties::packStrokeColors(const QVector<glm::vec3>& strokeColors) const {
int strokeColorsSize = strokeColors.size();
QByteArray packedStrokeColors = QByteArray(strokeColorsSize * 3 + 1, '0');
// add size of the array
packedStrokeColors[0] = ((uint8_t)strokeColorsSize);
for (int i = 0; i < strokeColorsSize; i++) {
// add the color to the QByteArray
packedStrokeColors[i * 3 + 1] = strokeColors[i].r * 255;
packedStrokeColors[i * 3 + 2] = strokeColors[i].g * 255;
packedStrokeColors[i * 3 + 3] = strokeColors[i].b * 255;
}
return packedStrokeColors;
}
// TODO:
// how to handle lastEdited?
// how to handle lastUpdated?
@ -1758,9 +1819,11 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
if (properties.getType() == EntityTypes::PolyLine) {
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_WIDTH, float, setLineWidth);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_POINTS, QVector<glm::vec3>, setLinePoints);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NORMALS, QVector<glm::vec3>, setNormals);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NORMALS, QByteArray, setPackedNormals);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STROKE_COLORS, QByteArray, setPackedStrokeColors);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STROKE_WIDTHS, QVector<float>, setStrokeWidths);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXTURES, QString, setTextures);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IS_UV_MODE_STRETCH, bool, setIsUVModeStretch);
}
// NOTE: Spheres and Boxes are just special cases of Shape, and they need to include their PROP_SHAPE
@ -1791,6 +1854,53 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
return valid;
}
void EntityItemProperties::setPackedNormals(const QByteArray& value) {
setNormals(unpackNormals(value));
}
QVector<glm::vec3> EntityItemProperties::unpackNormals(const QByteArray& normals) {
// the size of the vector is packed first
QVector<glm::vec3> unpackedNormals = QVector<glm::vec3>((int)normals[0]);
if ((int)normals[0] == normals.size() / 6) {
int j = 0;
for (int i = 1; i < normals.size();) {
glm::vec3 aux = glm::vec3();
i += unpackFloatVec3FromSignedTwoByteFixed((unsigned char*)normals.data() + i, aux, 15);
unpackedNormals[j] = aux;
j++;
}
} else {
qCDebug(entities) << "WARNING - Expected received size for normals does not match. Expected: " << (int)normals[0]
<< " Received: " << (normals.size() / 6);
}
return unpackedNormals;
}
void EntityItemProperties::setPackedStrokeColors(const QByteArray& value) {
setStrokeColors(unpackStrokeColors(value));
}
QVector<glm::vec3> EntityItemProperties::unpackStrokeColors(const QByteArray& strokeColors) {
// the size of the vector is packed first
QVector<glm::vec3> unpackedStrokeColors = QVector<glm::vec3>((int)strokeColors[0]);
if ((int)strokeColors[0] == strokeColors.size() / 3) {
int j = 0;
for (int i = 1; i < strokeColors.size();) {
float r = (uint8_t)strokeColors[i++] / 255.0f;
float g = (uint8_t)strokeColors[i++] / 255.0f;
float b = (uint8_t)strokeColors[i++] / 255.0f;
unpackedStrokeColors[j++] = glmVec3(r, g, b);
}
} else {
qCDebug(entities) << "WARNING - Expected received size for stroke colors does not match. Expected: "
<< (int)strokeColors[0] << " Received: " << (strokeColors.size() / 3);
}
return unpackedStrokeColors;
}
// NOTE: This version will only encode the portion of the edit message immediately following the
// header it does not include the send times and sequence number because that is handled by the
@ -1932,7 +2042,9 @@ void EntityItemProperties::markAllChanged() {
_actionDataChanged = true;
_normalsChanged = true;
_strokeColorsChanged = true;
_strokeWidthsChanged = true;
_isUVModeStretchChanged = true;
_xTextureURLChanged = true;
_yTextureURLChanged = true;
@ -2347,6 +2459,14 @@ QList<QString> EntityItemProperties::listChangedProperties() {
out += "shape";
}
if (strokeColorsChanged()) {
out += "strokeColors";
}
if (isUVModeStretchChanged()) {
out += "isUVModeStretch";
}
getAnimation().listChangedProperties(out);
getKeyLight().listChangedProperties(out);
getSkybox().listChangedProperties(out);

View file

@ -191,8 +191,10 @@ public:
DEFINE_PROPERTY_REF(PROP_DESCRIPTION, Description, description, QString, "");
DEFINE_PROPERTY(PROP_FACE_CAMERA, FaceCamera, faceCamera, bool, TextEntityItem::DEFAULT_FACE_CAMERA);
DEFINE_PROPERTY_REF(PROP_ACTION_DATA, ActionData, actionData, QByteArray, QByteArray());
DEFINE_PROPERTY(PROP_NORMALS, Normals, normals, QVector<glm::vec3>, QVector<glm::vec3>());
DEFINE_PROPERTY(PROP_NORMALS, Normals, normals, QVector<glm::vec3>, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC);
DEFINE_PROPERTY(PROP_STROKE_COLORS, StrokeColors, strokeColors, QVector<glm::vec3>, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC);
DEFINE_PROPERTY(PROP_STROKE_WIDTHS, StrokeWidths, strokeWidths, QVector<float>, QVector<float>());
DEFINE_PROPERTY(PROP_IS_UV_MODE_STRETCH, IsUVModeStretch, isUVModeStretch, bool, true);
DEFINE_PROPERTY_REF(PROP_X_TEXTURE_URL, XTextureURL, xTextureURL, QString, "");
DEFINE_PROPERTY_REF(PROP_Y_TEXTURE_URL, YTextureURL, yTextureURL, QString, "");
DEFINE_PROPERTY_REF(PROP_Z_TEXTURE_URL, ZTextureURL, zTextureURL, QString, "");
@ -322,6 +324,17 @@ public:
bool getRenderInfoHasTransparent() const { return _renderInfoHasTransparent; }
void setRenderInfoHasTransparent(bool value) { _renderInfoHasTransparent = value; }
void setPackedNormals(const QByteArray& value);
QVector<glm::vec3> unpackNormals(const QByteArray& normals);
void setPackedStrokeColors(const QByteArray& value);
QVector<glm::vec3> unpackStrokeColors(const QByteArray& strokeColors);
QByteArray getPackedNormals() const;
QByteArray packNormals(const QVector<glm::vec3>& normals) const;
QByteArray getPackedStrokeColors() const;
QByteArray packStrokeColors(const QVector<glm::vec3>& strokeColors) const;
protected:
QString getCollisionMaskAsString() const;

View file

@ -24,6 +24,8 @@ const glm::vec3 ENTITY_ITEM_ZERO_VEC3 = glm::vec3(0.0f);
const glm::vec3 ENTITY_ITEM_ONE_VEC3 = glm::vec3(1.0f);
const glm::vec3 ENTITY_ITEM_HALF_VEC3 = glm::vec3(0.5f);
const QVector<glm::vec3> ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC = QVector<glm::vec3>();
const bool ENTITY_ITEM_DEFAULT_LOCKED = false;
const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString("");
const QUuid ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QUuid();

View file

@ -109,7 +109,9 @@ enum EntityPropertyList {
// Used by PolyLine entity
PROP_NORMALS,
PROP_STROKE_COLORS,
PROP_STROKE_WIDTHS,
PROP_IS_UV_MODE_STRETCH,
// used by particles
PROP_SPEED_SPREAD,

View file

@ -9,9 +9,11 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <AACube.h>
#include "EntitySimulation.h"
#include <AACube.h>
#include <Profile.h>
#include "EntitiesLogging.h"
#include "MovingEntitiesOperator.h"
@ -27,6 +29,7 @@ void EntitySimulation::setEntityTree(EntityTreePointer tree) {
}
void EntitySimulation::updateEntities() {
PROFILE_RANGE(simulation_physics, "ES::updateEntities");
QMutexLocker lock(&_mutex);
quint64 now = usecTimestampNow();
@ -35,8 +38,12 @@ void EntitySimulation::updateEntities() {
callUpdateOnEntitiesThatNeedIt(now);
moveSimpleKinematics(now);
updateEntitiesInternal(now);
PerformanceTimer perfTimer("sortingEntities");
sortEntitiesThatMoved();
{
PROFILE_RANGE(simulation_physics, "Sort");
PerformanceTimer perfTimer("sortingEntities");
sortEntitiesThatMoved();
}
}
void EntitySimulation::takeEntitiesToDelete(VectorOfEntities& entitiesToDelete) {
@ -258,6 +265,7 @@ void EntitySimulation::clearEntities() {
}
void EntitySimulation::moveSimpleKinematics(const quint64& now) {
PROFILE_RANGE_EX(simulation_physics, "Kinematics", 0xffff00ff, (uint64_t)_simpleKinematicEntities.size());
SetOfEntities::iterator itemItr = _simpleKinematicEntities.begin();
while (itemItr != _simpleKinematicEntities.end()) {
EntityItemPointer entity = *itemItr;

View file

@ -15,8 +15,9 @@
#include <QtScript/QScriptEngine>
#include <PerfStat.h>
#include <Extents.h>
#include <PerfStat.h>
#include <Profile.h>
#include "EntitySimulation.h"
#include "VariantMapToScriptValue.h"
@ -1370,6 +1371,7 @@ void EntityTree::entityChanged(EntityItemPointer entity) {
void EntityTree::fixupNeedsParentFixups() {
PROFILE_RANGE(simulation_physics, "FixupParents");
MovingEntitiesOperator moveOperator;
QWriteLocker locker(&_needsParentFixupLock);
@ -1459,6 +1461,7 @@ void EntityTree::addToNeedsParentFixupList(EntityItemPointer entity) {
}
void EntityTree::update(bool simulate) {
PROFILE_RANGE(simulation_physics, "ET::update");
fixupNeedsParentFixups();
if (simulate && _simulation) {
withWriteLock([&] {

View file

@ -557,12 +557,6 @@ void ModelEntityItem::setAnimationLoop(bool loop) {
});
}
bool ModelEntityItem::getAnimationLoop() const {
return resultWithReadLock<bool>([&] {
return _animationProperties.getLoop();
});
}
void ModelEntityItem::setAnimationHold(bool hold) {
withWriteLock([&] {
_animationProperties.setHold(hold);
@ -610,8 +604,10 @@ float ModelEntityItem::getAnimationCurrentFrame() const {
});
}
float ModelEntityItem::getAnimationFPS() const {
bool ModelEntityItem::isAnimatingSomething() const {
return resultWithReadLock<float>([&] {
return _animationProperties.getFPS();
});
return !_animationProperties.getURL().isEmpty() &&
_animationProperties.getRunning() &&
(_animationProperties.getFPS() != 0.0f);
});
}

View file

@ -90,7 +90,6 @@ public:
bool getAnimationAllowTranslation() const { return _animationProperties.getAllowTranslation(); };
void setAnimationLoop(bool loop);
bool getAnimationLoop() const;
void setAnimationHold(bool hold);
bool getAnimationHold() const;
@ -101,10 +100,9 @@ public:
void setAnimationLastFrame(float lastFrame);
float getAnimationLastFrame() const;
bool getAnimationIsPlaying() const;
float getAnimationCurrentFrame() const;
float getAnimationFPS() const;
bool isAnimatingSomething() const;
static const QString DEFAULT_TEXTURES;
const QString getTextures() const;
@ -123,7 +121,6 @@ public:
QVector<bool> getJointRotationsSet() const;
QVector<glm::vec3> getJointTranslations() const;
QVector<bool> getJointTranslationsSet() const;
bool isAnimatingSomething() const;
private:
void setAnimationSettings(const QString& value); // only called for old bitstream format

View file

@ -22,7 +22,7 @@
#include "PolyLineEntityItem.h"
const float PolyLineEntityItem::DEFAULT_LINE_WIDTH = 0.1f;
const int PolyLineEntityItem::MAX_POINTS_PER_LINE = 70;
const int PolyLineEntityItem::MAX_POINTS_PER_LINE = 60;
EntityItemPointer PolyLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
@ -31,6 +31,7 @@ EntityItemPointer PolyLineEntityItem::factory(const EntityItemID& entityID, cons
return entity;
}
PolyLineEntityItem::PolyLineEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) {
_type = EntityTypes::PolyLine;
}
@ -42,12 +43,15 @@ EntityItemProperties PolyLineEntityItem::getProperties(EntityPropertyFlags desir
properties._color = getXColor();
properties._colorChanged = false;
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineWidth, getLineWidth);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(linePoints, getLinePoints);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(normals, getNormals);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(strokeColors, getStrokeColors);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(strokeWidths, getStrokeWidths);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(isUVModeStretch, getIsUVModeStretch);
return properties;
}
@ -60,8 +64,10 @@ bool PolyLineEntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lineWidth, setLineWidth);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(linePoints, setLinePoints);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(normals, setNormals);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(strokeColors, setStrokeColors);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(strokeWidths, setStrokeWidths);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(isUVModeStretch, setIsUVModeStretch);
if (somethingChanged) {
bool wantDebug = false;
@ -108,6 +114,15 @@ bool PolyLineEntityItem::setNormals(const QVector<glm::vec3>& normals) {
return true;
}
bool PolyLineEntityItem::setStrokeColors(const QVector<glm::vec3>& strokeColors) {
withWriteLock([&] {
_strokeColors = strokeColors;
_strokeColorsChanged = true;
});
return true;
}
bool PolyLineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
if (points.size() > MAX_POINTS_PER_LINE) {
return false;
@ -193,8 +208,10 @@ int PolyLineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da
READ_ENTITY_PROPERTY(PROP_LINE_WIDTH, float, setLineWidth);
READ_ENTITY_PROPERTY(PROP_LINE_POINTS, QVector<glm::vec3>, setLinePoints);
READ_ENTITY_PROPERTY(PROP_NORMALS, QVector<glm::vec3>, setNormals);
READ_ENTITY_PROPERTY(PROP_STROKE_COLORS, QVector<glm::vec3>, setStrokeColors);
READ_ENTITY_PROPERTY(PROP_STROKE_WIDTHS, QVector<float>, setStrokeWidths);
READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures);
READ_ENTITY_PROPERTY(PROP_IS_UV_MODE_STRETCH, bool, setIsUVModeStretch);
return bytesRead;
}
@ -207,8 +224,10 @@ EntityPropertyFlags PolyLineEntityItem::getEntityProperties(EncodeBitstreamParam
requestedProperties += PROP_LINE_WIDTH;
requestedProperties += PROP_LINE_POINTS;
requestedProperties += PROP_NORMALS;
requestedProperties += PROP_STROKE_COLORS;
requestedProperties += PROP_STROKE_WIDTHS;
requestedProperties += PROP_TEXTURES;
requestedProperties += PROP_IS_UV_MODE_STRETCH;
return requestedProperties;
}
@ -227,8 +246,10 @@ void PolyLineEntityItem::appendSubclassData(OctreePacketData* packetData, Encode
APPEND_ENTITY_PROPERTY(PROP_LINE_WIDTH, getLineWidth());
APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, getLinePoints());
APPEND_ENTITY_PROPERTY(PROP_NORMALS, getNormals());
APPEND_ENTITY_PROPERTY(PROP_STROKE_COLORS, getStrokeColors());
APPEND_ENTITY_PROPERTY(PROP_STROKE_WIDTHS, getStrokeWidths());
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures());
APPEND_ENTITY_PROPERTY(PROP_IS_UV_MODE_STRETCH, getIsUVModeStretch());
}
void PolyLineEntityItem::debugDump() const {
@ -258,6 +279,14 @@ QVector<glm::vec3> PolyLineEntityItem::getNormals() const {
return result;
}
QVector<glm::vec3> PolyLineEntityItem::getStrokeColors() const {
QVector<glm::vec3> result;
withReadLock([&] {
result = _strokeColors;
});
return result;
}
QVector<float> PolyLineEntityItem::getStrokeWidths() const {
QVector<float> result;
withReadLock([&] {

View file

@ -46,9 +46,11 @@ class PolyLineEntityItem : public EntityItem {
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
void setColor(const rgbColor& value) {
_strokeColorsChanged = true;
memcpy(_color, value, sizeof(_color));
}
void setColor(const xColor& value) {
_strokeColorsChanged = true;
_color[RED_INDEX] = value.red;
_color[GREEN_INDEX] = value.green;
_color[BLUE_INDEX] = value.blue;
@ -64,9 +66,15 @@ class PolyLineEntityItem : public EntityItem {
bool setNormals(const QVector<glm::vec3>& normals);
QVector<glm::vec3> getNormals() const;
bool setStrokeColors(const QVector<glm::vec3>& strokeColors);
QVector<glm::vec3> getStrokeColors() const;
bool setStrokeWidths(const QVector<float>& strokeWidths);
QVector<float> getStrokeWidths() const;
void setIsUVModeStretch(bool isUVModeStretch){ _isUVModeStretch = isUVModeStretch; }
bool getIsUVModeStretch() const{ return _isUVModeStretch; }
QString getTextures() const;
void setTextures(const QString& textures);
@ -76,10 +84,11 @@ class PolyLineEntityItem : public EntityItem {
bool pointsChanged() const { return _pointsChanged; }
bool normalsChanged() const { return _normalsChanged; }
bool strokeColorsChanged() const { return _strokeColorsChanged; }
bool strokeWidthsChanged() const { return _strokeWidthsChanged; }
bool texturesChanged() const { return _texturesChangedFlag; }
void resetTexturesChanged() { _texturesChangedFlag = false; }
void resetPolyLineChanged() { _strokeWidthsChanged = _normalsChanged = _pointsChanged = false; }
void resetPolyLineChanged() { _strokeColorsChanged = _strokeWidthsChanged = _normalsChanged = _pointsChanged = false; }
// never have a ray intersection pick a PolyLineEntityItem.
@ -103,11 +112,14 @@ private:
float _lineWidth { DEFAULT_LINE_WIDTH };
bool _pointsChanged { true };
bool _normalsChanged { true };
bool _strokeColorsChanged { true };
bool _strokeWidthsChanged { true };
QVector<glm::vec3> _points;
QVector<glm::vec3> _normals;
QVector<glm::vec3> _strokeColors;
QVector<float> _strokeWidths;
QString _textures;
bool _isUVModeStretch;
bool _texturesChangedFlag { false };
mutable QReadWriteLock _quadReadWriteLock;
};

View file

@ -321,8 +321,10 @@ void ZoneEntityItem::resetRenderingPropertiesChanged() {
}
void ZoneEntityItem::setHazeMode(const uint32_t value) {
_hazeMode = value;
_hazePropertiesChanged = true;
if (value < COMPONENT_MODE_ITEM_COUNT) {
_hazeMode = value;
_hazePropertiesChanged = true;
}
}
uint32_t ZoneEntityItem::getHazeMode() const {

View file

@ -138,6 +138,8 @@ public:
static const bool DEFAULT_GHOSTING_ALLOWED;
static const QString DEFAULT_FILTER_URL;
static const uint32_t DEFAULT_HAZE_MODE{ (uint32_t)COMPONENT_MODE_INHERIT };
protected:
KeyLightPropertyGroup _keyLightProperties;
@ -146,7 +148,7 @@ protected:
BackgroundMode _backgroundMode = BACKGROUND_MODE_INHERIT;
uint8_t _hazeMode{ (uint8_t)COMPONENT_MODE_INHERIT };
uint32_t _hazeMode{ DEFAULT_HAZE_MODE };
float _hazeRange{ HazePropertyGroup::DEFAULT_HAZE_RANGE };
xColor _hazeColor{ HazePropertyGroup::DEFAULT_HAZE_COLOR };

View file

@ -13,6 +13,7 @@
#include <glm/gtx/transform.hpp>
#include <math.h>
#include <qcompilerdetection.h>
#include <ComponentMode.h>
using namespace model;
@ -256,8 +257,9 @@ void SunSkyStage::setSkybox(const SkyboxPointer& skybox) {
invalidate();
}
// Haze
void SunSkyStage::setHazeMode(uint32_t mode) {
_hazeMode = mode;
invalidate();
void SunSkyStage::setHazeMode(uint32_t hazeMode) {
if (hazeMode < COMPONENT_MODE_ITEM_COUNT) {
_hazeMode = hazeMode;
invalidate();
}
}

View file

@ -29,6 +29,7 @@ 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;
case PacketType::EntityQuery:

View file

@ -269,6 +269,9 @@ 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 EntityQueryPacketVersion: PacketVersion {
JSONFilter = 18,

View file

@ -0,0 +1,5 @@
set(TARGET_NAME pointers)
setup_hifi_library()
GroupSources(src)
link_hifi_libraries(shared)

View file

@ -0,0 +1,6 @@
#include "PointerManager.h"
PointerManager::PointerManager() {
}

View file

@ -0,0 +1,30 @@
//
// Created by Bradley Austin Davis on 2017/10/16
// Copyright 2013-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
//
#ifndef hifi_pointers_PointerManager_h
#define hifi_pointers_PointerManager_h
#include <DependencyManager.h>
#include <PointerEvent.h>
class PointerManager : public QObject, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY
public:
PointerManager();
signals:
void triggerBegin(const QUuid& id, const PointerEvent& pointerEvent);
void triggerContinue(const QUuid& id, const PointerEvent& pointerEvent);
void triggerEnd(const QUuid& id, const PointerEvent& pointerEvent);
void hoverEnter(const QUuid& id, const PointerEvent& pointerEvent);
void hoverOver(const QUuid& id, const PointerEvent& pointerEvent);
void hoverLeave(const QUuid& id, const PointerEvent& pointerEvent);
};
#endif // hifi_pointers_PointerManager_h

View file

@ -0,0 +1,81 @@
//
// Created by Sam Gondelman 7/11/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
//
#include "RayPick.h"
const RayPickFilter RayPickFilter::NOTHING;
RayPick::RayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) :
_filter(filter),
_maxDistance(maxDistance),
_enabled(enabled)
{
}
void RayPick::enable(bool enabled) {
withWriteLock([&] {
_enabled = enabled;
});
}
RayPickFilter RayPick::getFilter() const {
return resultWithReadLock<RayPickFilter>([&] {
return _filter;
});
}
float RayPick::getMaxDistance() const {
return _maxDistance;
}
bool RayPick::isEnabled() const {
return resultWithReadLock<bool>([&] {
return _enabled;
});
}
void RayPick::setPrecisionPicking(bool precisionPicking) {
withWriteLock([&]{
_filter.setFlag(RayPickFilter::PICK_COARSE, !precisionPicking);
});
}
void RayPick::setRayPickResult(const RayPickResult& rayPickResult) {
withWriteLock([&] {
_prevResult = rayPickResult;
});
}
QVector<QUuid> RayPick::getIgnoreItems() const {
return resultWithReadLock<QVector<QUuid>>([&] {
return _ignoreItems;
});
}
QVector<QUuid> RayPick::getIncludeItems() const {
return resultWithReadLock<QVector<QUuid>>([&] {
return _includeItems;
});
}
RayPickResult RayPick::getPrevRayPickResult() const {
return resultWithReadLock<RayPickResult>([&] {
return _prevResult;
});
}
void RayPick::setIgnoreItems(const QVector<QUuid>& ignoreItems) {
withWriteLock([&] {
_ignoreItems = ignoreItems;
});
}
void RayPick::setIncludeItems(const QVector<QUuid>& includeItems) {
withWriteLock([&] {
_includeItems = includeItems;
});
}

View file

@ -1,7 +1,4 @@
//
// RayPick.h
// interface/src/raypick
//
// Created by Sam Gondelman 7/11/2017
// Copyright 2017 High Fidelity, Inc.
//
@ -12,22 +9,22 @@
#define hifi_RayPick_h
#include <stdint.h>
#include "RegisteredMetaTypes.h"
#include <bitset>
#include "EntityItemID.h"
#include "ui/overlays/Overlay.h"
#include <QReadWriteLock>
#include <QtCore/QUuid>
#include <RegisteredMetaTypes.h>
#include <shared/ReadWriteLockable.h>
class RayPickFilter {
public:
enum FlagBit {
PICK_NOTHING = 0,
PICK_ENTITIES,
PICK_ENTITIES = 0,
PICK_OVERLAYS,
PICK_AVATARS,
PICK_HUD,
PICK_COURSE, // if not set, does precise intersection, otherwise, doesn't
PICK_COARSE, // if not set, does precise intersection, otherwise, doesn't
PICK_INCLUDE_INVISIBLE, // if not set, will not intersect invisible elements, otherwise, intersects both visible and invisible elements
PICK_INCLUDE_NONCOLLIDABLE, // if not set, will not intersect noncollidable elements, otherwise, intersects both collidable and noncollidable elements
@ -42,7 +39,7 @@ public:
// The key is the Flags
Flags _flags;
RayPickFilter() : _flags(getBitMask(PICK_NOTHING)) {}
RayPickFilter() {}
RayPickFilter(const Flags& flags) : _flags(flags) {}
bool operator== (const RayPickFilter& rhs) const { return _flags == rhs._flags; }
@ -50,13 +47,13 @@ public:
void setFlag(FlagBit flag, bool value) { _flags[flag] = value; }
bool doesPickNothing() const { return _flags[PICK_NOTHING]; }
bool doesPickNothing() const { return _flags == NOTHING._flags; }
bool doesPickEntities() const { return _flags[PICK_ENTITIES]; }
bool doesPickOverlays() const { return _flags[PICK_OVERLAYS]; }
bool doesPickAvatars() const { return _flags[PICK_AVATARS]; }
bool doesPickHUD() const { return _flags[PICK_HUD]; }
bool doesPickCourse() const { return _flags[PICK_COURSE]; }
bool doesPickCoarse() const { return _flags[PICK_COARSE]; }
bool doesPickInvisible() const { return _flags[PICK_INCLUDE_INVISIBLE]; }
bool doesPickNonCollidable() const { return _flags[PICK_INCLUDE_NONCOLLIDABLE]; }
@ -71,8 +68,8 @@ public:
if (doesPickNonCollidable()) {
toReturn |= getBitMask(PICK_INCLUDE_NONCOLLIDABLE);
}
if (doesPickCourse()) {
toReturn |= getBitMask(PICK_COURSE);
if (doesPickCoarse()) {
toReturn |= getBitMask(PICK_COARSE);
}
return Flags(toReturn);
}
@ -84,66 +81,76 @@ public:
if (doesPickNonCollidable()) {
toReturn |= getBitMask(PICK_INCLUDE_NONCOLLIDABLE);
}
if (doesPickCourse()) {
toReturn |= getBitMask(PICK_COURSE);
if (doesPickCoarse()) {
toReturn |= getBitMask(PICK_COARSE);
}
return Flags(toReturn);
}
Flags getAvatarFlags() const { return Flags(getBitMask(PICK_AVATARS)); }
Flags getHUDFlags() const { return Flags(getBitMask(PICK_HUD)); }
static unsigned int getBitMask(FlagBit bit) { return 1 << bit; }
static constexpr unsigned int getBitMask(FlagBit bit) { return 1 << bit; }
static const RayPickFilter NOTHING;
};
class RayPick {
class RayPick : protected ReadWriteLockable {
public:
using Pointer = std::shared_ptr<RayPick>;
RayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled);
virtual const PickRay getPickRay(bool& valid) const = 0;
void enable();
void disable();
void enable(bool enabled = true);
void disable() { enable(false); }
const RayPickFilter& getFilter() { return _filter; }
float getMaxDistance() { return _maxDistance; }
bool isEnabled() { return _enabled; }
const RayPickResult& getPrevRayPickResult();
RayPickFilter getFilter() const;
float getMaxDistance() const;
bool isEnabled() const;
RayPickResult getPrevRayPickResult() const;
void setPrecisionPicking(bool precisionPicking) { _filter.setFlag(RayPickFilter::PICK_COURSE, !precisionPicking); }
void setPrecisionPicking(bool precisionPicking);
void setRayPickResult(const RayPickResult& rayPickResult) { _prevResult = rayPickResult; }
void setRayPickResult(const RayPickResult& rayPickResult);
const QVector<EntityItemID>& getIgnoreEntites() { return _ignoreEntities; }
const QVector<EntityItemID>& getIncludeEntites() { return _includeEntities; }
const QVector<OverlayID>& getIgnoreOverlays() { return _ignoreOverlays; }
const QVector<OverlayID>& getIncludeOverlays() { return _includeOverlays; }
const QVector<EntityItemID>& getIgnoreAvatars() { return _ignoreAvatars; }
const QVector<EntityItemID>& getIncludeAvatars() { return _includeAvatars; }
void setIgnoreEntities(const QScriptValue& ignoreEntities);
void setIncludeEntities(const QScriptValue& includeEntities);
void setIgnoreOverlays(const QScriptValue& ignoreOverlays);
void setIncludeOverlays(const QScriptValue& includeOverlays);
void setIgnoreAvatars(const QScriptValue& ignoreAvatars);
void setIncludeAvatars(const QScriptValue& includeAvatars);
QVector<QUuid> getIgnoreItems() const;
QVector<QUuid> getIncludeItems() const;
QReadWriteLock* getLock() { return &_lock; }
template <typename T>
QVector<T> getIgnoreItemsAs() const {
QVector<T> result;
withReadLock([&] {
for (const auto& uid : _ignoreItems) {
result.push_back(uid);
}
});
return result;
}
template <typename T>
QVector<T> getIncludeItemsAs() const {
QVector<T> result;
withReadLock([&] {
for (const auto& uid : _includeItems) {
result.push_back(uid);
}
});
return result;
}
void setIgnoreItems(const QVector<QUuid>& items);
void setIncludeItems(const QVector<QUuid>& items);
private:
RayPickFilter _filter;
float _maxDistance;
const float _maxDistance;
bool _enabled;
RayPickResult _prevResult;
QVector<EntityItemID> _ignoreEntities;
QVector<EntityItemID> _includeEntities;
QVector<OverlayID> _ignoreOverlays;
QVector<OverlayID> _includeOverlays;
QVector<EntityItemID> _ignoreAvatars;
QVector<EntityItemID> _includeAvatars;
QReadWriteLock _lock;
QVector<QUuid> _ignoreItems;
QVector<QUuid> _includeItems;
};
#endif // hifi_RayPick_h

View file

@ -1,7 +1,4 @@
//
// StaticRayPick.cpp
// interface/src/raypick
//
// Created by Sam Gondelman 7/11/2017
// Copyright 2017 High Fidelity, Inc.
//

View file

@ -1,7 +1,4 @@
//
// StaticRayPick.h
// interface/src/raypick
//
// Created by Sam Gondelman 7/11/2017
// Copyright 2017 High Fidelity, Inc.
//

View file

@ -121,8 +121,6 @@ bool Model::needsFixupInScene() const {
return (_needsFixupInScene || !_addedToScene) && !_needsReload && isLoaded();
}
// TODO?: should we combine translation and rotation into single method to avoid double-work?
// (figure out where we call these)
void Model::setTranslation(const glm::vec3& translation) {
_translation = translation;
updateRenderItems();
@ -133,6 +131,14 @@ void Model::setRotation(const glm::quat& rotation) {
updateRenderItems();
}
// temporary HACK: set transform while avoiding implicit calls to updateRenderItems()
// TODO: make setRotation() and friends set flag to be used later to decide to updateRenderItems()
void Model::setTransformNoUpdateRenderItems(const Transform& transform) {
_translation = transform.getTranslation();
_rotation = transform.getRotation();
// DO NOT call updateRenderItems() here!
}
Transform Model::getTransform() const {
if (_spatiallyNestableOverride) {
bool success;
@ -957,7 +963,7 @@ Blender::Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointe
}
void Blender::run() {
PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xFFFF0000, 0, { { "url", _model->getURL().toString() } });
DETAILED_PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xFFFF0000, 0, { { "url", _model->getURL().toString() } });
QVector<glm::vec3> vertices, normals;
if (_model) {
int offset = 0;
@ -1078,8 +1084,7 @@ void Model::snapToRegistrationPoint() {
}
void Model::simulate(float deltaTime, bool fullUpdate) {
PROFILE_RANGE(simulation_detail, __FUNCTION__);
PerformanceTimer perfTimer("Model::simulate");
DETAILED_PROFILE_RANGE(simulation_detail, __FUNCTION__);
fullUpdate = updateGeometry() || fullUpdate || (_scaleToFit && !_scaledToFit)
|| (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint);
@ -1117,7 +1122,7 @@ void Model::computeMeshPartLocalBounds() {
// virtual
void Model::updateClusterMatrices() {
PerformanceTimer perfTimer("Model::updateClusterMatrices");
DETAILED_PERFORMANCE_TIMER("Model::updateClusterMatrices");
if (!_needsUpdateClusterMatrices || !isLoaded()) {
return;

View file

@ -206,6 +206,7 @@ public:
void setTranslation(const glm::vec3& translation);
void setRotation(const glm::quat& rotation);
void setTransformNoUpdateRenderItems(const Transform& transform); // temporary HACK
const glm::vec3& getTranslation() const { return _translation; }
const glm::quat& getRotation() const { return _rotation; }

View file

@ -97,5 +97,12 @@ private:
static QMap<QString, PerformanceTimerRecord> _records;
};
// uncomment WANT_DETAILED_PERFORMANCE_TIMERS definition to enable performance timers in high-frequency contexts
//#define WANT_DETAILED_PERFORMANCE_TIMERS
#ifdef WANT_DETAILED_PERFORMANCE_TIMERS
#define DETAILED_PERFORMANCE_TIMER(name) PerformanceTimer detailedPerformanceTimer(name);
#else // WANT_DETAILED_PERFORMANCE_TIMERS
#define DETAILED_PERFORMANCE_TIMER(name) ; // no-op
#endif // WANT_DETAILED_PERFORMANCE_TIMERS
#endif // hifi_PerfStat_h

View file

@ -108,4 +108,14 @@ inline void metadata(const QString& metadataType, const QVariantMap& args) {
#define SAMPLE_PROFILE_COUNTER(chance, category, name, ...) if (randFloat() <= chance) { PROFILE_COUNTER(category, name, ##__VA_ARGS__); }
#define SAMPLE_PROFILE_INSTANT(chance, category, name, ...) if (randFloat() <= chance) { PROFILE_INSTANT(category, name, ##__VA_ARGS__); }
// uncomment WANT_DETAILED_PROFILING definition to enable profiling in high-frequency contexts
//#define WANT_DETAILED_PROFILING
#ifdef WANT_DETAILED_PROFILING
#define DETAILED_PROFILE_RANGE(category, name) Duration profileRangeThis(trace_##category(), name);
#define DETAILED_PROFILE_RANGE_EX(category, name, argbColor, payload, ...) Duration profileRangeThis(trace_##category(), name, argbColor, (uint64_t)payload, ##__VA_ARGS__);
#else // WANT_DETAILED_PROFILING
#define DETAILED_PROFILE_RANGE(category, name) ; // no-op
#define DETAILED_PROFILE_RANGE_EX(category, name, argbColor, payload, ...) ; // no-op
#endif // WANT_DETAILED_PROFILING
#endif

View file

@ -23,16 +23,28 @@
#include "ToolbarScriptingInterface.h"
#include "Logging.h"
#include <AudioInjector.h>
#include "SettingHandle.h"
// FIXME move to global app properties
const QString SYSTEM_TOOLBAR = "com.highfidelity.interface.toolbar.system";
const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system";
const QString TabletScriptingInterface::QML = "hifi/tablet/TabletRoot.qml";
static Setting::Handle<QStringList> tabletSoundsButtonClick("TabletSounds", QStringList { "/sounds/Button06.wav",
"/sounds/Button04.wav",
"/sounds/Button07.wav",
"/sounds/Tab01.wav",
"/sounds/Tab02.wav" });
TabletScriptingInterface::TabletScriptingInterface() {
qmlRegisterType<TabletScriptingInterface>("TabletScriptingInterface", 1, 0, "TabletEnums");
}
TabletScriptingInterface::~TabletScriptingInterface() {
tabletSoundsButtonClick.set(tabletSoundsButtonClick.get());
}
ToolbarProxy* TabletScriptingInterface::getSystemToolbarProxy() {
@ -63,6 +75,29 @@ TabletProxy* TabletScriptingInterface::getTablet(const QString& tabletId) {
return tabletProxy;
}
void TabletScriptingInterface::preloadSounds() {
//preload audio events
const QStringList &audioSettings = tabletSoundsButtonClick.get();
for (int i = 0; i < TabletAudioEvents::Last; i++) {
QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + audioSettings.at(i));
SharedSoundPointer sound = DependencyManager::get<SoundCache>()->
getSound(QUrl::fromLocalFile(inf.absoluteFilePath()));
_audioEvents.insert(static_cast<TabletAudioEvents>(i), sound);
}
}
void TabletScriptingInterface::playSound(TabletAudioEvents aEvent) {
SharedSoundPointer sound = _audioEvents[aEvent];
if (sound) {
AudioInjectorOptions options;
options.stereo = sound->isStereo();
options.ambisonic = sound->isAmbisonic();
options.localOnly = true;
AudioInjectorPointer injector = AudioInjector::playSoundAndDelete(sound->getByteArray(), options);
}
}
void TabletScriptingInterface::setToolbarMode(bool toolbarMode) {
Q_ASSERT(QThread::currentThread() == qApp->thread());
_toolbarMode = toolbarMode;
@ -323,9 +358,12 @@ void TabletProxy::emitWebEvent(const QVariant& msg) {
}
void TabletProxy::onTabletShown() {
if (_tabletShown && _showRunningScripts) {
_showRunningScripts = false;
pushOntoStack("../../hifi/dialogs/TabletRunningScripts.qml");
if (_tabletShown) {
static_cast<TabletScriptingInterface*>(parent())->playSound(TabletScriptingInterface::TabletOpen);
if (_showRunningScripts) {
_showRunningScripts = false;
pushOntoStack("../../hifi/dialogs/TabletRunningScripts.qml");
}
}
}

View file

@ -23,7 +23,7 @@
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>
#include "SoundCache.h"
#include <DependencyManager.h>
class ToolbarProxy;
@ -40,8 +40,11 @@ class OffscreenQmlSurface;
class TabletScriptingInterface : public QObject, public Dependency {
Q_OBJECT
public:
enum TabletAudioEvents { ButtonClick, ButtonHover, TabletOpen, TabletHandsIn, TabletHandsOut, Last};
Q_ENUM(TabletAudioEvents)
TabletScriptingInterface();
~TabletScriptingInterface();
virtual ~TabletScriptingInterface();
static const QString QML;
void setToolbarScriptingInterface(ToolbarScriptingInterface* toolbarScriptingInterface) { _toolbarScriptingInterface = toolbarScriptingInterface; }
@ -54,6 +57,9 @@ public:
*/
Q_INVOKABLE TabletProxy* getTablet(const QString& tabletId);
void preloadSounds();
Q_INVOKABLE void playSound(TabletAudioEvents aEvent);
void setToolbarMode(bool toolbarMode);
void setQmlTabletRoot(QString tabletId, OffscreenQmlSurface* offscreenQmlSurface);
@ -77,6 +83,7 @@ private:
void processTabletEvents(QObject* object, const QKeyEvent* event);
ToolbarProxy* getSystemToolbarProxy();
QMap<TabletAudioEvents, SharedSoundPointer> _audioEvents;
protected:
std::map<QString, TabletProxy*> _tabletProxies;
ToolbarScriptingInterface* _toolbarScriptingInterface { nullptr };

View file

@ -32,7 +32,7 @@ var DEFAULT_SCRIPTS_COMBINED = [
"system/tablet-ui/tabletUI.js"
];
var DEFAULT_SCRIPTS_SEPARATE = [
"system/controllers/controllerScripts.js",
"system/controllers/controllerScripts.js"
// "system/chat.js"
];

View file

@ -141,8 +141,11 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
};
this.setIgnoreTablet = function() {
RayPick.setIgnoreOverlays(_this.leftControllerRayPick, [HMD.tabletID]);
RayPick.setIgnoreOverlays(_this.rightControllerRayPick, [HMD.tabletID]);
if (HMD.tabletID !== this.tabletID) {
this.tabletID = HMD.tabletID;
RayPick.setIgnoreItems(_this.leftControllerRayPick, _this.blacklist.concat([HMD.tabletID]));
RayPick.setIgnoreItems(_this.rightControllerRayPick, _this.blacklist.concat([HMD.tabletID]));
}
};
this.update = function () {
@ -367,9 +370,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
};
this.setBlacklist = function() {
RayPick.setIgnoreEntities(_this.leftControllerRayPick, this.blacklist);
RayPick.setIgnoreEntities(_this.rightControllerRayPick, this.blacklist);
RayPick.setIgnoreItems(_this.leftControllerRayPick, this.blacklist.concat(HMD.tabletID));
RayPick.setIgnoreItems(_this.rightControllerRayPick, this.blacklist.concat(HMD.tabletID));
};
var MAPPING_NAME = "com.highfidelity.controllerDispatcher";

View file

@ -127,6 +127,13 @@ Script.include("/~/system/libraries/utils.js");
this.updateLaserPointer = function(controllerData) {
LaserPointers.enableLaserPointer(this.laserPointer);
LaserPointers.setRenderState(this.laserPointer, this.mode);
if (HMD.tabletID !== this.tabletID || HMD.tabletButtonID !== this.tabletButtonID || HMD.tabletScreenID !== this.tabletScreenID) {
this.tabletID = HMD.tabletID;
this.tabletButtonID = HMD.tabletButtonID;
this.tabletScreenID = HMD.tabletScreenID;
LaserPointers.setIgnoreItems(this.laserPointer, [HMD.tabletID, HMD.tabletButtonID, HMD.tabletScreenID]);
}
};
this.pointingAtTablet = function(objectID) {
@ -233,7 +240,7 @@ Script.include("/~/system/libraries/utils.js");
defaultRenderStates: defaultRenderStates
});
LaserPointers.setIgnoreOverlays(this.laserPointer, [HMD.tabletID, HMD.tabletButtonID, HMD.tabletScreenID]);
LaserPointers.setIgnoreItems(this.laserPointer, [HMD.tabletID, HMD.tabletButtonID, HMD.tabletScreenID]);
}
var leftHandInEditMode = new InEditMode(LEFT_HAND);

View file

@ -177,6 +177,11 @@ Script.include("/~/system/libraries/controllers.js");
this.updateLaserPointer = function(controllerData) {
LaserPointers.enableLaserPointer(this.laserPointer);
LaserPointers.setRenderState(this.laserPointer, this.mode);
if (HMD.tabletID !== this.tabletID) {
this.tabletID = HMD.tabletID;
LaserPointers.setIgnoreItems(this.laserPointer, [HMD.tabletID]);
}
};
this.processControllerTriggers = function(controllerData) {
@ -369,7 +374,7 @@ Script.include("/~/system/libraries/controllers.js");
defaultRenderStates: defaultRenderStates
});
LaserPointers.setIgnoreOverlays(this.laserPointer, [HMD.tabletID]);
LaserPointers.setIgnoreItems(this.laserPointer, [HMD.tabletID]);
}
var leftOverlayLaserInput = new OverlayLaserInput(LEFT_HAND);

View file

@ -349,10 +349,10 @@ Script.include("/~/system/libraries/controllers.js");
};
this.setIgnoreEntities = function(entitiesToIgnore) {
LaserPointers.setIgnoreEntities(this.teleportRayHandVisible, entitiesToIgnore);
LaserPointers.setIgnoreEntities(this.teleportRayHandInvisible, entitiesToIgnore);
LaserPointers.setIgnoreEntities(this.teleportRayHeadVisible, entitiesToIgnore);
LaserPointers.setIgnoreEntities(this.teleportRayHeadInvisible, entitiesToIgnore);
LaserPointers.setIgnoreItems(this.teleportRayHandVisible, entitiesToIgnore);
LaserPointers.setIgnoreItems(this.teleportRayHandInvisible, entitiesToIgnore);
LaserPointers.setIgnoreItems(this.teleportRayHeadVisible, entitiesToIgnore);
LaserPointers.setIgnoreItems(this.teleportRayHeadInvisible, entitiesToIgnore);
};
}

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