mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 21:23:18 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into palm-rotation
This commit is contained in:
commit
050c472d6a
10 changed files with 205 additions and 73 deletions
|
@ -24,7 +24,7 @@ public:
|
|||
inline bool extraDebugging() { return _extraDebugging; }
|
||||
inline void setExtraDebugging(bool debugging) { _extraDebugging = debugging; }
|
||||
|
||||
virtual void addMessage(QString) = 0;
|
||||
virtual void addMessage(const QString&) = 0;
|
||||
virtual QString getLogData() = 0;
|
||||
virtual void locateLog() = 0;
|
||||
|
||||
|
@ -32,7 +32,7 @@ signals:
|
|||
void logReceived(QString message);
|
||||
|
||||
private:
|
||||
bool _extraDebugging;
|
||||
bool _extraDebugging{ false };
|
||||
};
|
||||
|
||||
#endif // hifi_AbstractLoggerInterface_h
|
||||
|
|
|
@ -21,11 +21,34 @@ const QString FILENAME_FORMAT = "hifi-log_%1_%2.txt";
|
|||
const QString DATETIME_FORMAT = "yyyy-MM-dd_hh.mm.ss";
|
||||
const QString LOGS_DIRECTORY = "Logs";
|
||||
|
||||
class FilePersistThread : public GenericQueueThread < QString > {
|
||||
public:
|
||||
FilePersistThread(const FileLogger& logger) : _logger(logger) {
|
||||
setObjectName("LogFileWriter");
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool processQueueItems(const Queue& messages) {
|
||||
QFile file(_logger._fileName);
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
|
||||
QTextStream out(&file);
|
||||
foreach(const QString& message, messages) {
|
||||
out << message;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
const FileLogger& _logger;
|
||||
};
|
||||
|
||||
static FilePersistThread* _persistThreadInstance;
|
||||
|
||||
FileLogger::FileLogger(QObject* parent) :
|
||||
AbstractLoggerInterface(parent),
|
||||
_logData("")
|
||||
AbstractLoggerInterface(parent)
|
||||
{
|
||||
setExtraDebugging(false);
|
||||
_persistThreadInstance = new FilePersistThread(*this);
|
||||
_persistThreadInstance->initialize(true, QThread::LowestPriority);
|
||||
|
||||
_fileName = FileUtils::standardPath(LOGS_DIRECTORY);
|
||||
QHostAddress clientAddress = getLocalAddress();
|
||||
|
@ -33,18 +56,24 @@ FileLogger::FileLogger(QObject* parent) :
|
|||
_fileName.append(QString(FILENAME_FORMAT).arg(clientAddress.toString(), now.toString(DATETIME_FORMAT)));
|
||||
}
|
||||
|
||||
void FileLogger::addMessage(QString message) {
|
||||
QMutexLocker locker(&_mutex);
|
||||
emit logReceived(message);
|
||||
_logData += message;
|
||||
FileLogger::~FileLogger() {
|
||||
_persistThreadInstance->terminate();
|
||||
}
|
||||
|
||||
QFile file(_fileName);
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
|
||||
QTextStream out(&file);
|
||||
out << message;
|
||||
}
|
||||
void FileLogger::addMessage(const QString& message) {
|
||||
_persistThreadInstance->queueItem(message);
|
||||
emit logReceived(message);
|
||||
}
|
||||
|
||||
void FileLogger::locateLog() {
|
||||
FileUtils::locateFile(_fileName);
|
||||
}
|
||||
|
||||
QString FileLogger::getLogData() {
|
||||
QString result;
|
||||
QFile f(_fileName);
|
||||
if (f.open(QFile::ReadOnly | QFile::Text)) {
|
||||
result = QTextStream(&f).readAll();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -13,23 +13,24 @@
|
|||
#define hifi_FileLogger_h
|
||||
|
||||
#include "AbstractLoggerInterface.h"
|
||||
#include <QMutex>
|
||||
#include <GenericQueueThread.h>
|
||||
|
||||
class FileLogger : public AbstractLoggerInterface {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FileLogger(QObject* parent = NULL);
|
||||
virtual ~FileLogger();
|
||||
|
||||
virtual void addMessage(QString);
|
||||
virtual QString getLogData() { return _logData; }
|
||||
virtual void locateLog();
|
||||
virtual void addMessage(const QString&) override;
|
||||
virtual QString getLogData() override;
|
||||
virtual void locateLog() override;
|
||||
|
||||
private:
|
||||
QString _logData;
|
||||
QString _fileName;
|
||||
QMutex _mutex;
|
||||
|
||||
friend class FilePersistThread;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // hifi_FileLogger_h
|
||||
|
|
|
@ -248,7 +248,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
|||
btTransform xform = _body->getWorldTransform();
|
||||
_serverPosition = bulletToGLM(xform.getOrigin());
|
||||
_serverRotation = bulletToGLM(xform.getRotation());
|
||||
_serverVelocity = bulletToGLM(_body->getLinearVelocity());
|
||||
_serverVelocity = getBodyLinearVelocity();
|
||||
_serverAngularVelocity = bulletToGLM(_body->getAngularVelocity());
|
||||
_lastStep = simulationStep;
|
||||
_serverActionData = _entity->getActionData();
|
||||
|
@ -536,7 +536,7 @@ void EntityMotionState::bump(quint8 priority) {
|
|||
void EntityMotionState::resetMeasuredBodyAcceleration() {
|
||||
_lastMeasureStep = ObjectMotionState::getWorldSimulationStep();
|
||||
if (_body) {
|
||||
_lastVelocity = bulletToGLM(_body->getLinearVelocity());
|
||||
_lastVelocity = getBodyLinearVelocity();
|
||||
} else {
|
||||
_lastVelocity = glm::vec3(0.0f);
|
||||
}
|
||||
|
@ -555,7 +555,7 @@ void EntityMotionState::measureBodyAcceleration() {
|
|||
|
||||
// Note: the integration equation for velocity uses damping: v1 = (v0 + a * dt) * (1 - D)^dt
|
||||
// hence the equation for acceleration is: a = (v1 / (1 - D)^dt - v0) / dt
|
||||
glm::vec3 velocity = bulletToGLM(_body->getLinearVelocity());
|
||||
glm::vec3 velocity = getBodyLinearVelocity();
|
||||
_measuredAcceleration = (velocity / powf(1.0f - _body->getLinearDamping(), dt) - _lastVelocity) * invDt;
|
||||
_lastVelocity = velocity;
|
||||
if (numSubsteps > PHYSICS_ENGINE_MAX_NUM_SUBSTEPS) {
|
||||
|
|
|
@ -16,7 +16,11 @@
|
|||
const uint16_t ObjectActionOffset::offsetVersion = 1;
|
||||
|
||||
ObjectActionOffset::ObjectActionOffset(const QUuid& id, EntityItemPointer ownerEntity) :
|
||||
ObjectAction(ACTION_TYPE_OFFSET, id, ownerEntity) {
|
||||
ObjectAction(ACTION_TYPE_OFFSET, id, ownerEntity),
|
||||
_pointToOffsetFrom(0.0f),
|
||||
_linearDistance(0.0f),
|
||||
_linearTimeScale(FLT_MAX),
|
||||
_positionalTargetSet(false) {
|
||||
#if WANT_DEBUG
|
||||
qDebug() << "ObjectActionOffset::ObjectActionOffset";
|
||||
#endif
|
||||
|
@ -44,6 +48,7 @@ void ObjectActionOffset::updateActionWorker(btScalar deltaTimeStep) {
|
|||
unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
|
||||
btRigidBody* rigidBody = motionState->getRigidBody();
|
||||
if (!rigidBody) {
|
||||
|
@ -52,21 +57,32 @@ void ObjectActionOffset::updateActionWorker(btScalar deltaTimeStep) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (_positionalTargetSet) {
|
||||
glm::vec3 offset = _pointToOffsetFrom - bulletToGLM(rigidBody->getCenterOfMassPosition());
|
||||
float offsetLength = glm::length(offset);
|
||||
float offsetError = _linearDistance - offsetLength;
|
||||
|
||||
// if (glm::abs(offsetError) > IGNORE_POSITION_DELTA) {
|
||||
if (glm::abs(offsetError) > 0.0f) {
|
||||
float offsetErrorAbs = glm::abs(offsetError);
|
||||
float offsetErrorDirection = - offsetError / offsetErrorAbs;
|
||||
glm::vec3 previousVelocity = bulletToGLM(rigidBody->getLinearVelocity());
|
||||
|
||||
glm::vec3 velocityAdjustment = glm::normalize(offset) * offsetErrorDirection * offsetErrorAbs / _linearTimeScale;
|
||||
rigidBody->setLinearVelocity(glmToBullet(previousVelocity + velocityAdjustment));
|
||||
// rigidBody->setLinearVelocity(glmToBullet(velocityAdjustment));
|
||||
const float MAX_LINEAR_TIMESCALE = 600.0f; // 10 minutes is a long time
|
||||
if (_positionalTargetSet && _linearTimeScale < MAX_LINEAR_TIMESCALE) {
|
||||
if (_needsActivation) {
|
||||
rigidBody->activate();
|
||||
_needsActivation = false;
|
||||
}
|
||||
glm::vec3 objectPosition = bulletToGLM(rigidBody->getCenterOfMassPosition());
|
||||
glm::vec3 springAxis = objectPosition - _pointToOffsetFrom; // from anchor to object
|
||||
float distance = glm::length(springAxis);
|
||||
if (distance > FLT_EPSILON) {
|
||||
springAxis /= distance; // normalize springAxis
|
||||
|
||||
// compute (critically damped) target velocity of spring relaxation
|
||||
glm::vec3 offset = (distance - _linearDistance) * springAxis;
|
||||
glm::vec3 targetVelocity = (-1.0f / _linearTimeScale) * offset;
|
||||
|
||||
// compute current velocity and its parallel component
|
||||
glm::vec3 currentVelocity = bulletToGLM(rigidBody->getLinearVelocity());
|
||||
glm::vec3 parallelVelocity = glm::dot(currentVelocity, springAxis) * springAxis;
|
||||
|
||||
// we blend the parallel component with the spring's target velocity to get the new velocity
|
||||
float blend = deltaTimeStep / _linearTimeScale;
|
||||
if (blend > 1.0f) {
|
||||
blend = 1.0f;
|
||||
}
|
||||
rigidBody->setLinearVelocity(glmToBullet(currentVelocity + blend * (targetVelocity - parallelVelocity)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,45 +91,45 @@ void ObjectActionOffset::updateActionWorker(btScalar deltaTimeStep) {
|
|||
|
||||
|
||||
bool ObjectActionOffset::updateArguments(QVariantMap arguments) {
|
||||
bool pOk0 = true;
|
||||
bool ok = true;
|
||||
glm::vec3 pointToOffsetFrom =
|
||||
EntityActionInterface::extractVec3Argument("offset action", arguments, "pointToOffsetFrom", pOk0, true);
|
||||
EntityActionInterface::extractVec3Argument("offset action", arguments, "pointToOffsetFrom", ok, true);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pOk1 = true;
|
||||
ok = true;
|
||||
float linearTimeScale =
|
||||
EntityActionInterface::extractFloatArgument("offset action", arguments, "linearTimeScale", pOk1, false);
|
||||
EntityActionInterface::extractFloatArgument("offset action", arguments, "linearTimeScale", ok, false);
|
||||
if (ok) {
|
||||
if (linearTimeScale <= 0.0f) {
|
||||
qDebug() << "offset action -- linearTimeScale must be greater than zero.";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
linearTimeScale = 0.1f;
|
||||
}
|
||||
|
||||
bool pOk2 = true;
|
||||
ok = true;
|
||||
float linearDistance =
|
||||
EntityActionInterface::extractFloatArgument("offset action", arguments, "linearDistance", pOk2, false);
|
||||
|
||||
if (!pOk0) {
|
||||
return false;
|
||||
}
|
||||
if (pOk1 && linearTimeScale <= 0.0f) {
|
||||
qDebug() << "offset action -- linearTimeScale must be greater than zero.";
|
||||
return false;
|
||||
EntityActionInterface::extractFloatArgument("offset action", arguments, "linearDistance", ok, false);
|
||||
if (!ok) {
|
||||
linearDistance = 0.0f;
|
||||
}
|
||||
|
||||
lockForWrite();
|
||||
|
||||
_pointToOffsetFrom = pointToOffsetFrom;
|
||||
_positionalTargetSet = true;
|
||||
|
||||
if (pOk1) {
|
||||
// only change stuff if something actually changed
|
||||
if (_pointToOffsetFrom != pointToOffsetFrom
|
||||
|| _linearTimeScale != linearTimeScale
|
||||
|| _linearDistance != linearDistance) {
|
||||
lockForWrite();
|
||||
_pointToOffsetFrom = pointToOffsetFrom;
|
||||
_linearTimeScale = linearTimeScale;
|
||||
} else {
|
||||
_linearTimeScale = 0.1f;
|
||||
}
|
||||
|
||||
if (pOk2) {
|
||||
_linearDistance = linearDistance;
|
||||
} else {
|
||||
_linearDistance = 1.0f;
|
||||
_positionalTargetSet = true;
|
||||
_active = true;
|
||||
_needsActivation = true;
|
||||
unlock();
|
||||
}
|
||||
|
||||
_active = true;
|
||||
unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
float _linearDistance;
|
||||
float _linearTimeScale;
|
||||
bool _positionalTargetSet;
|
||||
bool _needsActivation = true;
|
||||
};
|
||||
|
||||
#endif // hifi_ObjectActionOffset_h
|
||||
|
|
|
@ -80,8 +80,19 @@ void ObjectMotionState::setBodyGravity(const glm::vec3& gravity) const {
|
|||
}
|
||||
|
||||
glm::vec3 ObjectMotionState::getBodyLinearVelocity() const {
|
||||
return bulletToGLM(_body->getLinearVelocity());
|
||||
// returns the body's velocity unless it is moving too slow in which case returns zero
|
||||
btVector3 velocity = _body->getLinearVelocity();
|
||||
|
||||
// NOTE: the threshold to use here relates to the linear displacement threshold (dX) for sending updates
|
||||
// to objects that are tracked server-side (e.g. entities which use dX = 2mm). Hence an object moving
|
||||
// just under this velocity threshold would trigger an update about V/dX times per second.
|
||||
const float MIN_LINEAR_SPEED_SQUARED = 0.0036f; // 6 mm/sec
|
||||
if (velocity.length2() < MIN_LINEAR_SPEED_SQUARED) {
|
||||
velocity *= 0.0f;
|
||||
}
|
||||
return bulletToGLM(velocity);
|
||||
}
|
||||
|
||||
glm::vec3 ObjectMotionState::getObjectLinearVelocityChange() const {
|
||||
return glm::vec3(0.0f); // Subclasses override where meaningful.
|
||||
}
|
||||
|
|
72
libraries/shared/src/GenericQueueThread.h
Normal file
72
libraries/shared/src/GenericQueueThread.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/07/08.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_GenericQueueThread_h
|
||||
#define hifi_GenericQueueThread_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <QQueue>
|
||||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
|
||||
#include "GenericThread.h"
|
||||
#include "NumericalConstants.h"
|
||||
|
||||
template <typename T>
|
||||
class GenericQueueThread : public GenericThread {
|
||||
public:
|
||||
using Queue = QQueue<T>;
|
||||
GenericQueueThread(QObject* parent = nullptr)
|
||||
: GenericThread(parent) {}
|
||||
|
||||
virtual ~GenericQueueThread() {}
|
||||
|
||||
void queueItem(const T& t) {
|
||||
lock();
|
||||
queueItemInternal(t);
|
||||
unlock();
|
||||
_hasItems.wakeAll();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void queueItemInternal(const T& t) {
|
||||
_items.push_back(t);
|
||||
}
|
||||
|
||||
virtual uint32_t getMaxWait() {
|
||||
return MSECS_PER_SECOND;
|
||||
}
|
||||
|
||||
virtual bool process() {
|
||||
if (!_items.size()) {
|
||||
_hasItemsMutex.lock();
|
||||
_hasItems.wait(&_hasItemsMutex, getMaxWait());
|
||||
_hasItemsMutex.unlock();
|
||||
}
|
||||
|
||||
if (!_items.size()) {
|
||||
return isStillRunning();
|
||||
}
|
||||
|
||||
Queue processItems;
|
||||
lock();
|
||||
processItems.swap(_items);
|
||||
unlock();
|
||||
return processQueueItems(processItems);
|
||||
}
|
||||
|
||||
virtual bool processQueueItems(const Queue& items) = 0;
|
||||
|
||||
Queue _items;
|
||||
QWaitCondition _hasItems;
|
||||
QMutex _hasItemsMutex;
|
||||
};
|
||||
|
||||
#endif // hifi_GenericQueueThread_h
|
|
@ -14,7 +14,8 @@
|
|||
#include "GenericThread.h"
|
||||
|
||||
|
||||
GenericThread::GenericThread() :
|
||||
GenericThread::GenericThread(QObject* parent) :
|
||||
QObject(parent),
|
||||
_stopThread(false),
|
||||
_isThreaded(false) // assume non-threaded, must call initialize()
|
||||
{
|
||||
|
@ -27,13 +28,14 @@ GenericThread::~GenericThread() {
|
|||
}
|
||||
}
|
||||
|
||||
void GenericThread::initialize(bool isThreaded) {
|
||||
void GenericThread::initialize(bool isThreaded, QThread::Priority priority) {
|
||||
_isThreaded = isThreaded;
|
||||
if (_isThreaded) {
|
||||
_thread = new QThread(this);
|
||||
|
||||
// match the thread name to our object name
|
||||
_thread->setObjectName(objectName());
|
||||
_thread->setPriority(priority);
|
||||
|
||||
// when the worker thread is started, call our engine's run..
|
||||
connect(_thread, SIGNAL(started()), this, SLOT(threadRoutine()));
|
||||
|
|
|
@ -23,12 +23,12 @@
|
|||
class GenericThread : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
GenericThread();
|
||||
GenericThread(QObject* parent = nullptr);
|
||||
virtual ~GenericThread();
|
||||
|
||||
/// Call to start the thread.
|
||||
/// \param bool isThreaded true by default. false for non-threaded mode and caller must call threadRoutine() regularly.
|
||||
void initialize(bool isThreaded = true);
|
||||
void initialize(bool isThreaded = true, QThread::Priority priority = QThread::NormalPriority);
|
||||
|
||||
/// Call to stop the thread
|
||||
void terminate();
|
||||
|
|
Loading…
Reference in a new issue