3
0
Fork 0
mirror of https://github.com/lubosz/overte.git synced 2025-04-26 18:15:49 +02:00

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

This commit is contained in:
NissimHadar 2018-10-22 10:55:56 -07:00
commit c9f9679cf7
130 changed files with 1127 additions and 792 deletions
CMakeLists.txt
android
assignment-client/src
domain-server
resources/web/content/js
src
interface
libraries

View file

@ -7,6 +7,11 @@ else()
cmake_minimum_required(VERSION 3.2)
endif()
# squelch the Policy CMP0074 warning without requiring an update to cmake 3.12.
if ((${CMAKE_MAJOR_VERSION} EQUAL 3 AND ${CMAKE_MINOR_VERSION} GREATER 11) OR ${CMAKE_MAJOR_VERSION} GREATER 3)
cmake_policy(SET CMP0074 NEW)
endif()
project(hifi)
include("cmake/init.cmake")

View file

@ -0,0 +1 @@
org.gradle.jvmargs=-Xms2g -Xmx4g

View file

@ -368,11 +368,7 @@ void Agent::executeScript() {
// setup an Avatar for the script to use
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
scriptedAvatar->setID(getSessionUUID());
connect(_scriptEngine.data(), SIGNAL(update(float)),
scriptedAvatar.data(), SLOT(update(float)), Qt::ConnectionType::QueuedConnection);
scriptedAvatar->setForceFaceTrackerConnected(true);
// call model URL setters with empty URLs so our avatar, if user, will have the default models
@ -504,8 +500,6 @@ void Agent::executeScript() {
DependencyManager::set<AssignmentParentFinder>(_entityViewer.getTree());
_avatarAudioTimer.start();
// Agents should run at 45hz
static const int AVATAR_DATA_HZ = 45;
static const int AVATAR_DATA_IN_MSECS = MSECS_PER_SECOND / AVATAR_DATA_HZ;
@ -530,7 +524,8 @@ void Agent::executeScript() {
}
avatarDataTimer->stop();
_avatarAudioTimer.stop();
setIsAvatar(false); // will stop timers for sending identity packets
}
setFinished(true);
@ -582,28 +577,33 @@ void Agent::setIsAvatar(bool isAvatar) {
}
_isAvatar = isAvatar;
if (_isAvatar && !_avatarIdentityTimer) {
// set up the avatar timers
_avatarIdentityTimer = new QTimer(this);
_avatarQueryTimer = new QTimer(this);
auto scriptableAvatar = DependencyManager::get<ScriptableAvatar>();
if (_isAvatar) {
if (!_avatarIdentityTimer) {
// set up the avatar timers
_avatarIdentityTimer = new QTimer(this);
_avatarQueryTimer = new QTimer(this);
// connect our slot
connect(_avatarIdentityTimer, &QTimer::timeout, this, &Agent::sendAvatarIdentityPacket);
connect(_avatarQueryTimer, &QTimer::timeout, this, &Agent::queryAvatars);
// connect our slot
connect(_avatarIdentityTimer, &QTimer::timeout, this, &Agent::sendAvatarIdentityPacket);
connect(_avatarQueryTimer, &QTimer::timeout, this, &Agent::queryAvatars);
static const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000;
static const int AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS = 1000;
static const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000;
static const int AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS = 1000;
// start the timers
_avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); // FIXME - we shouldn't really need to constantly send identity packets
_avatarQueryTimer->start(AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS);
// start the timers
_avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); // FIXME - we shouldn't really need to constantly send identity packets
_avatarQueryTimer->start(AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS);
// tell the avatarAudioTimer to start ticking
QMetaObject::invokeMethod(&_avatarAudioTimer, "start");
}
connect(_scriptEngine.data(), &ScriptEngine::update,
scriptableAvatar.data(), &ScriptableAvatar::update, Qt::QueuedConnection);
if (!_isAvatar) {
// tell the avatarAudioTimer to start ticking
QMetaObject::invokeMethod(&_avatarAudioTimer, "start");
}
_entityEditSender.setMyAvatar(scriptableAvatar.data());
} else {
if (_avatarIdentityTimer) {
_avatarIdentityTimer->stop();
delete _avatarIdentityTimer;
@ -630,14 +630,14 @@ void Agent::setIsAvatar(bool isAvatar) {
packet->writePrimitive(KillAvatarReason::NoReason);
nodeList->sendPacket(std::move(packet), *node);
});
disconnect(_scriptEngine.data(), &ScriptEngine::update,
scriptableAvatar.data(), &ScriptableAvatar::update);
QMetaObject::invokeMethod(&_avatarAudioTimer, "stop");
}
QMetaObject::invokeMethod(&_avatarAudioTimer, "stop");
_entityEditSender.setMyAvatar(nullptr);
} else {
auto scriptableAvatar = DependencyManager::get<ScriptableAvatar>();
_entityEditSender.setMyAvatar(scriptableAvatar.data());
}
}
@ -788,7 +788,7 @@ void Agent::processAgentAvatarAudio() {
// seek past the sequence number, will be packed when destination node is known
audioPacket->seek(sizeof(quint16));
if (silentFrame) {
if (silentFrame && !_flushEncoder) {
if (!_isListeningToAudioStream) {
// if we have a silent frame and we're not listening then just send nothing and break out of here
@ -810,7 +810,7 @@ void Agent::processAgentAvatarAudio() {
// no matter what, the loudness should be set to 0
computeLoudness(nullptr, scriptedAvatar);
} else if (nextSoundOutput) {
} else if (nextSoundOutput || _flushEncoder) {
// write the codec
audioPacket->writeString(_selectedCodecName);
@ -864,8 +864,6 @@ void Agent::processAgentAvatarAudio() {
}
void Agent::aboutToFinish() {
setIsAvatar(false);// will stop timers for sending identity packets
// our entity tree is going to go away so tell that to the EntityScriptingInterface
DependencyManager::get<EntityScriptingInterface>()->setEntityTree(nullptr);

View file

@ -497,7 +497,7 @@ void AudioMixerClientData::processStreamPacket(ReceivedMessage& message, Concurr
if (newStream) {
// whenever a stream is added, push it to the concurrent vector of streams added this frame
addedStreams.emplace_back(getNodeID(), getNodeLocalID(), matchingStream->getStreamIdentifier(), matchingStream.get());
addedStreams.push_back(AddedStream(getNodeID(), getNodeLocalID(), matchingStream->getStreamIdentifier(), matchingStream.get()));
}
}

View file

@ -380,6 +380,11 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) {
++numAvatarsHeldBack;
shouldIgnore = true;
} else if (lastSeqFromSender == 0) {
// We have have not yet recieved any data about this avatar. Ignore it for now
// This is important for Agent scripts that are not avatar
// so that they don't appear to be an avatar at the origin
shouldIgnore = true;
} else if (lastSeqFromSender - lastSeqToReceiver > 1) {
// this is a skip - we still send the packet but capture the presence of the skip so we see it happening
++numAvatarsWithSkippedFrames;

View file

@ -164,7 +164,7 @@ public:
void setHasAudioEnabledFaceMovement(bool hasAudioEnabledFaceMovement);
bool getHasAudioEnabledFaceMovement() const override { return _headData->getHasAudioEnabledFaceMovement(); }
private slots:
public slots:
void update(float deltatime);
private:

View file

@ -59,6 +59,7 @@ $(document).ready(function(){
$.ajax({
url: '/content/upload',
type: 'POST',
timeout: 3600000, // Set timeout to 1h
cache: false,
processData: false,
contentType: false,

View file

@ -2906,7 +2906,7 @@ void DomainServer::updateReplicationNodes(ReplicationServerDirection direction)
// collect them in a vector to separately remove them with handleKillNode (since eachNode has a read lock and
// we cannot recursively take the write lock required by handleKillNode)
std::vector<SharedNodePointer> nodesToKill;
nodeList->eachNode([direction, replicationNodesInSettings, replicationDirection, &nodesToKill](const SharedNodePointer& otherNode) {
nodeList->eachNode([&direction, &replicationNodesInSettings, &replicationDirection, &nodesToKill](const SharedNodePointer& otherNode) {
if ((direction == Upstream && NodeType::isUpstream(otherNode->getType()))
|| (direction == Downstream && NodeType::isDownstream(otherNode->getType()))) {
bool nodeInSettings = find(replicationNodesInSettings.cbegin(), replicationNodesInSettings.cend(),

Binary file not shown.

Before

(image error) Size: 76 KiB

After

(image error) Size: 82 KiB

Binary file not shown.

Before

(image error) Size: 72 KiB

After

(image error) Size: 164 KiB

Binary file not shown.

Before

(image error) Size: 81 KiB

After

(image error) Size: 175 KiB

View file

@ -39,6 +39,7 @@ Item {
property string sendingPubliclyEffectImage;
property var http;
property var listModelName;
property var keyboardContainer: nil;
// This object is always used in a popup or full-screen Wallet section.
// This MouseArea is used to prevent a user from being
@ -1125,8 +1126,7 @@ Item {
checked: Settings.getValue("sendAssetsNearbyPublicly", true);
text: "Show Effect"
// Anchors
anchors.top: messageContainer.bottom;
anchors.topMargin: 16;
anchors.verticalCenter: bottomBarContainer.verticalCenter;
anchors.left: parent.left;
anchors.leftMargin: 20;
width: 130;
@ -1168,6 +1168,9 @@ Item {
lightboxPopup.visible = false;
}
lightboxPopup.visible = true;
if (keyboardContainer) {
keyboardContainer.keyboardRaised = false;
}
}
}
}
@ -1178,8 +1181,8 @@ Item {
anchors.leftMargin: 20;
anchors.right: parent.right;
anchors.rightMargin: 20;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 20;
anchors.top: messageContainer.bottom;
anchors.topMargin: 20;
height: 60;
// "CANCEL" button
@ -1187,11 +1190,11 @@ Item {
id: cancelButton_sendAssetStep;
color: root.assetName === "" ? hifi.buttons.noneBorderlessWhite : hifi.buttons.noneBorderlessGray;
colorScheme: hifi.colorSchemes.dark;
anchors.left: parent.left;
anchors.leftMargin: 24;
anchors.right: sendButton.left;
anchors.rightMargin: 24;
anchors.verticalCenter: parent.verticalCenter;
height: 40;
width: 150;
width: 100;
text: "CANCEL";
onClicked: {
resetSendAssetData();
@ -1205,10 +1208,10 @@ Item {
color: hifi.buttons.blue;
colorScheme: root.assetName === "" ? hifi.colorSchemes.dark : hifi.colorSchemes.light;
anchors.right: parent.right;
anchors.rightMargin: 24;
anchors.rightMargin: 0;
anchors.verticalCenter: parent.verticalCenter;
height: 40;
width: 150;
width: 100;
text: "SUBMIT";
onClicked: {
if (root.assetName === "" && parseInt(amountTextField.text) > parseInt(balanceText.text)) {

View file

@ -158,6 +158,7 @@ Rectangle {
listModelName: "Gift Connections";
z: 998;
visible: root.activeView === "giftAsset";
keyboardContainer: root;
anchors.fill: parent;
parentAppTitleBarHeight: 70;
parentAppNavBarHeight: 0;
@ -585,7 +586,7 @@ Rectangle {
visible: purchasesModel.count !== 0;
clip: true;
model: purchasesModel;
snapMode: ListView.SnapToItem;
snapMode: ListView.NoSnap;
// Anchors
anchors.top: separator.bottom;
anchors.left: parent.left;

View file

@ -354,6 +354,7 @@ Rectangle {
listModelName: "Send Money Connections";
z: 997;
visible: root.activeView === "sendMoney";
keyboardContainer: root;
anchors.fill: parent;
parentAppTitleBarHeight: titleBarContainer.height;
parentAppNavBarHeight: tabButtonsContainer.height;

View file

@ -3540,6 +3540,7 @@ void Application::setIsInterstitialMode(bool interstitialMode) {
if (enableInterstitial) {
if (_interstitialMode != interstitialMode) {
_interstitialMode = interstitialMode;
emit interstitialModeChanged(_interstitialMode);
DependencyManager::get<AudioClient>()->setAudioPaused(_interstitialMode);
DependencyManager::get<AvatarManager>()->setMyAvatarDataPacketsPaused(_interstitialMode);

View file

@ -52,7 +52,6 @@
#include <RunningMarker.h>
#include "avatar/MyAvatar.h"
#include "BandwidthRecorder.h"
#include "FancyCamera.h"
#include "ConnectionMonitor.h"
#include "CursorManager.h"
@ -335,6 +334,8 @@ signals:
void uploadRequest(QString path);
void interstitialModeChanged(bool isInInterstitialMode);
void loginDialogPoppedUp();
public slots:

View file

@ -78,8 +78,10 @@ void addAvatarEntities(const QVariantList& avatarEntities) {
}
entity->setLastBroadcast(usecTimestampNow());
// since we're creating this object we will immediately volunteer to own its simulation
entity->setScriptSimulationPriority(VOLUNTEER_SIMULATION_PRIORITY);
if (entityProperties.getDynamic()) {
// since we're creating a dynamic object we volunteer immediately to own its simulation
entity->upgradeScriptSimulationPriority(VOLUNTEER_SIMULATION_PRIORITY);
}
entityProperties.setLastEdited(entity->getLastEdited());
} else {
qCDebug(entities) << "AvatarEntitiesBookmark failed to add new Entity to local Octree";
@ -108,6 +110,9 @@ AvatarBookmarks::AvatarBookmarks() {
if (!QFile::copy(defaultBookmarksFilename, _bookmarksFilename)) {
qDebug() << "failed to copy" << defaultBookmarksFilename << "to" << _bookmarksFilename;
} else {
QFile bookmarksFile(_bookmarksFilename);
bookmarksFile.setPermissions(bookmarksFile.permissions() | QFile::WriteUser);
}
}
readFromFile();

View file

@ -55,15 +55,7 @@ static const quint64 MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS = USECS_PER_SECOND /
// We add _myAvatar into the hash with all the other AvatarData, and we use the default NULL QUid as the key.
const QUuid MY_AVATAR_KEY; // NULL key
namespace {
// For an unknown avatar-data packet, wait this long before requesting the identity.
constexpr std::chrono::milliseconds REQUEST_UNKNOWN_IDENTITY_DELAY { 5 * 1000 };
constexpr int REQUEST_UNKNOWN_IDENTITY_TRANSMITS = 3;
}
using std::chrono::steady_clock;
AvatarManager::AvatarManager(QObject* parent) :
_avatarsToFade(),
_myAvatar(new MyAvatar(qApp->thread()), [](MyAvatar* ptr) { ptr->deleteLater(); })
{
// register a meta type for the weak pointer we'll use for the owning avatar mixer for each avatar
@ -322,28 +314,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
simulateAvatarFades(deltaTime);
// Check on avatars with pending identities:
steady_clock::time_point now = steady_clock::now();
QWriteLocker writeLock(&_hashLock);
for (auto pendingAvatar = _pendingAvatars.begin(); pendingAvatar != _pendingAvatars.end(); ++pendingAvatar) {
if (now - pendingAvatar->creationTime >= REQUEST_UNKNOWN_IDENTITY_DELAY) {
// Too long without an ID
sendIdentityRequest(pendingAvatar->avatar->getID());
if (++pendingAvatar->transmits >= REQUEST_UNKNOWN_IDENTITY_TRANSMITS) {
qCDebug(avatars) << "Requesting identity for unknown avatar (final request)" <<
pendingAvatar->avatar->getID().toString();
pendingAvatar = _pendingAvatars.erase(pendingAvatar);
if (pendingAvatar == _pendingAvatars.end()) {
break;
}
} else {
pendingAvatar->creationTime = now;
qCDebug(avatars) << "Requesting identity for unknown avatar" << pendingAvatar->avatar->getID().toString();
}
}
}
_avatarSimulationTime = (float)(usecTimestampNow() - startTime) / (float)USECS_PER_MSEC;
}

View file

@ -55,6 +55,7 @@ using SortedAvatar = std::pair<float, std::shared_ptr<Avatar>>;
* @borrows AvatarList.sessionUUIDChanged as sessionUUIDChanged
* @borrows AvatarList.processAvatarDataPacket as processAvatarDataPacket
* @borrows AvatarList.processAvatarIdentityPacket as processAvatarIdentityPacket
* @borrows AvatarList.processBulkAvatarTraits as processBulkAvatarTraits
* @borrows AvatarList.processKillAvatar as processKillAvatar
*/
@ -152,6 +153,13 @@ public:
const QVector<EntityItemID>& avatarsToInclude,
const QVector<EntityItemID>& avatarsToDiscard);
/**jsdoc
* @function AvatarManager.findParabolaIntersectionVector
* @param {PickParabola} pick
* @param {Uuid[]} avatarsToInclude
* @param {Uuid[]} avatarsToDiscard
* @returns {ParabolaToAvatarIntersectionResult}
*/
Q_INVOKABLE ParabolaToAvatarIntersectionResult findParabolaIntersectionVector(const PickParabola& pick,
const QVector<EntityItemID>& avatarsToInclude,
const QVector<EntityItemID>& avatarsToDiscard);
@ -176,7 +184,7 @@ public:
* than iterating over each avatar and obtaining data about them in JavaScript, as that method
* locks and unlocks each avatar's data structure potentially hundreds of times per update tick.
* @function AvatarManager.getPalData
* @param {string[]} specificAvatarIdentifiers - A list of specific Avatar Identifiers about
* @param {string[]} [specificAvatarIdentifiers] - A list of specific Avatar Identifiers about
* which you want to get PAL data
* @returns {object}
*/

View file

@ -122,7 +122,6 @@ MyAvatar::MyAvatar(QThread* thread) :
_goToOrientation(),
_prevShouldDrawHead(true),
_audioListenerMode(FROM_HEAD),
_hmdAtRestDetector(glm::vec3(0), glm::quat()),
_dominantHandSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "dominantHand", DOMINANT_RIGHT_HAND),
_headPitchSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "", 0.0f),
_scaleSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "scale", _targetScale),
@ -702,6 +701,46 @@ void MyAvatar::simulate(float deltaTime) {
// before we perform rig animations and IK.
updateSensorToWorldMatrix();
// if we detect the hand controller is at rest, i.e. lying on the table, or the hand is too far away from the hmd
// disable the associated hand controller input.
{
// NOTE: all poses are in sensor space.
auto leftHandIter = _controllerPoseMap.find(controller::Action::LEFT_HAND);
if (leftHandIter != _controllerPoseMap.end() && leftHandIter->second.isValid()) {
_leftHandAtRestDetector.update(leftHandIter->second.getTranslation(), leftHandIter->second.getRotation());
if (_leftHandAtRestDetector.isAtRest()) {
leftHandIter->second.valid = false;
}
} else {
_leftHandAtRestDetector.invalidate();
}
auto rightHandIter = _controllerPoseMap.find(controller::Action::RIGHT_HAND);
if (rightHandIter != _controllerPoseMap.end() && rightHandIter->second.isValid()) {
_rightHandAtRestDetector.update(rightHandIter->second.getTranslation(), rightHandIter->second.getRotation());
if (_rightHandAtRestDetector.isAtRest()) {
rightHandIter->second.valid = false;
}
} else {
_rightHandAtRestDetector.invalidate();
}
auto headIter = _controllerPoseMap.find(controller::Action::HEAD);
// The 99th percentile man has a spine to fingertip to height ratio of 0.45. Lets increase that by about 10% to 0.5
// then measure the distance the center of the eyes to the finger tips. To come up with this ratio.
// From "The Measure of Man and Woman: Human Factors in Design, Revised Edition" by Alvin R. Tilley, Henry Dreyfuss Associates
const float MAX_HEAD_TO_HAND_DISTANCE_RATIO = 0.52f;
float maxHeadHandDistance = getUserHeight() * MAX_HEAD_TO_HAND_DISTANCE_RATIO;
if (glm::length(headIter->second.getTranslation() - leftHandIter->second.getTranslation()) > maxHeadHandDistance) {
leftHandIter->second.valid = false;
}
if (glm::length(headIter->second.getTranslation() - rightHandIter->second.getTranslation()) > maxHeadHandDistance) {
rightHandIter->second.valid = false;
}
}
{
PerformanceTimer perfTimer("skeleton");

View file

@ -629,8 +629,6 @@ public:
const MyHead* getMyHead() const;
Q_INVOKABLE void toggleSmoothPoleVectors() { _skeletonModel->getRig().toggleSmoothPoleVectors(); };
/**jsdoc
* Get the current position of the avatar's "Head" joint.
* @function MyAvatar.getHeadPosition
@ -951,50 +949,72 @@ public:
void removeWearableAvatarEntities();
/**jsdoc
* Check whether your avatar is flying or not.
* @function MyAvatar.isFlying
* @returns {boolean}
* @returns {boolean} <code>true</code> if your avatar is flying and not taking off or falling, otherwise
* <code>false</code>.
*/
Q_INVOKABLE bool isFlying();
/**jsdoc
* Check whether your avatar is in the air or not.
* @function MyAvatar.isInAir
* @returns {boolean}
* @returns {boolean} <code>true</code> if your avatar is taking off, flying, or falling, otherwise <code>false</code>
* because your avatar is on the ground.
*/
Q_INVOKABLE bool isInAir();
/**jsdoc
* Set your preference for flying in your current desktop or HMD display mode. Note that your ability to fly also depends
* on whether the domain you're in allows you to fly.
* @function MyAvatar.setFlyingEnabled
* @param {boolean} enabled
* @param {boolean} enabled - Set <code>true</code> if you want to enable flying in your current desktop or HMD display
* mode, otherwise set <code>false</code>.
*/
Q_INVOKABLE void setFlyingEnabled(bool enabled);
/**jsdoc
* Get your preference for flying in your current desktop or HMD display mode. Note that your ability to fly also depends
* on whether the domain you're in allows you to fly.
* @function MyAvatar.getFlyingEnabled
* @returns {boolean}
* @returns {boolean} <code>true</code> if your preference is to enable flying in your current desktop or HMD display mode,
* otherwise <code>false</code>.
*/
Q_INVOKABLE bool getFlyingEnabled();
/**jsdoc
* Set your preference for flying in desktop display mode. Note that your ability to fly also depends on whether the domain
* you're in allows you to fly.
* @function MyAvatar.setFlyingDesktopPref
* @param {boolean} enabled
* @param {boolean} enabled - Set <code>true</code> if you want to enable flying in desktop display mode, otherwise set
* <code>false</code>.
*/
Q_INVOKABLE void setFlyingDesktopPref(bool enabled);
/**jsdoc
* Get your preference for flying in desktop display mode. Note that your ability to fly also depends on whether the domain
* you're in allows you to fly.
* @function MyAvatar.getFlyingDesktopPref
* @returns {boolean}
* @returns {boolean} <code>true</code> if your preference is to enable flying in desktop display mode, otherwise
* <code>false</code>.
*/
Q_INVOKABLE bool getFlyingDesktopPref();
/**jsdoc
* @function MyAvatar.setFlyingDesktopPref
* @param {boolean} enabled
* Set your preference for flying in HMD display mode. Note that your ability to fly also depends on whether the domain
* you're in allows you to fly.
* @function MyAvatar.setFlyingHMDPref
* @param {boolean} enabled - Set <code>true</code> if you want to enable flying in HMD display mode, otherwise set
* <code>false</code>.
*/
Q_INVOKABLE void setFlyingHMDPref(bool enabled);
/**jsdoc
* @function MyAvatar.getFlyingDesktopPref
* @returns {boolean}
* Get your preference for flying in HMD display mode. Note that your ability to fly also depends on whether the domain
* you're in allows you to fly.
* @function MyAvatar.getFlyingHMDPref
* @returns {boolean} <code>true</code> if your preference is to enable flying in HMD display mode, otherwise
* <code>false</code>.
*/
Q_INVOKABLE bool getFlyingHMDPref();
@ -1766,8 +1786,8 @@ private:
glm::vec3 _customListenPosition;
glm::quat _customListenOrientation;
AtRestDetector _hmdAtRestDetector;
bool _lastIsMoving { false };
AtRestDetector _leftHandAtRestDetector;
AtRestDetector _rightHandAtRestDetector;
// all poses are in sensor-frame
std::map<controller::Action, controller::Pose> _controllerPoseMap;

View file

@ -46,7 +46,7 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) {
}
glm::mat4 hipsMat;
if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState())) {
if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState()) && myAvatar->getHMDLeanRecenterEnabled()) {
// then we use center of gravity model
hipsMat = myAvatar->deriveBodyUsingCgModel();
} else {

View file

@ -76,4 +76,4 @@ protected:
bool _includeNormals;
};
#endif // hifi_CollisionPick_h
#endif // hifi_CollisionPick_h

View file

@ -27,7 +27,7 @@ class StartEndRenderState {
public:
StartEndRenderState() {}
StartEndRenderState(const OverlayID& startID, const OverlayID& endID);
virtual ~StartEndRenderState() {}
virtual ~StartEndRenderState() = default;
const OverlayID& getStartID() const { return _startID; }
const OverlayID& getEndID() const { return _endID; }

View file

@ -54,6 +54,9 @@ WindowScriptingInterface::WindowScriptingInterface() {
});
connect(qApp->getWindow(), &MainWindow::windowGeometryChanged, this, &WindowScriptingInterface::onWindowGeometryChanged);
connect(qApp, &Application::interstitialModeChanged, [this] (bool interstitialMode) {
emit interstitialModeChanged(interstitialMode);
});
}
WindowScriptingInterface::~WindowScriptingInterface() {

View file

@ -619,6 +619,14 @@ signals:
*/
void redirectErrorStateChanged(bool isInErrorState);
/**jsdoc
* Triggered when interstitial mode changes.
* @function Window.interstitialModeChanged
* @param {bool} interstitialMode - The mode of the interstitial is changed to.
* @returns {Signal}
*/
void interstitialModeChanged(bool interstitialMode);
/**jsdoc
* Triggered when a still snapshot has been taken by calling {@link Window.takeSnapshot|takeSnapshot} with
* <code>includeAnimated = false</code> or {@link Window.takeSecondaryCameraSnapshot|takeSecondaryCameraSnapshot}.

View file

@ -169,7 +169,8 @@ std::map<QString, QString> AnimVariantMap::toDebugMap() const {
break;
*/
default:
assert(("invalid AnimVariant::Type", false));
// invalid AnimVariant::Type
assert(false);
}
}
return result;

View file

@ -22,7 +22,7 @@
class Animation;
typedef QSharedPointer<Animation> AnimationPointer;
using AnimationPointer = QSharedPointer<Animation>;
class AnimationCache : public ResourceCache, public Dependency {
Q_OBJECT

View file

@ -1253,7 +1253,6 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab
const glm::mat4& rigToSensorMatrix, const glm::mat4& sensorToRigMatrix) {
const bool ENABLE_POLE_VECTORS = true;
const float ELBOW_POLE_VECTOR_BLEND_FACTOR = 0.95f;
if (leftHandEnabled) {
@ -1279,33 +1278,16 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab
bool usePoleVector = calculateElbowPoleVector(handJointIndex, elbowJointIndex, armJointIndex, oppositeArmJointIndex, poleVector);
if (usePoleVector) {
glm::vec3 sensorPoleVector = transformVectorFast(rigToSensorMatrix, poleVector);
if (_smoothPoleVectors) {
// smooth toward desired pole vector from previous pole vector... to reduce jitter
if (!_prevLeftHandPoleVectorValid) {
_prevLeftHandPoleVectorValid = true;
_prevLeftHandPoleVector = sensorPoleVector;
}
glm::quat deltaRot = rotationBetween(_prevLeftHandPoleVector, sensorPoleVector);
glm::quat smoothDeltaRot = safeMix(deltaRot, Quaternions::IDENTITY, ELBOW_POLE_VECTOR_BLEND_FACTOR);
_prevLeftHandPoleVector = smoothDeltaRot * _prevLeftHandPoleVector;
} else {
_prevLeftHandPoleVector = sensorPoleVector;
}
_animVars.set("leftHandPoleVectorEnabled", true);
_animVars.set("leftHandPoleReferenceVector", Vectors::UNIT_X);
_animVars.set("leftHandPoleVector", transformVectorFast(sensorToRigMatrix, _prevLeftHandPoleVector));
_animVars.set("leftHandPoleVector", transformVectorFast(sensorToRigMatrix, sensorPoleVector));
} else {
_prevLeftHandPoleVectorValid = false;
_animVars.set("leftHandPoleVectorEnabled", false);
}
} else {
_prevLeftHandPoleVectorValid = false;
_animVars.set("leftHandPoleVectorEnabled", false);
}
} else {
_prevLeftHandPoleVectorValid = false;
_animVars.set("leftHandPoleVectorEnabled", false);
_animVars.unset("leftHandPosition");
@ -1344,33 +1326,16 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab
bool usePoleVector = calculateElbowPoleVector(handJointIndex, elbowJointIndex, armJointIndex, oppositeArmJointIndex, poleVector);
if (usePoleVector) {
glm::vec3 sensorPoleVector = transformVectorFast(rigToSensorMatrix, poleVector);
if (_smoothPoleVectors) {
// smooth toward desired pole vector from previous pole vector... to reduce jitter
if (!_prevRightHandPoleVectorValid) {
_prevRightHandPoleVectorValid = true;
_prevRightHandPoleVector = sensorPoleVector;
}
glm::quat deltaRot = rotationBetween(_prevRightHandPoleVector, sensorPoleVector);
glm::quat smoothDeltaRot = safeMix(deltaRot, Quaternions::IDENTITY, ELBOW_POLE_VECTOR_BLEND_FACTOR);
_prevRightHandPoleVector = smoothDeltaRot * _prevRightHandPoleVector;
} else {
_prevRightHandPoleVector = sensorPoleVector;
}
_animVars.set("rightHandPoleVectorEnabled", true);
_animVars.set("rightHandPoleReferenceVector", -Vectors::UNIT_X);
_animVars.set("rightHandPoleVector", transformVectorFast(sensorToRigMatrix, _prevRightHandPoleVector));
_animVars.set("rightHandPoleVector", transformVectorFast(sensorToRigMatrix, sensorPoleVector));
} else {
_prevRightHandPoleVectorValid = false;
_animVars.set("rightHandPoleVectorEnabled", false);
}
} else {
_prevRightHandPoleVectorValid = false;
_animVars.set("rightHandPoleVectorEnabled", false);
}
} else {
_prevRightHandPoleVectorValid = false;
_animVars.set("rightHandPoleVectorEnabled", false);
_animVars.unset("rightHandPosition");

View file

@ -227,7 +227,6 @@ public:
const AnimVariantMap& getAnimVars() const { return _lastAnimVars; }
const AnimContext::DebugStateMachineMap& getStateMachineMap() const { return _lastContext.getStateMachineMap(); }
void toggleSmoothPoleVectors() { _smoothPoleVectors = !_smoothPoleVectors; };
signals:
void onLoadComplete();
@ -381,14 +380,6 @@ protected:
glm::vec3 _prevLeftFootPoleVector { Vectors::UNIT_Z }; // sensor space
bool _prevLeftFootPoleVectorValid { false };
glm::vec3 _prevRightHandPoleVector{ -Vectors::UNIT_Z }; // sensor space
bool _prevRightHandPoleVectorValid{ false };
glm::vec3 _prevLeftHandPoleVector{ -Vectors::UNIT_Z }; // sensor space
bool _prevLeftHandPoleVectorValid{ false };
bool _smoothPoleVectors { false };
int _rigId;
bool _headEnabled { false };

View file

@ -173,7 +173,6 @@ AvatarTransit::Status AvatarTransit::updatePosition(float deltaTime) {
Status status = Status::IDLE;
if (_isTransiting) {
float nextTime = _currentTime + deltaTime;
glm::vec3 newPosition;
if (nextTime >= _totalTime) {
_currentPosition = _endPosition;
_isTransiting = false;
@ -704,6 +703,19 @@ static TextRenderer3D* textRenderer(TextRendererType type) {
return displayNameRenderer;
}
void Avatar::metaBlendshapeOperator(int blendshapeNumber, const QVector<BlendshapeOffset>& blendshapeOffsets, const QVector<int>& blendedMeshSizes,
const render::ItemIDs& subItemIDs) {
render::Transaction transaction;
transaction.updateItem<AvatarData>(_renderItemID, [blendshapeNumber, blendshapeOffsets, blendedMeshSizes,
subItemIDs](AvatarData& avatar) {
auto avatarPtr = dynamic_cast<Avatar*>(&avatar);
if (avatarPtr) {
avatarPtr->setBlendedVertices(blendshapeNumber, blendshapeOffsets, blendedMeshSizes, subItemIDs);
}
});
AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
}
void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& scene, render::Transaction& transaction) {
auto avatarPayload = new render::Payload<AvatarData>(self);
auto avatarPayloadPointer = std::shared_ptr<render::Payload<AvatarData>>(avatarPayload);
@ -713,7 +725,8 @@ void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& sc
// INitialize the _render bound as we are creating the avatar render item
_renderBound = getBounds();
transaction.resetItem(_renderItemID, avatarPayloadPointer);
_skeletonModel->addToScene(scene, transaction);
using namespace std::placeholders;
_skeletonModel->addToScene(scene, transaction, std::bind(&Avatar::metaBlendshapeOperator, this, _1, _2, _3, _4));
_skeletonModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
_skeletonModel->setGroupCulled(true);
_skeletonModel->setCanCastShadow(true);
@ -792,7 +805,7 @@ void Avatar::updateRenderItem(render::Transaction& transaction) {
avatarPtr->_renderBound = renderBound;
}
}
);
);
}
}
@ -936,7 +949,8 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
render::Transaction transaction;
if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) {
_skeletonModel->removeFromScene(scene, transaction);
_skeletonModel->addToScene(scene, transaction);
using namespace std::placeholders;
_skeletonModel->addToScene(scene, transaction, std::bind(&Avatar::metaBlendshapeOperator, this, _1, _2, _3, _4));
_skeletonModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
_skeletonModel->setGroupCulled(true);

View file

@ -28,6 +28,8 @@
#include "Rig.h"
#include <ThreadSafeValueCache.h>
#include "MetaModelPayload.h"
namespace render {
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar);
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar);
@ -108,7 +110,7 @@ private:
float _scale { 1.0f };
};
class Avatar : public AvatarData, public scriptable::ModelProvider {
class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaModelPayload {
Q_OBJECT
// This property has JSDoc in MyAvatar.h.
@ -620,6 +622,9 @@ protected:
static const float ATTACHMENT_LOADING_PRIORITY;
LoadingStatus _loadingStatus { LoadingStatus::NoModel };
void metaBlendshapeOperator(int blendshapeNumber, const QVector<BlendshapeOffset>& blendshapeOffsets, const QVector<int>& blendedMeshSizes,
const render::ItemIDs& subItemIDs);
};
#endif // hifi_Avatar_h

View file

@ -258,7 +258,6 @@ AvatarSharedPointer AvatarHashMap::parseAvatarData(QSharedPointer<ReceivedMessag
if (isNewAvatar) {
QWriteLocker locker(&_hashLock);
_pendingAvatars.insert(sessionUUID, { std::chrono::steady_clock::now(), 0, avatar });
avatar->setIsNewAvatar(true);
auto replicaIDs = _replicas.getReplicaIDs(sessionUUID);
for (auto replicaID : replicaIDs) {
@ -300,7 +299,6 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer<ReceivedMessage>
{
QReadLocker locker(&_hashLock);
_pendingAvatars.remove(identityUUID);
auto me = _avatarHash.find(EMPTY);
if ((me != _avatarHash.end()) && (identityUUID == me.value()->getSessionUUID())) {
// We add MyAvatar to _avatarHash with an empty UUID. Code relies on this. In order to correctly handle an
@ -419,7 +417,6 @@ void AvatarHashMap::removeAvatar(const QUuid& sessionUUID, KillAvatarReason remo
}
}
_pendingAvatars.remove(sessionUUID);
auto removedAvatar = _avatarHash.take(sessionUUID);
if (removedAvatar) {

View file

@ -161,6 +161,11 @@ protected slots:
*/
void processAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
/**jsdoc
* @function AvatarList.processBulkAvatarTraits
* @param {} message
* @param {} sendingNode
*/
void processBulkAvatarTraits(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
/**jsdoc
@ -183,15 +188,8 @@ protected:
virtual void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason);
AvatarHash _avatarHash;
struct PendingAvatar {
std::chrono::steady_clock::time_point creationTime;
int transmits;
AvatarSharedPointer avatar;
};
using AvatarPendingHash = QHash<QUuid, PendingAvatar>;
AvatarPendingHash _pendingAvatars;
mutable QReadWriteLock _hashLock;
AvatarHash _avatarHash;
std::unordered_map<QUuid, AvatarTraits::TraitVersions> _processedTraitVersions;
AvatarReplicas _replicas;

View file

@ -98,7 +98,7 @@ enum Hand {
class InputDevice {
public:
InputDevice(const QString& name) : _name(name) {}
virtual ~InputDevice() {}
virtual ~InputDevice() = default;
using Pointer = std::shared_ptr<InputDevice>;

View file

@ -30,6 +30,8 @@ namespace controller {
using Factory = hifi::SimpleFactory<Conditional, QString>;
using Lambda = std::function<bool()>;
virtual ~Conditional() = default;
virtual bool satisfied() = 0;
virtual bool parseParameters(const QJsonValue& parameters) { return true; }

View file

@ -35,6 +35,8 @@ namespace controller {
using Lambda = std::function<float(float)>;
using Factory = hifi::SimpleFactory<Filter, QString>;
virtual ~Filter() = default;
virtual float apply(float value) const = 0;
virtual Pose apply(Pose value) const = 0;

View file

@ -24,8 +24,6 @@ public:
AndConditional(Conditional::Pointer& first, Conditional::Pointer& second)
: _children({ first, second }) {}
virtual ~AndConditional() {}
virtual bool satisfied() override;
private:

View file

@ -18,7 +18,6 @@ namespace controller {
class EndpointConditional : public Conditional {
public:
EndpointConditional(Endpoint::Pointer endpoint) : _endpoint(endpoint) {}
virtual ~EndpointConditional() {}
virtual bool satisfied() override { return _endpoint && _endpoint->peek() != 0.0f; }
private:
Endpoint::Pointer _endpoint;

View file

@ -19,7 +19,6 @@ namespace controller {
using Pointer = std::shared_ptr<NotConditional>;
NotConditional(Conditional::Pointer operand) : _operand(operand) { }
virtual ~NotConditional() {}
virtual bool satisfied() override;

View file

@ -18,7 +18,6 @@ class ClampFilter : public Filter {
REGISTER_FILTER_CLASS(ClampFilter);
public:
ClampFilter(float min = 0.0, float max = 1.0) : _min(min), _max(max) {};
virtual ~ClampFilter() {}
virtual float apply(float value) const override {
return glm::clamp(value, _min, _max);
}

View file

@ -17,16 +17,13 @@ namespace controller {
class ConstrainToIntegerFilter : public Filter {
REGISTER_FILTER_CLASS(ConstrainToIntegerFilter);
public:
ConstrainToIntegerFilter() {};
virtual ~ConstrainToIntegerFilter() {}
ConstrainToIntegerFilter() = default;
virtual float apply(float value) const override {
return glm::sign(value);
}
virtual Pose apply(Pose value) const override { return value; }
protected:
};
}

View file

@ -17,16 +17,13 @@ namespace controller {
class ConstrainToPositiveIntegerFilter : public Filter {
REGISTER_FILTER_CLASS(ConstrainToPositiveIntegerFilter);
public:
ConstrainToPositiveIntegerFilter() {};
virtual ~ConstrainToPositiveIntegerFilter() {};
ConstrainToPositiveIntegerFilter() = default;
virtual float apply(float value) const override {
return (value <= 0.0f) ? 0.0f : 1.0f;
}
virtual Pose apply(Pose value) const override { return value; }
protected:
};
}

View file

@ -18,7 +18,6 @@ class DeadZoneFilter : public Filter {
REGISTER_FILTER_CLASS(DeadZoneFilter);
public:
DeadZoneFilter(float min = 0.0) : _min(min) {};
virtual ~DeadZoneFilter() {}
virtual float apply(float value) const override;

View file

@ -20,7 +20,6 @@ namespace controller {
ExponentialSmoothingFilter() {}
ExponentialSmoothingFilter(float rotationConstant, float translationConstant) :
_translationConstant(translationConstant), _rotationConstant(rotationConstant) {}
virtual ~ExponentialSmoothingFilter() {}
float apply(float value) const override { return value; }
Pose apply(Pose value) const override;

View file

@ -18,7 +18,6 @@ class HysteresisFilter : public Filter {
REGISTER_FILTER_CLASS(HysteresisFilter);
public:
HysteresisFilter(float min = 0.25, float max = 0.75);
virtual ~HysteresisFilter() {}
virtual float apply(float value) const override;
virtual Pose apply(Pose value) const override { return value; }

View file

@ -19,11 +19,8 @@ class InvertFilter : public ScaleFilter {
public:
using ScaleFilter::parseParameters;
InvertFilter() : ScaleFilter(-1.0f) {}
virtual ~InvertFilter() {}
virtual bool parseParameters(const QJsonArray& parameters) { return true; }
private:
};
}

View file

@ -17,10 +17,9 @@ namespace controller {
REGISTER_FILTER_CLASS(LowVelocityFilter);
public:
LowVelocityFilter() {}
LowVelocityFilter() = default;
LowVelocityFilter(float rotationConstant, float translationConstant) :
_translationConstant(translationConstant), _rotationConstant(rotationConstant) {}
virtual ~LowVelocityFilter() {}
float apply(float value) const override { return value; }
Pose apply(Pose newPose) const override;

View file

@ -10,7 +10,6 @@ class NotFilter : public Filter {
REGISTER_FILTER_CLASS(NotFilter);
public:
NotFilter();
virtual ~NotFilter() {}
virtual float apply(float value) const override;
virtual Pose apply(Pose value) const override { return value; }

View file

@ -19,9 +19,8 @@ namespace controller {
class PostTransformFilter : public Filter {
REGISTER_FILTER_CLASS(PostTransformFilter);
public:
PostTransformFilter() { }
PostTransformFilter() = default;
PostTransformFilter(glm::mat4 transform) : _transform(transform) {}
virtual ~PostTransformFilter() {}
virtual float apply(float value) const override { return value; }
virtual Pose apply(Pose value) const override { return value.postTransform(_transform); }
virtual bool parseParameters(const QJsonValue& parameters) override { return parseMat4Parameter(parameters, _transform); }

View file

@ -18,9 +18,8 @@ namespace controller {
class PulseFilter : public Filter {
REGISTER_FILTER_CLASS(PulseFilter);
public:
PulseFilter() {}
PulseFilter() = default;
PulseFilter(float interval) : _interval(interval) {}
virtual ~PulseFilter() {}
virtual float apply(float value) const override;

View file

@ -19,9 +19,8 @@ namespace controller {
class RotateFilter : public Filter {
REGISTER_FILTER_CLASS(RotateFilter);
public:
RotateFilter() { }
RotateFilter() = default;
RotateFilter(glm::quat rotation) : _rotation(rotation) {}
virtual ~RotateFilter() {}
virtual float apply(float value) const override { return value; }

View file

@ -19,9 +19,8 @@ namespace controller {
class ScaleFilter : public Filter {
REGISTER_FILTER_CLASS(ScaleFilter);
public:
ScaleFilter() {}
ScaleFilter() = default;
ScaleFilter(float scale) : _scale(scale) {}
virtual ~ScaleFilter() {}
virtual float apply(float value) const override {
return value * _scale;

View file

@ -19,9 +19,8 @@ namespace controller {
class TransformFilter : public Filter {
REGISTER_FILTER_CLASS(TransformFilter);
public:
TransformFilter() { }
TransformFilter() = default;
TransformFilter(glm::mat4 transform) : _transform(transform) {}
virtual ~TransformFilter() {}
virtual float apply(float value) const override { return value; }
virtual Pose apply(Pose value) const override { return value.transform(_transform); }

View file

@ -19,9 +19,8 @@ namespace controller {
class TranslateFilter : public Filter {
REGISTER_FILTER_CLASS(TranslateFilter);
public:
TranslateFilter() { }
TranslateFilter() = default;
TranslateFilter(glm::vec3 translate) : _translate(translate) {}
virtual ~TranslateFilter() {}
virtual float apply(float value) const override { return value; }
virtual Pose apply(Pose value) const override { return value.transform(glm::translate(_translate)); }

View file

@ -24,12 +24,18 @@ bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP
if (entity->getMaterialMappingPos() != _materialMappingPos || entity->getMaterialMappingScale() != _materialMappingScale || entity->getMaterialMappingRot() != _materialMappingRot) {
return true;
}
if (!_texturesLoaded) {
return true;
}
return false;
}
void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
withWriteLock([&] {
_drawMaterial = entity->getMaterial();
if (_drawMaterial != entity->getMaterial()) {
_texturesLoaded = false;
_drawMaterial = entity->getMaterial();
}
_parentID = entity->getParentID();
_materialMappingPos = entity->getMaterialMappingPos();
_materialMappingScale = entity->getMaterialMappingScale();
@ -38,6 +44,12 @@ void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer&
const float MATERIAL_ENTITY_SCALE = 0.5f;
_renderTransform.postScale(MATERIAL_ENTITY_SCALE);
_renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
bool newTexturesLoaded = _drawMaterial ? !_drawMaterial->isMissingTexture() : false;
if (!_texturesLoaded && newTexturesLoaded) {
_drawMaterial->checkResetOpacityMap();
}
_texturesLoaded = newTexturesLoaded;
});
}

View file

@ -35,6 +35,7 @@ private:
glm::vec2 _materialMappingPos;
glm::vec2 _materialMappingScale;
float _materialMappingRot;
bool _texturesLoaded { false };
std::shared_ptr<NetworkMaterial> _drawMaterial;
};

View file

@ -975,14 +975,21 @@ QStringList RenderableModelEntityItem::getJointNames() const {
return result;
}
// FIXME: deprecated; remove >= RC67
bool RenderableModelEntityItem::getMeshes(MeshProxyList& result) {
auto model = getModel();
if (!model || !model->isLoaded()) {
return false;
void RenderableModelEntityItem::setAnimationURL(const QString& url) {
QString oldURL = getAnimationURL();
ModelEntityItem::setAnimationURL(url);
if (oldURL != getAnimationURL()) {
_needsAnimationReset = true;
}
BLOCKING_INVOKE_METHOD(model.get(), "getMeshes", Q_RETURN_ARG(MeshProxyList, result));
return !result.isEmpty();
}
bool RenderableModelEntityItem::needsAnimationReset() const {
return _needsAnimationReset;
}
QString RenderableModelEntityItem::getAnimationURLAndReset() {
_needsAnimationReset = false;
return getAnimationURL();
}
scriptable::ScriptableModelBase render::entities::ModelEntityRenderer::getScriptableModel() {
@ -1068,6 +1075,13 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() {
}
}
bool RenderableModelEntityItem::readyToAnimate() const {
return resultWithReadLock<bool>([&] {
float firstFrame = _animationProperties.getFirstFrame();
return (firstFrame >= 0.0f) && (firstFrame <= _animationProperties.getLastFrame());
});
}
using namespace render;
using namespace render::entities;
@ -1155,7 +1169,7 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
const QVector<glm::quat>& rotations = frames[_lastKnownCurrentFrame].rotations;
const QVector<glm::vec3>& translations = frames[_lastKnownCurrentFrame].translations;
jointsData.resize(_jointMapping.size());
for (int j = 0; j < _jointMapping.size(); j++) {
int index = _jointMapping[j];
@ -1169,13 +1183,12 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
}
} else if (index < animationJointNames.size()) {
QString jointName = fbxJoints[index].name; // Pushing this here so its not done on every entity, with the exceptions of those allowing for translation
if (originalFbxIndices.contains(jointName)) {
// Making sure the joint names exist in the original model the animation is trying to apply onto. If they do, then remap and get it's translation.
int remappedIndex = originalFbxIndices[jointName] - 1; // JointIndeces seem to always start from 1 and the found index is always 1 higher than actual.
translationMat = glm::translate(originalFbxJoints[remappedIndex].translation);
}
}
}
glm::mat4 rotationMat;
if (index < rotations.size()) {
rotationMat = glm::mat4_cast(fbxJoints[index].preRotation * rotations[index] * fbxJoints[index].postRotation);
@ -1477,14 +1490,17 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
if (_animating) {
DETAILED_PROFILE_RANGE(simulation_physics, "Animate");
if (!jointsMapped()) {
mapJoints(entity, model->getJointNames());
//else the joint have been mapped before but we have a new animation to load
} else if (_animation && (_animation->getURL().toString() != entity->getAnimationURL())) {
if (_animation && entity->needsAnimationReset()) {
//(_animation->getURL().toString() != entity->getAnimationURL())) { // bad check
// the joints have been mapped before but we have a new animation to load
_animation.reset();
_jointMappingCompleted = false;
mapJoints(entity, model->getJointNames());
}
if (!(entity->getAnimationFirstFrame() < 0) && !(entity->getAnimationFirstFrame() > entity->getAnimationLastFrame())) {
if (!_jointMappingCompleted) {
mapJoints(entity, model);
}
if (entity->readyToAnimate()) {
animate(entity);
}
emit requestRenderUpdate();
@ -1518,19 +1534,20 @@ void ModelEntityRenderer::doRender(RenderArgs* args) {
#endif
}
void ModelEntityRenderer::mapJoints(const TypedEntityPointer& entity, const QStringList& modelJointNames) {
void ModelEntityRenderer::mapJoints(const TypedEntityPointer& entity, const ModelPointer& model) {
// if we don't have animation, or we're already joint mapped then bail early
if (!entity->hasAnimation() || jointsMapped()) {
if (!entity->hasAnimation()) {
return;
}
if (!_animation || _animation->getURL().toString() != entity->getAnimationURL()) {
_animation = DependencyManager::get<AnimationCache>()->getAnimation(entity->getAnimationURL());
if (!_animation) {
_animation = DependencyManager::get<AnimationCache>()->getAnimation(entity->getAnimationURLAndReset());
}
if (_animation && _animation->isLoaded()) {
QStringList animationJointNames = _animation->getJointNames();
auto modelJointNames = model->getJointNames();
if (modelJointNames.size() > 0 && animationJointNames.size() > 0) {
_jointMapping.resize(modelJointNames.size());
for (int i = 0; i < modelJointNames.size(); i++) {

View file

@ -24,8 +24,6 @@
#include "RenderableEntityItem.h"
class Model;
class EntityTreeRenderer;
@ -114,21 +112,25 @@ public:
virtual int getJointIndex(const QString& name) const override;
virtual QStringList getJointNames() const override;
bool getMeshes(MeshProxyList& result) override; // deprecated
void setAnimationURL(const QString& url) override;
bool needsAnimationReset() const;
QString getAnimationURLAndReset();
private:
bool needsUpdateModelBounds() const;
void autoResizeJointArrays();
void copyAnimationJointDataToModel();
bool readyToAnimate() const;
void getCollisionGeometryResource();
GeometryResource::Pointer _compoundShapeResource;
bool _jointMapCompleted { false };
bool _originalTexturesRead { false };
std::vector<int> _jointMap;
QVariantMap _originalTextures;
bool _jointMapCompleted { false };
bool _originalTexturesRead { false };
bool _dimensionsInitialized { true };
bool _needsJointSimulation { false };
bool _needsAnimationReset { false };
};
namespace render { namespace entities {
@ -169,8 +171,7 @@ protected:
private:
void animate(const TypedEntityPointer& entity);
void mapJoints(const TypedEntityPointer& entity, const QStringList& modelJointNames);
bool jointsMapped() const { return _jointMappingCompleted; }
void mapJoints(const TypedEntityPointer& entity, const ModelPointer& model);
// Transparency is handled in ModelMeshPartPayload
virtual bool isTransparent() const override { return false; }

View file

@ -673,7 +673,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
const QUuid& myNodeID = nodeList->getSessionUUID();
bool weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
// pack SimulationOwner and terse update properties near each other
// pack SimulationOwner, transform, and velocity properties near each other
// NOTE: the server is authoritative for changes to simOwnerID so we always unpack ownership data
// even when we would otherwise ignore the rest of the packet.
@ -1358,8 +1358,7 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire
return properties;
}
void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) const {
// a TerseUpdate includes the transform and its derivatives
void EntityItem::getTransformAndVelocityProperties(EntityItemProperties& properties) const {
if (!properties._positionChanged) {
properties._position = getLocalPosition();
}
@ -1383,8 +1382,11 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c
properties._accelerationChanged = true;
}
void EntityItem::setScriptSimulationPriority(uint8_t priority) {
uint8_t newPriority = stillHasGrabActions() ? glm::max(priority, SCRIPT_GRAB_SIMULATION_PRIORITY) : priority;
void EntityItem::upgradeScriptSimulationPriority(uint8_t priority) {
uint8_t newPriority = glm::max(priority, _scriptSimulationPriority);
if (newPriority < SCRIPT_GRAB_SIMULATION_PRIORITY && stillHasGrabActions()) {
newPriority = SCRIPT_GRAB_SIMULATION_PRIORITY;
}
if (newPriority != _scriptSimulationPriority) {
// set the dirty flag to trigger a bid or ownership update
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY);
@ -1419,7 +1421,7 @@ bool EntityItem::stillWaitingToTakeOwnership(uint64_t timestamp) const {
bool EntityItem::setProperties(const EntityItemProperties& properties) {
bool somethingChanged = false;
// these affect TerseUpdate properties
// these affect transform and velocity properties
SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, setSimulationOwner);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, setPosition);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation);
@ -3256,3 +3258,26 @@ void EntityItem::setScriptHasFinishedPreload(bool value) {
bool EntityItem::isScriptPreloadFinished() {
return _scriptPreloadFinished;
}
void EntityItem::prepareForSimulationOwnershipBid(EntityItemProperties& properties, uint64_t now, uint8_t priority) {
if (dynamicDataNeedsTransmit()) {
setDynamicDataNeedsTransmit(false);
properties.setActionData(getDynamicData());
}
if (updateQueryAACube()) {
// due to parenting, the server may not know where something is in world-space, so include the bounding cube.
properties.setQueryAACube(getQueryAACube());
}
// set the LastEdited of the properties but NOT the entity itself
properties.setLastEdited(now);
clearScriptSimulationPriority();
properties.setSimulationOwner(Physics::getSessionUUID(), priority);
setPendingOwnershipPriority(priority);
properties.setClientOnly(getClientOnly());
properties.setOwningAvatarID(getOwningAvatarID());
setLastBroadcast(now); // for debug/physics status icons
}

View file

@ -325,7 +325,7 @@ public:
// TODO: move this "ScriptSimulationPriority" and "PendingOwnership" stuff into EntityMotionState
// but first would need to do some other cleanup. In the meantime these live here as "scratch space"
// to allow libs that don't know about each other to communicate.
void setScriptSimulationPriority(uint8_t priority);
void upgradeScriptSimulationPriority(uint8_t priority);
void clearScriptSimulationPriority();
uint8_t getScriptSimulationPriority() const { return _scriptSimulationPriority; }
void setPendingOwnershipPriority(uint8_t priority);
@ -420,7 +420,7 @@ public:
quint64 getLastEditedFromRemote() const { return _lastEditedFromRemote; }
void updateLastEditedFromRemote() { _lastEditedFromRemote = usecTimestampNow(); }
void getAllTerseUpdateProperties(EntityItemProperties& properties) const;
void getTransformAndVelocityProperties(EntityItemProperties& properties) const;
void flagForMotionStateChange() { _flags |= Simulation::DIRTY_MOTION_TYPE; }
@ -535,6 +535,8 @@ public:
const GrabPropertyGroup& getGrabProperties() const { return _grabProperties; }
void prepareForSimulationOwnershipBid(EntityItemProperties& properties, uint64_t now, uint8_t priority);
signals:
void requestRenderUpdate();
void spaceUpdate(std::pair<int32_t, glm::vec4> data);

View file

@ -2387,8 +2387,8 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
}
if (properties.getType() == EntityTypes::Light) {
APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor());
APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, properties.getIsSpotlight());
APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor());
APPEND_ENTITY_PROPERTY(PROP_INTENSITY, properties.getIntensity());
APPEND_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, properties.getFalloffRadius());
APPEND_ENTITY_PROPERTY(PROP_EXPONENT, properties.getExponent());
@ -3244,9 +3244,12 @@ AABox EntityItemProperties::getAABox() const {
return AABox(rotatedExtentsRelativeToRegistrationPoint);
}
bool EntityItemProperties::hasTerseUpdateChanges() const {
// a TerseUpdate includes the transform and its derivatives
return _positionChanged || _velocityChanged || _rotationChanged || _angularVelocityChanged || _accelerationChanged;
bool EntityItemProperties::hasTransformOrVelocityChanges() const {
return _positionChanged ||_localPositionChanged
|| _rotationChanged || _localRotationChanged
|| _velocityChanged || _localVelocityChanged
|| _angularVelocityChanged || _localAngularVelocityChanged
|| _accelerationChanged;
}
bool EntityItemProperties::hasMiscPhysicsChanges() const {
@ -3255,6 +3258,56 @@ bool EntityItemProperties::hasMiscPhysicsChanges() const {
_compoundShapeURLChanged || _dynamicChanged || _collisionlessChanged || _collisionMaskChanged;
}
bool EntityItemProperties::hasSimulationRestrictedChanges() const {
return _positionChanged || _localPositionChanged
|| _rotationChanged || _localRotationChanged
|| _velocityChanged || _localVelocityChanged
|| _angularVelocityChanged || _localAngularVelocityChanged
|| _accelerationChanged
|| _parentIDChanged || _parentJointIndexChanged;
}
void EntityItemProperties::copySimulationRestrictedProperties(const EntityItemPointer& entity) {
if (!_parentIDChanged) {
setParentID(entity->getParentID());
}
if (!_parentJointIndexChanged) {
setParentJointIndex(entity->getParentJointIndex());
}
if (!_localPositionChanged && !_positionChanged) {
setPosition(entity->getWorldPosition());
}
if (!_localRotationChanged && !_rotationChanged) {
setRotation(entity->getWorldOrientation());
}
if (!_localVelocityChanged && !_velocityChanged) {
setVelocity(entity->getWorldVelocity());
}
if (!_localAngularVelocityChanged && !_angularVelocityChanged) {
setAngularVelocity(entity->getWorldAngularVelocity());
}
if (!_accelerationChanged) {
setAcceleration(entity->getAcceleration());
}
if (!_localDimensionsChanged && !_dimensionsChanged) {
setDimensions(entity->getScaledDimensions());
}
}
void EntityItemProperties::clearSimulationRestrictedProperties() {
_positionChanged = false;
_localPositionChanged = false;
_rotationChanged = false;
_localRotationChanged = false;
_velocityChanged = false;
_localVelocityChanged = false;
_angularVelocityChanged = false;
_localAngularVelocityChanged = false;
_accelerationChanged = false;
_parentIDChanged = false;
_parentJointIndexChanged = false;
}
void EntityItemProperties::clearSimulationOwner() {
_simulationOwner.clear();
_simulationOwnerChanged = true;
@ -3273,6 +3326,20 @@ void EntityItemProperties::setSimulationOwner(const QByteArray& data) {
}
}
uint8_t EntityItemProperties::computeSimulationBidPriority() const {
uint8_t priority = 0;
if (_parentIDChanged || _parentJointIndexChanged) {
// we need higher simulation ownership priority to chang parenting info
priority = SCRIPT_GRAB_SIMULATION_PRIORITY;
} else if ( _positionChanged || _localPositionChanged
|| _rotationChanged || _localRotationChanged
|| _velocityChanged || _localVelocityChanged
|| _angularVelocityChanged || _localAngularVelocityChanged) {
priority = SCRIPT_POKE_SIMULATION_PRIORITY;
}
return priority;
}
QList<QString> EntityItemProperties::listChangedProperties() {
QList<QString> out;
if (containsPositionChange()) {

View file

@ -349,13 +349,18 @@ public:
void setCreated(QDateTime& v);
bool hasTerseUpdateChanges() const;
bool hasTransformOrVelocityChanges() const;
bool hasMiscPhysicsChanges() const;
bool hasSimulationRestrictedChanges() const;
void copySimulationRestrictedProperties(const EntityItemPointer& entity);
void clearSimulationRestrictedProperties();
void clearSimulationOwner();
void setSimulationOwner(const QUuid& id, uint8_t priority);
void setSimulationOwner(const QByteArray& data);
void setSimulationPriority(uint8_t priority) { _simulationOwner.setPriority(priority); }
uint8_t computeSimulationBidPriority() const;
void setActionDataDirty() { _actionDataChanged = true; }

View file

@ -174,6 +174,7 @@ EntityItemProperties convertPropertiesToScriptSemantics(const EntityItemProperti
}
// TODO: this method looks expensive and should take properties by reference, update it, and return void
EntityItemProperties convertPropertiesFromScriptSemantics(const EntityItemProperties& scriptSideProperties,
bool scalesWithParent) {
// convert position and rotation properties from world-space to local, unless localPosition and localRotation
@ -242,13 +243,12 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
_activityTracking.addedEntityCount++;
auto nodeList = DependencyManager::get<NodeList>();
auto sessionID = nodeList->getSessionUUID();
const auto sessionID = nodeList->getSessionUUID();
EntityItemProperties propertiesWithSimID = properties;
if (clientOnly) {
const QUuid myNodeID = sessionID;
propertiesWithSimID.setClientOnly(clientOnly);
propertiesWithSimID.setOwningAvatarID(myNodeID);
propertiesWithSimID.setOwningAvatarID(sessionID);
}
propertiesWithSimID.setLastEditedBy(sessionID);
@ -290,7 +290,7 @@ bool EntityScriptingInterface::addLocalEntityCopy(EntityItemProperties& properti
entity->setLastBroadcast(usecTimestampNow());
// since we're creating this object we will immediately volunteer to own its simulation
entity->setScriptSimulationPriority(VOLUNTEER_SIMULATION_PRIORITY);
entity->upgradeScriptSimulationPriority(VOLUNTEER_SIMULATION_PRIORITY);
properties.setLastEdited(entity->getLastEdited());
} else {
qCDebug(entities) << "script failed to add new Entity to local Octree";
@ -530,54 +530,86 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
_activityTracking.editedEntityCount++;
auto nodeList = DependencyManager::get<NodeList>();
auto sessionID = nodeList->getSessionUUID();
const auto sessionID = DependencyManager::get<NodeList>()->getSessionUUID();
EntityItemProperties properties = scriptSideProperties;
properties.setLastEditedBy(sessionID);
EntityItemID entityID(id);
if (!_entityTree) {
properties.setLastEditedBy(sessionID);
queueEntityMessage(PacketType::EntityEdit, entityID, properties);
return id;
}
// If we have a local entity tree set, then also update it.
bool updatedEntity = false;
_entityTree->withWriteLock([&] {
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
EntityItemPointer entity(nullptr);
SimulationOwner simulationOwner;
_entityTree->withReadLock([&] {
// make a copy of entity for local logic outside of tree lock
entity = _entityTree->findEntityByEntityItemID(entityID);
if (!entity) {
return;
}
if (entity->getClientOnly() && entity->getOwningAvatarID() != nodeList->getSessionUUID()) {
if (entity->getClientOnly() && entity->getOwningAvatarID() != sessionID) {
// don't edit other avatar's avatarEntities
properties = EntityItemProperties();
return;
}
// make a copy of simulationOwner for local logic outside of tree lock
simulationOwner = entity->getSimulationOwner();
});
if (scriptSideProperties.parentRelatedPropertyChanged()) {
// All of parentID, parentJointIndex, position, rotation are needed to make sense of any of them.
// If any of these changed, pull any missing properties from the entity.
if (entity) {
if (properties.hasSimulationRestrictedChanges()) {
if (_bidOnSimulationOwnership) {
// flag for simulation ownership, or upgrade existing ownership priority
// (actual bids for simulation ownership are sent by the PhysicalEntitySimulation)
entity->upgradeScriptSimulationPriority(properties.computeSimulationBidPriority());
if (simulationOwner.getID() == sessionID) {
// we own the simulation --> copy ALL restricted properties
properties.copySimulationRestrictedProperties(entity);
} else {
// we don't own the simulation but think we would like to
if (!scriptSideProperties.parentIDChanged()) {
properties.setParentID(entity->getParentID());
}
if (!scriptSideProperties.parentJointIndexChanged()) {
properties.setParentJointIndex(entity->getParentJointIndex());
}
if (!scriptSideProperties.localPositionChanged() && !scriptSideProperties.positionChanged()) {
properties.setPosition(entity->getWorldPosition());
}
if (!scriptSideProperties.localRotationChanged() && !scriptSideProperties.rotationChanged()) {
properties.setRotation(entity->getWorldOrientation());
}
if (!scriptSideProperties.localDimensionsChanged() && !scriptSideProperties.dimensionsChanged()) {
properties.setDimensions(entity->getScaledDimensions());
uint8_t desiredPriority = entity->getScriptSimulationPriority();
if (desiredPriority < simulationOwner.getPriority()) {
// the priority at which we'd like to own it is not high enough
// --> assume failure and clear all restricted property changes
properties.clearSimulationRestrictedProperties();
} else {
// the priority at which we'd like to own it is high enough to win.
// --> assume success and copy ALL restricted properties
properties.copySimulationRestrictedProperties(entity);
}
}
} else if (!simulationOwner.getID().isNull()) {
// someone owns this but not us
// clear restricted properties
properties.clearSimulationRestrictedProperties();
}
// clear the cached simulationPriority level
entity->upgradeScriptSimulationPriority(0);
}
// set these to make EntityItemProperties::getScalesWithParent() work correctly
properties.setClientOnly(entity->getClientOnly());
properties.setOwningAvatarID(entity->getOwningAvatarID());
properties = convertPropertiesFromScriptSemantics(properties, properties.getScalesWithParent());
// make sure the properties has a type, so that the encode can know which properties to include
properties.setType(entity->getType());
} else if (_bidOnSimulationOwnership) {
// bail when simulation participants don't know about entity
return QUuid();
}
// TODO: it is possible there is no remaining useful changes in properties and we should bail early.
// How to check for this cheaply?
properties = convertPropertiesFromScriptSemantics(properties, properties.getScalesWithParent());
properties.setLastEditedBy(sessionID);
// done reading and modifying properties --> start write
bool updatedEntity = false;
_entityTree->withWriteLock([&] {
updatedEntity = _entityTree->updateEntity(entityID, properties);
});
@ -590,63 +622,37 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
// return QUuid();
// }
bool entityFound { false };
bool hasQueryAACubeRelatedChanges = properties.queryAACubeRelatedPropertyChanged();
// done writing, send update
_entityTree->withReadLock([&] {
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
// find the entity again: maybe it was removed since we last found it
entity = _entityTree->findEntityByEntityItemID(entityID);
if (entity) {
entityFound = true;
// make sure the properties has a type, so that the encode can know which properties to include
properties.setType(entity->getType());
bool hasTerseUpdateChanges = properties.hasTerseUpdateChanges();
bool hasPhysicsChanges = properties.hasMiscPhysicsChanges() || hasTerseUpdateChanges;
if (_bidOnSimulationOwnership && hasPhysicsChanges) {
auto nodeList = DependencyManager::get<NodeList>();
const QUuid myNodeID = nodeList->getSessionUUID();
uint64_t now = usecTimestampNow();
entity->setLastBroadcast(now);
if (entity->getSimulatorID() == myNodeID) {
// we think we already own the simulation, so make sure to send ALL TerseUpdate properties
if (hasTerseUpdateChanges) {
entity->getAllTerseUpdateProperties(properties);
}
// TODO: if we knew that ONLY TerseUpdate properties have changed in properties AND the object
// is dynamic AND it is active in the physics simulation then we could chose to NOT queue an update
// and instead let the physics simulation decide when to send a terse update. This would remove
// the "slide-no-rotate" glitch (and typical double-update) that we see during the "poke rolling
// balls" test. However, even if we solve this problem we still need to provide a "slerp the visible
// proxy toward the true physical position" feature to hide the final glitches in the remote watcher's
// simulation.
if (entity->getSimulationPriority() < SCRIPT_POKE_SIMULATION_PRIORITY) {
// we re-assert our simulation ownership at a higher priority
properties.setSimulationOwner(myNodeID, SCRIPT_POKE_SIMULATION_PRIORITY);
}
} else {
// we make a bid for simulation ownership
properties.setSimulationOwner(myNodeID, SCRIPT_POKE_SIMULATION_PRIORITY);
entity->setScriptSimulationPriority(SCRIPT_POKE_SIMULATION_PRIORITY);
}
}
if (properties.queryAACubeRelatedPropertyChanged()) {
if (hasQueryAACubeRelatedChanges) {
properties.setQueryAACube(entity->getQueryAACube());
}
entity->setLastBroadcast(usecTimestampNow());
properties.setLastEdited(entity->getLastEdited());
// if we've moved an entity with children, check/update the queryAACube of all descendents and tell the server
// if they've changed.
entity->forEachDescendant([&](SpatiallyNestablePointer descendant) {
if (descendant->getNestableType() == NestableType::Entity) {
if (descendant->updateQueryAACube()) {
EntityItemPointer entityDescendant = std::static_pointer_cast<EntityItem>(descendant);
EntityItemProperties newQueryCubeProperties;
newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube());
newQueryCubeProperties.setLastEdited(properties.getLastEdited());
queueEntityMessage(PacketType::EntityEdit, descendant->getID(), newQueryCubeProperties);
entityDescendant->setLastBroadcast(usecTimestampNow());
// if we've moved an entity with children, check/update the queryAACube of all descendents and tell the server
// if they've changed.
entity->forEachDescendant([&](SpatiallyNestablePointer descendant) {
if (descendant->getNestableType() == NestableType::Entity) {
if (descendant->updateQueryAACube()) {
EntityItemPointer entityDescendant = std::static_pointer_cast<EntityItem>(descendant);
EntityItemProperties newQueryCubeProperties;
newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube());
newQueryCubeProperties.setLastEdited(properties.getLastEdited());
queueEntityMessage(PacketType::EntityEdit, descendant->getID(), newQueryCubeProperties);
entityDescendant->setLastBroadcast(now);
}
}
}
});
} else {
});
}
}
});
if (!entity) {
if (hasQueryAACubeRelatedChanges) {
// Sometimes ESS don't have the entity they are trying to edit in their local tree. In this case,
// convertPropertiesFromScriptSemantics doesn't get called and local* edits will get dropped.
// This is because, on the script side, "position" is in world frame, but in the network
@ -668,8 +674,6 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
properties.setDimensions(properties.getLocalDimensions());
}
}
});
if (!entityFound) {
// we've made an edit to an entity we don't know about, or to a non-entity. If it's a known non-entity,
// print a warning and don't send an edit packet to the entity-server.
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
@ -1449,7 +1453,7 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString,
}
action->setIsMine(true);
success = entity->addAction(simulation, action);
entity->setScriptSimulationPriority(SCRIPT_GRAB_SIMULATION_PRIORITY);
entity->upgradeScriptSimulationPriority(SCRIPT_GRAB_SIMULATION_PRIORITY);
return false; // Physics will cause a packet to be sent, so don't send from here.
});
if (success) {
@ -1465,7 +1469,7 @@ bool EntityScriptingInterface::updateAction(const QUuid& entityID, const QUuid&
return actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) {
bool success = entity->updateAction(simulation, actionID, arguments);
if (success) {
entity->setScriptSimulationPriority(SCRIPT_GRAB_SIMULATION_PRIORITY);
entity->upgradeScriptSimulationPriority(SCRIPT_GRAB_SIMULATION_PRIORITY);
}
return success;
});
@ -1479,7 +1483,7 @@ bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid&
success = entity->removeAction(simulation, actionID);
if (success) {
// reduce from grab to poke
entity->setScriptSimulationPriority(SCRIPT_POKE_SIMULATION_PRIORITY);
entity->upgradeScriptSimulationPriority(SCRIPT_POKE_SIMULATION_PRIORITY);
}
return false; // Physics will cause a packet to be sent, so don't send from here.
});

View file

@ -629,30 +629,6 @@ bool ModelEntityItem::getAnimationHold() const {
});
}
void ModelEntityItem::setAnimationFirstFrame(float firstFrame) {
withWriteLock([&] {
_animationProperties.setFirstFrame(firstFrame);
});
}
float ModelEntityItem::getAnimationFirstFrame() const {
return resultWithReadLock<float>([&] {
return _animationProperties.getFirstFrame();
});
}
void ModelEntityItem::setAnimationLastFrame(float lastFrame) {
withWriteLock([&] {
_animationProperties.setLastFrame(lastFrame);
});
}
float ModelEntityItem::getAnimationLastFrame() const {
return resultWithReadLock<float>([&] {
return _animationProperties.getLastFrame();
});
}
bool ModelEntityItem::getAnimationIsPlaying() const {
return resultWithReadLock<bool>([&] {
return _animationProperties.getRunning();

View file

@ -79,9 +79,10 @@ public:
// Animation related items...
AnimationPropertyGroup getAnimationProperties() const;
// TODO: audit and remove unused Animation accessors
bool hasAnimation() const;
QString getAnimationURL() const;
void setAnimationURL(const QString& url);
virtual void setAnimationURL(const QString& url);
void setAnimationCurrentFrame(float value);
void setAnimationIsPlaying(bool value);
@ -99,12 +100,6 @@ public:
void setRelayParentJoints(bool relayJoints);
bool getRelayParentJoints() const;
void setAnimationFirstFrame(float firstFrame);
float getAnimationFirstFrame() const;
void setAnimationLastFrame(float lastFrame);
float getAnimationLastFrame() const;
bool getAnimationIsPlaying() const;
float getAnimationCurrentFrame() const;
float getAnimationFPS() const;

View file

@ -19,7 +19,11 @@ Q_DECLARE_LOGGING_CATEGORY(gpugllogging)
Q_DECLARE_LOGGING_CATEGORY(trace_render_gpu_gl)
Q_DECLARE_LOGGING_CATEGORY(trace_render_gpu_gl_detail)
#if defined(__clang__)
#define BUFFER_OFFSET(bytes) (reinterpret_cast<GLvoid*>(bytes))
#else
#define BUFFER_OFFSET(bytes) ((GLubyte*) nullptr + (bytes))
#endif
namespace gpu { namespace gl {

View file

@ -25,8 +25,10 @@ struct GLFilterMode {
class GLTextureTransferEngine {
public:
virtual ~GLTextureTransferEngine() {}
using Pointer = std::shared_ptr<GLTextureTransferEngine>;
virtual ~GLTextureTransferEngine() = default;
/// Called once per frame to perform any require memory management or transfer work
virtual void manageMemory() = 0;
virtual void shutdown() = 0;

View file

@ -118,11 +118,13 @@ public:
uint8 _function = LESS;
uint8 _writeMask = true;
uint8 _enabled = false;
uint8 _spare = 0; // _spare is here to to affect alignment
#if defined(__clang__)
__attribute__((unused))
#endif
uint8 _spare = 0; // Padding
public:
DepthTest(bool enabled = false, bool writeMask = true, ComparisonFunction func = LESS) :
_function(func), _writeMask(writeMask), _enabled(enabled) {
(void)_spare; // to avoid unusued variable warning
}
bool isEnabled() const { return _enabled != 0; }

View file

@ -320,7 +320,10 @@ public:
float _scattering{ 0.0f }; // Scattering info
glm::vec2 _spare{ 0.0f };
#if defined(__clang__)
__attribute__((unused))
#endif
glm::vec2 _spare{ 0.0f }; // Padding
uint32_t _key{ 0 }; // a copy of the materialKey

View file

@ -96,7 +96,6 @@ protected:
class InputDevice : public controller::InputDevice {
public:
InputDevice() : controller::InputDevice("Keyboard") {}
virtual ~InputDevice() {}
private:
// Device functions
virtual controller::Input::NamedVector getAvailableInputs() const override;

View file

@ -414,33 +414,13 @@ bool Geometry::areTexturesLoaded() const {
if (!_areTexturesLoaded) {
for (auto& material : _materials) {
// Check if material textures are loaded
bool materialMissingTexture = std::any_of(material->_textures.cbegin(), material->_textures.cend(),
[](const NetworkMaterial::Textures::value_type& it) {
auto texture = it.texture;
if (!texture) {
return false;
}
// Failed texture downloads need to be considered as 'loaded'
// or the object will never fade in
bool finished = texture->isFailed() || (texture->isLoaded() && texture->getGPUTexture() && texture->getGPUTexture()->isDefined());
if (!finished) {
return true;
}
return false;
});
bool materialMissingTexture = material->isMissingTexture();
if (materialMissingTexture) {
return false;
}
// If material textures are loaded, check the material translucency
// FIXME: This should not be done here. The opacity map should already be reset in Material::setTextureMap.
// However, currently that code can be called before the albedo map is defined, so resetOpacityMap will fail.
// Geometry::areTexturesLoaded() is called repeatedly until it returns true, so we do the check here for now
const auto albedoTexture = material->_textures[NetworkMaterial::MapChannel::ALBEDO_MAP];
if (albedoTexture.texture) {
material->resetOpacityMap();
}
material->checkResetOpacityMap();
}
_areTexturesLoaded = true;
@ -783,4 +763,31 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) {
}
}
bool NetworkMaterial::isMissingTexture() {
for (auto& networkTexture : _textures) {
auto& texture = networkTexture.texture;
if (!texture) {
continue;
}
// Failed texture downloads need to be considered as 'loaded'
// or the object will never fade in
bool finished = texture->isFailed() || (texture->isLoaded() && texture->getGPUTexture() && texture->getGPUTexture()->isDefined());
if (!finished) {
return true;
}
}
return false;
}
void NetworkMaterial::checkResetOpacityMap() {
// If material textures are loaded, check the material translucency
// FIXME: This should not be done here. The opacity map should already be reset in Material::setTextureMap.
// However, currently that code can be called before the albedo map is defined, so resetOpacityMap will fail.
// Geometry::areTexturesLoaded() is called repeatedly until it returns true, so we do the check here for now
const auto& albedoTexture = _textures[NetworkMaterial::MapChannel::ALBEDO_MAP];
if (albedoTexture.texture) {
resetOpacityMap();
}
}
#include "ModelCache.moc"

View file

@ -36,7 +36,7 @@ public:
Geometry() = default;
Geometry(const Geometry& geometry);
virtual ~Geometry() {}
virtual ~Geometry() = default;
// Immutable over lifetime
using GeometryMeshes = std::vector<std::shared_ptr<const graphics::Mesh>>;
@ -177,6 +177,9 @@ public:
void setScatteringMap(const QUrl& url);
void setLightmapMap(const QUrl& url);
bool isMissingTexture();
void checkResetOpacityMap();
protected:
friend class Geometry;

View file

@ -18,7 +18,7 @@
BandwidthRecorder::Channel::Channel() {
}
float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() {
float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() const {
float averageTimeBetweenPackets = _input.getEventDeltaAverage();
if (averageTimeBetweenPackets > 0.0f) {
return (1.0f / averageTimeBetweenPackets);
@ -26,7 +26,7 @@ float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() {
return 0.0f;
}
float BandwidthRecorder::Channel::getAverageOutputPacketsPerSecond() {
float BandwidthRecorder::Channel::getAverageOutputPacketsPerSecond() const {
float averageTimeBetweenPackets = _output.getEventDeltaAverage();
if (averageTimeBetweenPackets > 0.0f) {
return (1.0f / averageTimeBetweenPackets);
@ -34,11 +34,11 @@ float BandwidthRecorder::Channel::getAverageOutputPacketsPerSecond() {
return 0.0f;
}
float BandwidthRecorder::Channel::getAverageInputKilobitsPerSecond() {
float BandwidthRecorder::Channel::getAverageInputKilobitsPerSecond() const {
return (_input.getAverageSampleValuePerSecond() * (8.0f / 1000));
}
float BandwidthRecorder::Channel::getAverageOutputKilobitsPerSecond() {
float BandwidthRecorder::Channel::getAverageOutputKilobitsPerSecond() const {
return (_output.getAverageSampleValuePerSecond() * (8.0f / 1000));
}
@ -77,35 +77,35 @@ void BandwidthRecorder::updateOutboundData(const quint8 channelType, const int s
_channels[channelType]->updateOutputAverage(sample);
}
float BandwidthRecorder::getAverageInputPacketsPerSecond(const quint8 channelType) {
float BandwidthRecorder::getAverageInputPacketsPerSecond(const quint8 channelType) const {
if (! _channels[channelType]) {
return 0.0f;
}
return _channels[channelType]->getAverageInputPacketsPerSecond();
}
float BandwidthRecorder::getAverageOutputPacketsPerSecond(const quint8 channelType) {
float BandwidthRecorder::getAverageOutputPacketsPerSecond(const quint8 channelType) const {
if (! _channels[channelType]) {
return 0.0f;
}
return _channels[channelType]->getAverageOutputPacketsPerSecond();
}
float BandwidthRecorder::getAverageInputKilobitsPerSecond(const quint8 channelType) {
float BandwidthRecorder::getAverageInputKilobitsPerSecond(const quint8 channelType) const {
if (! _channels[channelType]) {
return 0.0f;
}
return _channels[channelType]->getAverageInputKilobitsPerSecond();
}
float BandwidthRecorder::getAverageOutputKilobitsPerSecond(const quint8 channelType) {
float BandwidthRecorder::getAverageOutputKilobitsPerSecond(const quint8 channelType) const {
if (! _channels[channelType]) {
return 0.0f;
}
return _channels[channelType]->getAverageOutputKilobitsPerSecond();
}
float BandwidthRecorder::getTotalAverageInputPacketsPerSecond() {
float BandwidthRecorder::getTotalAverageInputPacketsPerSecond() const {
float result = 0.0f;
for (uint i=0; i<CHANNEL_COUNT; i++) {
if (_channels[i]) {
@ -115,7 +115,7 @@ float BandwidthRecorder::getTotalAverageInputPacketsPerSecond() {
return result;
}
float BandwidthRecorder::getTotalAverageOutputPacketsPerSecond() {
float BandwidthRecorder::getTotalAverageOutputPacketsPerSecond() const {
float result = 0.0f;
for (uint i=0; i<CHANNEL_COUNT; i++) {
if (_channels[i]) {
@ -125,7 +125,7 @@ float BandwidthRecorder::getTotalAverageOutputPacketsPerSecond() {
return result;
}
float BandwidthRecorder::getTotalAverageInputKilobitsPerSecond(){
float BandwidthRecorder::getTotalAverageInputKilobitsPerSecond() const {
float result = 0.0f;
for (uint i=0; i<CHANNEL_COUNT; i++) {
if (_channels[i]) {
@ -135,7 +135,7 @@ float BandwidthRecorder::getTotalAverageInputKilobitsPerSecond(){
return result;
}
float BandwidthRecorder::getTotalAverageOutputKilobitsPerSecond(){
float BandwidthRecorder::getTotalAverageOutputKilobitsPerSecond() const {
float result = 0.0f;
for (uint i=0; i<CHANNEL_COUNT; i++) {
if (_channels[i]) {
@ -145,7 +145,7 @@ float BandwidthRecorder::getTotalAverageOutputKilobitsPerSecond(){
return result;
}
float BandwidthRecorder::getCachedTotalAverageInputPacketsPerSecond() {
float BandwidthRecorder::getCachedTotalAverageInputPacketsPerSecond() const {
static qint64 lastCalculated = 0;
static float cachedValue = 0.0f;
qint64 now = QDateTime::currentMSecsSinceEpoch();
@ -156,7 +156,7 @@ float BandwidthRecorder::getCachedTotalAverageInputPacketsPerSecond() {
return cachedValue;
}
float BandwidthRecorder::getCachedTotalAverageOutputPacketsPerSecond() {
float BandwidthRecorder::getCachedTotalAverageOutputPacketsPerSecond() const {
static qint64 lastCalculated = 0;
static float cachedValue = 0.0f;
qint64 now = QDateTime::currentMSecsSinceEpoch();
@ -167,7 +167,7 @@ float BandwidthRecorder::getCachedTotalAverageOutputPacketsPerSecond() {
return cachedValue;
}
float BandwidthRecorder::getCachedTotalAverageInputKilobitsPerSecond() {
float BandwidthRecorder::getCachedTotalAverageInputKilobitsPerSecond() const {
static qint64 lastCalculated = 0;
static float cachedValue = 0.0f;
qint64 now = QDateTime::currentMSecsSinceEpoch();
@ -178,7 +178,7 @@ float BandwidthRecorder::getCachedTotalAverageInputKilobitsPerSecond() {
return cachedValue;
}
float BandwidthRecorder::getCachedTotalAverageOutputKilobitsPerSecond() {
float BandwidthRecorder::getCachedTotalAverageOutputKilobitsPerSecond() const {
static qint64 lastCalculated = 0;
static float cachedValue = 0.0f;
qint64 now = QDateTime::currentMSecsSinceEpoch();

View file

@ -32,33 +32,33 @@ public:
class Channel {
public:
Channel();
float getAverageInputPacketsPerSecond();
float getAverageOutputPacketsPerSecond();
float getAverageInputKilobitsPerSecond();
float getAverageOutputKilobitsPerSecond();
float getAverageInputPacketsPerSecond() const;
float getAverageOutputPacketsPerSecond() const;
float getAverageInputKilobitsPerSecond() const;
float getAverageOutputKilobitsPerSecond() const;
void updateInputAverage(const float sample);
void updateOutputAverage(const float sample);
private:
SimpleMovingAverage _input = SimpleMovingAverage();
SimpleMovingAverage _output = SimpleMovingAverage();
SimpleMovingAverage _input;
SimpleMovingAverage _output;
};
float getAverageInputPacketsPerSecond(const quint8 channelType);
float getAverageOutputPacketsPerSecond(const quint8 channelType);
float getAverageInputKilobitsPerSecond(const quint8 channelType);
float getAverageOutputKilobitsPerSecond(const quint8 channelType);
float getAverageInputPacketsPerSecond(const quint8 channelType) const;
float getAverageOutputPacketsPerSecond(const quint8 channelType) const;
float getAverageInputKilobitsPerSecond(const quint8 channelType) const;
float getAverageOutputKilobitsPerSecond(const quint8 channelType) const;
float getTotalAverageInputPacketsPerSecond();
float getTotalAverageOutputPacketsPerSecond();
float getTotalAverageInputKilobitsPerSecond();
float getTotalAverageOutputKilobitsPerSecond();
float getTotalAverageInputPacketsPerSecond() const;
float getTotalAverageOutputPacketsPerSecond() const;
float getTotalAverageInputKilobitsPerSecond() const;
float getTotalAverageOutputKilobitsPerSecond() const;
float getCachedTotalAverageInputPacketsPerSecond();
float getCachedTotalAverageOutputPacketsPerSecond();
float getCachedTotalAverageInputKilobitsPerSecond();
float getCachedTotalAverageOutputKilobitsPerSecond();
float getCachedTotalAverageInputPacketsPerSecond() const;
float getCachedTotalAverageOutputPacketsPerSecond() const;
float getCachedTotalAverageInputKilobitsPerSecond() const;
float getCachedTotalAverageOutputKilobitsPerSecond() const;
private:

View file

@ -140,8 +140,10 @@ void DomainHandler::hardReset() {
}
bool DomainHandler::isHardRefusal(int reasonCode) {
return (reasonCode == (int)ConnectionRefusedReason::ProtocolMismatch || reasonCode == (int)ConnectionRefusedReason::NotAuthorized ||
reasonCode == (int)ConnectionRefusedReason::TimedOut);
return (reasonCode == (int)ConnectionRefusedReason::ProtocolMismatch ||
reasonCode == (int)ConnectionRefusedReason::TooManyUsers ||
reasonCode == (int)ConnectionRefusedReason::NotAuthorized ||
reasonCode == (int)ConnectionRefusedReason::TimedOut);
}
bool DomainHandler::getInterstitialModeEnabled() const {
@ -473,7 +475,7 @@ bool DomainHandler::reasonSuggestsLogin(ConnectionRefusedReason reasonCode) {
case ConnectionRefusedReason::LoginError:
case ConnectionRefusedReason::NotAuthorized:
return true;
default:
case ConnectionRefusedReason::Unknown:
case ConnectionRefusedReason::ProtocolMismatch:

View file

@ -18,7 +18,6 @@
#include <SharedUtil.h>
#include <UUID.h>
#include "BandwidthRecorder.h"
#include "NetworkLogging.h"
#include <Trace.h>
#include "NodeType.h"
@ -230,35 +229,18 @@ QDebug operator<<(QDebug debug, const NetworkPeer &peer) {
return debug;
}
// FIXME this is a temporary implementation to determine if this is the right approach.
// If so, migrate the BandwidthRecorder into the NetworkPeer class
using BandwidthRecorderPtr = QSharedPointer<BandwidthRecorder>;
static QHash<QUuid, BandwidthRecorderPtr> PEER_BANDWIDTH;
BandwidthRecorder& getBandwidthRecorder(const QUuid & uuid) {
if (!PEER_BANDWIDTH.count(uuid)) {
PEER_BANDWIDTH.insert(uuid, QSharedPointer<BandwidthRecorder>::create());
}
return *PEER_BANDWIDTH[uuid].data();
}
void NetworkPeer::recordBytesSent(int count) const {
auto& bw = getBandwidthRecorder(_uuid);
bw.updateOutboundData(0, count);
_bandwidthRecorder.updateOutboundData(0, count);
}
void NetworkPeer::recordBytesReceived(int count) const {
auto& bw = getBandwidthRecorder(_uuid);
bw.updateInboundData(0, count);
_bandwidthRecorder.updateInboundData(0, count);
}
float NetworkPeer::getOutboundBandwidth() const {
auto& bw = getBandwidthRecorder(_uuid);
return bw.getAverageOutputKilobitsPerSecond(0);
return _bandwidthRecorder.getAverageOutputKilobitsPerSecond(0);
}
float NetworkPeer::getInboundBandwidth() const {
auto& bw = getBandwidthRecorder(_uuid);
return bw.getAverageInputKilobitsPerSecond(0);
return _bandwidthRecorder.getAverageInputKilobitsPerSecond(0);
}

View file

@ -18,8 +18,9 @@
#include <QtCore/QTimer>
#include <QtCore/QUuid>
#include "UUID.h"
#include "BandwidthRecorder.h"
#include "HifiSockAddr.h"
#include "UUID.h"
const QString ICE_SERVER_HOSTNAME = "localhost";
const quint16 ICE_SERVER_DEFAULT_PORT = 7337;
@ -113,6 +114,8 @@ protected:
HifiSockAddr _symmetricSocket;
HifiSockAddr* _activeSocket;
mutable BandwidthRecorder _bandwidthRecorder;
quint64 _wakeTimestamp;
std::atomic_ullong _lastHeardMicrostamp;

View file

@ -427,8 +427,10 @@ void NodeList::sendDomainServerCheckIn() {
flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::SendDSCheckIn);
// Send duplicate check-ins in the exponentially increasing sequence 1, 1, 2, 4, ...
static const int MAX_CHECKINS_TOGETHER = 20;
int outstandingCheckins = _domainHandler.getCheckInPacketsSinceLastReply();
int checkinCount = outstandingCheckins > 1 ? std::pow(2, outstandingCheckins - 2) : 1;
checkinCount = std::min(checkinCount, MAX_CHECKINS_TOGETHER);
for (int i = 1; i < checkinCount; ++i) {
auto packetCopy = domainPacket->createCopy(*domainPacket);
sendPacket(std::move(packetCopy), _domainHandler.getSockAddr());

View file

@ -33,7 +33,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::EntityEdit:
case PacketType::EntityData:
case PacketType::EntityPhysics:
return static_cast<PacketVersion>(EntityVersion::ScriptGlmVectors);
return static_cast<PacketVersion>(EntityVersion::FixedLightSerialization);
case PacketType::EntityQuery:
return static_cast<PacketVersion>(EntityQueryPacketVersion::ConicalFrustums);
case PacketType::AvatarIdentity:

View file

@ -244,7 +244,8 @@ enum class EntityVersion : PacketVersion {
ParticleSpin,
BloomEffect,
GrabProperties,
ScriptGlmVectors
ScriptGlmVectors,
FixedLightSerialization
};
enum class EntityScriptCallMethodVersion : PacketVersion {

View file

@ -37,7 +37,6 @@ Socket::Socket(QObject* parent, bool shouldChangeSocketOptions) :
_shouldChangeSocketOptions(shouldChangeSocketOptions)
{
connect(&_udpSocket, &QUdpSocket::readyRead, this, &Socket::readPendingDatagrams);
connect(this, &Socket::pendingDatagrams, this, &Socket::processPendingDatagrams, Qt::QueuedConnection);
// make sure we hear about errors and state changes from the underlying socket
connect(&_udpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
@ -316,85 +315,64 @@ void Socket::checkForReadyReadBackup() {
}
void Socket::readPendingDatagrams() {
int packetsRead = 0;
using namespace std::chrono;
static const auto MAX_PROCESS_TIME { 100ms };
const auto abortTime = system_clock::now() + MAX_PROCESS_TIME;
int packetSizeWithHeader = -1;
// Max datagrams to read before processing:
static const int MAX_DATAGRAMS_CONSECUTIVELY = 10000;
while (_udpSocket.hasPendingDatagrams()
&& (packetSizeWithHeader = _udpSocket.pendingDatagramSize()) != -1
&& packetsRead <= MAX_DATAGRAMS_CONSECUTIVELY) {
// grab a time point we can mark as the receive time of this packet
auto receiveTime = p_high_resolution_clock::now();
// setup a buffer to read the packet into
auto buffer = std::unique_ptr<char[]>(new char[packetSizeWithHeader]);
QHostAddress senderAddress;
quint16 senderPort;
// pull the datagram
auto sizeRead = _udpSocket.readDatagram(buffer.get(), packetSizeWithHeader,
&senderAddress, &senderPort);
// we either didn't pull anything for this packet or there was an error reading (this seems to trigger
// on windows even if there's not a packet available)
if (sizeRead < 0) {
continue;
while (_udpSocket.hasPendingDatagrams() &&
(packetSizeWithHeader = _udpSocket.pendingDatagramSize()) != -1) {
if (system_clock::now() > abortTime) {
// We've been running for too long, stop processing packets for now
// Once we've processed the event queue, we'll come back to packet processing
break;
}
_incomingDatagrams.push_back({ senderAddress, senderPort, packetSizeWithHeader,
std::move(buffer), receiveTime });
++packetsRead;
}
if (packetsRead > _maxDatagramsRead) {
_maxDatagramsRead = packetsRead;
qCDebug(networking) << "readPendingDatagrams: Datagrams read:" << packetsRead;
}
emit pendingDatagrams(packetsRead);
}
void Socket::processPendingDatagrams(int) {
// setup a HifiSockAddr to read into
HifiSockAddr senderSockAddr;
while (!_incomingDatagrams.empty()) {
auto& datagram = _incomingDatagrams.front();
senderSockAddr.setAddress(datagram._senderAddress);
senderSockAddr.setPort(datagram._senderPort);
int datagramSize = datagram._datagramLength;
auto receiveTime = datagram._receiveTime;
// we're reading a packet so re-start the readyRead backup timer
_readyReadBackupTimer->start();
// grab a time point we can mark as the receive time of this packet
auto receiveTime = p_high_resolution_clock::now();
// setup a HifiSockAddr to read into
HifiSockAddr senderSockAddr;
// setup a buffer to read the packet into
auto buffer = std::unique_ptr<char[]>(new char[packetSizeWithHeader]);
// pull the datagram
auto sizeRead = _udpSocket.readDatagram(buffer.get(), packetSizeWithHeader,
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
// save information for this packet, in case it is the one that sticks readyRead
_lastPacketSizeRead = datagramSize;
_lastPacketSizeRead = sizeRead;
_lastPacketSockAddr = senderSockAddr;
// Process unfiltered packets first.
if (sizeRead <= 0) {
// we either didn't pull anything for this packet or there was an error reading (this seems to trigger
// on windows even if there's not a packet available)
continue;
}
auto it = _unfilteredHandlers.find(senderSockAddr);
if (it != _unfilteredHandlers.end()) {
// we have a registered unfiltered handler for this HifiSockAddr (eg. STUN packet) - call that and return
// we have a registered unfiltered handler for this HifiSockAddr - call that and return
if (it->second) {
auto basePacket = BasePacket::fromReceivedPacket(std::move(datagram._datagram),
datagramSize, senderSockAddr);
auto basePacket = BasePacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr);
basePacket->setReceiveTime(receiveTime);
it->second(std::move(basePacket));
}
_incomingDatagrams.pop_front();
continue;
}
// check if this was a control packet or a data packet
bool isControlPacket = *reinterpret_cast<uint32_t*>(datagram._datagram.get()) & CONTROL_BIT_MASK;
bool isControlPacket = *reinterpret_cast<uint32_t*>(buffer.get()) & CONTROL_BIT_MASK;
if (isControlPacket) {
// setup a control packet from the data we just read
auto controlPacket = ControlPacket::fromReceivedPacket(std::move(datagram._datagram), datagramSize, senderSockAddr);
auto controlPacket = ControlPacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr);
controlPacket->setReceiveTime(receiveTime);
// move this control packet to the matching connection, if there is one
@ -406,13 +384,13 @@ void Socket::processPendingDatagrams(int) {
} else {
// setup a Packet from the data we just read
auto packet = Packet::fromReceivedPacket(std::move(datagram._datagram), datagramSize, senderSockAddr);
auto packet = Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr);
packet->setReceiveTime(receiveTime);
// save the sequence number in case this is the packet that sticks readyRead
_lastReceivedSequenceNumber = packet->getSequenceNumber();
// call our hash verification operator to see if this packet is verified
// call our verification operator to see if this packet is verified
if (!_packetFilterOperator || _packetFilterOperator(*packet)) {
if (packet->isReliable()) {
// if this was a reliable packet then signal the matching connection with the sequence number
@ -426,7 +404,6 @@ void Socket::processPendingDatagrams(int) {
qCDebug(networking) << "Can't process packet: version" << (unsigned int)NLPacket::versionInHeader(*packet)
<< ", type" << NLPacket::typeInHeader(*packet);
#endif
_incomingDatagrams.pop_front();
continue;
}
}
@ -442,8 +419,6 @@ void Socket::processPendingDatagrams(int) {
}
}
}
_incomingDatagrams.pop_front();
}
}

View file

@ -95,7 +95,6 @@ public:
signals:
void clientHandshakeRequestComplete(const HifiSockAddr& sockAddr);
void pendingDatagrams(int datagramCount);
public slots:
void cleanupConnection(HifiSockAddr sockAddr);
@ -103,7 +102,6 @@ public slots:
private slots:
void readPendingDatagrams();
void processPendingDatagrams(int datagramCount);
void checkForReadyReadBackup();
void handleSocketError(QAbstractSocket::SocketError socketError);
@ -147,17 +145,6 @@ private:
int _lastPacketSizeRead { 0 };
SequenceNumber _lastReceivedSequenceNumber;
HifiSockAddr _lastPacketSockAddr;
struct Datagram {
QHostAddress _senderAddress;
int _senderPort;
int _datagramLength;
std::unique_ptr<char[]> _datagram;
p_high_resolution_clock::time_point _receiveTime;
};
std::list<Datagram> _incomingDatagrams;
int _maxDatagramsRead { 0 };
friend UDTTest;
};

View file

@ -502,36 +502,18 @@ void EntityMotionState::sendBid(OctreeEditPacketSender* packetSender, uint32_t s
properties.setVelocity(linearVelocity);
properties.setAcceleration(_entity->getAcceleration());
properties.setAngularVelocity(angularVelocity);
if (_entity->dynamicDataNeedsTransmit()) {
_entity->setDynamicDataNeedsTransmit(false);
properties.setActionData(_entity->getDynamicData());
}
if (_entity->updateQueryAACube()) {
// due to parenting, the server may not know where something is in world-space, so include the bounding cube.
properties.setQueryAACube(_entity->getQueryAACube());
}
// set the LastEdited of the properties but NOT the entity itself
quint64 now = usecTimestampNow();
properties.setLastEdited(now);
// we don't own the simulation for this entity yet, but we're sending a bid for it
quint64 now = usecTimestampNow();
uint8_t finalBidPriority = computeFinalBidPriority();
_entity->clearScriptSimulationPriority();
properties.setSimulationOwner(Physics::getSessionUUID(), finalBidPriority);
_entity->setPendingOwnershipPriority(finalBidPriority);
_entity->prepareForSimulationOwnershipBid(properties, now, finalBidPriority);
EntityTreeElementPointer element = _entity->getElement();
EntityTreePointer tree = element ? element->getTree() : nullptr;
properties.setClientOnly(_entity->getClientOnly());
properties.setOwningAvatarID(_entity->getOwningAvatarID());
EntityItemID id(_entity->getID());
EntityEditPacketSender* entityPacketSender = static_cast<EntityEditPacketSender*>(packetSender);
entityPacketSender->queueEditEntityMessage(PacketType::EntityPhysics, tree, id, properties);
_entity->setLastBroadcast(now); // for debug/physics status icons
// NOTE: we don't descend to children for ownership bid. Instead, if we win ownership of the parent
// then in sendUpdate() we'll walk descendents and send updates for their QueryAACubes if necessary.

View file

@ -19,7 +19,6 @@ namespace controller {
class InputPlugin : public Plugin {
public:
virtual ~InputPlugin() {}
virtual void pluginFocusOutEvent() = 0;
virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) = 0;

View file

@ -109,7 +109,7 @@ class PickResult {
public:
PickResult() {}
PickResult(const QVariantMap& pickVariant) : pickVariant(pickVariant) {}
virtual ~PickResult() {}
virtual ~PickResult() = default;
virtual QVariantMap toVariantMap() const {
return pickVariant;
@ -135,6 +135,7 @@ class PickQuery : protected ReadWriteLockable {
Q_GADGET
public:
PickQuery(const PickFilter& filter, const float maxDistance, const bool enabled);
virtual ~PickQuery() = default;
/**jsdoc
* Enum for different types of Picks and Pointers.
@ -145,9 +146,11 @@ public:
* @hifi-interface
* @hifi-client-entity
*
* @property {number} Ray Ray Picks intersect a ray with the nearest object in front of them, along a given direction.
* @property {number} Stylus Stylus Picks provide "tapping" functionality on/into flat surfaces.
* @property {number} Parabola Parabola Picks intersect a parabola with the nearest object in front of them, with a given initial velocity and acceleration.
* @property {number} Ray Ray picks intersect a ray with the nearest object in front of them, along a given direction.
* @property {number} Stylus Stylus picks provide "tapping" functionality on/into flat surfaces.
* @property {number} Parabola Parabola picks intersect a parabola with the nearest object in front of them, with a given
* initial velocity and acceleration.
* @property {number} Collision Collision picks intersect a collision volume with avatars and entities that have collisions.
*/
/**jsdoc
* <table>
@ -158,6 +161,7 @@ public:
* <tr><td><code>{@link PickType(0)|PickType.Ray}</code></td><td></td></tr>
* <tr><td><code>{@link PickType(0)|PickType.Stylus}</code></td><td></td></tr>
* <tr><td><code>{@link PickType(0)|PickType.Parabola}</code></td><td></td></tr>
* <tr><td><code>{@link PickType(0)|PickType.Collision}</code></td><td></td></tr>
* </tbody>
* </table>
* @typedef {number} PickType
@ -245,7 +249,6 @@ template<typename T>
class Pick : public PickQuery {
public:
Pick(const T& mathPick, const PickFilter& filter, const float maxDistance, const bool enabled) : PickQuery(filter, maxDistance, enabled), _mathPick(mathPick) {}
virtual ~Pick() {}
virtual T getMathematicalPick() const = 0;
virtual PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const = 0;

View file

@ -38,11 +38,11 @@ std::shared_ptr<PickQuery> PickManager::findPick(unsigned int uid) const {
void PickManager::removePick(unsigned int uid) {
withWriteLock([&] {
auto type = _typeMap.find(uid);
if (type != _typeMap.end()) {
_picks[type->second].erase(uid);
_typeMap.erase(uid);
_totalPickCounts[type->second]--;
auto typeIt = _typeMap.find(uid);
if (typeIt != _typeMap.end()) {
_picks[typeIt->second].erase(uid);
_totalPickCounts[typeIt->second]--;
_typeMap.erase(typeIt);
}
});
}

View file

@ -96,7 +96,7 @@ void CauterizedModel::createRenderItemSet() {
shapeID++;
}
}
_blendshapeBuffersInitialized = true;
_blendshapeOffsetsInitialized = true;
} else {
Model::createRenderItemSet();
}
@ -175,7 +175,7 @@ void CauterizedModel::updateClusterMatrices() {
// post the blender if we're not currently waiting for one to finish
auto modelBlender = DependencyManager::get<ModelBlender>();
if (_blendshapeBuffersInitialized && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
if (_blendshapeOffsetsInitialized && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
_blendedBlendshapeCoefficients = _blendshapeCoefficients;
modelBlender->noteRequiresBlend(getThisPointer());
}

View file

@ -2175,7 +2175,10 @@ public:
bool isAntiAliased() const { return isFlag(IS_ANTIALIASED); }
Flags _flags = 0;
short _spare = 0;
#if defined(__clang__)
__attribute__((unused))
#endif
short _spare = 0; // Padding
int getRaw() const { return *reinterpret_cast<const int*>(this); }

View file

@ -39,10 +39,10 @@ namespace gr {
extern void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state);
HighlightRessources::HighlightRessources() {
HighlightResources::HighlightResources() {
}
void HighlightRessources::update(const gpu::FramebufferPointer& primaryFrameBuffer) {
void HighlightResources::update(const gpu::FramebufferPointer& primaryFrameBuffer) {
auto newFrameSize = glm::ivec2(primaryFrameBuffer->getSize());
// If the buffer size changed, we need to delete our FBOs and recreate them at the
@ -58,32 +58,37 @@ void HighlightRessources::update(const gpu::FramebufferPointer& primaryFrameBuff
if (!_colorFrameBuffer) {
allocateColorBuffer(primaryFrameBuffer);
}
// The primaryFrameBuffer render buffer can change
if (_colorFrameBuffer->getRenderBuffer(0) != primaryFrameBuffer->getRenderBuffer(0)) {
_colorFrameBuffer->setRenderBuffer(0, primaryFrameBuffer->getRenderBuffer(0));
}
}
}
void HighlightRessources::allocateColorBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) {
void HighlightResources::allocateColorBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) {
_colorFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithStencil"));
_colorFrameBuffer->setRenderBuffer(0, primaryFrameBuffer->getRenderBuffer(0));
_colorFrameBuffer->setStencilBuffer(_depthStencilTexture, _depthStencilTexture->getTexelFormat());
}
void HighlightRessources::allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) {
void HighlightResources::allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) {
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL);
_depthStencilTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, _frameSize.x, _frameSize.y));
_depthFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("highlightDepth"));
_depthFrameBuffer->setDepthStencilBuffer(_depthStencilTexture, depthFormat);
}
gpu::FramebufferPointer HighlightRessources::getDepthFramebuffer() {
gpu::FramebufferPointer HighlightResources::getDepthFramebuffer() {
assert(_depthFrameBuffer);
return _depthFrameBuffer;
}
gpu::TexturePointer HighlightRessources::getDepthTexture() {
gpu::TexturePointer HighlightResources::getDepthTexture() {
return _depthStencilTexture;
}
gpu::FramebufferPointer HighlightRessources::getColorFramebuffer() {
gpu::FramebufferPointer HighlightResources::getColorFramebuffer() {
assert(_colorFrameBuffer);
return _colorFrameBuffer;
}
@ -97,25 +102,21 @@ float HighlightSharedParameters::getBlurPixelWidth(const render::HighlightStyle&
}
PrepareDrawHighlight::PrepareDrawHighlight() {
_ressources = std::make_shared<HighlightRessources>();
_resources = std::make_shared<HighlightResources>();
}
void PrepareDrawHighlight::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
auto destinationFrameBuffer = inputs;
_ressources->update(destinationFrameBuffer);
outputs = _ressources;
_resources->update(destinationFrameBuffer);
outputs = _resources;
}
gpu::PipelinePointer DrawHighlightMask::_stencilMaskPipeline;
gpu::PipelinePointer DrawHighlightMask::_stencilMaskFillPipeline;
DrawHighlightMask::DrawHighlightMask(unsigned int highlightIndex,
render::ShapePlumberPointer shapePlumber, HighlightSharedParametersPointer parameters) :
_highlightPassIndex{ highlightIndex },
_shapePlumber { shapePlumber },
_sharedParameters{ parameters } {
}
DrawHighlightMask::DrawHighlightMask(unsigned int highlightIndex, render::ShapePlumberPointer shapePlumber,
HighlightSharedParametersPointer parameters) : _highlightPassIndex(highlightIndex), _shapePlumber(shapePlumber), _sharedParameters(parameters) {}
void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
assert(renderContext->args);
@ -126,13 +127,13 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c
const int PARAMETERS_SLOT = 0;
if (!_stencilMaskPipeline || !_stencilMaskFillPipeline) {
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
gpu::StatePointer state = std::make_shared<gpu::State>();
state->setDepthTest(true, false, gpu::LESS_EQUAL);
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_ZERO, gpu::State::STENCIL_OP_REPLACE));
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_REPLACE));
state->setColorWriteMask(false, false, false, false);
state->setCullMode(gpu::State::CULL_FRONT);
gpu::StatePointer fillState = gpu::StatePointer(new gpu::State());
gpu::StatePointer fillState = std::make_shared<gpu::State>();
fillState->setDepthTest(false, false, gpu::LESS_EQUAL);
fillState->setStencilTest(true, 0xFF, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_REPLACE));
fillState->setColorWriteMask(false, false, false, false);
@ -151,7 +152,7 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c
auto highlightId = _sharedParameters->_highlightIds[_highlightPassIndex];
if (!inShapes.empty() && !render::HighlightStage::isIndexInvalid(highlightId)) {
auto ressources = inputs.get1();
auto resources = inputs.get1();
auto& highlight = highlightStage->getHighlight(highlightId);
RenderArgs* args = renderContext->args;
@ -165,15 +166,11 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c
// while stereo is enabled triggers a warning
gpu::doInBatch("DrawHighlightMask::run::begin", args->_context, [&](gpu::Batch& batch) {
batch.enableStereo(false);
batch.setFramebuffer(ressources->getDepthFramebuffer());
batch.setFramebuffer(resources->getDepthFramebuffer());
batch.clearDepthStencilFramebuffer(1.0f, 0);
});
glm::mat4 projMat;
Transform viewMat;
const auto jitter = inputs.get2();
args->getViewFrustum().evalProjectionMatrix(projMat);
args->getViewFrustum().evalViewTransform(viewMat);
render::ItemBounds itemBounds;
@ -185,6 +182,10 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c
auto maskDeformedDQPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withDeformed().withDualQuatSkinned());
// Setup camera, projection and viewport for all items
glm::mat4 projMat;
Transform viewMat;
args->getViewFrustum().evalProjectionMatrix(projMat);
args->getViewFrustum().evalViewTransform(viewMat);
batch.setViewportTransform(args->_viewport);
batch.setProjectionTransform(projMat);
batch.setProjectionJitter(jitter.x, jitter.y);
@ -233,7 +234,7 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c
const auto securityMargin = 2.0f;
const float blurPixelWidth = 2.0f * securityMargin * HighlightSharedParameters::getBlurPixelWidth(highlight._style, args->_viewport.w);
const auto framebufferSize = ressources->getSourceFrameSize();
const auto framebufferSize = resources->getSourceFrameSize();
const glm::vec2 highlightWidth = { blurPixelWidth / framebufferSize.x, blurPixelWidth / framebufferSize.y };
if (highlightWidth != _outlineWidth.get()) {
@ -241,11 +242,6 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c
}
gpu::doInBatch("DrawHighlightMask::run::end", args->_context, [&](gpu::Batch& batch) {
// Setup camera, projection and viewport for all items
batch.setViewportTransform(args->_viewport);
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat);
// Draw stencil mask with object bounding boxes
auto stencilPipeline = highlight._style.isFilled() ? _stencilMaskFillPipeline : _stencilMaskPipeline;
batch.setPipeline(stencilPipeline);
@ -264,15 +260,14 @@ gpu::PipelinePointer DrawHighlight::_pipeline;
gpu::PipelinePointer DrawHighlight::_pipelineFilled;
DrawHighlight::DrawHighlight(unsigned int highlightIndex, HighlightSharedParametersPointer parameters) :
_highlightPassIndex{ highlightIndex },
_sharedParameters{ parameters } {
_highlightPassIndex(highlightIndex), _sharedParameters(parameters) {
}
void DrawHighlight::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
auto highlightFrameBuffer = inputs.get1();
auto highlightRect = inputs.get3();
if (highlightFrameBuffer && highlightRect.z>0 && highlightRect.w>0) {
if (highlightFrameBuffer && highlightRect.z > 0 && highlightRect.w > 0) {
auto sceneDepthBuffer = inputs.get2();
const auto frameTransform = inputs.get0();
auto highlightedDepthTexture = highlightFrameBuffer->getDepthTexture();
@ -334,10 +329,11 @@ void DrawHighlight::run(const render::RenderContextPointer& renderContext, const
const gpu::PipelinePointer& DrawHighlight::getPipeline(const render::HighlightStyle& style) {
if (!_pipeline) {
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
gpu::StatePointer state = std::make_shared<gpu::State>();
state->setDepthTest(gpu::State::DepthTest(false, false));
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL));
state->setColorWriteMask(true, true, true, true);
auto program = gpu::Shader::createProgram(shader::render_utils::program::highlight);
_pipeline = gpu::Pipeline::create(program, state);
@ -364,10 +360,10 @@ void DebugHighlight::configure(const Config& config) {
}
void DebugHighlight::run(const render::RenderContextPointer& renderContext, const Inputs& input) {
const auto highlightRessources = input.get0();
const auto highlightResources = input.get0();
const auto highlightRect = input.get1();
if (_isDisplayEnabled && highlightRessources && highlightRect.z>0 && highlightRect.w>0) {
if (_isDisplayEnabled && highlightResources && highlightRect.z > 0 && highlightRect.w > 0) {
assert(renderContext->args);
assert(renderContext->args->hasViewFrustum());
RenderArgs* args = renderContext->args;
@ -376,7 +372,7 @@ void DebugHighlight::run(const render::RenderContextPointer& renderContext, cons
auto primaryFramebuffer = input.get3();
gpu::doInBatch("DebugHighlight::run", args->_context, [&](gpu::Batch& batch) {
batch.setViewportTransform(args->_viewport);
batch.setFramebuffer(highlightRessources->getColorFramebuffer());
batch.setFramebuffer(highlightResources->getColorFramebuffer());
const auto geometryBuffer = DependencyManager::get<GeometryCache>();
@ -386,13 +382,13 @@ void DebugHighlight::run(const render::RenderContextPointer& renderContext, cons
args->getViewFrustum().evalViewTransform(viewMat);
batch.setProjectionTransform(projMat);
batch.setProjectionJitter(jitter.x, jitter.y);
batch.setViewTransform(viewMat, true);
batch.setViewTransform(viewMat);
batch.setModelTransform(Transform());
const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
batch.setPipeline(getDepthPipeline());
batch.setResourceTexture(0, highlightRessources->getDepthTexture());
batch.setResourceTexture(0, highlightResources->getDepthTexture());
const glm::vec2 bottomLeft(-1.0f, -1.0f);
const glm::vec2 topRight(1.0f, 1.0f);
geometryBuffer->renderQuad(batch, bottomLeft, topRight, color, _geometryDepthId);
@ -415,6 +411,7 @@ void DebugHighlight::initializePipelines() {
auto state = std::make_shared<gpu::State>();
state->setDepthTest(gpu::State::DepthTest(false, false));
state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL));
state->setColorWriteMask(true, true, true, true);
const auto vs = gpu::Shader::createVertex(shader::render_utils::vertex::debug_deferred_buffer);
@ -512,7 +509,7 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren
const auto highlightSelectionNames = task.addJob<SelectionToHighlight>("SelectionToHighlight", sharedParameters);
// Prepare for highlight group rendering.
const auto highlightRessources = task.addJob<PrepareDrawHighlight>("PrepareHighlight", primaryFramebuffer);
const auto highlightResources = task.addJob<PrepareDrawHighlight>("PrepareHighlight", primaryFramebuffer);
render::Varying highlight0Rect;
for (auto i = 0; i < HighlightSharedParameters::MAX_PASS_COUNT; i++) {
@ -532,7 +529,7 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren
stream << "HighlightMask" << i;
name = stream.str();
}
const auto drawMaskInputs = DrawHighlightMask::Inputs(sortedBounds, highlightRessources, jitter).asVarying();
const auto drawMaskInputs = DrawHighlightMask::Inputs(sortedBounds, highlightResources, jitter).asVarying();
const auto highlightedRect = task.addJob<DrawHighlightMask>(name, drawMaskInputs, i, shapePlumber, sharedParameters);
if (i == 0) {
highlight0Rect = highlightedRect;
@ -544,12 +541,12 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren
stream << "HighlightEffect" << i;
name = stream.str();
}
const auto drawHighlightInputs = DrawHighlight::Inputs(deferredFrameTransform, highlightRessources, sceneFrameBuffer, highlightedRect, primaryFramebuffer).asVarying();
const auto drawHighlightInputs = DrawHighlight::Inputs(deferredFrameTransform, highlightResources, sceneFrameBuffer, highlightedRect, primaryFramebuffer).asVarying();
task.addJob<DrawHighlight>(name, drawHighlightInputs, i, sharedParameters);
}
// Debug highlight
const auto debugInputs = DebugHighlight::Inputs(highlightRessources, const_cast<const render::Varying&>(highlight0Rect), jitter, primaryFramebuffer).asVarying();
const auto debugInputs = DebugHighlight::Inputs(highlightResources, const_cast<const render::Varying&>(highlight0Rect), jitter, primaryFramebuffer).asVarying();
task.addJob<DebugHighlight>("HighlightDebug", debugInputs);
}

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