mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 20:31:29 +02:00
Merge remote-tracking branch 'upstream/master' into HEAD
This commit is contained in:
commit
9f7b6f543d
56 changed files with 617 additions and 214 deletions
|
@ -477,7 +477,7 @@ void EntityServer::startDynamicDomainVerification() {
|
||||||
QNetworkRequest networkRequest;
|
QNetworkRequest networkRequest;
|
||||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||||
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL;
|
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||||
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/location");
|
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/location");
|
||||||
QJsonObject request;
|
QJsonObject request;
|
||||||
request["certificate_id"] = i.key();
|
request["certificate_id"] = i.key();
|
||||||
|
|
|
@ -94,7 +94,7 @@ bool DomainServer::forwardMetaverseAPIRequest(HTTPConnection* connection,
|
||||||
root.insert(requestSubobjectKey, subobject);
|
root.insert(requestSubobjectKey, subobject);
|
||||||
QJsonDocument doc { root };
|
QJsonDocument doc { root };
|
||||||
|
|
||||||
QUrl url { NetworkingConstants::METAVERSE_SERVER_URL.toString() + metaversePath };
|
QUrl url { NetworkingConstants::METAVERSE_SERVER_URL().toString() + metaversePath };
|
||||||
|
|
||||||
QNetworkRequest req(url);
|
QNetworkRequest req(url);
|
||||||
req.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
req.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||||
|
@ -420,7 +420,7 @@ bool DomainServer::optionallySetupOAuth() {
|
||||||
|
|
||||||
// if we don't have an oauth provider URL then we default to the default node auth url
|
// if we don't have an oauth provider URL then we default to the default node auth url
|
||||||
if (_oauthProviderURL.isEmpty()) {
|
if (_oauthProviderURL.isEmpty()) {
|
||||||
_oauthProviderURL = NetworkingConstants::METAVERSE_SERVER_URL;
|
_oauthProviderURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
|
@ -2159,7 +2159,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
||||||
QJsonDocument doc(root);
|
QJsonDocument doc(root);
|
||||||
|
|
||||||
|
|
||||||
QUrl url { NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/api/v1/places/" + place_id };
|
QUrl url { NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/api/v1/places/" + place_id };
|
||||||
|
|
||||||
url.setQuery("access_token=" + accessTokenVariant->toString());
|
url.setQuery("access_token=" + accessTokenVariant->toString());
|
||||||
|
|
||||||
|
|
|
@ -208,7 +208,7 @@ void IceServer::requestDomainPublicKey(const QUuid& domainID) {
|
||||||
// send a request to the metaverse API for the public key for this domain
|
// send a request to the metaverse API for the public key for this domain
|
||||||
auto& networkAccessManager = NetworkAccessManager::getInstance();
|
auto& networkAccessManager = NetworkAccessManager::getInstance();
|
||||||
|
|
||||||
QUrl publicKeyURL { NetworkingConstants::METAVERSE_SERVER_URL };
|
QUrl publicKeyURL { NetworkingConstants::METAVERSE_SERVER_URL() };
|
||||||
QString publicKeyPath = QString("/api/v1/domains/%1/public_key").arg(uuidStringWithoutCurlyBraces(domainID));
|
QString publicKeyPath = QString("/api/v1/domains/%1/public_key").arg(uuidStringWithoutCurlyBraces(domainID));
|
||||||
publicKeyURL.setPath(publicKeyPath);
|
publicKeyURL.setPath(publicKeyPath);
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,11 @@ Item {
|
||||||
targetHeight += hifi.dimensions.contentSpacing.y + additionalInformation.height
|
targetHeight += hifi.dimensions.contentSpacing.y + additionalInformation.height
|
||||||
}
|
}
|
||||||
|
|
||||||
parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth));
|
var newWidth = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth));
|
||||||
|
if(!isNaN(newWidth)) {
|
||||||
|
parent.width = root.width = newWidth;
|
||||||
|
}
|
||||||
|
|
||||||
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||||
+ (keyboardEnabled && keyboardRaised ? (200 + 2 * hifi.dimensions.contentSpacing.y) : hifi.dimensions.contentSpacing.y);
|
+ (keyboardEnabled && keyboardRaised ? (200 + 2 * hifi.dimensions.contentSpacing.y) : hifi.dimensions.contentSpacing.y);
|
||||||
}
|
}
|
||||||
|
|
|
@ -971,7 +971,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
|
|
||||||
// set the account manager's root URL and trigger a login request if we don't have the access token
|
// set the account manager's root URL and trigger a login request if we don't have the access token
|
||||||
accountManager->setIsAgent(true);
|
accountManager->setIsAgent(true);
|
||||||
accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);
|
accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL());
|
||||||
|
|
||||||
auto addressManager = DependencyManager::get<AddressManager>();
|
auto addressManager = DependencyManager::get<AddressManager>();
|
||||||
|
|
||||||
|
@ -3257,8 +3257,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Application::keyReleaseEvent(QKeyEvent* event) {
|
void Application::keyReleaseEvent(QKeyEvent* event) {
|
||||||
_keysPressed.remove(event->key());
|
_keysPressed.remove(event->key());
|
||||||
|
|
||||||
|
@ -4883,8 +4881,7 @@ void Application::update(float deltaTime) {
|
||||||
if (_physicsEnabled) {
|
if (_physicsEnabled) {
|
||||||
{
|
{
|
||||||
PROFILE_RANGE(simulation_physics, "PreStep");
|
PROFILE_RANGE(simulation_physics, "PreStep");
|
||||||
|
PerformanceTimer perfTimer("preStep)");
|
||||||
PerformanceTimer perfTimer("updateStates)");
|
|
||||||
static VectorOfMotionStates motionStates;
|
static VectorOfMotionStates motionStates;
|
||||||
_entitySimulation->getObjectsToRemoveFromPhysics(motionStates);
|
_entitySimulation->getObjectsToRemoveFromPhysics(motionStates);
|
||||||
_physicsEngine->removeObjects(motionStates);
|
_physicsEngine->removeObjects(motionStates);
|
||||||
|
@ -4917,22 +4914,22 @@ void Application::update(float deltaTime) {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
PROFILE_RANGE(simulation_physics, "Step");
|
PROFILE_RANGE(simulation_physics, "Step");
|
||||||
PerformanceTimer perfTimer("stepSimulation");
|
PerformanceTimer perfTimer("step");
|
||||||
getEntities()->getTree()->withWriteLock([&] {
|
getEntities()->getTree()->withWriteLock([&] {
|
||||||
_physicsEngine->stepSimulation();
|
_physicsEngine->stepSimulation();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
PROFILE_RANGE(simulation_physics, "PostStep");
|
PROFILE_RANGE(simulation_physics, "PostStep");
|
||||||
PerformanceTimer perfTimer("harvestChanges");
|
PerformanceTimer perfTimer("postStep");
|
||||||
if (_physicsEngine->hasOutgoingChanges()) {
|
if (_physicsEngine->hasOutgoingChanges()) {
|
||||||
// grab the collision events BEFORE handleOutgoingChanges() because at this point
|
// grab the collision events BEFORE handleOutgoingChanges() because at this point
|
||||||
// we have a better idea of which objects we own or should own.
|
// we have a better idea of which objects we own or should own.
|
||||||
auto& collisionEvents = _physicsEngine->getCollisionEvents();
|
auto& collisionEvents = _physicsEngine->getCollisionEvents();
|
||||||
|
|
||||||
getEntities()->getTree()->withWriteLock([&] {
|
getEntities()->getTree()->withWriteLock([&] {
|
||||||
PROFILE_RANGE(simulation_physics, "Harvest");
|
PROFILE_RANGE(simulation_physics, "HandleChanges");
|
||||||
PerformanceTimer perfTimer("handleOutgoingChanges");
|
PerformanceTimer perfTimer("handleChanges");
|
||||||
|
|
||||||
const VectorOfMotionStates& outgoingChanges = _physicsEngine->getChangedMotionStates();
|
const VectorOfMotionStates& outgoingChanges = _physicsEngine->getChangedMotionStates();
|
||||||
_entitySimulation->handleChangedMotionStates(outgoingChanges);
|
_entitySimulation->handleChangedMotionStates(outgoingChanges);
|
||||||
|
@ -4943,17 +4940,15 @@ void Application::update(float deltaTime) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!_aboutToQuit) {
|
if (!_aboutToQuit) {
|
||||||
// handleCollisionEvents() AFTER handleOutgoinChanges()
|
// handleCollisionEvents() AFTER handleOutgoingChanges()
|
||||||
{
|
{
|
||||||
PROFILE_RANGE(simulation_physics, "CollisionEvents");
|
PROFILE_RANGE(simulation_physics, "CollisionEvents");
|
||||||
PerformanceTimer perfTimer("entities");
|
|
||||||
avatarManager->handleCollisionEvents(collisionEvents);
|
avatarManager->handleCollisionEvents(collisionEvents);
|
||||||
// Collision events (and their scripts) must not be handled when we're locked, above. (That would risk
|
// Collision events (and their scripts) must not be handled when we're locked, above. (That would risk
|
||||||
// deadlock.)
|
// deadlock.)
|
||||||
_entitySimulation->handleCollisionEvents(collisionEvents);
|
_entitySimulation->handleCollisionEvents(collisionEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
PROFILE_RANGE(simulation_physics, "UpdateEntities");
|
|
||||||
// NOTE: the getEntities()->update() call below will wait for lock
|
// NOTE: the getEntities()->update() call below will wait for lock
|
||||||
// and will simulate entity motion (the EntityTree has been given an EntitySimulation).
|
// and will simulate entity motion (the EntityTree has been given an EntitySimulation).
|
||||||
getEntities()->update(true); // update the models...
|
getEntities()->update(true); // update the models...
|
||||||
|
@ -4964,7 +4959,8 @@ void Application::update(float deltaTime) {
|
||||||
myAvatar->harvestResultsFromPhysicsSimulation(deltaTime);
|
myAvatar->harvestResultsFromPhysicsSimulation(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) &&
|
if (PerformanceTimer::isActive() &&
|
||||||
|
Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) &&
|
||||||
Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsSimulationTiming)) {
|
Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsSimulationTiming)) {
|
||||||
_physicsEngine->harvestPerformanceStats();
|
_physicsEngine->harvestPerformanceStats();
|
||||||
}
|
}
|
||||||
|
@ -7544,4 +7540,9 @@ void Application::setAvatarOverrideUrl(const QUrl& url, bool save) {
|
||||||
_avatarOverrideUrl = url;
|
_avatarOverrideUrl = url;
|
||||||
_saveAvatarOverrideUrl = save;
|
_saveAvatarOverrideUrl = save;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::saveNextPhysicsStats(QString filename) {
|
||||||
|
_physicsEngine->saveNextPhysicsStats(filename);
|
||||||
|
}
|
||||||
|
|
||||||
#include "Application.moc"
|
#include "Application.moc"
|
||||||
|
|
|
@ -280,6 +280,7 @@ public:
|
||||||
void clearAvatarOverrideUrl() { _avatarOverrideUrl = QUrl(); _saveAvatarOverrideUrl = false; }
|
void clearAvatarOverrideUrl() { _avatarOverrideUrl = QUrl(); _saveAvatarOverrideUrl = false; }
|
||||||
QUrl getAvatarOverrideUrl() { return _avatarOverrideUrl; }
|
QUrl getAvatarOverrideUrl() { return _avatarOverrideUrl; }
|
||||||
bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; }
|
bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; }
|
||||||
|
void saveNextPhysicsStats(QString filename);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void svoImportRequested(const QString& url);
|
void svoImportRequested(const QString& url);
|
||||||
|
@ -432,6 +433,7 @@ private slots:
|
||||||
|
|
||||||
void handleSandboxStatus(QNetworkReply* reply);
|
void handleSandboxStatus(QNetworkReply* reply);
|
||||||
void switchDisplayMode();
|
void switchDisplayMode();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void initDisplay();
|
static void initDisplay();
|
||||||
void init();
|
void init();
|
||||||
|
|
|
@ -645,7 +645,8 @@ Menu::Menu() {
|
||||||
// Developer > Timing >>>
|
// Developer > Timing >>>
|
||||||
MenuWrapper* timingMenu = developerMenu->addMenu("Timing");
|
MenuWrapper* timingMenu = developerMenu->addMenu("Timing");
|
||||||
MenuWrapper* perfTimerMenu = timingMenu->addMenu("Performance Timer");
|
MenuWrapper* perfTimerMenu = timingMenu->addMenu("Performance Timer");
|
||||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayDebugTimingDetails, 0, false);
|
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayDebugTimingDetails, 0, false,
|
||||||
|
qApp, SLOT(enablePerfStats(bool)));
|
||||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::OnlyDisplayTopTen, 0, true);
|
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::OnlyDisplayTopTen, 0, true);
|
||||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false);
|
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false);
|
||||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarTiming, 0, false);
|
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarTiming, 0, false);
|
||||||
|
|
|
@ -81,6 +81,7 @@ const QString& DEFAULT_AVATAR_COLLISION_SOUND_URL = "https://hifi-public.s3.amaz
|
||||||
const float MyAvatar::ZOOM_MIN = 0.5f;
|
const float MyAvatar::ZOOM_MIN = 0.5f;
|
||||||
const float MyAvatar::ZOOM_MAX = 25.0f;
|
const float MyAvatar::ZOOM_MAX = 25.0f;
|
||||||
const float MyAvatar::ZOOM_DEFAULT = 1.5f;
|
const float MyAvatar::ZOOM_DEFAULT = 1.5f;
|
||||||
|
const float MIN_SCALE_CHANGED_DELTA = 0.001f;
|
||||||
|
|
||||||
MyAvatar::MyAvatar(QThread* thread) :
|
MyAvatar::MyAvatar(QThread* thread) :
|
||||||
Avatar(thread),
|
Avatar(thread),
|
||||||
|
@ -670,6 +671,11 @@ void MyAvatar::updateSensorToWorldMatrix() {
|
||||||
glm::mat4 desiredMat = createMatFromScaleQuatAndPos(glm::vec3(sensorToWorldScale), getWorldOrientation(), getWorldPosition());
|
glm::mat4 desiredMat = createMatFromScaleQuatAndPos(glm::vec3(sensorToWorldScale), getWorldOrientation(), getWorldPosition());
|
||||||
_sensorToWorldMatrix = desiredMat * glm::inverse(_bodySensorMatrix);
|
_sensorToWorldMatrix = desiredMat * glm::inverse(_bodySensorMatrix);
|
||||||
|
|
||||||
|
bool hasSensorToWorldScaleChanged = false;
|
||||||
|
if (fabsf(getSensorToWorldScale() - sensorToWorldScale) > MIN_SCALE_CHANGED_DELTA) {
|
||||||
|
hasSensorToWorldScaleChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
lateUpdatePalms();
|
lateUpdatePalms();
|
||||||
|
|
||||||
if (_enableDebugDrawSensorToWorldMatrix) {
|
if (_enableDebugDrawSensorToWorldMatrix) {
|
||||||
|
@ -678,9 +684,13 @@ void MyAvatar::updateSensorToWorldMatrix() {
|
||||||
}
|
}
|
||||||
|
|
||||||
_sensorToWorldMatrixCache.set(_sensorToWorldMatrix);
|
_sensorToWorldMatrixCache.set(_sensorToWorldMatrix);
|
||||||
|
|
||||||
updateJointFromController(controller::Action::LEFT_HAND, _controllerLeftHandMatrixCache);
|
updateJointFromController(controller::Action::LEFT_HAND, _controllerLeftHandMatrixCache);
|
||||||
updateJointFromController(controller::Action::RIGHT_HAND, _controllerRightHandMatrixCache);
|
updateJointFromController(controller::Action::RIGHT_HAND, _controllerRightHandMatrixCache);
|
||||||
|
|
||||||
|
if (hasSensorToWorldScaleChanged) {
|
||||||
|
emit sensorToWorldScaleChanged(sensorToWorldScale);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update avatar head rotation with sensor data
|
// Update avatar head rotation with sensor data
|
||||||
|
@ -1405,6 +1415,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene());
|
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene());
|
||||||
_headBoneSet.clear();
|
_headBoneSet.clear();
|
||||||
emit skeletonChanged();
|
emit skeletonChanged();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1440,6 +1451,7 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN
|
||||||
UserActivityLogger::getInstance().changedModel("skeleton", urlString);
|
UserActivityLogger::getInstance().changedModel("skeleton", urlString);
|
||||||
}
|
}
|
||||||
markIdentityDataChanged();
|
markIdentityDataChanged();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
||||||
|
|
|
@ -9,9 +9,12 @@
|
||||||
#include "MySkeletonModel.h"
|
#include "MySkeletonModel.h"
|
||||||
|
|
||||||
#include <avatars-renderer/Avatar.h>
|
#include <avatars-renderer/Avatar.h>
|
||||||
|
#include <DebugDraw.h>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "InterfaceLogging.h"
|
#include "InterfaceLogging.h"
|
||||||
|
#include "AnimUtil.h"
|
||||||
|
|
||||||
|
|
||||||
MySkeletonModel::MySkeletonModel(Avatar* owningAvatar, QObject* parent) : SkeletonModel(owningAvatar, parent) {
|
MySkeletonModel::MySkeletonModel(Avatar* owningAvatar, QObject* parent) : SkeletonModel(owningAvatar, parent) {
|
||||||
}
|
}
|
||||||
|
@ -30,6 +33,39 @@ Rig::CharacterControllerState convertCharacterControllerState(CharacterControlle
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) {
|
||||||
|
glm::mat4 hipsMat = myAvatar->deriveBodyFromHMDSensor();
|
||||||
|
glm::vec3 hipsPos = extractTranslation(hipsMat);
|
||||||
|
glm::quat hipsRot = glmExtractRotation(hipsMat);
|
||||||
|
|
||||||
|
glm::mat4 avatarToWorldMat = myAvatar->getTransform().getMatrix();
|
||||||
|
glm::mat4 worldToSensorMat = glm::inverse(myAvatar->getSensorToWorldMatrix());
|
||||||
|
glm::mat4 avatarToSensorMat = worldToSensorMat * avatarToWorldMat;
|
||||||
|
|
||||||
|
// dampen hips rotation, by mixing it with the avatar orientation in sensor space
|
||||||
|
const float MIX_RATIO = 0.5f;
|
||||||
|
hipsRot = safeLerp(glmExtractRotation(avatarToSensorMat), hipsRot, MIX_RATIO);
|
||||||
|
|
||||||
|
if (isFlying) {
|
||||||
|
// rotate the hips back to match the flying animation.
|
||||||
|
|
||||||
|
const float TILT_ANGLE = 0.523f;
|
||||||
|
const glm::quat tiltRot = glm::angleAxis(TILT_ANGLE, transformVectorFast(avatarToSensorMat, -Vectors::UNIT_X));
|
||||||
|
|
||||||
|
glm::vec3 headPos;
|
||||||
|
int headIndex = myAvatar->getJointIndex("Head");
|
||||||
|
if (headIndex != -1) {
|
||||||
|
headPos = transformPoint(avatarToSensorMat, myAvatar->getAbsoluteJointTranslationInObjectFrame(headIndex));
|
||||||
|
} else {
|
||||||
|
headPos = transformPoint(myAvatar->getSensorToWorldMatrix(), myAvatar->getHMDSensorPosition());
|
||||||
|
}
|
||||||
|
hipsRot = tiltRot * hipsRot;
|
||||||
|
hipsPos = headPos + tiltRot * (hipsPos - headPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AnimPose(hipsRot * Quaternions::Y_180, hipsPos);
|
||||||
|
}
|
||||||
|
|
||||||
// Called within Model::simulate call, below.
|
// Called within Model::simulate call, below.
|
||||||
void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||||
const FBXGeometry& geometry = getFBXGeometry();
|
const FBXGeometry& geometry = getFBXGeometry();
|
||||||
|
@ -124,6 +160,39 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if hips are not under direct control, estimate the hips position.
|
||||||
|
if (avatarHeadPose.isValid() && !params.primaryControllerActiveFlags[Rig::PrimaryControllerType_Hips]) {
|
||||||
|
bool isFlying = (myAvatar->getCharacterController()->getState() == CharacterController::State::Hover || myAvatar->getCharacterController()->computeCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS);
|
||||||
|
|
||||||
|
if (!_prevHipsValid) {
|
||||||
|
AnimPose hips = computeHipsInSensorFrame(myAvatar, isFlying);
|
||||||
|
_prevHips = hips;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimPose hips = computeHipsInSensorFrame(myAvatar, isFlying);
|
||||||
|
|
||||||
|
// smootly lerp hips, in sensorframe, with different coeff for horiz and vertical translation.
|
||||||
|
const float ROT_ALPHA = 0.9f;
|
||||||
|
const float TRANS_HORIZ_ALPHA = 0.9f;
|
||||||
|
const float TRANS_VERT_ALPHA = 0.1f;
|
||||||
|
float hipsY = hips.trans().y;
|
||||||
|
hips.trans() = lerp(hips.trans(), _prevHips.trans(), TRANS_HORIZ_ALPHA);
|
||||||
|
hips.trans().y = lerp(hipsY, _prevHips.trans().y, TRANS_VERT_ALPHA);
|
||||||
|
hips.rot() = safeLerp(hips.rot(), _prevHips.rot(), ROT_ALPHA);
|
||||||
|
|
||||||
|
_prevHips = hips;
|
||||||
|
_prevHipsValid = true;
|
||||||
|
|
||||||
|
glm::mat4 invRigMat = glm::inverse(myAvatar->getTransform().getMatrix() * Matrices::Y_180);
|
||||||
|
AnimPose sensorToRigPose(invRigMat * myAvatar->getSensorToWorldMatrix());
|
||||||
|
|
||||||
|
params.primaryControllerPoses[Rig::PrimaryControllerType_Hips] = sensorToRigPose * hips;
|
||||||
|
params.primaryControllerActiveFlags[Rig::PrimaryControllerType_Hips] = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
_prevHipsValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
params.isTalking = head->getTimeWithoutTalking() <= 1.5f;
|
params.isTalking = head->getTimeWithoutTalking() <= 1.5f;
|
||||||
|
|
||||||
// pass detailed torso k-dops to rig.
|
// pass detailed torso k-dops to rig.
|
||||||
|
|
|
@ -25,6 +25,9 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateFingers();
|
void updateFingers();
|
||||||
|
|
||||||
|
AnimPose _prevHips; // sensor frame
|
||||||
|
bool _prevHipsValid { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_MySkeletonModel_h
|
#endif // hifi_MySkeletonModel_h
|
||||||
|
|
|
@ -130,7 +130,7 @@ QString amountString(const QString& label, const QString&color, const QJsonValue
|
||||||
return result + QString("</font>");
|
return result + QString("</font>");
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QString MARKETPLACE_ITEMS_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace/items/";
|
static const QString MARKETPLACE_ITEMS_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/marketplace/items/";
|
||||||
void Ledger::historySuccess(QNetworkReply& reply) {
|
void Ledger::historySuccess(QNetworkReply& reply) {
|
||||||
// here we send a historyResult with some extra stuff in it
|
// here we send a historyResult with some extra stuff in it
|
||||||
// Namely, the styled text we'd like to show. The issue is the
|
// Namely, the styled text we'd like to show. The issue is the
|
||||||
|
|
|
@ -28,7 +28,7 @@ QNetworkRequest createNetworkRequest() {
|
||||||
|
|
||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
|
|
||||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL;
|
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||||
requestURL.setPath(USER_ACTIVITY_URL);
|
requestURL.setPath(USER_ACTIVITY_URL);
|
||||||
|
|
||||||
request.setUrl(requestURL);
|
request.setUrl(requestURL);
|
||||||
|
|
|
@ -23,10 +23,10 @@ static const float WEB_STYLUS_LENGTH = 0.2f;
|
||||||
static const float TABLET_MIN_HOVER_DISTANCE = -0.1f;
|
static const float TABLET_MIN_HOVER_DISTANCE = -0.1f;
|
||||||
static const float TABLET_MAX_HOVER_DISTANCE = 0.1f;
|
static const float TABLET_MAX_HOVER_DISTANCE = 0.1f;
|
||||||
static const float TABLET_MIN_TOUCH_DISTANCE = -0.1f;
|
static const float TABLET_MIN_TOUCH_DISTANCE = -0.1f;
|
||||||
static const float TABLET_MAX_TOUCH_DISTANCE = 0.01f;
|
static const float TABLET_MAX_TOUCH_DISTANCE = 0.005f;
|
||||||
|
|
||||||
static const float HOVER_HYSTERESIS = 0.01f;
|
static const float HOVER_HYSTERESIS = 0.01f;
|
||||||
static const float TOUCH_HYSTERESIS = 0.02f;
|
static const float TOUCH_HYSTERESIS = 0.001f;
|
||||||
|
|
||||||
static const float STYLUS_MOVE_DELAY = 0.33f * USECS_PER_SECOND;
|
static const float STYLUS_MOVE_DELAY = 0.33f * USECS_PER_SECOND;
|
||||||
static const float TOUCH_PRESS_TO_MOVE_DEADSPOT = 0.0481f;
|
static const float TOUCH_PRESS_TO_MOVE_DEADSPOT = 0.0481f;
|
||||||
|
|
|
@ -11,11 +11,12 @@
|
||||||
#include <QtCore/QLoggingCategory>
|
#include <QtCore/QLoggingCategory>
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
|
|
||||||
|
#include <shared/FileUtils.h>
|
||||||
#include <shared/QtHelpers.h>
|
#include <shared/QtHelpers.h>
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
#include <Trace.h>
|
|
||||||
#include <StatTracker.h>
|
|
||||||
#include <OffscreenUi.h>
|
#include <OffscreenUi.h>
|
||||||
|
#include <StatTracker.h>
|
||||||
|
#include <Trace.h>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
|
||||||
|
@ -141,6 +142,15 @@ void TestScriptingInterface::endTraceEvent(QString name) {
|
||||||
tracing::traceEvent(trace_test(), name, tracing::DurationEnd);
|
tracing::traceEvent(trace_test(), name, tracing::DurationEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestScriptingInterface::savePhysicsSimulationStats(QString originalPath) {
|
||||||
|
QString path = FileUtils::replaceDateTimeTokens(originalPath);
|
||||||
|
path = FileUtils::computeDocumentPath(path);
|
||||||
|
if (!FileUtils::canCreateFile(path)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qApp->saveNextPhysicsStats(path);
|
||||||
|
}
|
||||||
|
|
||||||
void TestScriptingInterface::profileRange(const QString& name, QScriptValue fn) {
|
void TestScriptingInterface::profileRange(const QString& name, QScriptValue fn) {
|
||||||
PROFILE_RANGE(script, name);
|
PROFILE_RANGE(script, name);
|
||||||
fn.call();
|
fn.call();
|
||||||
|
|
|
@ -71,6 +71,11 @@ public slots:
|
||||||
|
|
||||||
void endTraceEvent(QString name);
|
void endTraceEvent(QString name);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Write detailed timing stats of next physics stepSimulation() to filename
|
||||||
|
*/
|
||||||
|
void savePhysicsSimulationStats(QString filename);
|
||||||
|
|
||||||
Q_INVOKABLE void profileRange(const QString& name, QScriptValue function);
|
Q_INVOKABLE void profileRange(const QString& name, QScriptValue function);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -30,7 +30,7 @@ public:
|
||||||
bool forwardEnabled() { return _forwardEnabled; }
|
bool forwardEnabled() { return _forwardEnabled; }
|
||||||
bool useFeed() { return _useFeed; }
|
bool useFeed() { return _useFeed; }
|
||||||
void setUseFeed(bool useFeed) { if (_useFeed != useFeed) { _useFeed = useFeed; emit useFeedChanged(); } }
|
void setUseFeed(bool useFeed) { if (_useFeed != useFeed) { _useFeed = useFeed; emit useFeedChanged(); } }
|
||||||
QString metaverseServerUrl() { return NetworkingConstants::METAVERSE_SERVER_URL.toString(); }
|
QString metaverseServerUrl() { return NetworkingConstants::METAVERSE_SERVER_URL().toString(); }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void backEnabledChanged();
|
void backEnabledChanged();
|
||||||
|
|
|
@ -78,6 +78,8 @@ bool Stats::includeTimingRecord(const QString& name) {
|
||||||
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming);
|
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming);
|
||||||
} else if (name.startsWith("/paintGL/")) {
|
} else if (name.startsWith("/paintGL/")) {
|
||||||
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming);
|
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming);
|
||||||
|
} else if (name.startsWith("step/")) {
|
||||||
|
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsSimulationTiming);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -289,7 +289,7 @@ void ContextOverlayInterface::openInspectionCertificate() {
|
||||||
QNetworkRequest networkRequest;
|
QNetworkRequest networkRequest;
|
||||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||||
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL;
|
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||||
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer");
|
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer");
|
||||||
QJsonObject request;
|
QJsonObject request;
|
||||||
request["certificate_id"] = entityProperties.getCertificateID();
|
request["certificate_id"] = entityProperties.getCertificateID();
|
||||||
|
@ -359,7 +359,7 @@ void ContextOverlayInterface::openInspectionCertificate() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QString MARKETPLACE_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace/items/";
|
static const QString MARKETPLACE_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/marketplace/items/";
|
||||||
|
|
||||||
void ContextOverlayInterface::openMarketplace() {
|
void ContextOverlayInterface::openMarketplace() {
|
||||||
// lets open the tablet and go to the current item in
|
// lets open the tablet and go to the current item in
|
||||||
|
|
|
@ -1641,9 +1641,17 @@ void Rig::initAnimGraph(const QUrl& url) {
|
||||||
// load the anim graph
|
// load the anim graph
|
||||||
_animLoader.reset(new AnimNodeLoader(url));
|
_animLoader.reset(new AnimNodeLoader(url));
|
||||||
_animLoading = true;
|
_animLoading = true;
|
||||||
connect(_animLoader.get(), &AnimNodeLoader::success, [this](AnimNode::Pointer nodeIn) {
|
std::weak_ptr<AnimSkeleton> weakSkeletonPtr = _animSkeleton;
|
||||||
|
connect(_animLoader.get(), &AnimNodeLoader::success, [this, weakSkeletonPtr](AnimNode::Pointer nodeIn) {
|
||||||
_animNode = nodeIn;
|
_animNode = nodeIn;
|
||||||
_animNode->setSkeleton(_animSkeleton);
|
|
||||||
|
// abort load if the previous skeleton was deleted.
|
||||||
|
auto sharedSkeletonPtr = weakSkeletonPtr.lock();
|
||||||
|
if (!sharedSkeletonPtr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_animNode->setSkeleton(sharedSkeletonPtr);
|
||||||
|
|
||||||
if (_userAnimState.clipNodeEnum != UserAnimState::None) {
|
if (_userAnimState.clipNodeEnum != UserAnimState::None) {
|
||||||
// restore the user animation we had before reset.
|
// restore the user animation we had before reset.
|
||||||
|
@ -1651,6 +1659,7 @@ void Rig::initAnimGraph(const QUrl& url) {
|
||||||
_userAnimState = { UserAnimState::None, "", 30.0f, false, 0.0f, 0.0f };
|
_userAnimState = { UserAnimState::None, "", 30.0f, false, 0.0f, 0.0f };
|
||||||
overrideAnimation(origState.url, origState.fps, origState.loop, origState.firstFrame, origState.lastFrame);
|
overrideAnimation(origState.url, origState.fps, origState.loop, origState.firstFrame, origState.lastFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
// restore the role animations we had before reset.
|
// restore the role animations we had before reset.
|
||||||
for (auto& roleAnimState : _roleAnimStates) {
|
for (auto& roleAnimState : _roleAnimStates) {
|
||||||
auto roleState = roleAnimState.second;
|
auto roleState = roleAnimState.second;
|
||||||
|
|
|
@ -31,7 +31,7 @@ class AnimInverseKinematics;
|
||||||
// Rig instances are reentrant.
|
// Rig instances are reentrant.
|
||||||
// However only specific methods thread-safe. Noted below.
|
// However only specific methods thread-safe. Noted below.
|
||||||
|
|
||||||
class Rig : public QObject, public std::enable_shared_from_this<Rig> {
|
class Rig : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
struct StateHandler {
|
struct StateHandler {
|
||||||
|
|
|
@ -96,9 +96,13 @@ void SoundProcessor::run() {
|
||||||
QByteArray outputAudioByteArray;
|
QByteArray outputAudioByteArray;
|
||||||
|
|
||||||
int sampleRate = interpretAsWav(rawAudioByteArray, outputAudioByteArray);
|
int sampleRate = interpretAsWav(rawAudioByteArray, outputAudioByteArray);
|
||||||
if (sampleRate != 0) {
|
if (sampleRate == 0) {
|
||||||
downSample(outputAudioByteArray, sampleRate);
|
qCDebug(audio) << "Unsupported WAV file type";
|
||||||
|
emit onError(300, "Failed to load sound file, reason: unsupported WAV file type");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
downSample(outputAudioByteArray, sampleRate);
|
||||||
} else if (fileName.endsWith(RAW_EXTENSION)) {
|
} else if (fileName.endsWith(RAW_EXTENSION)) {
|
||||||
// check if this was a stereo raw file
|
// check if this was a stereo raw file
|
||||||
// since it's raw the only way for us to know that is if the file was called .stereo.raw
|
// since it's raw the only way for us to know that is if the file was called .stereo.raw
|
||||||
|
|
|
@ -251,10 +251,10 @@ void EntityTreeRenderer::shutdown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, render::Transaction& transaction) {
|
void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, render::Transaction& transaction) {
|
||||||
PROFILE_RANGE_EX(simulation_physics, "Add", 0xffff00ff, (uint64_t)_entitiesToAdd.size());
|
PROFILE_RANGE_EX(simulation_physics, "AddToScene", 0xffff00ff, (uint64_t)_entitiesToAdd.size());
|
||||||
PerformanceTimer pt("add");
|
PerformanceTimer pt("add");
|
||||||
// Clear any expired entities
|
// Clear any expired entities
|
||||||
// FIXME should be able to use std::remove_if, but it fails due to some
|
// FIXME should be able to use std::remove_if, but it fails due to some
|
||||||
// weird compilation error related to EntityItemID assignment operators
|
// weird compilation error related to EntityItemID assignment operators
|
||||||
for (auto itr = _entitiesToAdd.begin(); _entitiesToAdd.end() != itr; ) {
|
for (auto itr = _entitiesToAdd.begin(); _entitiesToAdd.end() != itr; ) {
|
||||||
if (itr->second.expired()) {
|
if (itr->second.expired()) {
|
||||||
|
@ -272,7 +272,7 @@ void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, r
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path to the parent transforms is not valid,
|
// Path to the parent transforms is not valid,
|
||||||
// don't add to the scene graph yet
|
// don't add to the scene graph yet
|
||||||
if (!entity->isParentPathComplete()) {
|
if (!entity->isParentPathComplete()) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -296,7 +296,7 @@ void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, r
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene, const ViewFrustum& view, render::Transaction& transaction) {
|
void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene, const ViewFrustum& view, render::Transaction& transaction) {
|
||||||
PROFILE_RANGE_EX(simulation_physics, "Change", 0xffff00ff, (uint64_t)_changedEntities.size());
|
PROFILE_RANGE_EX(simulation_physics, "ChangeInScene", 0xffff00ff, (uint64_t)_changedEntities.size());
|
||||||
PerformanceTimer pt("change");
|
PerformanceTimer pt("change");
|
||||||
std::unordered_set<EntityItemID> changedEntities;
|
std::unordered_set<EntityItemID> changedEntities;
|
||||||
_changedEntitiesGuard.withWriteLock([&] {
|
_changedEntitiesGuard.withWriteLock([&] {
|
||||||
|
@ -402,6 +402,8 @@ void EntityTreeRenderer::update(bool simulate) {
|
||||||
PerformanceTimer perfTimer("ETRupdate");
|
PerformanceTimer perfTimer("ETRupdate");
|
||||||
if (_tree && !_shuttingDown) {
|
if (_tree && !_shuttingDown) {
|
||||||
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
|
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
|
||||||
|
|
||||||
|
// here we update _currentFrame and _lastAnimated and sync with the server properties.
|
||||||
tree->update(simulate);
|
tree->update(simulate);
|
||||||
|
|
||||||
// Update the rendereable entities as needed
|
// Update the rendereable entities as needed
|
||||||
|
@ -736,7 +738,7 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
PickRay ray = _viewState->computePickRay(event->x(), event->y());
|
PickRay ray = _viewState->computePickRay(event->x(), event->y());
|
||||||
RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID);
|
RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID);
|
||||||
if (rayPickResult.intersects && rayPickResult.entity) {
|
if (rayPickResult.intersects && rayPickResult.entity) {
|
||||||
//qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
|
// qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
|
||||||
|
|
||||||
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
|
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
|
||||||
PointerEvent pointerEvent(PointerEvent::Release, PointerManager::MOUSE_POINTER_ID,
|
PointerEvent pointerEvent(PointerEvent::Release, PointerManager::MOUSE_POINTER_ID,
|
||||||
|
|
|
@ -63,13 +63,17 @@ bool ModelEntityWrapper::isModelLoaded() const {
|
||||||
EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||||
EntityItemPointer entity(new RenderableModelEntityItem(entityID, properties.getDimensionsInitialized()),
|
EntityItemPointer entity(new RenderableModelEntityItem(entityID, properties.getDimensionsInitialized()),
|
||||||
[](EntityItem* ptr) { ptr->deleteLater(); });
|
[](EntityItem* ptr) { ptr->deleteLater(); });
|
||||||
|
|
||||||
entity->setProperties(properties);
|
entity->setProperties(properties);
|
||||||
|
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized) :
|
RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized) :
|
||||||
ModelEntityWrapper(entityItemID),
|
ModelEntityWrapper(entityItemID),
|
||||||
_dimensionsInitialized(dimensionsInitialized) {
|
_dimensionsInitialized(dimensionsInitialized) {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderableModelEntityItem::~RenderableModelEntityItem() { }
|
RenderableModelEntityItem::~RenderableModelEntityItem() { }
|
||||||
|
@ -464,7 +468,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
||||||
shapeInfo.setParams(type, dimensions, getCompoundShapeURL());
|
shapeInfo.setParams(type, dimensions, getCompoundShapeURL());
|
||||||
} else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
|
} else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
|
||||||
// TODO: assert we never fall in here when model not fully loaded
|
// TODO: assert we never fall in here when model not fully loaded
|
||||||
//assert(_model && _model->isLoaded());
|
// assert(_model && _model->isLoaded());
|
||||||
|
|
||||||
updateModelBounds();
|
updateModelBounds();
|
||||||
model->updateGeometry();
|
model->updateGeometry();
|
||||||
|
@ -974,9 +978,6 @@ void ModelEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entit
|
||||||
entity->setModel({});
|
entity->setModel({});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) {
|
|
||||||
return !(a == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
||||||
if (!_animation || !_animation->isLoaded()) {
|
if (!_animation || !_animation->isLoaded()) {
|
||||||
|
@ -991,19 +992,12 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_lastAnimated) {
|
|
||||||
_lastAnimated = usecTimestampNow();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto now = usecTimestampNow();
|
|
||||||
auto interval = now - _lastAnimated;
|
|
||||||
_lastAnimated = now;
|
|
||||||
float deltaTime = (float)interval / (float)USECS_PER_SECOND;
|
|
||||||
_currentFrame += (deltaTime * _renderAnimationProperties.getFPS());
|
|
||||||
|
|
||||||
{
|
{
|
||||||
int animationCurrentFrame = (int)(glm::floor(_currentFrame)) % frameCount;
|
// the current frame is set on the server in update() in ModelEntityItem.cpp
|
||||||
|
int animationCurrentFrame = (int)(glm::floor(entity->getAnimationCurrentFrame()));
|
||||||
|
|
||||||
|
// in the case where the last frame is greater than the framecount then clamp
|
||||||
|
// it to the end of the animation until it loops around.
|
||||||
if (animationCurrentFrame < 0 || animationCurrentFrame > frameCount) {
|
if (animationCurrentFrame < 0 || animationCurrentFrame > frameCount) {
|
||||||
animationCurrentFrame = 0;
|
animationCurrentFrame = 0;
|
||||||
}
|
}
|
||||||
|
@ -1039,10 +1033,10 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
||||||
glm::mat4 translationMat;
|
glm::mat4 translationMat;
|
||||||
|
|
||||||
if (allowTranslation) {
|
if (allowTranslation) {
|
||||||
if(index < translations.size()){
|
if (index < translations.size()) {
|
||||||
translationMat = glm::translate(translations[index]);
|
translationMat = glm::translate(translations[index]);
|
||||||
}
|
}
|
||||||
} else if (index < animationJointNames.size()){
|
} 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
|
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)) {
|
if (originalFbxIndices.contains(jointName)) {
|
||||||
|
@ -1317,25 +1311,17 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
||||||
if (model->getRenderItemsNeedUpdate()) {
|
if (model->getRenderItemsNeedUpdate()) {
|
||||||
model->updateRenderItems();
|
model->updateRenderItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
// The code to deal with the change of properties is now in ModelEntityItem.cpp
|
||||||
DETAILED_PROFILE_RANGE(simulation_physics, "CheckAnimation");
|
// That is where _currentFrame and _lastAnimated were updated.
|
||||||
// make a copy of the animation properites
|
|
||||||
auto newAnimationProperties = entity->getAnimationProperties();
|
|
||||||
if (newAnimationProperties != _renderAnimationProperties) {
|
|
||||||
withWriteLock([&] {
|
|
||||||
_renderAnimationProperties = newAnimationProperties;
|
|
||||||
_currentFrame = _renderAnimationProperties.getCurrentFrame();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_animating) {
|
if (_animating) {
|
||||||
DETAILED_PROFILE_RANGE(simulation_physics, "Animate");
|
DETAILED_PROFILE_RANGE(simulation_physics, "Animate");
|
||||||
if (!jointsMapped()) {
|
if (!jointsMapped()) {
|
||||||
mapJoints(entity, model->getJointNames());
|
mapJoints(entity, model->getJointNames());
|
||||||
}
|
}
|
||||||
animate(entity);
|
if (!(entity->getAnimationFirstFrame() < 0) && !(entity->getAnimationFirstFrame() > entity->getAnimationLastFrame())) {
|
||||||
|
animate(entity);
|
||||||
|
}
|
||||||
emit requestRenderUpdate();
|
emit requestRenderUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace render { namespace entities {
|
||||||
class ModelEntityRenderer;
|
class ModelEntityRenderer;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
//#define MODEL_ENTITY_USE_FADE_EFFECT
|
// #define MODEL_ENTITY_USE_FADE_EFFECT
|
||||||
class ModelEntityWrapper : public ModelEntityItem {
|
class ModelEntityWrapper : public ModelEntityItem {
|
||||||
using Parent = ModelEntityItem;
|
using Parent = ModelEntityItem;
|
||||||
friend class render::entities::ModelEntityRenderer;
|
friend class render::entities::ModelEntityRenderer;
|
||||||
|
@ -133,7 +133,7 @@ class ModelEntityRenderer : public TypedEntityRenderer<RenderableModelEntityItem
|
||||||
friend class EntityRenderer;
|
friend class EntityRenderer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ModelEntityRenderer(const EntityItemPointer& entity) : Parent(entity) { }
|
ModelEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override;
|
virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override;
|
||||||
|
@ -184,8 +184,6 @@ private:
|
||||||
bool _shouldHighlight { false };
|
bool _shouldHighlight { false };
|
||||||
bool _animating { false };
|
bool _animating { false };
|
||||||
uint64_t _lastAnimated { 0 };
|
uint64_t _lastAnimated { 0 };
|
||||||
float _currentFrame { 0 };
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // namespace
|
} } // namespace
|
||||||
|
|
|
@ -22,15 +22,28 @@ const float AnimationPropertyGroup::MAXIMUM_POSSIBLE_FRAME = 100000.0f;
|
||||||
|
|
||||||
bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) {
|
bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) {
|
||||||
return
|
return
|
||||||
(a._url == b._url) &&
|
|
||||||
(a._currentFrame == b._currentFrame) &&
|
(a._currentFrame == b._currentFrame) &&
|
||||||
(a._running == b._running) &&
|
(a._running == b._running) &&
|
||||||
(a._loop == b._loop) &&
|
(a._loop == b._loop) &&
|
||||||
|
(a._hold == b._hold) &&
|
||||||
(a._firstFrame == b._firstFrame) &&
|
(a._firstFrame == b._firstFrame) &&
|
||||||
(a._lastFrame == b._lastFrame) &&
|
(a._lastFrame == b._lastFrame) &&
|
||||||
(a._hold == b._hold);
|
(a._url == b._url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) {
|
||||||
|
return
|
||||||
|
(a._currentFrame != b._currentFrame) ||
|
||||||
|
(a._running != b._running) ||
|
||||||
|
(a._loop != b._loop) ||
|
||||||
|
(a._hold != b._hold) ||
|
||||||
|
(a._firstFrame != b._firstFrame) ||
|
||||||
|
(a._lastFrame != b._lastFrame) ||
|
||||||
|
(a._url != b._url);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
|
void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
|
||||||
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, Animation, animation, URL, url);
|
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, Animation, animation, URL, url);
|
||||||
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation);
|
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation);
|
||||||
|
@ -130,6 +143,7 @@ void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
|
||||||
allowTranslation = settingsMap["allowTranslation"].toBool();
|
allowTranslation = settingsMap["allowTranslation"].toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
setAllowTranslation(allowTranslation);
|
setAllowTranslation(allowTranslation);
|
||||||
setFPS(fps);
|
setFPS(fps);
|
||||||
setCurrentFrame(currentFrame);
|
setCurrentFrame(currentFrame);
|
||||||
|
|
|
@ -89,6 +89,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b);
|
friend bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b);
|
||||||
|
friend bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b);
|
||||||
void setFromOldAnimationSettings(const QString& value);
|
void setFromOldAnimationSettings(const QString& value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
#include <Octree.h>
|
#include <Octree.h>
|
||||||
#include <PhysicsHelpers.h>
|
#include <PhysicsHelpers.h>
|
||||||
|
#include <Profile.h>
|
||||||
#include <RegisteredMetaTypes.h>
|
#include <RegisteredMetaTypes.h>
|
||||||
#include <SharedUtil.h> // usecTimestampNow()
|
#include <SharedUtil.h> // usecTimestampNow()
|
||||||
#include <LogHandler.h>
|
#include <LogHandler.h>
|
||||||
|
@ -984,6 +985,7 @@ void EntityItem::setCollisionSoundURL(const QString& value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::simulate(const quint64& now) {
|
void EntityItem::simulate(const quint64& now) {
|
||||||
|
DETAILED_PROFILE_RANGE(simulation_physics, "Simulate");
|
||||||
if (getLastSimulated() == 0) {
|
if (getLastSimulated() == 0) {
|
||||||
setLastSimulated(now);
|
setLastSimulated(now);
|
||||||
}
|
}
|
||||||
|
@ -1039,6 +1041,7 @@ void EntityItem::simulate(const quint64& now) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityItem::stepKinematicMotion(float timeElapsed) {
|
bool EntityItem::stepKinematicMotion(float timeElapsed) {
|
||||||
|
DETAILED_PROFILE_RANGE(simulation_physics, "StepKinematicMotion");
|
||||||
// get all the data
|
// get all the data
|
||||||
Transform transform;
|
Transform transform;
|
||||||
glm::vec3 linearVelocity;
|
glm::vec3 linearVelocity;
|
||||||
|
@ -2840,7 +2843,7 @@ void EntityItem::retrieveMarketplacePublicKey() {
|
||||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||||
QNetworkRequest networkRequest;
|
QNetworkRequest networkRequest;
|
||||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL;
|
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||||
requestURL.setPath("/api/v1/commerce/marketplace_key");
|
requestURL.setPath("/api/v1/commerce/marketplace_key");
|
||||||
QJsonObject request;
|
QJsonObject request;
|
||||||
networkRequest.setUrl(requestURL);
|
networkRequest.setUrl(requestURL);
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
#include <openssl/ecdsa.h>
|
#include <openssl/ecdsa.h>
|
||||||
#include <NetworkingConstants.h>
|
|
||||||
#include <NetworkAccessManager.h>
|
#include <NetworkAccessManager.h>
|
||||||
#include <QtNetwork/QNetworkReply>
|
#include <QtNetwork/QNetworkReply>
|
||||||
#include <QtNetwork/QNetworkRequest>
|
#include <QtNetwork/QNetworkRequest>
|
||||||
|
|
|
@ -29,7 +29,6 @@ void EntitySimulation::setEntityTree(EntityTreePointer tree) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntitySimulation::updateEntities() {
|
void EntitySimulation::updateEntities() {
|
||||||
PROFILE_RANGE(simulation_physics, "ES::updateEntities");
|
|
||||||
QMutexLocker lock(&_mutex);
|
QMutexLocker lock(&_mutex);
|
||||||
quint64 now = usecTimestampNow();
|
quint64 now = usecTimestampNow();
|
||||||
|
|
||||||
|
@ -38,12 +37,7 @@ void EntitySimulation::updateEntities() {
|
||||||
callUpdateOnEntitiesThatNeedIt(now);
|
callUpdateOnEntitiesThatNeedIt(now);
|
||||||
moveSimpleKinematics(now);
|
moveSimpleKinematics(now);
|
||||||
updateEntitiesInternal(now);
|
updateEntitiesInternal(now);
|
||||||
|
sortEntitiesThatMoved();
|
||||||
{
|
|
||||||
PROFILE_RANGE(simulation_physics, "Sort");
|
|
||||||
PerformanceTimer perfTimer("sortingEntities");
|
|
||||||
sortEntitiesThatMoved();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntitySimulation::takeEntitiesToDelete(VectorOfEntities& entitiesToDelete) {
|
void EntitySimulation::takeEntitiesToDelete(VectorOfEntities& entitiesToDelete) {
|
||||||
|
@ -101,6 +95,7 @@ void EntitySimulation::changeEntityInternal(EntityItemPointer entity) {
|
||||||
// protected
|
// protected
|
||||||
void EntitySimulation::expireMortalEntities(const quint64& now) {
|
void EntitySimulation::expireMortalEntities(const quint64& now) {
|
||||||
if (now > _nextExpiry) {
|
if (now > _nextExpiry) {
|
||||||
|
PROFILE_RANGE_EX(simulation_physics, "ExpireMortals", 0xffff00ff, (uint64_t)_mortalEntities.size());
|
||||||
// only search for expired entities if we expect to find one
|
// only search for expired entities if we expect to find one
|
||||||
_nextExpiry = quint64(-1);
|
_nextExpiry = quint64(-1);
|
||||||
QMutexLocker lock(&_mutex);
|
QMutexLocker lock(&_mutex);
|
||||||
|
@ -146,6 +141,7 @@ void EntitySimulation::callUpdateOnEntitiesThatNeedIt(const quint64& now) {
|
||||||
|
|
||||||
// protected
|
// protected
|
||||||
void EntitySimulation::sortEntitiesThatMoved() {
|
void EntitySimulation::sortEntitiesThatMoved() {
|
||||||
|
PROFILE_RANGE_EX(simulation_physics, "SortTree", 0xffff00ff, (uint64_t)_entitiesToSort.size());
|
||||||
// NOTE: this is only for entities that have been moved by THIS EntitySimulation.
|
// NOTE: this is only for entities that have been moved by THIS EntitySimulation.
|
||||||
// External changes to entity position/shape are expected to be sorted outside of the EntitySimulation.
|
// External changes to entity position/shape are expected to be sorted outside of the EntitySimulation.
|
||||||
MovingEntitiesOperator moveOperator;
|
MovingEntitiesOperator moveOperator;
|
||||||
|
@ -265,7 +261,7 @@ void EntitySimulation::clearEntities() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntitySimulation::moveSimpleKinematics(const quint64& now) {
|
void EntitySimulation::moveSimpleKinematics(const quint64& now) {
|
||||||
PROFILE_RANGE_EX(simulation_physics, "Kinematics", 0xffff00ff, (uint64_t)_simpleKinematicEntities.size());
|
PROFILE_RANGE_EX(simulation_physics, "MoveSimples", 0xffff00ff, (uint64_t)_simpleKinematicEntities.size());
|
||||||
SetOfEntities::iterator itemItr = _simpleKinematicEntities.begin();
|
SetOfEntities::iterator itemItr = _simpleKinematicEntities.begin();
|
||||||
while (itemItr != _simpleKinematicEntities.end()) {
|
while (itemItr != _simpleKinematicEntities.end()) {
|
||||||
EntityItemPointer entity = *itemItr;
|
EntityItemPointer entity = *itemItr;
|
||||||
|
|
|
@ -1308,7 +1308,7 @@ void EntityTree::validatePop(const QString& certID, const EntityItemID& entityIt
|
||||||
QNetworkRequest networkRequest;
|
QNetworkRequest networkRequest;
|
||||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||||
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL;
|
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||||
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer");
|
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer");
|
||||||
QJsonObject request;
|
QJsonObject request;
|
||||||
request["certificate_id"] = certID;
|
request["certificate_id"] = certID;
|
||||||
|
@ -1770,24 +1770,26 @@ void EntityTree::addToNeedsParentFixupList(EntityItemPointer entity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTree::update(bool simulate) {
|
void EntityTree::update(bool simulate) {
|
||||||
PROFILE_RANGE(simulation_physics, "ET::update");
|
PROFILE_RANGE(simulation_physics, "UpdateTree");
|
||||||
fixupNeedsParentFixups();
|
fixupNeedsParentFixups();
|
||||||
if (simulate && _simulation) {
|
if (simulate && _simulation) {
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
_simulation->updateEntities();
|
_simulation->updateEntities();
|
||||||
VectorOfEntities pendingDeletes;
|
{
|
||||||
_simulation->takeEntitiesToDelete(pendingDeletes);
|
PROFILE_RANGE(simulation_physics, "Deletes");
|
||||||
|
VectorOfEntities pendingDeletes;
|
||||||
|
_simulation->takeEntitiesToDelete(pendingDeletes);
|
||||||
|
if (pendingDeletes.size() > 0) {
|
||||||
|
// translate into list of ID's
|
||||||
|
QSet<EntityItemID> idsToDelete;
|
||||||
|
|
||||||
if (pendingDeletes.size() > 0) {
|
for (auto entity : pendingDeletes) {
|
||||||
// translate into list of ID's
|
idsToDelete.insert(entity->getEntityItemID());
|
||||||
QSet<EntityItemID> idsToDelete;
|
}
|
||||||
|
|
||||||
for (auto entity : pendingDeletes) {
|
// delete these things the roundabout way
|
||||||
idsToDelete.insert(entity->getEntityItemID());
|
deleteEntities(idsToDelete, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete these things the roundabout way
|
|
||||||
deleteEntities(idsToDelete, true);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,8 @@ EntityItemPointer ModelEntityItem::factory(const EntityItemID& entityID, const E
|
||||||
|
|
||||||
ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID)
|
ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID)
|
||||||
{
|
{
|
||||||
|
_lastAnimated = usecTimestampNow();
|
||||||
|
// set the last animated when interface (re)starts
|
||||||
_type = EntityTypes::Model;
|
_type = EntityTypes::Model;
|
||||||
_lastKnownCurrentFrame = -1;
|
_lastKnownCurrentFrame = -1;
|
||||||
_color[0] = _color[1] = _color[2] = 0;
|
_color[0] = _color[1] = _color[2] = 0;
|
||||||
|
@ -186,6 +188,105 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// added update function back for property fix
|
||||||
|
void ModelEntityItem::update(const quint64& now) {
|
||||||
|
|
||||||
|
{
|
||||||
|
auto currentAnimationProperties = this->getAnimationProperties();
|
||||||
|
|
||||||
|
if (_previousAnimationProperties != currentAnimationProperties) {
|
||||||
|
withWriteLock([&] {
|
||||||
|
// if we hit start animation or change the first or last frame then restart the animation
|
||||||
|
if ((currentAnimationProperties.getFirstFrame() != _previousAnimationProperties.getFirstFrame()) ||
|
||||||
|
(currentAnimationProperties.getLastFrame() != _previousAnimationProperties.getLastFrame()) ||
|
||||||
|
(currentAnimationProperties.getRunning() && !_previousAnimationProperties.getRunning())) {
|
||||||
|
|
||||||
|
// when we start interface and the property is are set then the current frame is initialized to -1
|
||||||
|
if (_currentFrame < 0) {
|
||||||
|
// don't reset _lastAnimated here because we need the timestamp from the ModelEntityItem constructor for when the properties were set
|
||||||
|
_currentFrame = currentAnimationProperties.getCurrentFrame();
|
||||||
|
setAnimationCurrentFrame(_currentFrame);
|
||||||
|
} else {
|
||||||
|
_lastAnimated = usecTimestampNow();
|
||||||
|
_currentFrame = currentAnimationProperties.getFirstFrame();
|
||||||
|
setAnimationCurrentFrame(currentAnimationProperties.getFirstFrame());
|
||||||
|
}
|
||||||
|
} else if (!currentAnimationProperties.getRunning() && _previousAnimationProperties.getRunning()) {
|
||||||
|
_currentFrame = currentAnimationProperties.getFirstFrame();
|
||||||
|
setAnimationCurrentFrame(_currentFrame);
|
||||||
|
} else if (currentAnimationProperties.getCurrentFrame() != _previousAnimationProperties.getCurrentFrame()) {
|
||||||
|
// don't reset _lastAnimated here because the currentFrame was set with the previous setting of _lastAnimated
|
||||||
|
_currentFrame = currentAnimationProperties.getCurrentFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
_previousAnimationProperties = this->getAnimationProperties();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAnimatingSomething()) {
|
||||||
|
if (!(getAnimationFirstFrame() < 0) && !(getAnimationFirstFrame() > getAnimationLastFrame())) {
|
||||||
|
updateFrameCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityItem::update(now);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModelEntityItem::needsToCallUpdate() const {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelEntityItem::updateFrameCount() {
|
||||||
|
|
||||||
|
if (_currentFrame < 0.0f) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_lastAnimated) {
|
||||||
|
_lastAnimated = usecTimestampNow();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto now = usecTimestampNow();
|
||||||
|
|
||||||
|
// update the interval since the last animation.
|
||||||
|
auto interval = now - _lastAnimated;
|
||||||
|
_lastAnimated = now;
|
||||||
|
|
||||||
|
// if fps is negative then increment timestamp and return.
|
||||||
|
if (getAnimationFPS() < 0.0f) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int updatedFrameCount = getAnimationLastFrame() - getAnimationFirstFrame() + 1;
|
||||||
|
|
||||||
|
if (!getAnimationHold() && getAnimationIsPlaying()) {
|
||||||
|
float deltaTime = (float)interval / (float)USECS_PER_SECOND;
|
||||||
|
_currentFrame += (deltaTime * getAnimationFPS());
|
||||||
|
if (_currentFrame > getAnimationLastFrame()) {
|
||||||
|
if (getAnimationLoop()) {
|
||||||
|
_currentFrame = getAnimationFirstFrame() + (int)(glm::floor(_currentFrame - getAnimationFirstFrame())) % (updatedFrameCount - 1);
|
||||||
|
} else {
|
||||||
|
_currentFrame = getAnimationLastFrame();
|
||||||
|
}
|
||||||
|
} else if (_currentFrame < getAnimationFirstFrame()) {
|
||||||
|
if (getAnimationFirstFrame() < 0) {
|
||||||
|
_currentFrame = 0;
|
||||||
|
} else {
|
||||||
|
_currentFrame = getAnimationFirstFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// qCDebug(entities) << "in update frame " << _currentFrame;
|
||||||
|
setAnimationCurrentFrame(_currentFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void ModelEntityItem::debugDump() const {
|
void ModelEntityItem::debugDump() const {
|
||||||
qCDebug(entities) << "ModelEntityItem id:" << getEntityItemID();
|
qCDebug(entities) << "ModelEntityItem id:" << getEntityItemID();
|
||||||
qCDebug(entities) << " edited ago:" << getEditedAgo();
|
qCDebug(entities) << " edited ago:" << getEditedAgo();
|
||||||
|
@ -538,6 +639,13 @@ void ModelEntityItem::setAnimationLoop(bool loop) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ModelEntityItem::getAnimationLoop() const {
|
||||||
|
return resultWithReadLock<bool>([&] {
|
||||||
|
return _animationProperties.getLoop();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ModelEntityItem::setAnimationHold(bool hold) {
|
void ModelEntityItem::setAnimationHold(bool hold) {
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
_animationProperties.setHold(hold);
|
_animationProperties.setHold(hold);
|
||||||
|
@ -573,8 +681,9 @@ float ModelEntityItem::getAnimationLastFrame() const {
|
||||||
return _animationProperties.getLastFrame();
|
return _animationProperties.getLastFrame();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelEntityItem::getAnimationIsPlaying() const {
|
bool ModelEntityItem::getAnimationIsPlaying() const {
|
||||||
return resultWithReadLock<float>([&] {
|
return resultWithReadLock<bool>([&] {
|
||||||
return _animationProperties.getRunning();
|
return _animationProperties.getRunning();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -585,8 +694,15 @@ float ModelEntityItem::getAnimationCurrentFrame() const {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelEntityItem::isAnimatingSomething() const {
|
float ModelEntityItem::getAnimationFPS() const {
|
||||||
return resultWithReadLock<float>([&] {
|
return resultWithReadLock<float>([&] {
|
||||||
|
return _animationProperties.getFPS();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ModelEntityItem::isAnimatingSomething() const {
|
||||||
|
return resultWithReadLock<bool>([&] {
|
||||||
return !_animationProperties.getURL().isEmpty() &&
|
return !_animationProperties.getURL().isEmpty() &&
|
||||||
_animationProperties.getRunning() &&
|
_animationProperties.getRunning() &&
|
||||||
(_animationProperties.getFPS() != 0.0f);
|
(_animationProperties.getFPS() != 0.0f);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <ThreadSafeValueCache.h>
|
#include <ThreadSafeValueCache.h>
|
||||||
#include "AnimationPropertyGroup.h"
|
#include "AnimationPropertyGroup.h"
|
||||||
|
|
||||||
|
|
||||||
class ModelEntityItem : public EntityItem {
|
class ModelEntityItem : public EntityItem {
|
||||||
public:
|
public:
|
||||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||||
|
@ -46,8 +47,11 @@ public:
|
||||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
||||||
bool& somethingChanged) override;
|
bool& somethingChanged) override;
|
||||||
|
|
||||||
//virtual void update(const quint64& now) override;
|
// update() and needstocallupdate() added back for the entity property fix
|
||||||
//virtual bool needsToCallUpdate() const override;
|
virtual void update(const quint64& now) override;
|
||||||
|
virtual bool needsToCallUpdate() const override;
|
||||||
|
void updateFrameCount();
|
||||||
|
|
||||||
virtual void debugDump() const override;
|
virtual void debugDump() const override;
|
||||||
|
|
||||||
void setShapeType(ShapeType type) override;
|
void setShapeType(ShapeType type) override;
|
||||||
|
@ -90,6 +94,7 @@ public:
|
||||||
bool getAnimationAllowTranslation() const { return _animationProperties.getAllowTranslation(); };
|
bool getAnimationAllowTranslation() const { return _animationProperties.getAllowTranslation(); };
|
||||||
|
|
||||||
void setAnimationLoop(bool loop);
|
void setAnimationLoop(bool loop);
|
||||||
|
bool getAnimationLoop() const;
|
||||||
|
|
||||||
void setAnimationHold(bool hold);
|
void setAnimationHold(bool hold);
|
||||||
bool getAnimationHold() const;
|
bool getAnimationHold() const;
|
||||||
|
@ -102,6 +107,7 @@ public:
|
||||||
|
|
||||||
bool getAnimationIsPlaying() const;
|
bool getAnimationIsPlaying() const;
|
||||||
float getAnimationCurrentFrame() const;
|
float getAnimationCurrentFrame() const;
|
||||||
|
float getAnimationFPS() const;
|
||||||
bool isAnimatingSomething() const;
|
bool isAnimatingSomething() const;
|
||||||
|
|
||||||
static const QString DEFAULT_TEXTURES;
|
static const QString DEFAULT_TEXTURES;
|
||||||
|
@ -147,7 +153,7 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
QVector<ModelJointData> _localJointData;
|
QVector<ModelJointData> _localJointData;
|
||||||
int _lastKnownCurrentFrame;
|
int _lastKnownCurrentFrame{-1};
|
||||||
|
|
||||||
rgbColor _color;
|
rgbColor _color;
|
||||||
QString _modelURL;
|
QString _modelURL;
|
||||||
|
@ -160,6 +166,11 @@ protected:
|
||||||
QString _textures;
|
QString _textures;
|
||||||
|
|
||||||
ShapeType _shapeType = SHAPE_TYPE_NONE;
|
ShapeType _shapeType = SHAPE_TYPE_NONE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t _lastAnimated{ 0 };
|
||||||
|
AnimationPropertyGroup _previousAnimationProperties;
|
||||||
|
float _currentFrame{ -1.0f };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ModelEntityItem_h
|
#endif // hifi_ModelEntityItem_h
|
||||||
|
|
|
@ -56,7 +56,7 @@ float OBJTokenizer::getFloat() {
|
||||||
return std::stof((nextToken() != OBJTokenizer::DATUM_TOKEN) ? nullptr : getDatum().data());
|
return std::stof((nextToken() != OBJTokenizer::DATUM_TOKEN) ? nullptr : getDatum().data());
|
||||||
}
|
}
|
||||||
|
|
||||||
int OBJTokenizer::nextToken() {
|
int OBJTokenizer::nextToken(bool allowSpaceChar /*= false*/) {
|
||||||
if (_pushedBackToken != NO_PUSHBACKED_TOKEN) {
|
if (_pushedBackToken != NO_PUSHBACKED_TOKEN) {
|
||||||
int token = _pushedBackToken;
|
int token = _pushedBackToken;
|
||||||
_pushedBackToken = NO_PUSHBACKED_TOKEN;
|
_pushedBackToken = NO_PUSHBACKED_TOKEN;
|
||||||
|
@ -93,7 +93,7 @@ int OBJTokenizer::nextToken() {
|
||||||
_datum = "";
|
_datum = "";
|
||||||
_datum.append(ch);
|
_datum.append(ch);
|
||||||
while (_device->getChar(&ch)) {
|
while (_device->getChar(&ch)) {
|
||||||
if (QChar(ch).isSpace() || ch == '\"') {
|
if ((QChar(ch).isSpace() || ch == '\"') && (!allowSpaceChar || ch != ' ')) {
|
||||||
ungetChar(ch); // read until we encounter a special character, then replace it
|
ungetChar(ch); // read until we encounter a special character, then replace it
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -399,7 +399,7 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi
|
||||||
currentMaterialName = QString("part-") + QString::number(_partCounter++);
|
currentMaterialName = QString("part-") + QString::number(_partCounter++);
|
||||||
}
|
}
|
||||||
} else if (token == "mtllib" && !_url.isEmpty()) {
|
} else if (token == "mtllib" && !_url.isEmpty()) {
|
||||||
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
if (tokenizer.nextToken(true) != OBJTokenizer::DATUM_TOKEN) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
QByteArray libraryName = tokenizer.getDatum();
|
QByteArray libraryName = tokenizer.getDatum();
|
||||||
|
|
|
@ -11,7 +11,7 @@ public:
|
||||||
DATUM_TOKEN = 0x100,
|
DATUM_TOKEN = 0x100,
|
||||||
COMMENT_TOKEN = 0x101
|
COMMENT_TOKEN = 0x101
|
||||||
};
|
};
|
||||||
int nextToken();
|
int nextToken(bool allowSpaceChar = false);
|
||||||
const QByteArray& getDatum() const { return _datum; }
|
const QByteArray& getDatum() const { return _datum; }
|
||||||
bool isNextTokenFloat();
|
bool isNextTokenFloat();
|
||||||
const QByteArray getLineAsDatum(); // some "filenames" have spaces in them
|
const QByteArray getLineAsDatum(); // some "filenames" have spaces in them
|
||||||
|
|
|
@ -97,7 +97,7 @@ public:
|
||||||
void setTemporaryDomain(const QUuid& domainID, const QString& key);
|
void setTemporaryDomain(const QUuid& domainID, const QString& key);
|
||||||
const QString& getTemporaryDomainKey(const QUuid& domainID) { return _accountInfo.getTemporaryDomainKey(domainID); }
|
const QString& getTemporaryDomainKey(const QUuid& domainID) { return _accountInfo.getTemporaryDomainKey(domainID); }
|
||||||
|
|
||||||
QUrl getMetaverseServerURL() { return NetworkingConstants::METAVERSE_SERVER_URL; }
|
QUrl getMetaverseServerURL() { return NetworkingConstants::METAVERSE_SERVER_URL(); }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void requestAccessToken(const QString& login, const QString& password);
|
void requestAccessToken(const QString& login, const QString& password);
|
||||||
|
|
|
@ -12,15 +12,31 @@
|
||||||
#ifndef hifi_NetworkingConstants_h
|
#ifndef hifi_NetworkingConstants_h
|
||||||
#define hifi_NetworkingConstants_h
|
#define hifi_NetworkingConstants_h
|
||||||
|
|
||||||
|
#include <QtCore/QProcessEnvironment>
|
||||||
#include <QtCore/QUrl>
|
#include <QtCore/QUrl>
|
||||||
|
|
||||||
namespace NetworkingConstants {
|
namespace NetworkingConstants {
|
||||||
// If you want to use STAGING instead of STABLE,
|
// If you want to use STAGING instead of STABLE,
|
||||||
// don't forget to ALSO change the Domain Server Metaverse Server URL inside of:
|
// links from the Domain Server web interface (like the connect account token generation)
|
||||||
|
// will still point at stable unless you ALSO change the Domain Server Metaverse Server URL inside of:
|
||||||
// <hifi repo>\domain-server\resources\web\js\shared.js
|
// <hifi repo>\domain-server\resources\web\js\shared.js
|
||||||
|
|
||||||
|
// You can avoid changing that and still effectively use a connected domain on staging
|
||||||
|
// if you manually generate a personal access token for the domains scope
|
||||||
|
// at https://staging.highfidelity.com/user/tokens/new?for_domain_server=true
|
||||||
|
|
||||||
const QUrl METAVERSE_SERVER_URL_STABLE("https://metaverse.highfidelity.com");
|
const QUrl METAVERSE_SERVER_URL_STABLE("https://metaverse.highfidelity.com");
|
||||||
const QUrl METAVERSE_SERVER_URL_STAGING("https://staging.highfidelity.com");
|
const QUrl METAVERSE_SERVER_URL_STAGING("https://staging.highfidelity.com");
|
||||||
const QUrl METAVERSE_SERVER_URL = METAVERSE_SERVER_URL_STABLE;
|
|
||||||
|
// You can change the return of this function if you want to use a custom metaverse URL at compile time
|
||||||
|
// or you can pass a custom URL via the env variable
|
||||||
|
static const QUrl METAVERSE_SERVER_URL() {
|
||||||
|
static const QString HIFI_METAVERSE_URL_ENV = "HIFI_METAVERSE_URL";
|
||||||
|
static const QUrl serverURL = QProcessEnvironment::systemEnvironment().contains(HIFI_METAVERSE_URL_ENV)
|
||||||
|
? QUrl(QProcessEnvironment::systemEnvironment().value(HIFI_METAVERSE_URL_ENV))
|
||||||
|
: METAVERSE_SERVER_URL_STABLE;
|
||||||
|
return serverURL;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // hifi_NetworkingConstants_h
|
#endif // hifi_NetworkingConstants_h
|
||||||
|
|
|
@ -35,7 +35,7 @@ QNetworkReply* OAuthNetworkAccessManager::createRequest(QNetworkAccessManager::O
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
|
|
||||||
if (accountManager->hasValidAccessToken()
|
if (accountManager->hasValidAccessToken()
|
||||||
&& req.url().host() == NetworkingConstants::METAVERSE_SERVER_URL.host()) {
|
&& req.url().host() == NetworkingConstants::METAVERSE_SERVER_URL().host()) {
|
||||||
QNetworkRequest authenticatedRequest(req);
|
QNetworkRequest authenticatedRequest(req);
|
||||||
authenticatedRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
authenticatedRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||||
authenticatedRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
authenticatedRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||||
|
|
|
@ -14,8 +14,9 @@
|
||||||
#include <EntityItem.h>
|
#include <EntityItem.h>
|
||||||
#include <EntityItemProperties.h>
|
#include <EntityItemProperties.h>
|
||||||
#include <EntityEditPacketSender.h>
|
#include <EntityEditPacketSender.h>
|
||||||
#include <PhysicsCollisionGroups.h>
|
|
||||||
#include <LogHandler.h>
|
#include <LogHandler.h>
|
||||||
|
#include <PhysicsCollisionGroups.h>
|
||||||
|
#include <Profile.h>
|
||||||
|
|
||||||
#include "BulletUtil.h"
|
#include "BulletUtil.h"
|
||||||
#include "EntityMotionState.h"
|
#include "EntityMotionState.h"
|
||||||
|
@ -325,6 +326,7 @@ bool EntityMotionState::isCandidateForOwnership() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
||||||
|
DETAILED_PROFILE_RANGE(simulation_physics, "CheckOutOfSync");
|
||||||
// NOTE: we only get here if we think we own the simulation
|
// NOTE: we only get here if we think we own the simulation
|
||||||
assert(_body);
|
assert(_body);
|
||||||
|
|
||||||
|
@ -476,6 +478,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {
|
bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {
|
||||||
|
DETAILED_PROFILE_RANGE(simulation_physics, "ShouldSend");
|
||||||
// NOTE: we expect _entity and _body to be valid in this context, since shouldSendUpdate() is only called
|
// NOTE: we expect _entity and _body to be valid in this context, since shouldSendUpdate() is only called
|
||||||
// after doesNotNeedToSendUpdate() returns false and that call should return 'true' if _entity or _body are NULL.
|
// after doesNotNeedToSendUpdate() returns false and that call should return 'true' if _entity or _body are NULL.
|
||||||
assert(_entity);
|
assert(_entity);
|
||||||
|
@ -516,6 +519,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step) {
|
void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step) {
|
||||||
|
DETAILED_PROFILE_RANGE(simulation_physics, "Send");
|
||||||
assert(_entity);
|
assert(_entity);
|
||||||
assert(entityTreeIsLocked());
|
assert(entityTreeIsLocked());
|
||||||
|
|
||||||
|
@ -731,6 +735,7 @@ void EntityMotionState::resetMeasuredBodyAcceleration() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityMotionState::measureBodyAcceleration() {
|
void EntityMotionState::measureBodyAcceleration() {
|
||||||
|
DETAILED_PROFILE_RANGE(simulation_physics, "MeasureAccel");
|
||||||
// try to manually measure the true acceleration of the object
|
// try to manually measure the true acceleration of the object
|
||||||
uint32_t thisStep = ObjectMotionState::getWorldSimulationStep();
|
uint32_t thisStep = ObjectMotionState::getWorldSimulationStep();
|
||||||
uint32_t numSubsteps = thisStep - _lastMeasureStep;
|
uint32_t numSubsteps = thisStep - _lastMeasureStep;
|
||||||
|
|
|
@ -10,12 +10,14 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#include "PhysicalEntitySimulation.h"
|
||||||
|
|
||||||
|
#include <Profile.h>
|
||||||
|
|
||||||
#include "PhysicsHelpers.h"
|
#include "PhysicsHelpers.h"
|
||||||
#include "PhysicsLogging.h"
|
#include "PhysicsLogging.h"
|
||||||
#include "ShapeManager.h"
|
#include "ShapeManager.h"
|
||||||
|
|
||||||
#include "PhysicalEntitySimulation.h"
|
|
||||||
|
|
||||||
PhysicalEntitySimulation::PhysicalEntitySimulation() {
|
PhysicalEntitySimulation::PhysicalEntitySimulation() {
|
||||||
}
|
}
|
||||||
|
@ -274,20 +276,24 @@ void PhysicalEntitySimulation::handleDeactivatedMotionStates(const VectorOfMotio
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicalEntitySimulation::handleChangedMotionStates(const VectorOfMotionStates& motionStates) {
|
void PhysicalEntitySimulation::handleChangedMotionStates(const VectorOfMotionStates& motionStates) {
|
||||||
|
PROFILE_RANGE_EX(simulation_physics, "ChangedEntities", 0x00000000, (uint64_t)motionStates.size());
|
||||||
QMutexLocker lock(&_mutex);
|
QMutexLocker lock(&_mutex);
|
||||||
|
|
||||||
// walk the motionStates looking for those that correspond to entities
|
// walk the motionStates looking for those that correspond to entities
|
||||||
for (auto stateItr : motionStates) {
|
{
|
||||||
ObjectMotionState* state = &(*stateItr);
|
PROFILE_RANGE_EX(simulation_physics, "Filter", 0x00000000, (uint64_t)motionStates.size());
|
||||||
assert(state);
|
for (auto stateItr : motionStates) {
|
||||||
if (state->getType() == MOTIONSTATE_TYPE_ENTITY) {
|
ObjectMotionState* state = &(*stateItr);
|
||||||
EntityMotionState* entityState = static_cast<EntityMotionState*>(state);
|
assert(state);
|
||||||
EntityItemPointer entity = entityState->getEntity();
|
if (state->getType() == MOTIONSTATE_TYPE_ENTITY) {
|
||||||
assert(entity.get());
|
EntityMotionState* entityState = static_cast<EntityMotionState*>(state);
|
||||||
if (entityState->isCandidateForOwnership()) {
|
EntityItemPointer entity = entityState->getEntity();
|
||||||
_outgoingChanges.insert(entityState);
|
assert(entity.get());
|
||||||
|
if (entityState->isCandidateForOwnership()) {
|
||||||
|
_outgoingChanges.insert(entityState);
|
||||||
|
}
|
||||||
|
_entitiesToSort.insert(entity);
|
||||||
}
|
}
|
||||||
_entitiesToSort.insert(entity);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,6 +308,7 @@ void PhysicalEntitySimulation::handleChangedMotionStates(const VectorOfMotionSta
|
||||||
}
|
}
|
||||||
|
|
||||||
// look for entities to prune or update
|
// look for entities to prune or update
|
||||||
|
PROFILE_RANGE_EX(simulation_physics, "Prune/Send", 0x00000000, (uint64_t)_outgoingChanges.size());
|
||||||
QSet<EntityMotionState*>::iterator stateItr = _outgoingChanges.begin();
|
QSet<EntityMotionState*>::iterator stateItr = _outgoingChanges.begin();
|
||||||
while (stateItr != _outgoingChanges.end()) {
|
while (stateItr != _outgoingChanges.end()) {
|
||||||
EntityMotionState* state = *stateItr;
|
EntityMotionState* state = *stateItr;
|
||||||
|
|
|
@ -11,7 +11,12 @@
|
||||||
|
|
||||||
#include <PhysicsCollisionGroups.h>
|
#include <PhysicsCollisionGroups.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
#include <Profile.h>
|
||||||
|
|
||||||
#include "CharacterController.h"
|
#include "CharacterController.h"
|
||||||
#include "ObjectMotionState.h"
|
#include "ObjectMotionState.h"
|
||||||
|
@ -290,6 +295,7 @@ void PhysicsEngine::stepSimulation() {
|
||||||
float timeStep = btMin(dt, MAX_TIMESTEP);
|
float timeStep = btMin(dt, MAX_TIMESTEP);
|
||||||
|
|
||||||
if (_myAvatarController) {
|
if (_myAvatarController) {
|
||||||
|
DETAILED_PROFILE_RANGE(simulation_physics, "avatarController");
|
||||||
BT_PROFILE("avatarController");
|
BT_PROFILE("avatarController");
|
||||||
// TODO: move this stuff outside and in front of stepSimulation, because
|
// TODO: move this stuff outside and in front of stepSimulation, because
|
||||||
// the updateShapeIfNecessary() call needs info from MyAvatar and should
|
// the updateShapeIfNecessary() call needs info from MyAvatar and should
|
||||||
|
@ -328,45 +334,107 @@ void PhysicsEngine::stepSimulation() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CProfileOperator {
|
||||||
|
public:
|
||||||
|
CProfileOperator() {}
|
||||||
|
void recurse(CProfileIterator* itr, QString context) {
|
||||||
|
// The context string will get too long if we accumulate it properly
|
||||||
|
//QString newContext = context + QString("/") + itr->Get_Current_Parent_Name();
|
||||||
|
// so we use this four-character indentation
|
||||||
|
QString newContext = context + QString(".../");
|
||||||
|
process(itr, newContext);
|
||||||
|
|
||||||
|
// count the children
|
||||||
|
int32_t numChildren = 0;
|
||||||
|
itr->First();
|
||||||
|
while (!itr->Is_Done()) {
|
||||||
|
itr->Next();
|
||||||
|
++numChildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
// recurse the children
|
||||||
|
if (numChildren > 0) {
|
||||||
|
// recurse the children
|
||||||
|
for (int32_t i = 0; i < numChildren; ++i) {
|
||||||
|
itr->Enter_Child(i);
|
||||||
|
recurse(itr, newContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// retreat back to parent
|
||||||
|
itr->Enter_Parent();
|
||||||
|
}
|
||||||
|
virtual void process(CProfileIterator*, QString context) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StatsHarvester : public CProfileOperator {
|
||||||
|
public:
|
||||||
|
StatsHarvester() {}
|
||||||
|
void process(CProfileIterator* itr, QString context) override {
|
||||||
|
QString name = context + itr->Get_Current_Parent_Name();
|
||||||
|
uint64_t time = (uint64_t)((btScalar)MSECS_PER_SECOND * itr->Get_Current_Parent_Total_Time());
|
||||||
|
PerformanceTimer::addTimerRecord(name, time);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class StatsWriter : public CProfileOperator {
|
||||||
|
public:
|
||||||
|
StatsWriter(QString filename) : _file(filename) {
|
||||||
|
_file.open(QFile::WriteOnly);
|
||||||
|
if (_file.error() != QFileDevice::NoError) {
|
||||||
|
qCDebug(physics) << "unable to open file " << _file.fileName() << " to save stepSimulation() stats";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~StatsWriter() {
|
||||||
|
_file.close();
|
||||||
|
}
|
||||||
|
void process(CProfileIterator* itr, QString context) override {
|
||||||
|
QString name = context + itr->Get_Current_Parent_Name();
|
||||||
|
float time = (btScalar)MSECS_PER_SECOND * itr->Get_Current_Parent_Total_Time();
|
||||||
|
if (_file.error() == QFileDevice::NoError) {
|
||||||
|
QTextStream s(&_file);
|
||||||
|
s << name << " = " << time << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
QFile _file;
|
||||||
|
};
|
||||||
|
|
||||||
void PhysicsEngine::harvestPerformanceStats() {
|
void PhysicsEngine::harvestPerformanceStats() {
|
||||||
// unfortunately the full context names get too long for our stats presentation format
|
// unfortunately the full context names get too long for our stats presentation format
|
||||||
//QString contextName = PerformanceTimer::getContextName(); // TODO: how to show full context name?
|
//QString contextName = PerformanceTimer::getContextName(); // TODO: how to show full context name?
|
||||||
QString contextName("...");
|
QString contextName("...");
|
||||||
|
|
||||||
CProfileIterator* profileIterator = CProfileManager::Get_Iterator();
|
CProfileIterator* itr = CProfileManager::Get_Iterator();
|
||||||
if (profileIterator) {
|
if (itr) {
|
||||||
// hunt for stepSimulation context
|
// hunt for stepSimulation context
|
||||||
profileIterator->First();
|
itr->First();
|
||||||
for (int32_t childIndex = 0; !profileIterator->Is_Done(); ++childIndex) {
|
for (int32_t childIndex = 0; !itr->Is_Done(); ++childIndex) {
|
||||||
if (QString(profileIterator->Get_Current_Name()) == "stepSimulation") {
|
if (QString(itr->Get_Current_Name()) == "stepSimulation") {
|
||||||
profileIterator->Enter_Child(childIndex);
|
itr->Enter_Child(childIndex);
|
||||||
recursivelyHarvestPerformanceStats(profileIterator, contextName);
|
StatsHarvester harvester;
|
||||||
|
harvester.recurse(itr, "step/");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
profileIterator->Next();
|
itr->Next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsEngine::recursivelyHarvestPerformanceStats(CProfileIterator* profileIterator, QString contextName) {
|
void PhysicsEngine::printPerformanceStatsToFile(const QString& filename) {
|
||||||
QString parentContextName = contextName + QString("/") + QString(profileIterator->Get_Current_Parent_Name());
|
CProfileIterator* itr = CProfileManager::Get_Iterator();
|
||||||
// get the stats for the children
|
if (itr) {
|
||||||
int32_t numChildren = 0;
|
// hunt for stepSimulation context
|
||||||
profileIterator->First();
|
itr->First();
|
||||||
while (!profileIterator->Is_Done()) {
|
for (int32_t childIndex = 0; !itr->Is_Done(); ++childIndex) {
|
||||||
QString childContextName = parentContextName + QString("/") + QString(profileIterator->Get_Current_Name());
|
if (QString(itr->Get_Current_Name()) == "stepSimulation") {
|
||||||
uint64_t time = (uint64_t)((btScalar)MSECS_PER_SECOND * profileIterator->Get_Current_Total_Time());
|
itr->Enter_Child(childIndex);
|
||||||
PerformanceTimer::addTimerRecord(childContextName, time);
|
StatsWriter writer(filename);
|
||||||
profileIterator->Next();
|
writer.recurse(itr, "");
|
||||||
++numChildren;
|
break;
|
||||||
|
}
|
||||||
|
itr->Next();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// recurse the children
|
|
||||||
for (int32_t i = 0; i < numChildren; ++i) {
|
|
||||||
profileIterator->Enter_Child(i);
|
|
||||||
recursivelyHarvestPerformanceStats(profileIterator, contextName);
|
|
||||||
}
|
|
||||||
// retreat back to parent
|
|
||||||
profileIterator->Enter_Parent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) {
|
void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) {
|
||||||
|
@ -399,6 +467,7 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsEngine::updateContactMap() {
|
void PhysicsEngine::updateContactMap() {
|
||||||
|
DETAILED_PROFILE_RANGE(simulation_physics, "updateContactMap");
|
||||||
BT_PROFILE("updateContactMap");
|
BT_PROFILE("updateContactMap");
|
||||||
++_numContactFrames;
|
++_numContactFrames;
|
||||||
|
|
||||||
|
@ -515,10 +584,21 @@ const VectorOfMotionStates& PhysicsEngine::getChangedMotionStates() {
|
||||||
void PhysicsEngine::dumpStatsIfNecessary() {
|
void PhysicsEngine::dumpStatsIfNecessary() {
|
||||||
if (_dumpNextStats) {
|
if (_dumpNextStats) {
|
||||||
_dumpNextStats = false;
|
_dumpNextStats = false;
|
||||||
|
CProfileManager::Increment_Frame_Counter();
|
||||||
|
if (_saveNextStats) {
|
||||||
|
_saveNextStats = false;
|
||||||
|
printPerformanceStatsToFile(_statsFilename);
|
||||||
|
}
|
||||||
CProfileManager::dumpAll();
|
CProfileManager::dumpAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PhysicsEngine::saveNextPhysicsStats(QString filename) {
|
||||||
|
_saveNextStats = true;
|
||||||
|
_dumpNextStats = true;
|
||||||
|
_statsFilename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
// Bullet collision flags are as follows:
|
// Bullet collision flags are as follows:
|
||||||
// CF_STATIC_OBJECT= 1,
|
// CF_STATIC_OBJECT= 1,
|
||||||
// CF_KINEMATIC_OBJECT= 2,
|
// CF_KINEMATIC_OBJECT= 2,
|
||||||
|
|
|
@ -62,6 +62,7 @@ public:
|
||||||
|
|
||||||
void stepSimulation();
|
void stepSimulation();
|
||||||
void harvestPerformanceStats();
|
void harvestPerformanceStats();
|
||||||
|
void printPerformanceStatsToFile(const QString& filename);
|
||||||
void updateContactMap();
|
void updateContactMap();
|
||||||
|
|
||||||
bool hasOutgoingChanges() const { return _hasOutgoingChanges; }
|
bool hasOutgoingChanges() const { return _hasOutgoingChanges; }
|
||||||
|
@ -76,6 +77,9 @@ public:
|
||||||
/// \brief prints timings for last frame if stats have been requested.
|
/// \brief prints timings for last frame if stats have been requested.
|
||||||
void dumpStatsIfNecessary();
|
void dumpStatsIfNecessary();
|
||||||
|
|
||||||
|
/// \brief saves timings for last frame in filename
|
||||||
|
void saveNextPhysicsStats(QString filename);
|
||||||
|
|
||||||
/// \param offset position of simulation origin in domain-frame
|
/// \param offset position of simulation origin in domain-frame
|
||||||
void setOriginOffset(const glm::vec3& offset) { _originOffset = offset; }
|
void setOriginOffset(const glm::vec3& offset) { _originOffset = offset; }
|
||||||
|
|
||||||
|
@ -94,7 +98,6 @@ public:
|
||||||
private:
|
private:
|
||||||
QList<EntityDynamicPointer> removeDynamicsForBody(btRigidBody* body);
|
QList<EntityDynamicPointer> removeDynamicsForBody(btRigidBody* body);
|
||||||
void addObjectToDynamicsWorld(ObjectMotionState* motionState);
|
void addObjectToDynamicsWorld(ObjectMotionState* motionState);
|
||||||
void recursivelyHarvestPerformanceStats(CProfileIterator* profileIterator, QString contextName);
|
|
||||||
|
|
||||||
/// \brief bump any objects that touch this one, then remove contact info
|
/// \brief bump any objects that touch this one, then remove contact info
|
||||||
void bumpAndPruneContacts(ObjectMotionState* motionState);
|
void bumpAndPruneContacts(ObjectMotionState* motionState);
|
||||||
|
@ -116,6 +119,7 @@ private:
|
||||||
QHash<QUuid, EntityDynamicPointer> _objectDynamics;
|
QHash<QUuid, EntityDynamicPointer> _objectDynamics;
|
||||||
QHash<btRigidBody*, QSet<QUuid>> _objectDynamicsByBody;
|
QHash<btRigidBody*, QSet<QUuid>> _objectDynamicsByBody;
|
||||||
std::set<btRigidBody*> _activeStaticBodies;
|
std::set<btRigidBody*> _activeStaticBodies;
|
||||||
|
QString _statsFilename;
|
||||||
|
|
||||||
glm::vec3 _originOffset;
|
glm::vec3 _originOffset;
|
||||||
|
|
||||||
|
@ -124,8 +128,9 @@ private:
|
||||||
uint32_t _numContactFrames = 0;
|
uint32_t _numContactFrames = 0;
|
||||||
uint32_t _numSubsteps;
|
uint32_t _numSubsteps;
|
||||||
|
|
||||||
bool _dumpNextStats = false;
|
bool _dumpNextStats { false };
|
||||||
bool _hasOutgoingChanges = false;
|
bool _saveNextStats { false };
|
||||||
|
bool _hasOutgoingChanges { false };
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <LinearMath/btQuickprof.h>
|
#include <LinearMath/btQuickprof.h>
|
||||||
|
|
||||||
#include "ThreadSafeDynamicsWorld.h"
|
#include "ThreadSafeDynamicsWorld.h"
|
||||||
|
#include "Profile.h"
|
||||||
|
|
||||||
ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld(
|
ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld(
|
||||||
btDispatcher* dispatcher,
|
btDispatcher* dispatcher,
|
||||||
|
@ -29,6 +30,7 @@ ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld(
|
||||||
|
|
||||||
int ThreadSafeDynamicsWorld::stepSimulationWithSubstepCallback(btScalar timeStep, int maxSubSteps,
|
int ThreadSafeDynamicsWorld::stepSimulationWithSubstepCallback(btScalar timeStep, int maxSubSteps,
|
||||||
btScalar fixedTimeStep, SubStepCallback onSubStep) {
|
btScalar fixedTimeStep, SubStepCallback onSubStep) {
|
||||||
|
DETAILED_PROFILE_RANGE(simulation_physics, "stepWithCB");
|
||||||
BT_PROFILE("stepSimulationWithSubstepCallback");
|
BT_PROFILE("stepSimulationWithSubstepCallback");
|
||||||
int subSteps = 0;
|
int subSteps = 0;
|
||||||
if (maxSubSteps) {
|
if (maxSubSteps) {
|
||||||
|
@ -68,11 +70,13 @@ int ThreadSafeDynamicsWorld::stepSimulationWithSubstepCallback(btScalar timeStep
|
||||||
saveKinematicState(fixedTimeStep*clampedSimulationSteps);
|
saveKinematicState(fixedTimeStep*clampedSimulationSteps);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
DETAILED_PROFILE_RANGE(simulation_physics, "applyGravity");
|
||||||
BT_PROFILE("applyGravity");
|
BT_PROFILE("applyGravity");
|
||||||
applyGravity();
|
applyGravity();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0;i<clampedSimulationSteps;i++) {
|
for (int i=0;i<clampedSimulationSteps;i++) {
|
||||||
|
DETAILED_PROFILE_RANGE(simulation_physics, "substep");
|
||||||
internalSingleStepSimulation(fixedTimeStep);
|
internalSingleStepSimulation(fixedTimeStep);
|
||||||
onSubStep();
|
onSubStep();
|
||||||
}
|
}
|
||||||
|
@ -118,7 +122,8 @@ void ThreadSafeDynamicsWorld::synchronizeMotionState(btRigidBody* body) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadSafeDynamicsWorld::synchronizeMotionStates() {
|
void ThreadSafeDynamicsWorld::synchronizeMotionStates() {
|
||||||
BT_PROFILE("synchronizeMotionStates");
|
PROFILE_RANGE(simulation_physics, "SyncMotionStates");
|
||||||
|
BT_PROFILE("syncMotionStates");
|
||||||
_changedMotionStates.clear();
|
_changedMotionStates.clear();
|
||||||
|
|
||||||
// NOTE: m_synchronizeAllMotionStates is 'false' by default for optimization.
|
// NOTE: m_synchronizeAllMotionStates is 'false' by default for optimization.
|
||||||
|
@ -161,6 +166,7 @@ void ThreadSafeDynamicsWorld::saveKinematicState(btScalar timeStep) {
|
||||||
///would like to iterate over m_nonStaticRigidBodies, but unfortunately old API allows
|
///would like to iterate over m_nonStaticRigidBodies, but unfortunately old API allows
|
||||||
///to switch status _after_ adding kinematic objects to the world
|
///to switch status _after_ adding kinematic objects to the world
|
||||||
///fix it for Bullet 3.x release
|
///fix it for Bullet 3.x release
|
||||||
|
DETAILED_PROFILE_RANGE(simulation_physics, "saveKinematicState");
|
||||||
BT_PROFILE("saveKinematicState");
|
BT_PROFILE("saveKinematicState");
|
||||||
for (int i=0;i<m_collisionObjects.size();i++)
|
for (int i=0;i<m_collisionObjects.size();i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -169,7 +169,12 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu
|
||||||
auto hazeStage = args->_scene->getStage<HazeStage>();
|
auto hazeStage = args->_scene->getStage<HazeStage>();
|
||||||
if (hazeStage && hazeStage->_currentFrame._hazes.size() > 0) {
|
if (hazeStage && hazeStage->_currentFrame._hazes.size() > 0) {
|
||||||
model::HazePointer hazePointer = hazeStage->getHaze(hazeStage->_currentFrame._hazes.front());
|
model::HazePointer hazePointer = hazeStage->getHaze(hazeStage->_currentFrame._hazes.front());
|
||||||
batch.setUniformBuffer(HazeEffect_ParamsSlot, hazePointer->getHazeParametersBuffer());
|
if (hazePointer) {
|
||||||
|
batch.setUniformBuffer(HazeEffect_ParamsSlot, hazePointer->getHazeParametersBuffer());
|
||||||
|
} else {
|
||||||
|
// Something is wrong, so just quit Haze
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
batch.setUniformBuffer(HazeEffect_TransformBufferSlot, transformBuffer->getFrameTransformBuffer());
|
batch.setUniformBuffer(HazeEffect_TransformBufferSlot, transformBuffer->getFrameTransformBuffer());
|
||||||
|
@ -178,7 +183,7 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu
|
||||||
if (lightStage) {
|
if (lightStage) {
|
||||||
model::LightPointer keyLight;
|
model::LightPointer keyLight;
|
||||||
keyLight = lightStage->getCurrentKeyLight();
|
keyLight = lightStage->getCurrentKeyLight();
|
||||||
if (keyLight != nullptr) {
|
if (keyLight) {
|
||||||
batch.setUniformBuffer(HazeEffect_LightingMapSlot, keyLight->getLightSchemaBuffer());
|
batch.setUniformBuffer(HazeEffect_LightingMapSlot, keyLight->getLightSchemaBuffer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "ScriptEngine.h"
|
#include "ScriptEngine.h"
|
||||||
#include "XMLHttpRequestClass.h"
|
#include "XMLHttpRequestClass.h"
|
||||||
|
|
||||||
const QString METAVERSE_API_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/api/";
|
const QString METAVERSE_API_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/api/";
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QByteArray*)
|
Q_DECLARE_METATYPE(QByteArray*)
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include <QtCore/QFileInfo>
|
#include <QtCore/QFileInfo>
|
||||||
#include <QtCore/QDir>
|
#include <QtCore/QDir>
|
||||||
#include <QtCore/QStandardPaths>
|
#include <QtCore/QStandardPaths>
|
||||||
#include <QtCore/QDateTime>
|
|
||||||
|
|
||||||
#include <QtCore/QFile>
|
#include <QtCore/QFile>
|
||||||
#include <QtCore/QFileInfo>
|
#include <QtCore/QFileInfo>
|
||||||
|
@ -31,6 +30,8 @@
|
||||||
|
|
||||||
#include "Gzip.h"
|
#include "Gzip.h"
|
||||||
#include "PortableHighResolutionClock.h"
|
#include "PortableHighResolutionClock.h"
|
||||||
|
#include "SharedLogging.h"
|
||||||
|
#include "shared/FileUtils.h"
|
||||||
#include "shared/GlobalAppProperties.h"
|
#include "shared/GlobalAppProperties.h"
|
||||||
|
|
||||||
using namespace tracing;
|
using namespace tracing;
|
||||||
|
@ -104,30 +105,13 @@ void TraceEvent::writeJson(QTextStream& out) const {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tracer::serialize(const QString& originalPath) {
|
void Tracer::serialize(const QString& filename) {
|
||||||
|
QString fullPath = FileUtils::replaceDateTimeTokens(filename);
|
||||||
QString path = originalPath;
|
fullPath = FileUtils::computeDocumentPath(fullPath);
|
||||||
|
if (!FileUtils::canCreateFile(fullPath)) {
|
||||||
// Filter for specific tokens potentially present in the path:
|
return;
|
||||||
auto now = QDateTime::currentDateTime();
|
|
||||||
|
|
||||||
path = path.replace("{DATE}", now.date().toString("yyyyMMdd"));
|
|
||||||
path = path.replace("{TIME}", now.time().toString("HHmm"));
|
|
||||||
|
|
||||||
// If the filename is relative, turn it into an absolute path relative to the document directory.
|
|
||||||
QFileInfo originalFileInfo(path);
|
|
||||||
if (originalFileInfo.isRelative()) {
|
|
||||||
QString docsLocation = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
|
||||||
path = docsLocation + "/" + path;
|
|
||||||
QFileInfo info(path);
|
|
||||||
if (!info.absoluteDir().exists()) {
|
|
||||||
QString originalRelativePath = originalFileInfo.path();
|
|
||||||
QDir(docsLocation).mkpath(originalRelativePath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::list<TraceEvent> currentEvents;
|
std::list<TraceEvent> currentEvents;
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(_eventsMutex);
|
std::lock_guard<std::mutex> guard(_eventsMutex);
|
||||||
|
@ -137,11 +121,6 @@ void Tracer::serialize(const QString& originalPath) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the file exists and we can't remove it, fail early
|
|
||||||
if (QFileInfo(path).exists() && !QFile::remove(path)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we can't open a temp file for writing, fail early
|
// If we can't open a temp file for writing, fail early
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
{
|
{
|
||||||
|
@ -159,15 +138,16 @@ void Tracer::serialize(const QString& originalPath) {
|
||||||
out << "\n]";
|
out << "\n]";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.endsWith(".gz")) {
|
if (fullPath.endsWith(".gz")) {
|
||||||
QByteArray compressed;
|
QByteArray compressed;
|
||||||
gzip(data, compressed);
|
gzip(data, compressed);
|
||||||
data = compressed;
|
data = compressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
QFile file(path);
|
QFile file(fullPath);
|
||||||
if (!file.open(QIODevice::WriteOnly)) {
|
if (!file.open(QIODevice::WriteOnly)) {
|
||||||
|
qDebug(shared) << "failed to open file '" << fullPath << "'";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
file.write(data);
|
file.write(data);
|
||||||
|
@ -191,7 +171,6 @@ void Tracer::serialize(const QString& originalPath) {
|
||||||
} }
|
} }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
data = document.toJson(QJsonDocument::Compact);
|
data = document.toJson(QJsonDocument::Compact);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "FileUtils.h"
|
#include "FileUtils.h"
|
||||||
|
|
||||||
|
#include <QtCore/QDateTime>
|
||||||
#include <QtCore/QDir>
|
#include <QtCore/QDir>
|
||||||
#include <QtCore/QFileInfo>
|
#include <QtCore/QFileInfo>
|
||||||
#include <QtCore/QProcess>
|
#include <QtCore/QProcess>
|
||||||
|
@ -20,6 +21,8 @@
|
||||||
#include <QtCore/QRegularExpression>
|
#include <QtCore/QRegularExpression>
|
||||||
#include <QtGui/QDesktopServices>
|
#include <QtGui/QDesktopServices>
|
||||||
|
|
||||||
|
#include "../SharedLogging.h"
|
||||||
|
|
||||||
|
|
||||||
QString FileUtils::readFile(const QString& filename) {
|
QString FileUtils::readFile(const QString& filename) {
|
||||||
QFile file(filename);
|
QFile file(filename);
|
||||||
|
@ -82,20 +85,54 @@ QString FileUtils::standardPath(QString subfolder) {
|
||||||
// standard path
|
// standard path
|
||||||
// Mac: ~/Library/Application Support/Interface
|
// Mac: ~/Library/Application Support/Interface
|
||||||
QString path = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
QString path = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||||
|
|
||||||
if (!subfolder.startsWith("/")) {
|
if (!subfolder.startsWith("/")) {
|
||||||
subfolder.prepend("/");
|
subfolder.prepend("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!subfolder.endsWith("/")) {
|
if (!subfolder.endsWith("/")) {
|
||||||
subfolder.append("/");
|
subfolder.append("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
path.append(subfolder);
|
path.append(subfolder);
|
||||||
QDir logDir(path);
|
QDir logDir(path);
|
||||||
if (!logDir.exists(path)) {
|
if (!logDir.exists(path)) {
|
||||||
logDir.mkpath(path);
|
logDir.mkpath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString FileUtils::replaceDateTimeTokens(const QString& originalPath) {
|
||||||
|
// Filter for specific tokens potentially present in the path:
|
||||||
|
auto now = QDateTime::currentDateTime();
|
||||||
|
QString path = originalPath;
|
||||||
|
path.replace("{DATE}", now.date().toString("yyyyMMdd"));
|
||||||
|
path.replace("{TIME}", now.time().toString("HHmm"));
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QString FileUtils::computeDocumentPath(const QString& originalPath) {
|
||||||
|
// If the filename is relative, turn it into an absolute path relative to the document directory.
|
||||||
|
QString path = originalPath;
|
||||||
|
QFileInfo originalFileInfo(originalPath);
|
||||||
|
if (originalFileInfo.isRelative()) {
|
||||||
|
QString docsLocation = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||||
|
path = docsLocation + "/" + originalPath;
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileUtils::canCreateFile(const QString& fullPath) {
|
||||||
|
// If the file exists and we can't remove it, fail early
|
||||||
|
QFileInfo fileInfo(fullPath);
|
||||||
|
if (fileInfo.exists() && !QFile::remove(fullPath)) {
|
||||||
|
qDebug(shared) << "unable to overwrite file '" << fullPath << "'";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QDir dir(fileInfo.absolutePath());
|
||||||
|
if (!dir.exists()) {
|
||||||
|
if (!dir.mkpath(fullPath)) {
|
||||||
|
qDebug(shared) << "unable to create dir '" << dir.absolutePath() << "'";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,9 @@ public:
|
||||||
static QString standardPath(QString subfolder);
|
static QString standardPath(QString subfolder);
|
||||||
static QString readFile(const QString& filename);
|
static QString readFile(const QString& filename);
|
||||||
static QStringList readLines(const QString& filename, QString::SplitBehavior splitBehavior = QString::KeepEmptyParts);
|
static QStringList readLines(const QString& filename, QString::SplitBehavior splitBehavior = QString::KeepEmptyParts);
|
||||||
|
static QString replaceDateTimeTokens(const QString& path);
|
||||||
|
static QString computeDocumentPath(const QString& path);
|
||||||
|
static bool canCreateFile(const QString& fullPath);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_FileUtils_h
|
#endif // hifi_FileUtils_h
|
||||||
|
|
|
@ -694,7 +694,9 @@ void OffscreenQmlSurface::create() {
|
||||||
|
|
||||||
// Setup the update of the QML media components with the current audio output device
|
// Setup the update of the QML media components with the current audio output device
|
||||||
QObject::connect(&_audioOutputUpdateTimer, &QTimer::timeout, this, [this]() {
|
QObject::connect(&_audioOutputUpdateTimer, &QTimer::timeout, this, [this]() {
|
||||||
new AudioHandler(sharedFromThis(), _currentAudioOutputDevice);
|
if (_currentAudioOutputDevice.size() > 0) {
|
||||||
|
new AudioHandler(sharedFromThis(), _currentAudioOutputDevice);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
int waitForAudioQmlMs = 200;
|
int waitForAudioQmlMs = 200;
|
||||||
_audioOutputUpdateTimer.setInterval(waitForAudioQmlMs);
|
_audioOutputUpdateTimer.setInterval(waitForAudioQmlMs);
|
||||||
|
@ -710,6 +712,7 @@ void OffscreenQmlSurface::create() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenQmlSurface::changeAudioOutputDevice(const QString& deviceName, bool isHtmlUpdate) {
|
void OffscreenQmlSurface::changeAudioOutputDevice(const QString& deviceName, bool isHtmlUpdate) {
|
||||||
|
_currentAudioOutputDevice = deviceName;
|
||||||
if (_rootItem != nullptr && !isHtmlUpdate) {
|
if (_rootItem != nullptr && !isHtmlUpdate) {
|
||||||
QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
@ -717,18 +720,16 @@ void OffscreenQmlSurface::changeAudioOutputDevice(const QString& deviceName, boo
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenQmlSurface::forceHtmlAudioOutputDeviceUpdate() {
|
void OffscreenQmlSurface::forceHtmlAudioOutputDeviceUpdate() {
|
||||||
auto audioIO = DependencyManager::get<AudioClient>();
|
if (_currentAudioOutputDevice.size() > 0) {
|
||||||
QString deviceName = audioIO->getActiveAudioDevice(QAudio::AudioOutput).deviceName();
|
QMetaObject::invokeMethod(this, "changeAudioOutputDevice", Qt::QueuedConnection,
|
||||||
QMetaObject::invokeMethod(this, "changeAudioOutputDevice", Qt::QueuedConnection,
|
Q_ARG(QString, _currentAudioOutputDevice), Q_ARG(bool, true));
|
||||||
Q_ARG(QString, deviceName), Q_ARG(bool, true));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenQmlSurface::forceQmlAudioOutputDeviceUpdate() {
|
void OffscreenQmlSurface::forceQmlAudioOutputDeviceUpdate() {
|
||||||
if (QThread::currentThread() != qApp->thread()) {
|
if (QThread::currentThread() != qApp->thread()) {
|
||||||
QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection);
|
||||||
} else {
|
} else {
|
||||||
auto audioIO = DependencyManager::get<AudioClient>();
|
|
||||||
_currentAudioOutputDevice = audioIO->getActiveAudioDevice(QAudio::AudioOutput).deviceName();
|
|
||||||
if (_audioOutputUpdateTimer.isActive()) {
|
if (_audioOutputUpdateTimer.isActive()) {
|
||||||
_audioOutputUpdateTimer.stop();
|
_audioOutputUpdateTimer.stop();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool isAuthableHighFidelityURL(const QUrl& url) {
|
bool isAuthableHighFidelityURL(const QUrl& url) {
|
||||||
auto metaverseServerURL = NetworkingConstants::METAVERSE_SERVER_URL;
|
auto metaverseServerURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||||
static const QStringList HF_HOSTS = {
|
static const QStringList HF_HOSTS = {
|
||||||
"highfidelity.com", "highfidelity.io",
|
"highfidelity.com", "highfidelity.io",
|
||||||
metaverseServerURL.toString(), "metaverse.highfidelity.io"
|
metaverseServerURL.toString(), "metaverse.highfidelity.io"
|
||||||
|
|
|
@ -412,6 +412,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
triggers: [{action: Controller.Standard.LTClick, button: "Focus"}, {action: Controller.Standard.LTClick, button: "Primary"}],
|
triggers: [{action: Controller.Standard.LTClick, button: "Focus"}, {action: Controller.Standard.LTClick, button: "Primary"}],
|
||||||
posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true),
|
posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true),
|
||||||
hover: true,
|
hover: true,
|
||||||
|
scaleWithAvatar: true,
|
||||||
distanceScaleEnd: true,
|
distanceScaleEnd: true,
|
||||||
hand: LEFT_HAND
|
hand: LEFT_HAND
|
||||||
});
|
});
|
||||||
|
@ -421,6 +422,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
triggers: [{action: Controller.Standard.RTClick, button: "Focus"}, {action: Controller.Standard.RTClick, button: "Primary"}],
|
triggers: [{action: Controller.Standard.RTClick, button: "Focus"}, {action: Controller.Standard.RTClick, button: "Primary"}],
|
||||||
posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true),
|
posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true),
|
||||||
hover: true,
|
hover: true,
|
||||||
|
scaleWithAvatar: true,
|
||||||
distanceScaleEnd: true,
|
distanceScaleEnd: true,
|
||||||
hand: RIGHT_HAND
|
hand: RIGHT_HAND
|
||||||
});
|
});
|
||||||
|
@ -431,6 +433,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true),
|
posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true),
|
||||||
triggers: [{action: Controller.Standard.LTClick, button: "Focus"}, {action: Controller.Standard.LTClick, button: "Primary"}],
|
triggers: [{action: Controller.Standard.LTClick, button: "Focus"}, {action: Controller.Standard.LTClick, button: "Primary"}],
|
||||||
hover: true,
|
hover: true,
|
||||||
|
scaleWithAvatar: true,
|
||||||
distanceScaleEnd: true,
|
distanceScaleEnd: true,
|
||||||
hand: LEFT_HAND
|
hand: LEFT_HAND
|
||||||
});
|
});
|
||||||
|
@ -441,6 +444,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true),
|
posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true),
|
||||||
triggers: [{action: Controller.Standard.RTClick, button: "Focus"}, {action: Controller.Standard.RTClick, button: "Primary"}],
|
triggers: [{action: Controller.Standard.RTClick, button: "Focus"}, {action: Controller.Standard.RTClick, button: "Primary"}],
|
||||||
hover: true,
|
hover: true,
|
||||||
|
scaleWithAvatar: true,
|
||||||
distanceScaleEnd: true,
|
distanceScaleEnd: true,
|
||||||
hand: RIGHT_HAND
|
hand: RIGHT_HAND
|
||||||
});
|
});
|
||||||
|
|
|
@ -269,6 +269,7 @@ function Grabber() {
|
||||||
joint: "Mouse",
|
joint: "Mouse",
|
||||||
filter: Picks.PICK_ENTITIES,
|
filter: Picks.PICK_ENTITIES,
|
||||||
faceAvatar: true,
|
faceAvatar: true,
|
||||||
|
scaleWithAvatar: true,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
renderStates: renderStates
|
renderStates: renderStates
|
||||||
});
|
});
|
||||||
|
|
|
@ -265,8 +265,10 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.grid-item').find('#price-or-edit').find('a').each(function() {
|
$('.grid-item').find('#price-or-edit').find('a').each(function() {
|
||||||
$(this).attr('data-href', $(this).attr('href'));
|
if ($(this).attr('href') !== '#') { // Guard necessary because of the AJAX nature of Marketplace site
|
||||||
$(this).attr('href', '#');
|
$(this).attr('data-href', $(this).attr('href'));
|
||||||
|
$(this).attr('href', '#');
|
||||||
|
}
|
||||||
cost = $(this).closest('.col-xs-3').find('.item-cost').text();
|
cost = $(this).closest('.col-xs-3').find('.item-cost').text();
|
||||||
|
|
||||||
$(this).closest('.col-xs-3').prev().attr("class", 'col-xs-6');
|
$(this).closest('.col-xs-3').prev().attr("class", 'col-xs-6');
|
||||||
|
|
|
@ -892,12 +892,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function keyPressEvent(event) {
|
function keyPressEvent(event) {
|
||||||
if ((event.text === "x") && !event.isAutoRepeat && !event.isShifted && !event.isMeta && !event.isControl && !event.isAlt) {
|
if ((event.text.toUpperCase() === "X") && !event.isAutoRepeat && !event.isShifted && !event.isMeta && !event.isControl
|
||||||
|
&& !event.isAlt) {
|
||||||
updateTriggers(1.0, true, Controller.Standard.RightHand);
|
updateTriggers(1.0, true, Controller.Standard.RightHand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function keyReleaseEvent(event) {
|
function keyReleaseEvent(event) {
|
||||||
if ((event.text === "x") && !event.isAutoRepeat && !event.isShifted && !event.isMeta && !event.isControl && !event.isAlt) {
|
if (event.text.toUpperCase() === "X" && !event.isAutoRepeat) {
|
||||||
updateTriggers(0.0, true, Controller.Standard.RightHand);
|
updateTriggers(0.0, true, Controller.Standard.RightHand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ ACClientApp::ACClientApp(int argc, char* argv[]) :
|
||||||
|
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
accountManager->setIsAgent(true);
|
accountManager->setIsAgent(true);
|
||||||
accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);
|
accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL());
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,7 @@ ATPClientApp::ATPClientApp(int argc, char* argv[]) :
|
||||||
|
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
accountManager->setIsAgent(true);
|
accountManager->setIsAgent(true);
|
||||||
accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);
|
accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL());
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,14 @@ setup_memory_debugger()
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
package_libraries_for_deployment()
|
package_libraries_for_deployment()
|
||||||
endif ()
|
elseif (UNIX AND NOT APPLE)
|
||||||
|
|
||||||
if (UNIX)
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
if(THREADS_HAVE_PTHREAD_ARG)
|
if(THREADS_HAVE_PTHREAD_ARG)
|
||||||
target_compile_options(PUBLIC oven "-pthread")
|
target_compile_options(PUBLIC oven "-pthread")
|
||||||
endif()
|
endif()
|
||||||
endif ()
|
elseif (APPLE)
|
||||||
|
# Fix up the rpath so macdeployqt works
|
||||||
|
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks")
|
||||||
|
endif()
|
||||||
|
|
||||||
install_beside_console()
|
install_beside_console()
|
||||||
|
|
Loading…
Reference in a new issue