Merge branch 'master' of https://github.com/worklist/hifi into 19507

This commit is contained in:
Stojce Slavkovski 2014-05-07 07:38:48 +02:00
commit 490ec23d8c
26 changed files with 1134 additions and 593 deletions

View file

@ -31,14 +31,14 @@ var grabbingWithLeftHand = false;
var wasGrabbingWithLeftHand = false;
var EPSILON = 0.000001;
var velocity = { x: 0, y: 0, z: 0};
var THRUST_MAG_UP = 800.0;
var THRUST_MAG_DOWN = 300.0;
var THRUST_MAG_FWD = 500.0;
var THRUST_MAG_BACK = 300.0;
var THRUST_MAG_LATERAL = 250.0;
var THRUST_MAG_UP = 100.0;
var THRUST_MAG_DOWN = 100.0;
var THRUST_MAG_FWD = 150.0;
var THRUST_MAG_BACK = 100.0;
var THRUST_MAG_LATERAL = 150.0;
var THRUST_JUMP = 120.0;
var YAW_MAG = 500.0;
var YAW_MAG = 100.0;
var PITCH_MAG = 100.0;
var THRUST_MAG_HAND_JETS = THRUST_MAG_FWD;
var JOYSTICK_YAW_MAG = YAW_MAG;

File diff suppressed because one or more lines are too long

View file

@ -2843,7 +2843,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
// save absolute translations
glm::vec3 absoluteSkeletonTranslation = _myAvatar->getSkeletonModel().getTranslation();
glm::vec3 absoluteFaceTranslation = _myAvatar->getHead()->getFaceModel().getTranslation();
// get the eye positions relative to the neck and use them to set the face translation
glm::vec3 leftEyePosition, rightEyePosition;
_myAvatar->getHead()->getFaceModel().setTranslation(glm::vec3());
@ -2857,11 +2857,22 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
_myAvatar->getSkeletonModel().setTranslation(_myAvatar->getHead()->getFaceModel().getTranslation() -
neckPosition);
// update the attachments to match
QVector<glm::vec3> absoluteAttachmentTranslations;
glm::vec3 delta = _myAvatar->getSkeletonModel().getTranslation() - absoluteSkeletonTranslation;
foreach (Model* attachment, _myAvatar->getAttachmentModels()) {
absoluteAttachmentTranslations.append(attachment->getTranslation());
attachment->setTranslation(attachment->getTranslation() + delta);
}
displaySide(_mirrorCamera, true);
// restore absolute translations
_myAvatar->getSkeletonModel().setTranslation(absoluteSkeletonTranslation);
_myAvatar->getHead()->getFaceModel().setTranslation(absoluteFaceTranslation);
for (int i = 0; i < absoluteAttachmentTranslations.size(); i++) {
_myAvatar->getAttachmentModels().at(i)->setTranslation(absoluteAttachmentTranslations.at(i));
}
} else {
displaySide(_mirrorCamera, true);
}

View file

@ -194,7 +194,7 @@ Menu::Menu() :
addDisabledActionAndSeparator(editMenu, "Physics");
QObject* avatar = appInstance->getAvatar();
addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::ObeyEnvironmentalGravity, Qt::SHIFT | Qt::Key_G, true,
addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::ObeyEnvironmentalGravity, Qt::SHIFT | Qt::Key_G, false,
avatar, SLOT(updateMotionBehaviorsFromMenu()));

View file

@ -424,19 +424,24 @@ void ModelUploader::processCheck() {
}
bool ModelUploader::addTextures(const QString& texdir, const FBXGeometry& geometry) {
QSet<QByteArray> added;
foreach (FBXMesh mesh, geometry.meshes) {
foreach (FBXMeshPart part, mesh.parts) {
if (!part.diffuseTexture.filename.isEmpty() && part.diffuseTexture.content.isEmpty()) {
if (!part.diffuseTexture.filename.isEmpty() && part.diffuseTexture.content.isEmpty() &&
!added.contains(part.diffuseTexture.filename)) {
if (!addPart(texdir + "/" + part.diffuseTexture.filename,
QString("texture%1").arg(++_texturesCount), true)) {
return false;
}
added.insert(part.diffuseTexture.filename);
}
if (!part.normalTexture.filename.isEmpty() && part.normalTexture.content.isEmpty()) {
if (!part.normalTexture.filename.isEmpty() && part.normalTexture.content.isEmpty() &&
!added.contains(part.normalTexture.filename)) {
if (!addPart(texdir + "/" + part.normalTexture.filename,
QString("texture%1").arg(++_texturesCount), true)) {
return false;
}
added.insert(part.normalTexture.filename);
}
}
}

View file

@ -369,7 +369,7 @@ void Avatar::simulateAttachments(float deltaTime) {
glm::quat jointRotation;
if (_skeletonModel.getJointPosition(jointIndex, jointPosition) &&
_skeletonModel.getJointRotation(jointIndex, jointRotation)) {
model->setTranslation(jointPosition + jointRotation * attachment.translation * _skeletonModel.getScale());
model->setTranslation(jointPosition + jointRotation * attachment.translation * _scale);
model->setRotation(jointRotation * attachment.rotation);
model->setScale(_skeletonModel.getScale() * attachment.scale);
model->simulate(deltaTime);

View file

@ -83,6 +83,7 @@ public:
//getters
bool isInitialized() const { return _initialized; }
SkeletonModel& getSkeletonModel() { return _skeletonModel; }
const QVector<Model*>& getAttachmentModels() const { return _attachmentModels; }
glm::vec3 getChestPosition() const;
float getScale() const { return _scale; }
const glm::vec3& getVelocity() const { return _velocity; }

View file

@ -59,7 +59,7 @@ MyAvatar::MyAvatar() :
_bodyPitchDelta(0.0f),
_bodyRollDelta(0.0f),
_shouldJump(false),
_gravity(0.0f, -1.0f, 0.0f),
_gravity(0.0f, 0.0f, 0.0f),
_distanceToNearestAvatar(std::numeric_limits<float>::max()),
_wasPushing(false),
_isPushing(false),
@ -146,7 +146,7 @@ void MyAvatar::simulate(float deltaTime) {
boundingShape.getStartPoint(startCap);
glm::vec3 bottomOfBoundingCapsule = startCap + (boundingShape.getRadius() / gravityLength) * _gravity;
float fallThreshold = 2.f * deltaTime * gravityLength;
float fallThreshold = 2.0f * deltaTime * gravityLength;
walkingOnFloor = (glm::distance(bottomOfBoundingCapsule, _lastFloorContactPoint) < fallThreshold);
}
@ -163,7 +163,7 @@ void MyAvatar::simulate(float deltaTime) {
// update position
if (glm::length2(_velocity) < EPSILON) {
_velocity = glm::vec3(0.0f);
} else {
} else {
_position += _velocity * deltaTime;
}
}
@ -349,8 +349,8 @@ void MyAvatar::renderHeadMouse(int screenWidth, int screenHeight) const {
float headYaw = getHead()->getFinalYaw();
float aspectRatio = (float) screenWidth / (float) screenHeight;
int headMouseX = screenWidth / 2.f - headYaw * aspectRatio * pixelsPerDegree;
int headMouseY = screenHeight / 2.f - headPitch * pixelsPerDegree;
int headMouseX = (int)((float)screenWidth / 2.0f - headYaw * aspectRatio * pixelsPerDegree);
int headMouseY = (int)((float)screenHeight / 2.0f - headPitch * pixelsPerDegree);
glColor3f(1.0f, 1.0f, 1.0f);
glDisable(GL_LINE_SMOOTH);
@ -367,8 +367,8 @@ void MyAvatar::renderHeadMouse(int screenWidth, int screenHeight) const {
float avgEyePitch = faceshift->getEstimatedEyePitch();
float avgEyeYaw = faceshift->getEstimatedEyeYaw();
int eyeTargetX = (screenWidth / 2) - avgEyeYaw * aspectRatio * pixelsPerDegree;
int eyeTargetY = (screenHeight / 2) - avgEyePitch * pixelsPerDegree;
int eyeTargetX = (int)((float)(screenWidth) / 2.0f - avgEyeYaw * aspectRatio * pixelsPerDegree);
int eyeTargetY = (int)((float)(screenHeight) / 2.0f - avgEyePitch * pixelsPerDegree);
glColor3f(0.0f, 1.0f, 1.0f);
glDisable(GL_LINE_SMOOTH);
@ -456,9 +456,9 @@ void MyAvatar::loadData(QSettings* settings) {
getHead()->setBasePitch(loadSetting(settings, "headPitch", 0.0f));
_position.x = loadSetting(settings, "position_x", 0.0f);
_position.y = loadSetting(settings, "position_y", 0.0f);
_position.z = loadSetting(settings, "position_z", 0.0f);
_position.x = loadSetting(settings, "position_x", START_LOCATION.x);
_position.y = loadSetting(settings, "position_y", START_LOCATION.y);
_position.z = loadSetting(settings, "position_z", START_LOCATION.z);
getHead()->setPupilDilation(loadSetting(settings, "pupilDilation", 0.0f));
@ -514,7 +514,7 @@ void MyAvatar::updateLookAtTargetAvatar() {
// Look at the avatar whose eyes are closest to the ray in direction of my avatar's head
//
_lookAtTargetAvatar.clear();
_targetAvatarPosition = glm::vec3(0, 0, 0);
_targetAvatarPosition = glm::vec3(0.0f);
const float MIN_LOOKAT_ANGLE = PI / 4.0f; // Smallest angle between face and person where we will look at someone
float smallestAngleTo = MIN_LOOKAT_ANGLE;
foreach (const AvatarSharedPointer& avatarPointer, Application::getInstance()->getAvatarManager().getAvatarHash()) {
@ -765,7 +765,7 @@ void MyAvatar::applyMotor(float deltaTime) {
targetVelocity = rotation * _motorVelocity;
}
glm::vec3 targetDirection(0.f);
glm::vec3 targetDirection(0.0f);
if (glm::length2(targetVelocity) > EPSILON) {
targetDirection = glm::normalize(targetVelocity);
}
@ -1382,6 +1382,8 @@ void MyAvatar::updateMotionBehaviorsFromMenu() {
_motionBehaviors |= AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY;
// Environmental and Local gravities are incompatible. Environmental setting trumps local.
_motionBehaviors &= ~AVATAR_MOTION_OBEY_LOCAL_GRAVITY;
} else {
_motionBehaviors &= ~AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY;
}
if (! (_motionBehaviors & (AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY | AVATAR_MOTION_OBEY_LOCAL_GRAVITY))) {
setGravity(glm::vec3(0.0f));

View file

@ -220,15 +220,10 @@ void FaceplusReader::update() {
if (!_referenceInitialized) {
_referenceX = x;
_referenceY = y;
_referenceScale = scale;
_referenceInitialized = true;
}
const float TRANSLATION_SCALE = 10.0f;
const float REFERENCE_DISTANCE = 10.0f;
float depthScale = _referenceScale / scale;
float z = REFERENCE_DISTANCE * (depthScale - 1.0f);
glm::vec3 headTranslation((x - _referenceX) * depthScale * TRANSLATION_SCALE,
(y - _referenceY) * depthScale * TRANSLATION_SCALE, z);
glm::vec3 headTranslation((x - _referenceX) * TRANSLATION_SCALE, (y - _referenceY) * TRANSLATION_SCALE, 0.0f);
glm::quat headRotation(glm::radians(glm::vec3(-_outputVector.at(_headRotationIndices[0]),
_outputVector.at(_headRotationIndices[1]), -_outputVector.at(_headRotationIndices[2]))));
float estimatedEyePitch = (_outputVector.at(_leftEyeRotationIndices[0]) +

View file

@ -76,7 +76,6 @@ private:
int _rightEyeRotationIndices[2];
float _referenceX;
float _referenceY;
float _referenceScale;
bool _referenceInitialized;
QVector<float> _blendshapeCoefficients;
#endif

View file

@ -37,6 +37,7 @@ AttachmentsDialog::AttachmentsDialog() :
container->setLayout(_attachments = new QVBoxLayout());
container->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred);
area->setWidget(container);
_attachments->addStretch(1);
foreach (const AttachmentData& data, Application::getInstance()->getAvatar()->getAttachmentData()) {
addAttachment(data);
@ -49,20 +50,30 @@ AttachmentsDialog::AttachmentsDialog() :
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok);
layout->addWidget(buttons);
connect(buttons, SIGNAL(accepted()), SLOT(deleteLater()));
_ok = buttons->button(QDialogButtonBox::Ok);
setMinimumSize(600, 600);
}
void AttachmentsDialog::setVisible(bool visible) {
QDialog::setVisible(visible);
// un-default the OK button
if (visible) {
_ok->setDefault(false);
}
}
void AttachmentsDialog::updateAttachmentData() {
QVector<AttachmentData> data;
for (int i = 0; i < _attachments->count(); i++) {
for (int i = 0; i < _attachments->count() - 1; i++) {
data.append(static_cast<AttachmentPanel*>(_attachments->itemAt(i)->widget())->getAttachmentData());
}
Application::getInstance()->getAvatar()->setAttachmentData(data);
}
void AttachmentsDialog::addAttachment(const AttachmentData& data) {
_attachments->addWidget(new AttachmentPanel(this, data));
_attachments->insertWidget(_attachments->count() - 1, new AttachmentPanel(this, data));
}
static QDoubleSpinBox* createTranslationBox(AttachmentsDialog* dialog, float value) {
@ -86,7 +97,10 @@ static QDoubleSpinBox* createRotationBox(AttachmentsDialog* dialog, float value)
}
AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData& data) {
setFrameStyle(QFrame::StyledPanel);
QFormLayout* layout = new QFormLayout();
layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
setLayout(layout);
QHBoxLayout* urlBox = new QHBoxLayout();
@ -130,6 +144,7 @@ AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData
QPushButton* remove = new QPushButton("Delete");
layout->addRow(remove);
connect(remove, SIGNAL(clicked(bool)), SLOT(deleteLater()));
dialog->connect(remove, SIGNAL(clicked(bool)), SLOT(updateAttachmentData()), Qt::QueuedConnection);
}
AttachmentData AttachmentPanel::getAttachmentData() const {

View file

@ -13,6 +13,7 @@
#define hifi_AttachmentsDialog_h
#include <QDialog>
#include <QFrame>
#include <AvatarData.h>
@ -29,6 +30,8 @@ public:
AttachmentsDialog();
virtual void setVisible(bool visible);
public slots:
void updateAttachmentData();
@ -40,10 +43,11 @@ private slots:
private:
QVBoxLayout* _attachments;
QPushButton* _ok;
};
/// A panel controlling a single attachment.
class AttachmentPanel : public QWidget {
class AttachmentPanel : public QFrame {
Q_OBJECT
public:

View file

@ -87,39 +87,13 @@ ChatWindow::ChatWindow(QWidget* parent) :
}
connect(&xmppClient, SIGNAL(messageReceived(QXmppMessage)), this, SLOT(messageReceived(QXmppMessage)));
connect(&_trayIcon, SIGNAL(messageClicked()), this, SLOT(notificationClicked()));
#endif
#endif // HAVE_QXMPP
QDir mentionSoundsDir(Application::resourcesPath() + mentionSoundsPath);
_mentionSounds = mentionSoundsDir.entryList(QDir::Files);
_trayIcon.setIcon(QIcon( Application::resourcesPath() + "/images/hifi-logo.svg"));
}
void ChatWindow::notificationClicked() {
if (parentWidget()->isMinimized()) {
parentWidget()->showNormal();
}
if (isHidden()) {
show();
}
// find last mention
int messageCount = ui->messagesVBoxLayout->count();
for (unsigned int i = messageCount; i > 0; i--) {
ChatMessageArea* area = (ChatMessageArea*)ui->messagesVBoxLayout->itemAt(i - 1)->widget();
QRegularExpression usernameMention(mentionRegex.arg(AccountManager::getInstance().getAccountInfo().getUsername()));
if (area->toPlainText().contains(usernameMention)) {
int top = area->geometry().top();
int height = area->geometry().height();
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar();
verticalScrollBar->setSliderPosition(top - verticalScrollBar->size().height() + height);
return;
}
}
scrollToBottom();
}
ChatWindow::~ChatWindow() {
#ifdef HAVE_QXMPP
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
@ -128,7 +102,7 @@ ChatWindow::~ChatWindow() {
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
disconnect(publicChatRoom, SIGNAL(participantsChanged()), this, SLOT(participantsChanged()));
#endif
#endif // HAVE_QXMPP
delete ui;
}
@ -147,10 +121,12 @@ void ChatWindow::showEvent(QShowEvent* event) {
ui->messagePlainTextEdit->setFocus();
}
#ifdef HAVE_QXMPP
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
if (xmppClient.isConnected()) {
participantsChanged();
}
#endif // HAVE_QXMPP
}
bool ChatWindow::eventFilter(QObject* sender, QEvent* event) {
@ -163,14 +139,14 @@ bool ChatWindow::eventFilter(QObject* sender, QEvent* event) {
(keyEvent->modifiers() & Qt::ShiftModifier) == 0) {
QString messageText = ui->messagePlainTextEdit->document()->toPlainText().trimmed();
if (!messageText.isEmpty()) {
#ifdef HAVE_QXMPP
#ifdef HAVE_QXMPP
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
QXmppMessage message;
message.setTo(publicChatRoom->jid());
message.setType(QXmppMessage::GroupChat);
message.setBody(messageText);
XmppClient::getInstance().getXMPPClient().sendPacket(message);
#endif
#endif // HAVE_QXMPP
QTextCursor cursor = ui->messagePlainTextEdit->textCursor();
cursor.select(QTextCursor::Document);
cursor.removeSelectedText();
@ -187,13 +163,6 @@ bool ChatWindow::eventFilter(QObject* sender, QEvent* event) {
return FramelessDialog::eventFilter(sender, event);
}
#ifdef HAVE_QXMPP
QString ChatWindow::getParticipantName(const QString& participant) {
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
return participant.right(participant.count() - 1 - publicChatRoom->jid().count());
}
#endif
void ChatWindow::addTimeStamp() {
QTimeSpan timePassed = QDateTime::currentDateTime() - lastMessageStamp;
int times[] = { timePassed.daysPart(), timePassed.hoursPart(), timePassed.minutesPart() };
@ -246,7 +215,7 @@ void ChatWindow::connected() {
#ifdef HAVE_QXMPP
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
connect(publicChatRoom, SIGNAL(participantsChanged()), this, SLOT(participantsChanged()));
#endif
#endif // HAVE_QXMPP
startTimerForTimeStamps();
}
@ -257,6 +226,36 @@ void ChatWindow::timeout() {
}
#ifdef HAVE_QXMPP
void ChatWindow::notificationClicked() {
if (parentWidget()->isMinimized()) {
parentWidget()->showNormal();
}
if (isHidden()) {
show();
}
// find last mention
int messageCount = ui->messagesVBoxLayout->count();
for (unsigned int i = messageCount; i > 0; i--) {
ChatMessageArea* area = (ChatMessageArea*)ui->messagesVBoxLayout->itemAt(i - 1)->widget();
QRegularExpression usernameMention(mentionRegex.arg(AccountManager::getInstance().getAccountInfo().getUsername()));
if (area->toPlainText().contains(usernameMention)) {
int top = area->geometry().top();
int height = area->geometry().height();
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar();
verticalScrollBar->setSliderPosition(top - verticalScrollBar->size().height() + height);
return;
}
}
scrollToBottom();
}
QString ChatWindow::getParticipantName(const QString& participant) {
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
return participant.right(participant.count() - 1 - publicChatRoom->jid().count());
}
void ChatWindow::error(QXmppClient::Error error) {
ui->connectingToXMPPLabel->setText(QString::number(error));
@ -363,8 +362,7 @@ void ChatWindow::messageReceived(const QXmppMessage& message) {
_trayIcon.showMessage(windowTitle(), message.body());
}
}
#endif
#endif // HAVE_QXMPP
bool ChatWindow::isNearBottom() {
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar();

View file

@ -2032,7 +2032,7 @@ bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData
// if this node is fully OUTSIDE the view, but previously intersected and/or was inside the last view, then
// we need to hide it. Additionally we know that ALL of it's children are also fully OUTSIDE so we can recurse
// the children and simply mark them as hidden
args->tree->recurseNodeWithOperation(voxel, hideAllSubTreeOperation, args );
args->tree->recurseElementWithOperation(voxel, hideAllSubTreeOperation, args );
return false;
} break;
@ -2049,7 +2049,7 @@ bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData
// if this node is fully INSIDE the view, but previously INTERSECTED and/or was OUTSIDE the last view, then
// we need to show it. Additionally we know that ALL of it's children are also fully INSIDE so we can recurse
// the children and simply mark them as visible (as appropriate based on LOD)
args->tree->recurseNodeWithOperation(voxel, showAllSubTreeOperation, args);
args->tree->recurseElementWithOperation(voxel, showAllSubTreeOperation, args);
return false;
} break;
case ViewFrustum::INTERSECT: {

View file

@ -817,7 +817,7 @@ ExtractedMesh extractMesh(const FBXNode& object) {
while (endIndex < data.polygonIndices.size() && data.polygonIndices.at(endIndex++) >= 0);
QPair<int, int> materialTexture((polygonIndex < materials.size()) ? materials.at(polygonIndex) : 0,
(polygonIndex < textures.size()) ? textures.at(polygonIndex) : 0);
(polygonIndex < textures.size()) ? textures.at(polygonIndex) : -1);
int& partIndex = materialTextureParts[materialTexture];
if (partIndex == 0) {
data.extracted.partMaterialTextures.append(materialTexture);

View file

@ -12,7 +12,7 @@
#include "ModelTree.h"
ModelTree::ModelTree(bool shouldReaverage) : Octree(shouldReaverage) {
_rootNode = createNewElement();
_rootElement = createNewElement();
}
ModelTreeElement* ModelTree::createNewElement(unsigned char * octalCode) {
@ -74,31 +74,48 @@ bool ModelTree::findAndDeleteOperation(OctreeElement* element, void* extraData)
return true;
}
class FindAndUpdateModelArgs {
class FindAndUpdateModelOperator : public RecurseOctreeOperator {
public:
const ModelItem& searchModel;
bool found;
FindAndUpdateModelOperator(const ModelItem& searchModel);
virtual bool PreRecursion(OctreeElement* element);
virtual bool PostRecursion(OctreeElement* element);
bool wasFound() const { return _found; }
private:
const ModelItem& _searchModel;
bool _found;
};
bool ModelTree::findAndUpdateOperation(OctreeElement* element, void* extraData) {
FindAndUpdateModelArgs* args = static_cast<FindAndUpdateModelArgs*>(extraData);
FindAndUpdateModelOperator::FindAndUpdateModelOperator(const ModelItem& searchModel) :
_searchModel(searchModel),
_found(false) {
};
bool FindAndUpdateModelOperator::PreRecursion(OctreeElement* element) {
ModelTreeElement* modelTreeElement = static_cast<ModelTreeElement*>(element);
// Note: updateModel() will only operate on correctly found models
if (modelTreeElement->updateModel(args->searchModel)) {
args->found = true;
if (modelTreeElement->updateModel(_searchModel)) {
_found = true;
return false; // stop searching
}
return true;
return !_found; // if we haven't yet found it, keep looking
}
bool FindAndUpdateModelOperator::PostRecursion(OctreeElement* element) {
if (_found) {
element->markWithChangedTime();
}
return !_found; // if we haven't yet found it, keep looking
}
void ModelTree::storeModel(const ModelItem& model, const SharedNodePointer& senderNode) {
// First, look for the existing model in the tree..
FindAndUpdateModelArgs args = { model, false };
recurseTreeWithOperation(findAndUpdateOperation, &args);
FindAndUpdateModelOperator theOperator(model);
recurseTreeWithOperator(&theOperator);
// if we didn't find it in the tree, then store it...
if (!args.found) {
if (!theOperator.wasFound()) {
glm::vec3 position = model.getPosition();
float size = std::max(MINIMUM_MODEL_ELEMENT_SIZE, model.getRadius());
@ -109,36 +126,49 @@ void ModelTree::storeModel(const ModelItem& model, const SharedNodePointer& send
_isDirty = true;
}
class FindAndUpdateModelWithIDandPropertiesArgs {
class FindAndUpdateModelWithIDandPropertiesOperator : public RecurseOctreeOperator {
public:
const ModelItemID& modelID;
const ModelItemProperties& properties;
bool found;
FindAndUpdateModelWithIDandPropertiesOperator(const ModelItemID& modelID, const ModelItemProperties& properties);
virtual bool PreRecursion(OctreeElement* element);
virtual bool PostRecursion(OctreeElement* element);
bool wasFound() const { return _found; }
private:
const ModelItemID& _modelID;
const ModelItemProperties& _properties;
bool _found;
};
bool ModelTree::findAndUpdateWithIDandPropertiesOperation(OctreeElement* element, void* extraData) {
FindAndUpdateModelWithIDandPropertiesArgs* args = static_cast<FindAndUpdateModelWithIDandPropertiesArgs*>(extraData);
FindAndUpdateModelWithIDandPropertiesOperator::FindAndUpdateModelWithIDandPropertiesOperator(const ModelItemID& modelID,
const ModelItemProperties& properties) :
_modelID(modelID),
_properties(properties),
_found(false) {
};
bool FindAndUpdateModelWithIDandPropertiesOperator::PreRecursion(OctreeElement* element) {
ModelTreeElement* modelTreeElement = static_cast<ModelTreeElement*>(element);
// Note: updateModel() will only operate on correctly found models
if (modelTreeElement->updateModel(args->modelID, args->properties)) {
args->found = true;
if (modelTreeElement->updateModel(_modelID, _properties)) {
_found = true;
return false; // stop searching
}
return !_found; // if we haven't yet found it, keep looking
}
// if we've found our model stop searching
if (args->found) {
return false;
bool FindAndUpdateModelWithIDandPropertiesOperator::PostRecursion(OctreeElement* element) {
if (_found) {
element->markWithChangedTime();
}
return true;
return !_found; // if we haven't yet found it, keep looking
}
void ModelTree::updateModel(const ModelItemID& modelID, const ModelItemProperties& properties) {
// First, look for the existing model in the tree..
FindAndUpdateModelWithIDandPropertiesArgs args = { modelID, properties, false };
recurseTreeWithOperation(findAndUpdateWithIDandPropertiesOperation, &args);
// if we found it in the tree, then mark the tree as dirty
if (args.found) {
// Look for the existing model in the tree..
FindAndUpdateModelWithIDandPropertiesOperator theOperator(modelID, properties);
recurseTreeWithOperator(&theOperator);
if (theOperator.wasFound()) {
_isDirty = true;
}
}
@ -464,29 +494,12 @@ void ModelTree::update() {
lockForWrite();
_isDirty = true;
ModelTreeUpdateArgs args = { };
recurseTreeWithOperation(updateOperation, &args);
// TODO: we don't need to update models yet, but when we do, for example
// when we add animation support, we will revisit this code.
//ModelTreeUpdateArgs args = { };
//recurseTreeWithOperation(updateOperation, &args);
// now add back any of the models that moved elements....
int movingModels = args._movingModels.size();
for (int i = 0; i < movingModels; i++) {
bool shouldDie = args._movingModels[i].getShouldDie();
// if the model is still inside our total bounds, then re-add it
AABox treeBounds = getRoot()->getAABox();
if (!shouldDie && treeBounds.contains(args._movingModels[i].getPosition())) {
storeModel(args._movingModels[i]);
} else {
uint32_t modelID = args._movingModels[i].getID();
quint64 deletedAt = usecTimestampNow();
_recentlyDeletedModelsLock.lockForWrite();
_recentlyDeletedModelItemIDs.insert(deletedAt, modelID);
_recentlyDeletedModelsLock.unlock();
}
}
// prune the tree...
// Now is a reasonable time to prune the tree...
recurseTreeWithOperation(pruneOperation, NULL);
unlock();
}

View file

@ -29,7 +29,7 @@ public:
virtual ModelTreeElement* createNewElement(unsigned char * octalCode = NULL);
/// Type safe version of getRoot()
ModelTreeElement* getRoot() { return (ModelTreeElement*)_rootNode; }
ModelTreeElement* getRoot() { return static_cast<ModelTreeElement*>(_rootElement); }
// These methods will allow the OctreeServer to send your tree inbound edit packets of your

View file

@ -137,6 +137,7 @@ bool ModelTreeElement::updateModel(const ModelItem& model) {
difference, debug::valueOf(model.isNewlyCreated()) );
}
thisModel.copyChangedProperties(model);
markWithChangedTime();
} else {
if (wantDebug) {
qDebug(">>> IGNORING SERVER!!! Would've caused jutter! <<< "
@ -167,7 +168,7 @@ bool ModelTreeElement::updateModel(const ModelItemID& modelID, const ModelItemPr
}
if (found) {
thisModel.setProperties(properties);
markWithChangedTime(); // mark our element as changed..
const bool wantDebug = false;
if (wantDebug) {
uint64_t now = usecTimestampNow();

File diff suppressed because it is too large Load diff

View file

@ -36,8 +36,15 @@ class Shape;
#include <QObject>
#include <QReadWriteLock>
/// derive from this class to use the Octree::recurseTreeWithOperator() method
class RecurseOctreeOperator {
public:
virtual bool PreRecursion(OctreeElement* element) = 0;
virtual bool PostRecursion(OctreeElement* element) = 0;
};
// Callback function, for recuseTreeWithOperation
typedef bool (*RecurseOctreeOperation)(OctreeElement* node, void* extraData);
typedef bool (*RecurseOctreeOperation)(OctreeElement* element, void* extraData);
typedef enum {GRADIENT, RANDOM, NATURAL} creationMode;
const bool NO_EXISTS_BITS = false;
@ -159,7 +166,7 @@ class ReadBitstreamToTreeParams {
public:
bool includeColor;
bool includeExistsBits;
OctreeElement* destinationNode;
OctreeElement* destinationElement;
QUuid sourceUUID;
SharedNodePointer sourceNode;
bool wantImportProgress;
@ -167,13 +174,13 @@ public:
ReadBitstreamToTreeParams(
bool includeColor = WANT_COLOR,
bool includeExistsBits = WANT_EXISTS_BITS,
OctreeElement* destinationNode = NULL,
OctreeElement* destinationElement = NULL,
QUuid sourceUUID = QUuid(),
SharedNodePointer sourceNode = SharedNodePointer(),
bool wantImportProgress = false) :
includeColor(includeColor),
includeExistsBits(includeExistsBits),
destinationNode(destinationNode),
destinationElement(destinationElement),
sourceUUID(sourceUUID),
sourceNode(sourceNode),
wantImportProgress(wantImportProgress)
@ -200,14 +207,14 @@ public:
virtual void update() { }; // nothing to do by default
OctreeElement* getRoot() { return _rootNode; }
OctreeElement* getRoot() { return _rootElement; }
void eraseAllOctreeElements();
void processRemoveOctreeElementsBitstream(const unsigned char* bitstream, int bufferSizeBytes);
void readBitstreamToTree(const unsigned char* bitstream, unsigned long int bufferSizeBytes, ReadBitstreamToTreeParams& args);
void deleteOctalCodeFromTree(const unsigned char* codeBuffer, bool collapseEmptyTrees = DONT_COLLAPSE);
void reaverageOctreeElements(OctreeElement* startNode = NULL);
void reaverageOctreeElements(OctreeElement* startElement = NULL);
void deleteOctreeElementAt(float x, float y, float z, float s);
@ -222,13 +229,14 @@ public:
OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s);
void recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData = NULL);
void recurseTreeWithPostOperation(RecurseOctreeOperation operation, void* extraData = NULL);
void recurseTreeWithOperationDistanceSorted(RecurseOctreeOperation operation,
const glm::vec3& point, void* extraData = NULL);
int encodeTreeBitstream(OctreeElement* node, OctreePacketData* packetData, OctreeElementBag& bag,
void recurseTreeWithOperator(RecurseOctreeOperator* operatorObject);
int encodeTreeBitstream(OctreeElement* element, OctreePacketData* packetData, OctreeElementBag& bag,
EncodeBitstreamParams& params) ;
bool isDirty() const { return _isDirty; }
@ -268,28 +276,30 @@ public:
void loadOctreeFile(const char* fileName, bool wantColorRandomizer);
// these will read/write files that match the wireformat, excluding the 'V' leading
void writeToSVOFile(const char* filename, OctreeElement* node = NULL);
void writeToSVOFile(const char* filename, OctreeElement* element = NULL);
bool readFromSVOFile(const char* filename);
unsigned long getOctreeElementsCount();
void copySubTreeIntoNewTree(OctreeElement* startNode, Octree* destinationTree, bool rebaseToRoot);
void copyFromTreeIntoSubTree(Octree* sourceTree, OctreeElement* destinationNode);
void copySubTreeIntoNewTree(OctreeElement* startElement, Octree* destinationTree, bool rebaseToRoot);
void copyFromTreeIntoSubTree(Octree* sourceTree, OctreeElement* destinationElement);
bool getShouldReaverage() const { return _shouldReaverage; }
void recurseNodeWithOperation(OctreeElement* node, RecurseOctreeOperation operation,
void recurseElementWithOperation(OctreeElement* element, RecurseOctreeOperation operation,
void* extraData, int recursionCount = 0);
/// Traverse child nodes of node applying operation in post-fix order
///
void recurseNodeWithPostOperation(OctreeElement* node, RecurseOctreeOperation operation,
void recurseElementWithPostOperation(OctreeElement* element, RecurseOctreeOperation operation,
void* extraData, int recursionCount = 0);
void recurseNodeWithOperationDistanceSorted(OctreeElement* node, RecurseOctreeOperation operation,
void recurseElementWithOperationDistanceSorted(OctreeElement* element, RecurseOctreeOperation operation,
const glm::vec3& point, void* extraData, int recursionCount = 0);
bool recurseElementWithOperator(OctreeElement* element, RecurseOctreeOperator* operatorObject, int recursionCount = 0);
bool getIsViewing() const { return _isViewing; }
void setIsViewing(bool isViewing) { _isViewing = isViewing; }
@ -302,21 +312,21 @@ public slots:
protected:
void deleteOctalCodeFromTreeRecursion(OctreeElement* node, void* extraData);
void deleteOctalCodeFromTreeRecursion(OctreeElement* element, void* extraData);
int encodeTreeBitstreamRecursion(OctreeElement* node,
int encodeTreeBitstreamRecursion(OctreeElement* element,
OctreePacketData* packetData, OctreeElementBag& bag,
EncodeBitstreamParams& params, int& currentEncodeLevel,
const ViewFrustum::location& parentLocationThisView) const;
static bool countOctreeElementsOperation(OctreeElement* node, void* extraData);
static bool countOctreeElementsOperation(OctreeElement* element, void* extraData);
OctreeElement* nodeForOctalCode(OctreeElement* ancestorNode, const unsigned char* needleCode, OctreeElement** parentOfFoundNode) const;
OctreeElement* createMissingNode(OctreeElement* lastParentNode, const unsigned char* codeToReach);
int readNodeData(OctreeElement *destinationNode, const unsigned char* nodeData,
OctreeElement* nodeForOctalCode(OctreeElement* ancestorElement, const unsigned char* needleCode, OctreeElement** parentOfFoundElement) const;
OctreeElement* createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach);
int readElementData(OctreeElement *destinationElement, const unsigned char* nodeData,
int bufferSizeBytes, ReadBitstreamToTreeParams& args);
OctreeElement* _rootNode;
OctreeElement* _rootElement;
bool _isDirty;
bool _shouldReaverage;

View file

@ -28,6 +28,7 @@
typedef unsigned char OCTREE_PACKET_FLAGS;
typedef uint16_t OCTREE_PACKET_SEQUENCE;
const uint16_t MAX_OCTREE_PACKET_SEQUENCE = 65535;
typedef quint64 OCTREE_PACKET_SENT_TIME;
typedef uint16_t OCTREE_PACKET_INTERNAL_SECTION_SIZE;
const int MAX_OCTREE_PACKET_SIZE = MAX_PACKET_SIZE;

View file

@ -875,10 +875,13 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet,
return; // ignore any packets that are unreasonable
}
// determine our expected sequence number... handle rollover appropriately
OCTREE_PACKET_SEQUENCE expected = _incomingPacket > 0 ? _incomingLastSequence + 1 : sequence;
// Guard against possible corrupted packets... with bad sequence numbers
const int MAX_RESONABLE_SEQUENCE_OFFSET = 2000;
const int MIN_RESONABLE_SEQUENCE_OFFSET = -2000;
int sequenceOffset = (sequence - _incomingLastSequence);
int sequenceOffset = (sequence - expected);
if (sequenceOffset > MAX_RESONABLE_SEQUENCE_OFFSET || sequenceOffset < MIN_RESONABLE_SEQUENCE_OFFSET) {
qDebug() << "ignoring unreasonable packet... sequence:" << sequence << "_incomingLastSequence:" << _incomingLastSequence;
return; // ignore any packets that are unreasonable
@ -901,7 +904,6 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet,
qDebug() << "last packet duplicate got:" << sequence << "_incomingLastSequence:" << _incomingLastSequence;
}
} else {
OCTREE_PACKET_SEQUENCE expected = _incomingLastSequence+1;
if (sequence != expected) {
if (wantExtraDebugging) {
qDebug() << "out of order... got:" << sequence << "expected:" << expected;
@ -958,9 +960,9 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet,
}
}
// only bump the last sequence if it was greater than our previous last sequence, this will keep us from
// only bump the last sequence if it was greater than our expected sequence, this will keep us from
// accidentally going backwards when an out of order (recovered) packet comes in
if (sequence > _incomingLastSequence) {
if (sequence >= expected) {
_incomingLastSequence = sequence;
}

View file

@ -12,7 +12,7 @@
#include "ParticleTree.h"
ParticleTree::ParticleTree(bool shouldReaverage) : Octree(shouldReaverage) {
_rootNode = createNewElement();
_rootElement = createNewElement();
}
ParticleTreeElement* ParticleTree::createNewElement(unsigned char * octalCode) {

View file

@ -29,7 +29,7 @@ public:
virtual ParticleTreeElement* createNewElement(unsigned char * octalCode = NULL);
/// Type safe version of getRoot()
ParticleTreeElement* getRoot() { return (ParticleTreeElement*)_rootNode; }
ParticleTreeElement* getRoot() { return static_cast<ParticleTreeElement*>(_rootElement); }
// These methods will allow the OctreeServer to send your tree inbound edit packets of your

View file

@ -23,13 +23,13 @@
VoxelTree::VoxelTree(bool shouldReaverage) : Octree(shouldReaverage)
{
_rootNode = createNewElement();
_rootElement = createNewElement();
}
VoxelTreeElement* VoxelTree::createNewElement(unsigned char * octalCode) {
VoxelSystem* voxelSystem = NULL;
if (_rootNode) {
voxelSystem = ((VoxelTreeElement*)_rootNode)->getVoxelSystem();
if (_rootElement) {
voxelSystem = (static_cast<VoxelTreeElement*>(_rootElement))->getVoxelSystem();
}
VoxelTreeElement* newElement = new VoxelTreeElement(octalCode);
newElement->setVoxelSystem(voxelSystem);

View file

@ -26,7 +26,7 @@ public:
VoxelTree(bool shouldReaverage = false);
virtual VoxelTreeElement* createNewElement(unsigned char * octalCode = NULL);
VoxelTreeElement* getRoot() { return (VoxelTreeElement*)_rootNode; }
VoxelTreeElement* getRoot() { return static_cast<VoxelTreeElement*>(_rootElement); }
void deleteVoxelAt(float x, float y, float z, float s);