mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 08:56:25 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into metavoxels
Conflicts: libraries/metavoxels/src/Spanner.cpp
This commit is contained in:
commit
e3074d726b
33 changed files with 171 additions and 167 deletions
|
@ -184,6 +184,7 @@ void Agent::run() {
|
||||||
loop.exec();
|
loop.exec();
|
||||||
|
|
||||||
QString scriptContents(reply->readAll());
|
QString scriptContents(reply->readAll());
|
||||||
|
delete reply;
|
||||||
|
|
||||||
qDebug() << "Downloaded script:" << scriptContents;
|
qDebug() << "Downloaded script:" << scriptContents;
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
#include "AudioMixer.h"
|
#include "AudioMixer.h"
|
||||||
|
|
||||||
const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f;
|
const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f;
|
||||||
const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.18;
|
const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.18f;
|
||||||
const float DEFAULT_NOISE_MUTING_THRESHOLD = 0.003f;
|
const float DEFAULT_NOISE_MUTING_THRESHOLD = 0.003f;
|
||||||
const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer";
|
const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer";
|
||||||
const QString AUDIO_ENV_GROUP_KEY = "audio_env";
|
const QString AUDIO_ENV_GROUP_KEY = "audio_env";
|
||||||
|
|
|
@ -1736,6 +1736,9 @@ bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &u
|
||||||
connection->respond(HTTPConnection::StatusCode302, QByteArray(),
|
connection->respond(HTTPConnection::StatusCode302, QByteArray(),
|
||||||
HTTPConnection::DefaultContentType, cookieHeaders);
|
HTTPConnection::DefaultContentType, cookieHeaders);
|
||||||
|
|
||||||
|
delete tokenReply;
|
||||||
|
delete profileReply;
|
||||||
|
|
||||||
// we've redirected the user back to our homepage
|
// we've redirected the user back to our homepage
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
|
@ -3770,9 +3770,9 @@ void Application::parseVersionXml() {
|
||||||
QString latestVersion;
|
QString latestVersion;
|
||||||
QUrl downloadUrl;
|
QUrl downloadUrl;
|
||||||
QString releaseNotes("Unavailable");
|
QString releaseNotes("Unavailable");
|
||||||
QObject* sender = QObject::sender();
|
QNetworkReply* sender = qobject_cast<QNetworkReply*>(QObject::sender());
|
||||||
|
|
||||||
QXmlStreamReader xml(qobject_cast<QNetworkReply*>(sender));
|
QXmlStreamReader xml(sender);
|
||||||
|
|
||||||
while (!xml.atEnd() && !xml.hasError()) {
|
while (!xml.atEnd() && !xml.hasError()) {
|
||||||
if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == operatingSystem) {
|
if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == operatingSystem) {
|
||||||
|
|
|
@ -454,47 +454,6 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
renderDisplayName();
|
renderDisplayName();
|
||||||
|
|
||||||
if (!_chatMessage.empty()) {
|
|
||||||
int width = 0;
|
|
||||||
int lastWidth = 0;
|
|
||||||
for (string::iterator it = _chatMessage.begin(); it != _chatMessage.end(); it++) {
|
|
||||||
width += (lastWidth = textRenderer(CHAT)->computeWidth(*it));
|
|
||||||
}
|
|
||||||
glPushMatrix();
|
|
||||||
|
|
||||||
glm::vec3 chatPosition = getHead()->getEyePosition() + getBodyUpDirection() * CHAT_MESSAGE_HEIGHT * _scale;
|
|
||||||
glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z);
|
|
||||||
glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation();
|
|
||||||
glm::vec3 chatAxis = glm::axis(chatRotation);
|
|
||||||
glRotatef(glm::degrees(glm::angle(chatRotation)), chatAxis.x, chatAxis.y, chatAxis.z);
|
|
||||||
|
|
||||||
glColor3f(0.0f, 0.8f, 0.0f);
|
|
||||||
glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
|
|
||||||
glRotatef(180.0f, 0.0f, 0.0f, 1.0f);
|
|
||||||
glScalef(_scale * CHAT_MESSAGE_SCALE, _scale * CHAT_MESSAGE_SCALE, 1.0f);
|
|
||||||
|
|
||||||
glDisable(GL_LIGHTING);
|
|
||||||
glDepthMask(false);
|
|
||||||
if (_keyState == NO_KEY_DOWN) {
|
|
||||||
textRenderer(CHAT)->draw(-width / 2.0f, 0, _chatMessage.c_str());
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// rather than using substr and allocating a new string, just replace the last
|
|
||||||
// character with a null, then restore it
|
|
||||||
int lastIndex = _chatMessage.size() - 1;
|
|
||||||
char lastChar = _chatMessage[lastIndex];
|
|
||||||
_chatMessage[lastIndex] = '\0';
|
|
||||||
textRenderer(CHAT)->draw(-width / 2.0f, 0, _chatMessage.c_str());
|
|
||||||
_chatMessage[lastIndex] = lastChar;
|
|
||||||
glColor3f(0.0f, 1.0f, 0.0f);
|
|
||||||
textRenderer(CHAT)->draw(width / 2.0f - lastWidth, 0, _chatMessage.c_str() + lastIndex);
|
|
||||||
}
|
|
||||||
glEnable(GL_LIGHTING);
|
|
||||||
glDepthMask(true);
|
|
||||||
|
|
||||||
glPopMatrix();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
||||||
|
|
|
@ -49,16 +49,22 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX
|
||||||
Avatar* owningAvatar = static_cast<Avatar*>(_owningHead->_owningAvatar);
|
Avatar* owningAvatar = static_cast<Avatar*>(_owningHead->_owningAvatar);
|
||||||
// get the rotation axes in joint space and use them to adjust the rotation
|
// get the rotation axes in joint space and use them to adjust the rotation
|
||||||
glm::mat3 axes = glm::mat3_cast(glm::quat());
|
glm::mat3 axes = glm::mat3_cast(glm::quat());
|
||||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() * glm::translate(state.getDefaultTranslationInConstrainedFrame()) *
|
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() *
|
||||||
joint.preTransform * glm::mat4_cast(joint.preRotation)));
|
glm::translate(state.getDefaultTranslationInConstrainedFrame()) *
|
||||||
state.setRotationInConstrainedFrame(
|
joint.preTransform * glm::mat4_cast(joint.preRotation)));
|
||||||
glm::angleAxis(- RADIANS_PER_DEGREE * (_owningHead->getFinalRoll() - owningAvatar->getHead()->getFinalLeanSideways()),
|
glm::vec3 pitchYawRoll = safeEulerAngles(_owningHead->getFinalOrientationInLocalFrame());
|
||||||
glm::normalize(inverse * axes[2]))
|
if (owningAvatar->isMyAvatar()) {
|
||||||
* glm::angleAxis(RADIANS_PER_DEGREE * (_owningHead->getFinalYaw() - _owningHead->getTorsoTwist()),
|
glm::vec3 lean = glm::radians(glm::vec3(_owningHead->getFinalLeanForward(),
|
||||||
glm::normalize(inverse * axes[1]))
|
_owningHead->getTorsoTwist(),
|
||||||
* glm::angleAxis(- RADIANS_PER_DEGREE * (_owningHead->getFinalPitch() - owningAvatar->getHead()->getFinalLeanForward()),
|
_owningHead->getFinalLeanSideways()));
|
||||||
glm::normalize(inverse * axes[0]))
|
pitchYawRoll -= lean;
|
||||||
* joint.rotation, DEFAULT_PRIORITY);
|
}
|
||||||
|
|
||||||
|
state.setRotationInConstrainedFrame(glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * axes[2]))
|
||||||
|
* glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * axes[1]))
|
||||||
|
* glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * axes[0]))
|
||||||
|
* joint.rotation, DEFAULT_PRIORITY);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentState, const FBXJoint& joint, JointState& state) {
|
void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentState, const FBXJoint& joint, JointState& state) {
|
||||||
|
|
|
@ -158,6 +158,8 @@ void ScriptEditorWidget::loadFile(const QString& scriptPath) {
|
||||||
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||||
loop.exec();
|
loop.exec();
|
||||||
_scriptEditorWidgetUI->scriptEdit->setPlainText(reply->readAll());
|
_scriptEditorWidgetUI->scriptEdit->setPlainText(reply->readAll());
|
||||||
|
delete reply;
|
||||||
|
|
||||||
if (!saveAs()) {
|
if (!saveAs()) {
|
||||||
static_cast<ScriptEditorWindow*>(this->parent()->parent()->parent())->terminateCurrentTab();
|
static_cast<ScriptEditorWindow*>(this->parent()->parent()->parent())->terminateCurrentTab();
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,6 +148,7 @@ void SnapshotShareDialog::postRequestFinished() {
|
||||||
|
|
||||||
QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender());
|
QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender());
|
||||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll());
|
QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll());
|
||||||
|
requestReply->deleteLater();
|
||||||
const QJsonObject& responseObject = jsonResponse.object();
|
const QJsonObject& responseObject = jsonResponse.object();
|
||||||
|
|
||||||
if (responseObject.contains("id")) {
|
if (responseObject.contains("id")) {
|
||||||
|
|
|
@ -205,6 +205,7 @@ void BillboardOverlay::replyFinished() {
|
||||||
QNetworkReply* reply = static_cast<QNetworkReply*>(sender());
|
QNetworkReply* reply = static_cast<QNetworkReply*>(sender());
|
||||||
_billboard = reply->readAll();
|
_billboard = reply->readAll();
|
||||||
_isLoaded = true;
|
_isLoaded = true;
|
||||||
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BillboardOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
bool BillboardOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||||
|
|
|
@ -66,6 +66,7 @@ void ImageOverlay::replyFinished() {
|
||||||
_textureImage.loadFromData(rawData);
|
_textureImage.loadFromData(rawData);
|
||||||
_renderImage = true;
|
_renderImage = true;
|
||||||
_isLoaded = true;
|
_isLoaded = true;
|
||||||
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageOverlay::render(RenderArgs* args) {
|
void ImageOverlay::render(RenderArgs* args) {
|
||||||
|
|
|
@ -26,8 +26,8 @@ namespace AudioConstants {
|
||||||
const int NETWORK_FRAME_BYTES_PER_CHANNEL = 512;
|
const int NETWORK_FRAME_BYTES_PER_CHANNEL = 512;
|
||||||
const int NETWORK_FRAME_SAMPLES_PER_CHANNEL = NETWORK_FRAME_BYTES_PER_CHANNEL / sizeof(AudioSample);
|
const int NETWORK_FRAME_SAMPLES_PER_CHANNEL = NETWORK_FRAME_BYTES_PER_CHANNEL / sizeof(AudioSample);
|
||||||
const float NETWORK_FRAME_MSECS = (AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL
|
const float NETWORK_FRAME_MSECS = (AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL
|
||||||
/ (float) AudioConstants::SAMPLE_RATE) * 1000.0;
|
/ (float)AudioConstants::SAMPLE_RATE) * 1000.0f;
|
||||||
const unsigned int NETWORK_FRAME_USECS = floorf(NETWORK_FRAME_MSECS * 1000.0);
|
const unsigned int NETWORK_FRAME_USECS = (unsigned int)floorf(NETWORK_FRAME_MSECS * 1000.0f);
|
||||||
const int MIN_SAMPLE_VALUE = std::numeric_limits<AudioSample>::min();
|
const int MIN_SAMPLE_VALUE = std::numeric_limits<AudioSample>::min();
|
||||||
const int MAX_SAMPLE_VALUE = std::numeric_limits<AudioSample>::max();
|
const int MAX_SAMPLE_VALUE = std::numeric_limits<AudioSample>::max();
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,7 @@ void Sound::downloadFinished(QNetworkReply* reply) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_isReady = true;
|
_isReady = true;
|
||||||
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::downSample(const QByteArray& rawAudioByteArray) {
|
void Sound::downSample(const QByteArray& rawAudioByteArray) {
|
||||||
|
|
|
@ -175,11 +175,6 @@ QByteArray AvatarData::toByteArray() {
|
||||||
// Instantaneous audio loudness (used to drive facial animation)
|
// Instantaneous audio loudness (used to drive facial animation)
|
||||||
memcpy(destinationBuffer, &_headData->_audioLoudness, sizeof(float));
|
memcpy(destinationBuffer, &_headData->_audioLoudness, sizeof(float));
|
||||||
destinationBuffer += sizeof(float);
|
destinationBuffer += sizeof(float);
|
||||||
|
|
||||||
// chat message
|
|
||||||
*destinationBuffer++ = _chatMessage.size();
|
|
||||||
memcpy(destinationBuffer, _chatMessage.data(), _chatMessage.size() * sizeof(char));
|
|
||||||
destinationBuffer += _chatMessage.size() * sizeof(char);
|
|
||||||
|
|
||||||
// bitMask of less than byte wide items
|
// bitMask of less than byte wide items
|
||||||
unsigned char bitItems = 0;
|
unsigned char bitItems = 0;
|
||||||
|
@ -300,11 +295,10 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
|
||||||
// lookAt = 12
|
// lookAt = 12
|
||||||
// audioLoudness = 4
|
// audioLoudness = 4
|
||||||
// }
|
// }
|
||||||
// + 1 byte for messageSize (0)
|
|
||||||
// + 1 byte for pupilSize
|
// + 1 byte for pupilSize
|
||||||
// + 1 byte for numJoints (0)
|
// + 1 byte for numJoints (0)
|
||||||
// = 53 bytes
|
// = 53 bytes
|
||||||
int minPossibleSize = 53;
|
int minPossibleSize = 52;
|
||||||
|
|
||||||
int maxAvailableSize = packet.size() - offset;
|
int maxAvailableSize = packet.size() - offset;
|
||||||
if (minPossibleSize > maxAvailableSize) {
|
if (minPossibleSize > maxAvailableSize) {
|
||||||
|
@ -420,23 +414,6 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
|
||||||
_headData->_audioLoudness = audioLoudness;
|
_headData->_audioLoudness = audioLoudness;
|
||||||
} // 4 bytes
|
} // 4 bytes
|
||||||
|
|
||||||
// chat
|
|
||||||
int chatMessageSize = *sourceBuffer++;
|
|
||||||
minPossibleSize += chatMessageSize;
|
|
||||||
if (minPossibleSize > maxAvailableSize) {
|
|
||||||
if (shouldLogError(now)) {
|
|
||||||
qDebug() << "Malformed AvatarData packet before ChatMessage;"
|
|
||||||
<< " displayName = '" << _displayName << "'"
|
|
||||||
<< " minPossibleSize = " << minPossibleSize
|
|
||||||
<< " maxAvailableSize = " << maxAvailableSize;
|
|
||||||
}
|
|
||||||
return maxAvailableSize;
|
|
||||||
}
|
|
||||||
{ // chat payload
|
|
||||||
_chatMessage = string((char*)sourceBuffer, chatMessageSize);
|
|
||||||
sourceBuffer += chatMessageSize * sizeof(char);
|
|
||||||
} // 1 + chatMessageSize bytes
|
|
||||||
|
|
||||||
{ // bitFlags and face data
|
{ // bitFlags and face data
|
||||||
unsigned char bitItems = *sourceBuffer++;
|
unsigned char bitItems = *sourceBuffer++;
|
||||||
|
|
||||||
|
|
|
@ -32,17 +32,17 @@ typedef unsigned long long quint64;
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/quaternion.hpp>
|
#include <glm/gtc/quaternion.hpp>
|
||||||
|
|
||||||
#include <QtCore/QElapsedTimer>
|
#include <QByteArray>
|
||||||
#include <QtCore/QByteArray>
|
#include <QElapsedTimer>
|
||||||
#include <QtCore/QHash>
|
#include <QHash>
|
||||||
#include <QtCore/QObject>
|
#include <QObject>
|
||||||
#include <QtCore/QStringList>
|
|
||||||
#include <QtCore/QUrl>
|
|
||||||
#include <QtCore/QVector>
|
|
||||||
#include <QtCore/QVariantMap>
|
|
||||||
#include <QRect>
|
#include <QRect>
|
||||||
#include <QScriptable>
|
#include <QScriptable>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QUrl>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
#include <QVariantMap>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
#include <CollisionInfo.h>
|
#include <CollisionInfo.h>
|
||||||
#include <RegisteredMetaTypes.h>
|
#include <RegisteredMetaTypes.h>
|
||||||
|
@ -130,7 +130,6 @@ class AvatarData : public QObject {
|
||||||
Q_PROPERTY(float bodyYaw READ getBodyYaw WRITE setBodyYaw)
|
Q_PROPERTY(float bodyYaw READ getBodyYaw WRITE setBodyYaw)
|
||||||
Q_PROPERTY(float bodyPitch READ getBodyPitch WRITE setBodyPitch)
|
Q_PROPERTY(float bodyPitch READ getBodyPitch WRITE setBodyPitch)
|
||||||
Q_PROPERTY(float bodyRoll READ getBodyRoll WRITE setBodyRoll)
|
Q_PROPERTY(float bodyRoll READ getBodyRoll WRITE setBodyRoll)
|
||||||
Q_PROPERTY(QString chatMessage READ getQStringChatMessage WRITE setChatMessage)
|
|
||||||
|
|
||||||
Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientation)
|
Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientation)
|
||||||
Q_PROPERTY(glm::quat headOrientation READ getHeadOrientation WRITE setHeadOrientation)
|
Q_PROPERTY(glm::quat headOrientation READ getHeadOrientation WRITE setHeadOrientation)
|
||||||
|
@ -242,12 +241,6 @@ public:
|
||||||
void setKeyState(KeyState s) { _keyState = s; }
|
void setKeyState(KeyState s) { _keyState = s; }
|
||||||
KeyState keyState() const { return _keyState; }
|
KeyState keyState() const { return _keyState; }
|
||||||
|
|
||||||
// chat message
|
|
||||||
void setChatMessage(const std::string& msg) { _chatMessage = msg; }
|
|
||||||
void setChatMessage(const QString& string) { _chatMessage = string.toLocal8Bit().constData(); }
|
|
||||||
const std::string& setChatMessage() const { return _chatMessage; }
|
|
||||||
QString getQStringChatMessage() { return QString(_chatMessage.data()); }
|
|
||||||
|
|
||||||
bool isChatCirclingEnabled() const { return _isChatCirclingEnabled; }
|
bool isChatCirclingEnabled() const { return _isChatCirclingEnabled; }
|
||||||
const HeadData* getHeadData() const { return _headData; }
|
const HeadData* getHeadData() const { return _headData; }
|
||||||
const HandData* getHandData() const { return _handData; }
|
const HandData* getHandData() const { return _handData; }
|
||||||
|
@ -355,9 +348,6 @@ protected:
|
||||||
// key state
|
// key state
|
||||||
KeyState _keyState;
|
KeyState _keyState;
|
||||||
|
|
||||||
// chat message
|
|
||||||
std::string _chatMessage;
|
|
||||||
|
|
||||||
bool _isChatCirclingEnabled;
|
bool _isChatCirclingEnabled;
|
||||||
bool _forceFaceshiftConnected;
|
bool _forceFaceshiftConnected;
|
||||||
bool _hasNewJointRotations; // set in AvatarData, cleared in Avatar
|
bool _hasNewJointRotations; // set in AvatarData, cleared in Avatar
|
||||||
|
@ -396,7 +386,6 @@ private:
|
||||||
AvatarData(const AvatarData&);
|
AvatarData(const AvatarData&);
|
||||||
AvatarData& operator= (const AvatarData&);
|
AvatarData& operator= (const AvatarData&);
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(AvatarData*)
|
Q_DECLARE_METATYPE(AvatarData*)
|
||||||
|
|
||||||
class JointData {
|
class JointData {
|
||||||
|
|
|
@ -145,6 +145,7 @@ QString EntityTreeRenderer::loadScriptContents(const QString& scriptMaybeURLorTe
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "ERROR Loading file:" << url.toString();
|
qDebug() << "ERROR Loading file:" << url.toString();
|
||||||
}
|
}
|
||||||
|
delete reply;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,13 +91,9 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) {
|
||||||
// If this is the element we're looking for, then ask it to remove the old entity
|
// If this is the element we're looking for, then ask it to remove the old entity
|
||||||
// and we can stop searching.
|
// and we can stop searching.
|
||||||
if (entityTreeElement == details.containingElement) {
|
if (entityTreeElement == details.containingElement) {
|
||||||
EntityItemID entityItemID = details.entity->getEntityItemID();
|
EntityItem* theEntity = details.entity;
|
||||||
EntityItem* theEntity = entityTreeElement->getEntityWithEntityItemID(entityItemID); // find the actual entity
|
assert(entityTreeElement->removeEntityItem(theEntity)); // remove it from the element
|
||||||
assert(theEntity);
|
_tree->setContainingElement(details.entity->getEntityItemID(), NULL); // update or id to element lookup
|
||||||
_tree->trackDeletedEntity(theEntity);
|
|
||||||
entityTreeElement->removeEntityItem(theEntity); // remove it from the element
|
|
||||||
_tree->setContainingElement(entityItemID, NULL); // update or id to element lookup
|
|
||||||
delete theEntity; // now actually delete the entity!
|
|
||||||
_foundCount++;
|
_foundCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,13 @@
|
||||||
|
|
||||||
class EntityToDeleteDetails {
|
class EntityToDeleteDetails {
|
||||||
public:
|
public:
|
||||||
const EntityItem* entity;
|
EntityItem* entity;
|
||||||
AACube cube;
|
AACube cube;
|
||||||
EntityTreeElement* containingElement;
|
EntityTreeElement* containingElement;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef QSet<EntityToDeleteDetails> RemovedEntities;
|
||||||
|
|
||||||
inline uint qHash(const EntityToDeleteDetails& a, uint seed) {
|
inline uint qHash(const EntityToDeleteDetails& a, uint seed) {
|
||||||
return qHash(a.entity->getEntityItemID(), seed);
|
return qHash(a.entity->getEntityItemID(), seed);
|
||||||
}
|
}
|
||||||
|
@ -36,9 +38,11 @@ public:
|
||||||
void addEntityIDToDeleteList(const EntityItemID& searchEntityID);
|
void addEntityIDToDeleteList(const EntityItemID& searchEntityID);
|
||||||
virtual bool preRecursion(OctreeElement* element);
|
virtual bool preRecursion(OctreeElement* element);
|
||||||
virtual bool postRecursion(OctreeElement* element);
|
virtual bool postRecursion(OctreeElement* element);
|
||||||
|
|
||||||
|
const RemovedEntities& getEntities() const { return _entitiesToDelete; }
|
||||||
private:
|
private:
|
||||||
EntityTree* _tree;
|
EntityTree* _tree;
|
||||||
QSet<EntityToDeleteDetails> _entitiesToDelete;
|
RemovedEntities _entitiesToDelete;
|
||||||
quint64 _changeTime;
|
quint64 _changeTime;
|
||||||
int _foundCount;
|
int _foundCount;
|
||||||
int _lookingCount;
|
int _lookingCount;
|
||||||
|
|
|
@ -1019,7 +1019,6 @@ void EntityItem::recalculateCollisionShape() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const float MIN_POSITION_DELTA = 0.0001f;
|
const float MIN_POSITION_DELTA = 0.0001f;
|
||||||
const float MIN_DIMENSION_DELTA = 0.0001f;
|
|
||||||
const float MIN_ALIGNMENT_DOT = 0.9999f;
|
const float MIN_ALIGNMENT_DOT = 0.9999f;
|
||||||
const float MIN_MASS_DELTA = 0.001f;
|
const float MIN_MASS_DELTA = 0.001f;
|
||||||
const float MIN_VELOCITY_DELTA = 0.025f;
|
const float MIN_VELOCITY_DELTA = 0.025f;
|
||||||
|
@ -1045,17 +1044,17 @@ void EntityItem::updatePositionInMeters(const glm::vec3& value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::updateDimensions(const glm::vec3& value) {
|
void EntityItem::updateDimensions(const glm::vec3& value) {
|
||||||
if (glm::distance(_dimensions, value) * (float)TREE_SCALE > MIN_DIMENSION_DELTA) {
|
if (_dimensions != value) {
|
||||||
_dimensions = value;
|
_dimensions = glm::abs(value);
|
||||||
recalculateCollisionShape();
|
recalculateCollisionShape();
|
||||||
_dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS);
|
_dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::updateDimensionsInMeters(const glm::vec3& value) {
|
void EntityItem::updateDimensionsInMeters(const glm::vec3& value) {
|
||||||
glm::vec3 dimensions = value / (float) TREE_SCALE;
|
glm::vec3 dimensions = glm::abs(value) / (float) TREE_SCALE;
|
||||||
if (glm::distance(_dimensions, dimensions) * (float)TREE_SCALE > MIN_DIMENSION_DELTA) {
|
if (_dimensions != dimensions) {
|
||||||
_dimensions = dimensions;
|
_dimensions = dimensions;
|
||||||
recalculateCollisionShape();
|
recalculateCollisionShape();
|
||||||
_dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS);
|
_dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ void EntitySimulation::updateEntities(QSet<EntityItem*>& entitiesToDelete) {
|
||||||
_entitiesToDelete.clear();
|
_entitiesToDelete.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// private
|
||||||
void EntitySimulation::expireMortalEntities(const quint64& now) {
|
void EntitySimulation::expireMortalEntities(const quint64& now) {
|
||||||
if (now > _nextExpiry) {
|
if (now > _nextExpiry) {
|
||||||
// only search for expired entities if we expect to find one
|
// only search for expired entities if we expect to find one
|
||||||
|
@ -63,6 +64,7 @@ void EntitySimulation::expireMortalEntities(const quint64& now) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// private
|
||||||
void EntitySimulation::callUpdateOnEntitiesThatNeedIt(const quint64& now) {
|
void EntitySimulation::callUpdateOnEntitiesThatNeedIt(const quint64& now) {
|
||||||
PerformanceTimer perfTimer("updatingEntities");
|
PerformanceTimer perfTimer("updatingEntities");
|
||||||
QSet<EntityItem*>::iterator itemItr = _updateableEntities.begin();
|
QSet<EntityItem*>::iterator itemItr = _updateableEntities.begin();
|
||||||
|
@ -79,6 +81,7 @@ void EntitySimulation::callUpdateOnEntitiesThatNeedIt(const quint64& now) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// private
|
||||||
void EntitySimulation::sortEntitiesThatMoved() {
|
void EntitySimulation::sortEntitiesThatMoved() {
|
||||||
// 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.
|
||||||
|
|
|
@ -33,9 +33,12 @@ const int DIRTY_SIMULATION_FLAGS =
|
||||||
|
|
||||||
class EntitySimulation {
|
class EntitySimulation {
|
||||||
public:
|
public:
|
||||||
EntitySimulation() : _entityTree(NULL) { }
|
EntitySimulation() : _mutex(QMutex::Recursive), _entityTree(NULL) { }
|
||||||
virtual ~EntitySimulation() { setEntityTree(NULL); }
|
virtual ~EntitySimulation() { setEntityTree(NULL); }
|
||||||
|
|
||||||
|
void lock() { _mutex.lock(); }
|
||||||
|
void unlock() { _mutex.unlock(); }
|
||||||
|
|
||||||
/// \param tree pointer to EntityTree which is stored internally
|
/// \param tree pointer to EntityTree which is stored internally
|
||||||
void setEntityTree(EntityTree* tree);
|
void setEntityTree(EntityTree* tree);
|
||||||
|
|
||||||
|
@ -80,6 +83,8 @@ protected:
|
||||||
void callUpdateOnEntitiesThatNeedIt(const quint64& now);
|
void callUpdateOnEntitiesThatNeedIt(const quint64& now);
|
||||||
void sortEntitiesThatMoved();
|
void sortEntitiesThatMoved();
|
||||||
|
|
||||||
|
QMutex _mutex;
|
||||||
|
|
||||||
// back pointer to EntityTree structure
|
// back pointer to EntityTree structure
|
||||||
EntityTree* _entityTree;
|
EntityTree* _entityTree;
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include "EntitySimulation.h"
|
#include "EntitySimulation.h"
|
||||||
|
|
||||||
#include "AddEntityOperator.h"
|
#include "AddEntityOperator.h"
|
||||||
#include "DeleteEntityOperator.h"
|
|
||||||
#include "MovingEntitiesOperator.h"
|
#include "MovingEntitiesOperator.h"
|
||||||
#include "UpdateEntityOperator.h"
|
#include "UpdateEntityOperator.h"
|
||||||
|
|
||||||
|
@ -40,7 +39,9 @@ EntityTreeElement* EntityTree::createNewElement(unsigned char * octalCode) {
|
||||||
void EntityTree::eraseAllOctreeElements(bool createNewRoot) {
|
void EntityTree::eraseAllOctreeElements(bool createNewRoot) {
|
||||||
// this would be a good place to clean up our entities...
|
// this would be a good place to clean up our entities...
|
||||||
if (_simulation) {
|
if (_simulation) {
|
||||||
|
_simulation->lock();
|
||||||
_simulation->clearEntities();
|
_simulation->clearEntities();
|
||||||
|
_simulation->unlock();
|
||||||
}
|
}
|
||||||
foreach (EntityTreeElement* element, _entityToElementMap) {
|
foreach (EntityTreeElement* element, _entityToElementMap) {
|
||||||
element->cleanupEntities();
|
element->cleanupEntities();
|
||||||
|
@ -84,7 +85,9 @@ void EntityTree::postAddEntity(EntityItem* entity) {
|
||||||
assert(entity);
|
assert(entity);
|
||||||
// check to see if we need to simulate this entity..
|
// check to see if we need to simulate this entity..
|
||||||
if (_simulation) {
|
if (_simulation) {
|
||||||
|
_simulation->lock();
|
||||||
_simulation->addEntity(entity);
|
_simulation->addEntity(entity);
|
||||||
|
_simulation->unlock();
|
||||||
}
|
}
|
||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
emit addingEntity(entity->getEntityItemID());
|
emit addingEntity(entity->getEntityItemID());
|
||||||
|
@ -141,7 +144,9 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro
|
||||||
if (newFlags) {
|
if (newFlags) {
|
||||||
if (_simulation) {
|
if (_simulation) {
|
||||||
if (newFlags & DIRTY_SIMULATION_FLAGS) {
|
if (newFlags & DIRTY_SIMULATION_FLAGS) {
|
||||||
|
_simulation->lock();
|
||||||
_simulation->entityChanged(entity);
|
_simulation->entityChanged(entity);
|
||||||
|
_simulation->unlock();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// normally the _simulation clears ALL updateFlags, but since there is none we do it explicitly
|
// normally the _simulation clears ALL updateFlags, but since there is none we do it explicitly
|
||||||
|
@ -204,21 +209,6 @@ EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItem
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EntityTree::trackDeletedEntity(EntityItem* entity) {
|
|
||||||
if (_simulation) {
|
|
||||||
_simulation->removeEntity(entity);
|
|
||||||
}
|
|
||||||
// this is only needed on the server to send delete messages for recently deleted entities to the viewers
|
|
||||||
if (getIsServer()) {
|
|
||||||
// set up the deleted entities ID
|
|
||||||
quint64 deletedAt = usecTimestampNow();
|
|
||||||
_recentlyDeletedEntitiesLock.lockForWrite();
|
|
||||||
_recentlyDeletedEntityItemIDs.insert(deletedAt, entity->getEntityItemID().id);
|
|
||||||
_recentlyDeletedEntitiesLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID) {
|
void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID) {
|
||||||
emit entityScriptChanging(entityItemID);
|
emit entityScriptChanging(entityItemID);
|
||||||
}
|
}
|
||||||
|
@ -231,7 +221,9 @@ void EntityTree::setSimulation(EntitySimulation* simulation) {
|
||||||
if (_simulation && _simulation != simulation) {
|
if (_simulation && _simulation != simulation) {
|
||||||
// It's important to clearEntities() on the simulation since taht will update each
|
// It's important to clearEntities() on the simulation since taht will update each
|
||||||
// EntityItem::_simulationState correctly so as to not confuse the next _simulation.
|
// EntityItem::_simulationState correctly so as to not confuse the next _simulation.
|
||||||
|
_simulation->lock();
|
||||||
_simulation->clearEntities();
|
_simulation->clearEntities();
|
||||||
|
_simulation->unlock();
|
||||||
}
|
}
|
||||||
_simulation = simulation;
|
_simulation = simulation;
|
||||||
}
|
}
|
||||||
|
@ -242,6 +234,7 @@ void EntityTree::deleteEntity(const EntityItemID& entityID) {
|
||||||
// NOTE: callers must lock the tree before using this method
|
// NOTE: callers must lock the tree before using this method
|
||||||
DeleteEntityOperator theOperator(this, entityID);
|
DeleteEntityOperator theOperator(this, entityID);
|
||||||
recurseTreeWithOperator(&theOperator);
|
recurseTreeWithOperator(&theOperator);
|
||||||
|
processRemovedEntities(theOperator);
|
||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,9 +248,36 @@ void EntityTree::deleteEntities(QSet<EntityItemID> entityIDs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
recurseTreeWithOperator(&theOperator);
|
recurseTreeWithOperator(&theOperator);
|
||||||
|
processRemovedEntities(theOperator);
|
||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) {
|
||||||
|
const RemovedEntities& entities = theOperator.getEntities();
|
||||||
|
if (_simulation) {
|
||||||
|
_simulation->lock();
|
||||||
|
}
|
||||||
|
foreach(const EntityToDeleteDetails& details, entities) {
|
||||||
|
EntityItem* theEntity = details.entity;
|
||||||
|
|
||||||
|
if (getIsServer()) {
|
||||||
|
// set up the deleted entities ID
|
||||||
|
quint64 deletedAt = usecTimestampNow();
|
||||||
|
_recentlyDeletedEntitiesLock.lockForWrite();
|
||||||
|
_recentlyDeletedEntityItemIDs.insert(deletedAt, theEntity->getEntityItemID().id);
|
||||||
|
_recentlyDeletedEntitiesLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_simulation) {
|
||||||
|
_simulation->removeEntity(theEntity);
|
||||||
|
}
|
||||||
|
delete theEntity; // now actually delete the entity!
|
||||||
|
}
|
||||||
|
if (_simulation) {
|
||||||
|
_simulation->unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This method is used to find and fix entity IDs that are shifting from creator token based to known ID based entity IDs.
|
/// This method is used to find and fix entity IDs that are shifting from creator token based to known ID based entity IDs.
|
||||||
/// This should only be used on a client side (viewing) tree. The typical usage is that a local editor has been creating
|
/// This should only be used on a client side (viewing) tree. The typical usage is that a local editor has been creating
|
||||||
/// entities in the local tree, those entities have creatorToken based entity IDs. But those entity edits are also sent up to
|
/// entities in the local tree, those entities have creatorToken based entity IDs. But those entity edits are also sent up to
|
||||||
|
@ -592,7 +612,9 @@ void EntityTree::releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncod
|
||||||
|
|
||||||
void EntityTree::entityChanged(EntityItem* entity) {
|
void EntityTree::entityChanged(EntityItem* entity) {
|
||||||
if (_simulation) {
|
if (_simulation) {
|
||||||
|
_simulation->lock();
|
||||||
_simulation->entityChanged(entity);
|
_simulation->entityChanged(entity);
|
||||||
|
_simulation->unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,7 +622,9 @@ void EntityTree::update() {
|
||||||
if (_simulation) {
|
if (_simulation) {
|
||||||
lockForWrite();
|
lockForWrite();
|
||||||
QSet<EntityItem*> entitiesToDelete;
|
QSet<EntityItem*> entitiesToDelete;
|
||||||
|
_simulation->lock();
|
||||||
_simulation->updateEntities(entitiesToDelete);
|
_simulation->updateEntities(entitiesToDelete);
|
||||||
|
_simulation->unlock();
|
||||||
if (entitiesToDelete.size() > 0) {
|
if (entitiesToDelete.size() > 0) {
|
||||||
// translate into list of ID's
|
// translate into list of ID's
|
||||||
QSet<EntityItemID> idsToDelete;
|
QSet<EntityItemID> idsToDelete;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include <Octree.h>
|
#include <Octree.h>
|
||||||
#include "EntityTreeElement.h"
|
#include "EntityTreeElement.h"
|
||||||
|
#include "DeleteEntityOperator.h"
|
||||||
|
|
||||||
|
|
||||||
class Model;
|
class Model;
|
||||||
|
@ -146,8 +147,6 @@ public:
|
||||||
|
|
||||||
void entityChanged(EntityItem* entity);
|
void entityChanged(EntityItem* entity);
|
||||||
|
|
||||||
void trackDeletedEntity(EntityItem* entity);
|
|
||||||
|
|
||||||
void emitEntityScriptChanging(const EntityItemID& entityItemID);
|
void emitEntityScriptChanging(const EntityItemID& entityItemID);
|
||||||
|
|
||||||
void setSimulation(EntitySimulation* simulation);
|
void setSimulation(EntitySimulation* simulation);
|
||||||
|
@ -160,6 +159,7 @@ signals:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void processRemovedEntities(const DeleteEntityOperator& theOperator);
|
||||||
bool updateEntityWithElement(EntityItem* entity, const EntityItemProperties& properties,
|
bool updateEntityWithElement(EntityItem* entity, const EntityItemProperties& properties,
|
||||||
EntityTreeElement* containingElement);
|
EntityTreeElement* containingElement);
|
||||||
static bool findNearPointOperation(OctreeElement* element, void* extraData);
|
static bool findNearPointOperation(OctreeElement* element, void* extraData);
|
||||||
|
|
|
@ -240,6 +240,7 @@ void DomainHandler::settingsRequestFinished() {
|
||||||
requestDomainSettings();
|
requestDomainSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
settingsReply->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainHandler::parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket) {
|
void DomainHandler::parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket) {
|
||||||
|
|
|
@ -57,7 +57,7 @@ PacketVersion versionForPacketType(PacketType type) {
|
||||||
case PacketTypeInjectAudio:
|
case PacketTypeInjectAudio:
|
||||||
return 1;
|
return 1;
|
||||||
case PacketTypeAvatarData:
|
case PacketTypeAvatarData:
|
||||||
return 3;
|
return 4;
|
||||||
case PacketTypeAvatarIdentity:
|
case PacketTypeAvatarIdentity:
|
||||||
return 1;
|
return 1;
|
||||||
case PacketTypeEnvironmentData:
|
case PacketTypeEnvironmentData:
|
||||||
|
|
|
@ -67,13 +67,27 @@ QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl&
|
||||||
_resources.insert(url, resource);
|
_resources.insert(url, resource);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_unusedResources.remove(resource->getLRUKey());
|
removeUnusedResource(resource);
|
||||||
}
|
}
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceCache::addUnusedResource(const QSharedPointer<Resource>& resource) {
|
void ResourceCache::addUnusedResource(const QSharedPointer<Resource>& resource) {
|
||||||
|
static const int BYTES_PER_MEGABYTES = 1024 * 1024;
|
||||||
const int RETAINED_RESOURCE_COUNT = 50;
|
const int RETAINED_RESOURCE_COUNT = 50;
|
||||||
|
const int RETAINED_RESOURCE_SIZE = 100 * BYTES_PER_MEGABYTES;
|
||||||
|
|
||||||
|
while (_unusedResourcesTotalBytes + resource->getBytesTotal() > RETAINED_RESOURCE_SIZE &&
|
||||||
|
!_unusedResources.empty()) {
|
||||||
|
// unload the oldest resource
|
||||||
|
QMap<int, QSharedPointer<Resource> >::iterator it = _unusedResources.begin();
|
||||||
|
|
||||||
|
_unusedResourcesTotalBytes -= it.value()->getBytesTotal();
|
||||||
|
it.value()->setCache(NULL);
|
||||||
|
_unusedResources.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (_unusedResources.size() > RETAINED_RESOURCE_COUNT) {
|
if (_unusedResources.size() > RETAINED_RESOURCE_COUNT) {
|
||||||
// unload the oldest resource
|
// unload the oldest resource
|
||||||
QMap<int, QSharedPointer<Resource> >::iterator it = _unusedResources.begin();
|
QMap<int, QSharedPointer<Resource> >::iterator it = _unusedResources.begin();
|
||||||
|
@ -82,6 +96,14 @@ void ResourceCache::addUnusedResource(const QSharedPointer<Resource>& resource)
|
||||||
}
|
}
|
||||||
resource->setLRUKey(++_lastLRUKey);
|
resource->setLRUKey(++_lastLRUKey);
|
||||||
_unusedResources.insert(resource->getLRUKey(), resource);
|
_unusedResources.insert(resource->getLRUKey(), resource);
|
||||||
|
_unusedResourcesTotalBytes += resource->getBytesTotal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceCache::removeUnusedResource(const QSharedPointer<Resource>& resource) {
|
||||||
|
if (_unusedResources.contains(resource->getLRUKey())) {
|
||||||
|
_unusedResources.remove(resource->getLRUKey());
|
||||||
|
_unusedResourcesTotalBytes -= resource->getBytesTotal();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceCache::attemptRequest(Resource* resource) {
|
void ResourceCache::attemptRequest(Resource* resource) {
|
||||||
|
|
|
@ -45,7 +45,8 @@ public:
|
||||||
void refresh(const QUrl& url);
|
void refresh(const QUrl& url);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
qint64 _unusedResourcesTotalBytes = 0;
|
||||||
QMap<int, QSharedPointer<Resource> > _unusedResources;
|
QMap<int, QSharedPointer<Resource> > _unusedResources;
|
||||||
|
|
||||||
/// Loads a resource from the specified URL.
|
/// Loads a resource from the specified URL.
|
||||||
|
@ -58,8 +59,9 @@ protected:
|
||||||
/// Creates a new resource.
|
/// Creates a new resource.
|
||||||
virtual QSharedPointer<Resource> createResource(const QUrl& url,
|
virtual QSharedPointer<Resource> createResource(const QUrl& url,
|
||||||
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) = 0;
|
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) = 0;
|
||||||
|
|
||||||
void addUnusedResource(const QSharedPointer<Resource>& resource);
|
void addUnusedResource(const QSharedPointer<Resource>& resource);
|
||||||
|
void removeUnusedResource(const QSharedPointer<Resource>& resource);
|
||||||
|
|
||||||
static void attemptRequest(Resource* resource);
|
static void attemptRequest(Resource* resource);
|
||||||
static void requestCompleted(Resource* resource);
|
static void requestCompleted(Resource* resource);
|
||||||
|
|
|
@ -169,7 +169,7 @@ void PhysicsEngine::init(EntityEditPacketSender* packetSender) {
|
||||||
_collisionDispatcher = new btCollisionDispatcher(_collisionConfig);
|
_collisionDispatcher = new btCollisionDispatcher(_collisionConfig);
|
||||||
_broadphaseFilter = new btDbvtBroadphase();
|
_broadphaseFilter = new btDbvtBroadphase();
|
||||||
_constraintSolver = new btSequentialImpulseConstraintSolver;
|
_constraintSolver = new btSequentialImpulseConstraintSolver;
|
||||||
_dynamicsWorld = new ThreadSafeDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig, _entityTree);
|
_dynamicsWorld = new ThreadSafeDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig);
|
||||||
|
|
||||||
// default gravity of the world is zero, so each object must specify its own gravity
|
// default gravity of the world is zero, so each object must specify its own gravity
|
||||||
// TODO: set up gravity zones
|
// TODO: set up gravity zones
|
||||||
|
@ -200,13 +200,14 @@ void PhysicsEngine::init(EntityEditPacketSender* packetSender) {
|
||||||
const float FIXED_SUBSTEP = 1.0f / 60.0f;
|
const float FIXED_SUBSTEP = 1.0f / 60.0f;
|
||||||
|
|
||||||
void PhysicsEngine::stepSimulation() {
|
void PhysicsEngine::stepSimulation() {
|
||||||
|
lock();
|
||||||
// NOTE: the grand order of operations is:
|
// NOTE: the grand order of operations is:
|
||||||
// (1) relay incoming changes
|
// (1) relay incoming changes
|
||||||
// (2) step simulation
|
// (2) step simulation
|
||||||
// (3) synchronize outgoing motion states
|
// (3) synchronize outgoing motion states
|
||||||
// (4) send outgoing packets
|
// (4) send outgoing packets
|
||||||
|
|
||||||
// this is step (1)
|
// This is step (1).
|
||||||
relayIncomingChangesToSimulation();
|
relayIncomingChangesToSimulation();
|
||||||
|
|
||||||
const int MAX_NUM_SUBSTEPS = 4;
|
const int MAX_NUM_SUBSTEPS = 4;
|
||||||
|
@ -215,9 +216,24 @@ void PhysicsEngine::stepSimulation() {
|
||||||
_clock.reset();
|
_clock.reset();
|
||||||
float timeStep = btMin(dt, MAX_TIMESTEP);
|
float timeStep = btMin(dt, MAX_TIMESTEP);
|
||||||
|
|
||||||
// steps (2) and (3) are performed by ThreadSafeDynamicsWorld::stepSimulation())
|
// This is step (2).
|
||||||
int numSubSteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, FIXED_SUBSTEP);
|
int numSubSteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, FIXED_SUBSTEP);
|
||||||
_frameCount += (uint32_t)numSubSteps;
|
_frameCount += (uint32_t)numSubSteps;
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
// This is step (3) which is done outside of stepSimulation() so we can lock _entityTree.
|
||||||
|
//
|
||||||
|
// Unfortunately we have to unlock the simulation (above) before we try to lock the _entityTree
|
||||||
|
// to avoid deadlock -- the _entityTree may try to lock its EntitySimulation (from which this
|
||||||
|
// PhysicsEngine derives) when updating/adding/deleting entities so we need to wait for our own
|
||||||
|
// lock on the tree before we re-lock ourselves.
|
||||||
|
//
|
||||||
|
// TODO: untangle these lock sequences.
|
||||||
|
_entityTree->lockForWrite();
|
||||||
|
lock();
|
||||||
|
_dynamicsWorld->synchronizeMotionStates();
|
||||||
|
unlock();
|
||||||
|
_entityTree->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bullet collision flags are as follows:
|
// Bullet collision flags are as follows:
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
* Copied and modified from btDiscreteDynamicsWorld.cpp by AndrewMeadows on 2014.11.12.
|
* Copied and modified from btDiscreteDynamicsWorld.cpp by AndrewMeadows on 2014.11.12.
|
||||||
* */
|
* */
|
||||||
|
|
||||||
#include <EntityTree.h>
|
|
||||||
|
|
||||||
#include "ThreadSafeDynamicsWorld.h"
|
#include "ThreadSafeDynamicsWorld.h"
|
||||||
|
|
||||||
#ifdef USE_BULLET_PHYSICS
|
#ifdef USE_BULLET_PHYSICS
|
||||||
|
@ -24,17 +22,8 @@ ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld(
|
||||||
btDispatcher* dispatcher,
|
btDispatcher* dispatcher,
|
||||||
btBroadphaseInterface* pairCache,
|
btBroadphaseInterface* pairCache,
|
||||||
btConstraintSolver* constraintSolver,
|
btConstraintSolver* constraintSolver,
|
||||||
btCollisionConfiguration* collisionConfiguration,
|
btCollisionConfiguration* collisionConfiguration)
|
||||||
EntityTree* entities)
|
|
||||||
: btDiscreteDynamicsWorld(dispatcher, pairCache, constraintSolver, collisionConfiguration) {
|
: btDiscreteDynamicsWorld(dispatcher, pairCache, constraintSolver, collisionConfiguration) {
|
||||||
assert(entities);
|
|
||||||
_entities = entities;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ThreadSafeDynamicsWorld::synchronizeMotionStates() {
|
|
||||||
_entities->lockForWrite();
|
|
||||||
btDiscreteDynamicsWorld::synchronizeMotionStates();
|
|
||||||
_entities->unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep) {
|
int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep) {
|
||||||
|
@ -82,10 +71,15 @@ int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only sync motion states once at the end of all substeps.
|
// NOTE: We do NOT call synchronizeMotionState() after each substep (to avoid multiple locks on the
|
||||||
// This is to avoid placing multiple, repeated thread locks on _entities.
|
// object data outside of the physics engine). A consequence of this is that the transforms of the
|
||||||
synchronizeMotionStates();
|
// external objects only ever update at the end of the full step.
|
||||||
|
|
||||||
|
// NOTE: We do NOT call synchronizeMotionStates() here. Instead it is called by an external class
|
||||||
|
// that knows how to lock threads correctly.
|
||||||
|
|
||||||
clearForces();
|
clearForces();
|
||||||
return subSteps;
|
|
||||||
|
return subSteps;
|
||||||
}
|
}
|
||||||
#endif // USE_BULLET_PHYSICS
|
#endif // USE_BULLET_PHYSICS
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
#ifdef USE_BULLET_PHYSICS
|
#ifdef USE_BULLET_PHYSICS
|
||||||
#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
|
#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
|
||||||
|
|
||||||
class EntityTree;
|
|
||||||
|
|
||||||
ATTRIBUTE_ALIGNED16(class) ThreadSafeDynamicsWorld : public btDiscreteDynamicsWorld {
|
ATTRIBUTE_ALIGNED16(class) ThreadSafeDynamicsWorld : public btDiscreteDynamicsWorld {
|
||||||
public:
|
public:
|
||||||
BT_DECLARE_ALIGNED_ALLOCATOR();
|
BT_DECLARE_ALIGNED_ALLOCATOR();
|
||||||
|
@ -31,20 +29,15 @@ public:
|
||||||
btDispatcher* dispatcher,
|
btDispatcher* dispatcher,
|
||||||
btBroadphaseInterface* pairCache,
|
btBroadphaseInterface* pairCache,
|
||||||
btConstraintSolver* constraintSolver,
|
btConstraintSolver* constraintSolver,
|
||||||
btCollisionConfiguration* collisionConfiguration,
|
btCollisionConfiguration* collisionConfiguration);
|
||||||
EntityTree* entities);
|
|
||||||
|
|
||||||
// virtual overrides from btDiscreteDynamicsWorld
|
// virtual overrides from btDiscreteDynamicsWorld
|
||||||
int stepSimulation( btScalar timeStep, int maxSubSteps=1, btScalar fixedTimeStep=btScalar(1.)/btScalar(60.));
|
int stepSimulation( btScalar timeStep, int maxSubSteps=1, btScalar fixedTimeStep=btScalar(1.)/btScalar(60.));
|
||||||
void synchronizeMotionStates();
|
|
||||||
|
|
||||||
// btDiscreteDynamicsWorld::m_localTime is the portion of real-time that has not yet been simulated
|
// btDiscreteDynamicsWorld::m_localTime is the portion of real-time that has not yet been simulated
|
||||||
// but is used for MotionState::setWorldTransform() extrapolation (a feature that Bullet uses to provide
|
// but is used for MotionState::setWorldTransform() extrapolation (a feature that Bullet uses to provide
|
||||||
// smoother rendering of objects when the physics simulation loop is ansynchronous to the render loop).
|
// smoother rendering of objects when the physics simulation loop is ansynchronous to the render loop).
|
||||||
float getLocalTimeAccumulation() const { return m_localTime; }
|
float getLocalTimeAccumulation() const { return m_localTime; }
|
||||||
|
|
||||||
private:
|
|
||||||
EntityTree* _entities;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#else // USE_BULLET_PHYSICS
|
#else // USE_BULLET_PHYSICS
|
||||||
|
|
|
@ -194,6 +194,8 @@ void ScriptEngine::handleScriptDownload() {
|
||||||
qDebug() << "ERROR Loading file:" << reply->url().toString();
|
qDebug() << "ERROR Loading file:" << reply->url().toString();
|
||||||
emit errorLoadingScript(_fileNameString);
|
emit errorLoadingScript(_fileNameString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::init() {
|
void ScriptEngine::init() {
|
||||||
|
@ -605,6 +607,7 @@ void ScriptEngine::include(const QString& includeFile) {
|
||||||
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||||
loop.exec();
|
loop.exec();
|
||||||
includeContents = reply->readAll();
|
includeContents = reply->readAll();
|
||||||
|
reply->deleteLater();
|
||||||
} else {
|
} else {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
QString fileName = url.toString();
|
QString fileName = url.toString();
|
||||||
|
|
|
@ -332,7 +332,7 @@ void XMLHttpRequestClass::abortRequest() {
|
||||||
if (_reply) {
|
if (_reply) {
|
||||||
disconnectFromReply(_reply);
|
disconnectFromReply(_reply);
|
||||||
_reply->abort();
|
_reply->abort();
|
||||||
delete _reply;
|
_reply->deleteLater();
|
||||||
_reply = NULL;
|
_reply = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -802,7 +802,7 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
||||||
qDebug() << "fill encoded byte array with extra garbage (as if it was bitstream with more content)";
|
qDebug() << "fill encoded byte array with extra garbage (as if it was bitstream with more content)";
|
||||||
}
|
}
|
||||||
QByteArray extraContent;
|
QByteArray extraContent;
|
||||||
extraContent.fill(0xba, 10);
|
extraContent.fill(0xbaU, 10);
|
||||||
encoded.append(extraContent);
|
encoded.append(extraContent);
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
|
|
|
@ -837,7 +837,7 @@ int TextTemplate::evalBlockGeneration(std::ostream& dst, const BlockPointer& blo
|
||||||
if (block->command.arguments.size()) {
|
if (block->command.arguments.size()) {
|
||||||
// THe actual value of the var defined sneeds to be evaluated:
|
// THe actual value of the var defined sneeds to be evaluated:
|
||||||
String val;
|
String val;
|
||||||
for (int t = 1; t < block->command.arguments.size(); t++) {
|
for (unsigned int t = 1; t < block->command.arguments.size(); t++) {
|
||||||
// detect if a param is a var
|
// detect if a param is a var
|
||||||
int len = block->command.arguments[t].length();
|
int len = block->command.arguments[t].length();
|
||||||
if ((block->command.arguments[t][0] == Tag::VAR)
|
if ((block->command.arguments[t][0] == Tag::VAR)
|
||||||
|
|
Loading…
Reference in a new issue