3
0
Fork 0
mirror of https://github.com/lubosz/overte.git synced 2025-04-27 07:15:30 +02:00

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

Conflicts:
	libraries/metavoxels/src/Spanner.cpp
This commit is contained in:
Andrzej Kapolka 2015-01-09 11:52:05 -08:00
commit e3074d726b
33 changed files with 171 additions and 167 deletions

View file

@ -184,6 +184,7 @@ void Agent::run() {
loop.exec();
QString scriptContents(reply->readAll());
delete reply;
qDebug() << "Downloaded script:" << scriptContents;

View file

@ -60,7 +60,7 @@
#include "AudioMixer.h"
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 QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer";
const QString AUDIO_ENV_GROUP_KEY = "audio_env";

View file

@ -1736,6 +1736,9 @@ bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &u
connection->respond(HTTPConnection::StatusCode302, QByteArray(),
HTTPConnection::DefaultContentType, cookieHeaders);
delete tokenReply;
delete profileReply;
// we've redirected the user back to our homepage
return true;

View file

@ -3770,9 +3770,9 @@ void Application::parseVersionXml() {
QString latestVersion;
QUrl downloadUrl;
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()) {
if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == operatingSystem) {

View file

@ -454,47 +454,6 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
return;
}
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 {

View file

@ -49,16 +49,22 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX
Avatar* owningAvatar = static_cast<Avatar*>(_owningHead->_owningAvatar);
// get the rotation axes in joint space and use them to adjust the rotation
glm::mat3 axes = glm::mat3_cast(glm::quat());
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() * glm::translate(state.getDefaultTranslationInConstrainedFrame()) *
joint.preTransform * glm::mat4_cast(joint.preRotation)));
state.setRotationInConstrainedFrame(
glm::angleAxis(- RADIANS_PER_DEGREE * (_owningHead->getFinalRoll() - owningAvatar->getHead()->getFinalLeanSideways()),
glm::normalize(inverse * axes[2]))
* glm::angleAxis(RADIANS_PER_DEGREE * (_owningHead->getFinalYaw() - _owningHead->getTorsoTwist()),
glm::normalize(inverse * axes[1]))
* glm::angleAxis(- RADIANS_PER_DEGREE * (_owningHead->getFinalPitch() - owningAvatar->getHead()->getFinalLeanForward()),
glm::normalize(inverse * axes[0]))
* joint.rotation, DEFAULT_PRIORITY);
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() *
glm::translate(state.getDefaultTranslationInConstrainedFrame()) *
joint.preTransform * glm::mat4_cast(joint.preRotation)));
glm::vec3 pitchYawRoll = safeEulerAngles(_owningHead->getFinalOrientationInLocalFrame());
if (owningAvatar->isMyAvatar()) {
glm::vec3 lean = glm::radians(glm::vec3(_owningHead->getFinalLeanForward(),
_owningHead->getTorsoTwist(),
_owningHead->getFinalLeanSideways()));
pitchYawRoll -= lean;
}
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) {

View file

@ -158,6 +158,8 @@ void ScriptEditorWidget::loadFile(const QString& scriptPath) {
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();
_scriptEditorWidgetUI->scriptEdit->setPlainText(reply->readAll());
delete reply;
if (!saveAs()) {
static_cast<ScriptEditorWindow*>(this->parent()->parent()->parent())->terminateCurrentTab();
}

View file

@ -148,6 +148,7 @@ void SnapshotShareDialog::postRequestFinished() {
QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender());
QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll());
requestReply->deleteLater();
const QJsonObject& responseObject = jsonResponse.object();
if (responseObject.contains("id")) {

View file

@ -205,6 +205,7 @@ void BillboardOverlay::replyFinished() {
QNetworkReply* reply = static_cast<QNetworkReply*>(sender());
_billboard = reply->readAll();
_isLoaded = true;
reply->deleteLater();
}
bool BillboardOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,

View file

@ -66,6 +66,7 @@ void ImageOverlay::replyFinished() {
_textureImage.loadFromData(rawData);
_renderImage = true;
_isLoaded = true;
reply->deleteLater();
}
void ImageOverlay::render(RenderArgs* args) {

View file

@ -26,8 +26,8 @@ namespace AudioConstants {
const int NETWORK_FRAME_BYTES_PER_CHANNEL = 512;
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
/ (float) AudioConstants::SAMPLE_RATE) * 1000.0;
const unsigned int NETWORK_FRAME_USECS = floorf(NETWORK_FRAME_MSECS * 1000.0);
/ (float)AudioConstants::SAMPLE_RATE) * 1000.0f;
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 MAX_SAMPLE_VALUE = std::numeric_limits<AudioSample>::max();
}

View file

@ -80,6 +80,7 @@ void Sound::downloadFinished(QNetworkReply* reply) {
}
_isReady = true;
reply->deleteLater();
}
void Sound::downSample(const QByteArray& rawAudioByteArray) {

View file

@ -175,11 +175,6 @@ QByteArray AvatarData::toByteArray() {
// Instantaneous audio loudness (used to drive facial animation)
memcpy(destinationBuffer, &_headData->_audioLoudness, 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
unsigned char bitItems = 0;
@ -300,11 +295,10 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
// lookAt = 12
// audioLoudness = 4
// }
// + 1 byte for messageSize (0)
// + 1 byte for pupilSize
// + 1 byte for numJoints (0)
// = 53 bytes
int minPossibleSize = 53;
int minPossibleSize = 52;
int maxAvailableSize = packet.size() - offset;
if (minPossibleSize > maxAvailableSize) {
@ -420,23 +414,6 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
_headData->_audioLoudness = audioLoudness;
} // 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
unsigned char bitItems = *sourceBuffer++;

View file

@ -32,17 +32,17 @@ typedef unsigned long long quint64;
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <QtCore/QElapsedTimer>
#include <QtCore/QByteArray>
#include <QtCore/QHash>
#include <QtCore/QObject>
#include <QtCore/QStringList>
#include <QtCore/QUrl>
#include <QtCore/QVector>
#include <QtCore/QVariantMap>
#include <QByteArray>
#include <QElapsedTimer>
#include <QHash>
#include <QObject>
#include <QRect>
#include <QScriptable>
#include <QStringList>
#include <QUrl>
#include <QUuid>
#include <QVariantMap>
#include <QVector>
#include <CollisionInfo.h>
#include <RegisteredMetaTypes.h>
@ -130,7 +130,6 @@ class AvatarData : public QObject {
Q_PROPERTY(float bodyYaw READ getBodyYaw WRITE setBodyYaw)
Q_PROPERTY(float bodyPitch READ getBodyPitch WRITE setBodyPitch)
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 headOrientation READ getHeadOrientation WRITE setHeadOrientation)
@ -242,12 +241,6 @@ public:
void setKeyState(KeyState s) { _keyState = s; }
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; }
const HeadData* getHeadData() const { return _headData; }
const HandData* getHandData() const { return _handData; }
@ -355,9 +348,6 @@ protected:
// key state
KeyState _keyState;
// chat message
std::string _chatMessage;
bool _isChatCirclingEnabled;
bool _forceFaceshiftConnected;
bool _hasNewJointRotations; // set in AvatarData, cleared in Avatar
@ -396,7 +386,6 @@ private:
AvatarData(const AvatarData&);
AvatarData& operator= (const AvatarData&);
};
Q_DECLARE_METATYPE(AvatarData*)
class JointData {

View file

@ -145,6 +145,7 @@ QString EntityTreeRenderer::loadScriptContents(const QString& scriptMaybeURLorTe
} else {
qDebug() << "ERROR Loading file:" << url.toString();
}
delete reply;
}
}

View file

@ -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
// and we can stop searching.
if (entityTreeElement == details.containingElement) {
EntityItemID entityItemID = details.entity->getEntityItemID();
EntityItem* theEntity = entityTreeElement->getEntityWithEntityItemID(entityItemID); // find the actual entity
assert(theEntity);
_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!
EntityItem* theEntity = details.entity;
assert(entityTreeElement->removeEntityItem(theEntity)); // remove it from the element
_tree->setContainingElement(details.entity->getEntityItemID(), NULL); // update or id to element lookup
_foundCount++;
}
}

View file

@ -14,11 +14,13 @@
class EntityToDeleteDetails {
public:
const EntityItem* entity;
EntityItem* entity;
AACube cube;
EntityTreeElement* containingElement;
};
typedef QSet<EntityToDeleteDetails> RemovedEntities;
inline uint qHash(const EntityToDeleteDetails& a, uint seed) {
return qHash(a.entity->getEntityItemID(), seed);
}
@ -36,9 +38,11 @@ public:
void addEntityIDToDeleteList(const EntityItemID& searchEntityID);
virtual bool preRecursion(OctreeElement* element);
virtual bool postRecursion(OctreeElement* element);
const RemovedEntities& getEntities() const { return _entitiesToDelete; }
private:
EntityTree* _tree;
QSet<EntityToDeleteDetails> _entitiesToDelete;
RemovedEntities _entitiesToDelete;
quint64 _changeTime;
int _foundCount;
int _lookingCount;

View file

@ -1019,7 +1019,6 @@ void EntityItem::recalculateCollisionShape() {
}
const float MIN_POSITION_DELTA = 0.0001f;
const float MIN_DIMENSION_DELTA = 0.0001f;
const float MIN_ALIGNMENT_DOT = 0.9999f;
const float MIN_MASS_DELTA = 0.001f;
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) {
if (glm::distance(_dimensions, value) * (float)TREE_SCALE > MIN_DIMENSION_DELTA) {
_dimensions = value;
if (_dimensions != value) {
_dimensions = glm::abs(value);
recalculateCollisionShape();
_dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS);
}
}
void EntityItem::updateDimensionsInMeters(const glm::vec3& value) {
glm::vec3 dimensions = value / (float) TREE_SCALE;
if (glm::distance(_dimensions, dimensions) * (float)TREE_SCALE > MIN_DIMENSION_DELTA) {
_dimensions = dimensions;
glm::vec3 dimensions = glm::abs(value) / (float) TREE_SCALE;
if (_dimensions != dimensions) {
_dimensions = dimensions;
recalculateCollisionShape();
_dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS);
}

View file

@ -38,6 +38,7 @@ void EntitySimulation::updateEntities(QSet<EntityItem*>& entitiesToDelete) {
_entitiesToDelete.clear();
}
// private
void EntitySimulation::expireMortalEntities(const quint64& now) {
if (now > _nextExpiry) {
// 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) {
PerformanceTimer perfTimer("updatingEntities");
QSet<EntityItem*>::iterator itemItr = _updateableEntities.begin();
@ -79,6 +81,7 @@ void EntitySimulation::callUpdateOnEntitiesThatNeedIt(const quint64& now) {
}
}
// private
void EntitySimulation::sortEntitiesThatMoved() {
// 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.

View file

@ -33,9 +33,12 @@ const int DIRTY_SIMULATION_FLAGS =
class EntitySimulation {
public:
EntitySimulation() : _entityTree(NULL) { }
EntitySimulation() : _mutex(QMutex::Recursive), _entityTree(NULL) { }
virtual ~EntitySimulation() { setEntityTree(NULL); }
void lock() { _mutex.lock(); }
void unlock() { _mutex.unlock(); }
/// \param tree pointer to EntityTree which is stored internally
void setEntityTree(EntityTree* tree);
@ -80,6 +83,8 @@ protected:
void callUpdateOnEntitiesThatNeedIt(const quint64& now);
void sortEntitiesThatMoved();
QMutex _mutex;
// back pointer to EntityTree structure
EntityTree* _entityTree;

View file

@ -15,7 +15,6 @@
#include "EntitySimulation.h"
#include "AddEntityOperator.h"
#include "DeleteEntityOperator.h"
#include "MovingEntitiesOperator.h"
#include "UpdateEntityOperator.h"
@ -40,7 +39,9 @@ EntityTreeElement* EntityTree::createNewElement(unsigned char * octalCode) {
void EntityTree::eraseAllOctreeElements(bool createNewRoot) {
// this would be a good place to clean up our entities...
if (_simulation) {
_simulation->lock();
_simulation->clearEntities();
_simulation->unlock();
}
foreach (EntityTreeElement* element, _entityToElementMap) {
element->cleanupEntities();
@ -84,7 +85,9 @@ void EntityTree::postAddEntity(EntityItem* entity) {
assert(entity);
// check to see if we need to simulate this entity..
if (_simulation) {
_simulation->lock();
_simulation->addEntity(entity);
_simulation->unlock();
}
_isDirty = true;
emit addingEntity(entity->getEntityItemID());
@ -141,7 +144,9 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro
if (newFlags) {
if (_simulation) {
if (newFlags & DIRTY_SIMULATION_FLAGS) {
_simulation->lock();
_simulation->entityChanged(entity);
_simulation->unlock();
}
} else {
// 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;
}
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) {
emit entityScriptChanging(entityItemID);
}
@ -231,7 +221,9 @@ void EntityTree::setSimulation(EntitySimulation* simulation) {
if (_simulation && _simulation != simulation) {
// It's important to clearEntities() on the simulation since taht will update each
// EntityItem::_simulationState correctly so as to not confuse the next _simulation.
_simulation->lock();
_simulation->clearEntities();
_simulation->unlock();
}
_simulation = simulation;
}
@ -242,6 +234,7 @@ void EntityTree::deleteEntity(const EntityItemID& entityID) {
// NOTE: callers must lock the tree before using this method
DeleteEntityOperator theOperator(this, entityID);
recurseTreeWithOperator(&theOperator);
processRemovedEntities(theOperator);
_isDirty = true;
}
@ -255,9 +248,36 @@ void EntityTree::deleteEntities(QSet<EntityItemID> entityIDs) {
}
recurseTreeWithOperator(&theOperator);
processRemovedEntities(theOperator);
_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 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
@ -592,7 +612,9 @@ void EntityTree::releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncod
void EntityTree::entityChanged(EntityItem* entity) {
if (_simulation) {
_simulation->lock();
_simulation->entityChanged(entity);
_simulation->unlock();
}
}
@ -600,7 +622,9 @@ void EntityTree::update() {
if (_simulation) {
lockForWrite();
QSet<EntityItem*> entitiesToDelete;
_simulation->lock();
_simulation->updateEntities(entitiesToDelete);
_simulation->unlock();
if (entitiesToDelete.size() > 0) {
// translate into list of ID's
QSet<EntityItemID> idsToDelete;

View file

@ -16,6 +16,7 @@
#include <Octree.h>
#include "EntityTreeElement.h"
#include "DeleteEntityOperator.h"
class Model;
@ -146,8 +147,6 @@ public:
void entityChanged(EntityItem* entity);
void trackDeletedEntity(EntityItem* entity);
void emitEntityScriptChanging(const EntityItemID& entityItemID);
void setSimulation(EntitySimulation* simulation);
@ -160,6 +159,7 @@ signals:
private:
void processRemovedEntities(const DeleteEntityOperator& theOperator);
bool updateEntityWithElement(EntityItem* entity, const EntityItemProperties& properties,
EntityTreeElement* containingElement);
static bool findNearPointOperation(OctreeElement* element, void* extraData);

View file

@ -240,6 +240,7 @@ void DomainHandler::settingsRequestFinished() {
requestDomainSettings();
}
}
settingsReply->deleteLater();
}
void DomainHandler::parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket) {

View file

@ -57,7 +57,7 @@ PacketVersion versionForPacketType(PacketType type) {
case PacketTypeInjectAudio:
return 1;
case PacketTypeAvatarData:
return 3;
return 4;
case PacketTypeAvatarIdentity:
return 1;
case PacketTypeEnvironmentData:

View file

@ -67,13 +67,27 @@ QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl&
_resources.insert(url, resource);
} else {
_unusedResources.remove(resource->getLRUKey());
removeUnusedResource(resource);
}
return 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_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) {
// unload the oldest resource
QMap<int, QSharedPointer<Resource> >::iterator it = _unusedResources.begin();
@ -82,6 +96,14 @@ void ResourceCache::addUnusedResource(const QSharedPointer<Resource>& resource)
}
resource->setLRUKey(++_lastLRUKey);
_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) {

View file

@ -45,7 +45,8 @@ public:
void refresh(const QUrl& url);
protected:
qint64 _unusedResourcesTotalBytes = 0;
QMap<int, QSharedPointer<Resource> > _unusedResources;
/// Loads a resource from the specified URL.
@ -58,8 +59,9 @@ protected:
/// Creates a new resource.
virtual QSharedPointer<Resource> createResource(const QUrl& url,
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) = 0;
void addUnusedResource(const QSharedPointer<Resource>& resource);
void removeUnusedResource(const QSharedPointer<Resource>& resource);
static void attemptRequest(Resource* resource);
static void requestCompleted(Resource* resource);

View file

@ -169,7 +169,7 @@ void PhysicsEngine::init(EntityEditPacketSender* packetSender) {
_collisionDispatcher = new btCollisionDispatcher(_collisionConfig);
_broadphaseFilter = new btDbvtBroadphase();
_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
// TODO: set up gravity zones
@ -200,13 +200,14 @@ void PhysicsEngine::init(EntityEditPacketSender* packetSender) {
const float FIXED_SUBSTEP = 1.0f / 60.0f;
void PhysicsEngine::stepSimulation() {
lock();
// NOTE: the grand order of operations is:
// (1) relay incoming changes
// (2) step simulation
// (3) synchronize outgoing motion states
// (4) send outgoing packets
// this is step (1)
// This is step (1).
relayIncomingChangesToSimulation();
const int MAX_NUM_SUBSTEPS = 4;
@ -215,9 +216,24 @@ void PhysicsEngine::stepSimulation() {
_clock.reset();
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);
_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:

View file

@ -15,8 +15,6 @@
* Copied and modified from btDiscreteDynamicsWorld.cpp by AndrewMeadows on 2014.11.12.
* */
#include <EntityTree.h>
#include "ThreadSafeDynamicsWorld.h"
#ifdef USE_BULLET_PHYSICS
@ -24,17 +22,8 @@ ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld(
btDispatcher* dispatcher,
btBroadphaseInterface* pairCache,
btConstraintSolver* constraintSolver,
btCollisionConfiguration* collisionConfiguration,
EntityTree* entities)
btCollisionConfiguration* 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) {
@ -82,10 +71,15 @@ int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps,
}
}
// We only sync motion states once at the end of all substeps.
// This is to avoid placing multiple, repeated thread locks on _entities.
synchronizeMotionStates();
// NOTE: We do NOT call synchronizeMotionState() after each substep (to avoid multiple locks on the
// object data outside of the physics engine). A consequence of this is that the transforms of the
// 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();
return subSteps;
return subSteps;
}
#endif // USE_BULLET_PHYSICS

View file

@ -21,8 +21,6 @@
#ifdef USE_BULLET_PHYSICS
#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
class EntityTree;
ATTRIBUTE_ALIGNED16(class) ThreadSafeDynamicsWorld : public btDiscreteDynamicsWorld {
public:
BT_DECLARE_ALIGNED_ALLOCATOR();
@ -31,20 +29,15 @@ public:
btDispatcher* dispatcher,
btBroadphaseInterface* pairCache,
btConstraintSolver* constraintSolver,
btCollisionConfiguration* collisionConfiguration,
EntityTree* entities);
btCollisionConfiguration* collisionConfiguration);
// virtual overrides from btDiscreteDynamicsWorld
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
// 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).
float getLocalTimeAccumulation() const { return m_localTime; }
private:
EntityTree* _entities;
};
#else // USE_BULLET_PHYSICS

View file

@ -194,6 +194,8 @@ void ScriptEngine::handleScriptDownload() {
qDebug() << "ERROR Loading file:" << reply->url().toString();
emit errorLoadingScript(_fileNameString);
}
reply->deleteLater();
}
void ScriptEngine::init() {
@ -605,6 +607,7 @@ void ScriptEngine::include(const QString& includeFile) {
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
includeContents = reply->readAll();
reply->deleteLater();
} else {
#ifdef _WIN32
QString fileName = url.toString();

View file

@ -332,7 +332,7 @@ void XMLHttpRequestClass::abortRequest() {
if (_reply) {
disconnectFromReply(_reply);
_reply->abort();
delete _reply;
_reply->deleteLater();
_reply = NULL;
}

View file

@ -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)";
}
QByteArray extraContent;
extraContent.fill(0xba, 10);
extraContent.fill(0xbaU, 10);
encoded.append(extraContent);
if (verbose) {

View file

@ -837,7 +837,7 @@ int TextTemplate::evalBlockGeneration(std::ostream& dst, const BlockPointer& blo
if (block->command.arguments.size()) {
// THe actual value of the var defined sneeds to be evaluated:
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
int len = block->command.arguments[t].length();
if ((block->command.arguments[t][0] == Tag::VAR)