From f3b8d04c068b9d845ec9d21921dd72ae55d85fe1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 6 May 2014 09:39:14 -0700 Subject: [PATCH 01/43] fixed packet sequence number rollover --- libraries/octree/src/OctreePacketData.h | 1 + libraries/octree/src/OctreeSceneStats.cpp | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index d802f8e808..d704923a11 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -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; diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 1dc1459771..c08e723f89 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -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; } From 7eef1b56a2d268d3c4322942b522714a77705eb9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 6 May 2014 10:19:29 -0700 Subject: [PATCH 02/43] Don't use the scale to determine the depth in Faceplus. Apparently it's not reliable. --- interface/src/devices/Faceplus.cpp | 7 +------ interface/src/devices/Faceplus.h | 1 - 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/interface/src/devices/Faceplus.cpp b/interface/src/devices/Faceplus.cpp index f8eec434b7..00bc9d2676 100644 --- a/interface/src/devices/Faceplus.cpp +++ b/interface/src/devices/Faceplus.cpp @@ -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]) + diff --git a/interface/src/devices/Faceplus.h b/interface/src/devices/Faceplus.h index f3c680c2d6..d52740ca5f 100644 --- a/interface/src/devices/Faceplus.h +++ b/interface/src/devices/Faceplus.h @@ -76,7 +76,6 @@ private: int _rightEyeRotationIndices[2]; float _referenceX; float _referenceY; - float _referenceScale; bool _referenceInitialized; QVector _blendshapeCoefficients; #endif From a06697f2a1a40eed07f0ace4fb99b27e09c7822f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 6 May 2014 10:37:27 -0700 Subject: [PATCH 03/43] Update attachment data on attachment delete. --- interface/src/ui/AttachmentsDialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/ui/AttachmentsDialog.cpp b/interface/src/ui/AttachmentsDialog.cpp index edd28d461c..2d28c51d7c 100644 --- a/interface/src/ui/AttachmentsDialog.cpp +++ b/interface/src/ui/AttachmentsDialog.cpp @@ -130,6 +130,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 { From e0ecd611c99cf228d766eb9204af200fd14c34fe Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 6 May 2014 10:53:54 -0700 Subject: [PATCH 04/43] Better attachment styling. --- interface/src/ui/AttachmentsDialog.cpp | 8 ++++++-- interface/src/ui/AttachmentsDialog.h | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/AttachmentsDialog.cpp b/interface/src/ui/AttachmentsDialog.cpp index 2d28c51d7c..79b8d42f41 100644 --- a/interface/src/ui/AttachmentsDialog.cpp +++ b/interface/src/ui/AttachmentsDialog.cpp @@ -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); @@ -55,14 +56,14 @@ AttachmentsDialog::AttachmentsDialog() : void AttachmentsDialog::updateAttachmentData() { QVector data; - for (int i = 0; i < _attachments->count(); i++) { + for (int i = 0; i < _attachments->count() - 1; i++) { data.append(static_cast(_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 +87,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(); diff --git a/interface/src/ui/AttachmentsDialog.h b/interface/src/ui/AttachmentsDialog.h index c23bd2efb8..663a831462 100644 --- a/interface/src/ui/AttachmentsDialog.h +++ b/interface/src/ui/AttachmentsDialog.h @@ -13,6 +13,7 @@ #define hifi_AttachmentsDialog_h #include +#include #include @@ -43,7 +44,7 @@ private: }; /// A panel controlling a single attachment. -class AttachmentPanel : public QWidget { +class AttachmentPanel : public QFrame { Q_OBJECT public: From c5fbf1b55f3f43ba5fec48dda3db602cce910d0d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 6 May 2014 10:57:11 -0700 Subject: [PATCH 05/43] Force the scroll bar. --- interface/src/ui/AttachmentsDialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/ui/AttachmentsDialog.cpp b/interface/src/ui/AttachmentsDialog.cpp index 79b8d42f41..9e244fda87 100644 --- a/interface/src/ui/AttachmentsDialog.cpp +++ b/interface/src/ui/AttachmentsDialog.cpp @@ -33,6 +33,7 @@ AttachmentsDialog::AttachmentsDialog() : QScrollArea* area = new QScrollArea(); layout->addWidget(area); area->setWidgetResizable(true); + area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); QWidget* container = new QWidget(); container->setLayout(_attachments = new QVBoxLayout()); container->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); From 72ebeffa5c471e595072a8cb055a7258102e83af Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 6 May 2014 10:59:28 -0700 Subject: [PATCH 06/43] Scratch that; I just didn't understand how magic invisible disappearing scroll bars worked on OS X. --- interface/src/ui/AttachmentsDialog.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/ui/AttachmentsDialog.cpp b/interface/src/ui/AttachmentsDialog.cpp index 9e244fda87..79b8d42f41 100644 --- a/interface/src/ui/AttachmentsDialog.cpp +++ b/interface/src/ui/AttachmentsDialog.cpp @@ -33,7 +33,6 @@ AttachmentsDialog::AttachmentsDialog() : QScrollArea* area = new QScrollArea(); layout->addWidget(area); area->setWidgetResizable(true); - area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); QWidget* container = new QWidget(); container->setLayout(_attachments = new QVBoxLayout()); container->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); From 9421af9f108bc4323181da90e9260332ca32f238 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 6 May 2014 11:14:48 -0700 Subject: [PATCH 07/43] Fix for attachments' not appearing in rear view mirror head mode. --- interface/src/Application.cpp | 13 ++++++++++++- interface/src/avatar/Avatar.h | 1 + interface/src/ui/AttachmentsDialog.cpp | 1 - 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d9cc78304f..b50e9ef1dc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -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 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); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index b96145b213..edd53e4b8f 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -83,6 +83,7 @@ public: //getters bool isInitialized() const { return _initialized; } SkeletonModel& getSkeletonModel() { return _skeletonModel; } + const QVector& getAttachmentModels() const { return _attachmentModels; } glm::vec3 getChestPosition() const; float getScale() const { return _scale; } const glm::vec3& getVelocity() const { return _velocity; } diff --git a/interface/src/ui/AttachmentsDialog.cpp b/interface/src/ui/AttachmentsDialog.cpp index 79b8d42f41..9fa26a2f00 100644 --- a/interface/src/ui/AttachmentsDialog.cpp +++ b/interface/src/ui/AttachmentsDialog.cpp @@ -68,7 +68,6 @@ void AttachmentsDialog::addAttachment(const AttachmentData& data) { static QDoubleSpinBox* createTranslationBox(AttachmentsDialog* dialog, float value) { QDoubleSpinBox* box = new QDoubleSpinBox(); - box->setSingleStep(0.01); box->setMinimum(-FLT_MAX); box->setMaximum(FLT_MAX); box->setValue(value); From 082ff760d6c317582453c09041621c4e86232af1 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 6 May 2014 11:47:35 -0700 Subject: [PATCH 08/43] Un-default the "OK" button so that we can press enter on the URL field. --- interface/src/ui/AttachmentsDialog.cpp | 10 ++++++++++ interface/src/ui/AttachmentsDialog.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/interface/src/ui/AttachmentsDialog.cpp b/interface/src/ui/AttachmentsDialog.cpp index 9fa26a2f00..bd531b1b46 100644 --- a/interface/src/ui/AttachmentsDialog.cpp +++ b/interface/src/ui/AttachmentsDialog.cpp @@ -50,10 +50,20 @@ 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 data; for (int i = 0; i < _attachments->count() - 1; i++) { diff --git a/interface/src/ui/AttachmentsDialog.h b/interface/src/ui/AttachmentsDialog.h index 663a831462..4e67ae8882 100644 --- a/interface/src/ui/AttachmentsDialog.h +++ b/interface/src/ui/AttachmentsDialog.h @@ -30,6 +30,8 @@ public: AttachmentsDialog(); + virtual void setVisible(bool visible); + public slots: void updateAttachmentData(); @@ -41,6 +43,7 @@ private slots: private: QVBoxLayout* _attachments; + QPushButton* _ok; }; /// A panel controlling a single attachment. From 983a3af4b9004dfdf5cfe6333f1b272d8343b566 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 6 May 2014 11:50:37 -0700 Subject: [PATCH 09/43] Attachment translations in world space. --- interface/src/avatar/Avatar.cpp | 2 +- interface/src/ui/AttachmentsDialog.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index bad4083fcf..f7bf4595d6 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -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); diff --git a/interface/src/ui/AttachmentsDialog.cpp b/interface/src/ui/AttachmentsDialog.cpp index bd531b1b46..016098699b 100644 --- a/interface/src/ui/AttachmentsDialog.cpp +++ b/interface/src/ui/AttachmentsDialog.cpp @@ -78,6 +78,7 @@ void AttachmentsDialog::addAttachment(const AttachmentData& data) { static QDoubleSpinBox* createTranslationBox(AttachmentsDialog* dialog, float value) { QDoubleSpinBox* box = new QDoubleSpinBox(); + box->setSingleStep(0.01); box->setMinimum(-FLT_MAX); box->setMaximum(FLT_MAX); box->setValue(value); From 432df1b65f7ecc80d3a0464aaedffdc44e43dcaa Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 6 May 2014 12:41:31 -0700 Subject: [PATCH 10/43] Only add each texture once. --- interface/src/ModelUploader.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/interface/src/ModelUploader.cpp b/interface/src/ModelUploader.cpp index 2b86e04829..bf6a868368 100644 --- a/interface/src/ModelUploader.cpp +++ b/interface/src/ModelUploader.cpp @@ -424,19 +424,24 @@ void ModelUploader::processCheck() { } bool ModelUploader::addTextures(const QString& texdir, const FBXGeometry& geometry) { + QSet 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); } } } From 61c2dd04688310ae16dfa8fe6276fbc1ecf923c2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 6 May 2014 13:07:31 -0700 Subject: [PATCH 11/43] Fixed orientation and offset issues --- examples/editModels.js | 327 +++++++++++++++++++------------ libraries/models/src/ModelItem.h | 2 +- 2 files changed, 199 insertions(+), 130 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 50b0137c4f..ecf398edfa 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +var windowDimensions = Controller.getViewportDimensions(); + var LASER_WIDTH = 4; var LASER_COLOR = { red: 255, green: 0, blue: 0 }; var LASER_LENGTH_FACTOR = 1.5; @@ -16,6 +18,40 @@ var LASER_LENGTH_FACTOR = 1.5; var LEFT = 0; var RIGHT = 1; + +var SPAWN_DISTANCE = 1; +var radiusDefault = 0.10; + +var modelURLs = [ + "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/Feisar_Ship.FBX", + "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/birarda/birarda_head.fbx", + "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/pug.fbx", + "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/newInvader16x16-large-purple.svo", + "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/minotaur/mino_full.fbx", + "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/Combat_tank_V01.FBX", + "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/orc.fbx", + "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/slimer.fbx", + ]; + +var toolIconUrl = "http://highfidelity-public.s3-us-west-1.amazonaws.com/images/tools/"; +var numberOfTools = 1; +var toolHeight = 50; +var toolWidth = 50; +var toolVerticalSpacing = 4; +var toolsHeight = toolHeight * numberOfTools + toolVerticalSpacing * (numberOfTools - 1); +var toolsX = windowDimensions.x - 8 - toolWidth; +var toolsY = (windowDimensions.y - toolsHeight) / 2; + + +var firstModel = Overlays.addOverlay("image", { + x: 0, y: 0, width: toolWidth, height: toolHeight, + subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight }, + imageURL: toolIconUrl + "voxel-tool.svg", + x: toolsX, y: toolsY + ((toolHeight + toolVerticalSpacing) * 0), width: toolWidth, height: toolHeight, + visible: true, + alpha: 0.9 + }); + function controller(wichSide) { this.side = wichSide; this.palm = 2 * wichSide; @@ -46,7 +82,10 @@ function controller(wichSide) { this.pressing = false; // is trigger being pressed (is pressed now but wasn't previously) this.grabbing = false; - this.modelID; + this.modelID = { isKnownID: false }; + this.oldModelRotation; + this.oldModelPosition; + this.oldModelRadius; this.laser = Overlays.addOverlay("line3d", { position: this.palmPosition, @@ -85,23 +124,19 @@ function controller(wichSide) { - this.grab = function (modelID) { - if (!modelID.isKnownID) { - var identify = Models.identifyModel(modelID); - if (!identify.isKnownID) { - print("Unknown ID " + identify.id + "(grab)"); - return; - } - modelID = identify; - } + this.grab = function (modelID, properties) { print("Grabbing " + modelID.id); this.grabbing = true; this.modelID = modelID; + + this.oldModelPosition = properties.position; + this.oldModelRotation = properties.modelRotation; + this.oldModelRadius = properties.radius; } this.release = function () { this.grabbing = false; - this.modelID = 0; + this.modelID.isKnownID = false; } this.checkTrigger = function () { @@ -118,6 +153,34 @@ function controller(wichSide) { } } + this.checkModel = function (properties) { + // P P - Model + // /| A - Palm + // / | d B - unit vector toward tip + // / | X - base of the perpendicular line + // A---X----->B d - distance fom axis + // x x - distance from A + // + // |X-A| = (P-A).B + // X == A + ((P-A).B)B + // d = |P-X| + + var A = this.palmPosition; + var B = this.front; + var P = properties.position; + + var x = Vec3.dot(Vec3.subtract(P, A), B); + var y = Vec3.dot(Vec3.subtract(P, A), this.up); + var z = Vec3.dot(Vec3.subtract(P, A), this.right); + var X = Vec3.sum(A, Vec3.multiply(B, x)); + var d = Vec3.length(Vec3.subtract(P, X)); + + if (d < properties.radius && 0 < x && x < LASER_LENGTH_FACTOR) { + return { valid: true, x: x, y: y, z: z }; + } + return { valid: false }; + } + this.moveLaser = function () { var endPosition = Vec3.sum(this.palmPosition, Vec3.multiply(this.front, LASER_LENGTH_FACTOR)); @@ -143,44 +206,33 @@ function controller(wichSide) { }); } - this.checkModel = function (modelID) { - if (!modelID.isKnownID) { - var identify = Models.identifyModel(modelID); - if (!identify.isKnownID) { - print("Unknown ID " + identify.id + "(checkModel)"); - return; - } - modelID = identify; + this.moveModel = function () { + if (this.grabbing) { + var newPosition = Vec3.sum(this.palmPosition, + Vec3.multiply(this.front, this.x)); + newPosition = Vec3.sum(newPosition, + Vec3.multiply(this.up, this.y)); + newPosition = Vec3.sum(newPosition, + Vec3.multiply(this.right, this.z)); + + var newRotation = Quat.multiply(this.rotation, + Quat.inverse(this.oldRotation)); + newRotation = Quat.multiply(newRotation, + this.oldModelRotation); + + Models.editModel(this.modelID, { + position: newPosition, + modelRotation: newRotation + }); + print("Moving " + this.modelID.id); +// Vec3.print("Old Position: ", this.oldModelPosition); +// Vec3.print("Sav Position: ", newPosition); + Quat.print("Old Rotation: ", this.oldModelRotation); + Quat.print("New Rotation: ", newRotation); + + this.oldModelRotation = newRotation; + this.oldModelPosition = newPosition; } - // P P - Model - // /| A - Palm - // / | d B - unit vector toward tip - // / | X - base of the perpendicular line - // A---X----->B d - distance fom axis - // x x - distance from A - // - // |X-A| = (P-A).B - // X == A + ((P-A).B)B - // d = |P-X| - - var A = this.palmPosition; - var B = this.front; - var P = Models.getModelProperties(modelID).position; - - this.x = Vec3.dot(Vec3.subtract(P, A), B); - this.y = Vec3.dot(Vec3.subtract(P, A), this.up); - this.z = Vec3.dot(Vec3.subtract(P, A), this.right); - var X = Vec3.sum(A, Vec3.multiply(B, this.x)); - var d = Vec3.length(Vec3.subtract(P, X)); - -// Vec3.print("A: ", A); -// Vec3.print("B: ", B); -// Vec3.print("Particle pos: ", P); -// print("d: " + d + ", x: " + this.x); - if (d < Models.getModelProperties(modelID).radius && 0 < this.x && this.x < LASER_LENGTH_FACTOR) { - return true; - } - return false; } this.update = function () { @@ -205,25 +257,40 @@ function controller(wichSide) { this.checkTrigger(); - if (this.pressing) { - Vec3.print("Looking at: ", this.palmPosition); - var foundModels = Models.findModels(this.palmPosition, LASER_LENGTH_FACTOR); - for (var i = 0; i < foundModels.length; i++) { - print("Model found ID (" + foundModels[i].id + ")"); - if (this.checkModel(foundModels[i])) { - if (this.grab(foundModels[i])) { - return; - } - } - } - } + this.moveLaser(); if (!this.pressed && this.grabbing) { // release if trigger not pressed anymore. this.release(); } - - this.moveLaser(); + + if (this.pressing) { + Vec3.print("Looking at: ", this.palmPosition); + var foundModels = Models.findModels(this.palmPosition, LASER_LENGTH_FACTOR); + for (var i = 0; i < foundModels.length; i++) { + + if (!foundModels[i].isKnownID) { + var identify = Models.identifyModel(foundModels[i]); + if (!identify.isKnownID) { + print("Unknown ID " + identify.id + "(update loop)"); + return; + } + foundModels[i] = identify; + } + + var properties = Models.getModelProperties(foundModels[i]); + print("Checking properties: " + properties.id + " " + properties.isKnownID); + + var check = this.checkModel(properties); + if (check.valid) { + this.grab(foundModels[i], properties); + this.x = check.x; + this.y = check.y; + this.z = check.z; + return; + } + } + } } this.cleanup = function () { @@ -238,78 +305,44 @@ var leftController = new controller(LEFT); var rightController = new controller(RIGHT); function moveModels() { - if (leftController.grabbing) { - if (rightController.grabbing) { - var properties = Models.getModelProperties(leftController.modelID); - - var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x)); - var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x)); - - var oldMiddle = Vec3.multiply(Vec3.sum(oldLeftPoint, oldRightPoint), 0.5); - var oldLength = Vec3.length(Vec3.subtract(oldLeftPoint, oldRightPoint)); - - - var leftPoint = Vec3.sum(leftController.palmPosition, Vec3.multiply(leftController.front, leftController.x)); - var rightPoint = Vec3.sum(rightController.palmPosition, Vec3.multiply(rightController.front, rightController.x)); - - var middle = Vec3.multiply(Vec3.sum(leftPoint, rightPoint), 0.5); - var length = Vec3.length(Vec3.subtract(leftPoint, rightPoint)); - - var ratio = length / oldLength; - - var newPosition = Vec3.sum(middle, - Vec3.multiply(Vec3.subtract(properties.position, oldMiddle), ratio)); - Vec3.print("Ratio : " + ratio + " New position: ", newPosition); - var rotation = Quat.multiply(leftController.rotation, - Quat.inverse(leftController.oldRotation)); - rotation = Quat.multiply(rotation, properties.modelRotation); - - Models.editModel(leftController.modelID, { - position: newPosition, - //modelRotation: rotation, - radius: properties.radius * ratio - }); - - return; - } else { - var newPosition = Vec3.sum(leftController.palmPosition, - Vec3.multiply(leftController.front, leftController.x)); - newPosition = Vec3.sum(newPosition, - Vec3.multiply(leftController.up, leftController.y)); - newPosition = Vec3.sum(newPosition, - Vec3.multiply(leftController.right, leftController.z)); - - var rotation = Quat.multiply(leftController.rotation, - Quat.inverse(leftController.oldRotation)); - rotation = Quat.multiply(rotation, - Models.getModelProperties(leftController.modelID).modelRotation); - - Models.editModel(leftController.modelID, { - position: newPosition, - modelRotation: rotation - }); - } - } - - - if (rightController.grabbing) { - var newPosition = Vec3.sum(rightController.palmPosition, - Vec3.multiply(rightController.front, rightController.x)); - newPosition = Vec3.sum(newPosition, - Vec3.multiply(rightController.up, rightController.y)); - newPosition = Vec3.sum(newPosition, - Vec3.multiply(rightController.right, rightController.z)); + if (leftController.grabbing && rightController.grabbing && rightController.modelID.id == leftController.modelID.id) { + print("Both controllers"); + var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x)); + var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x)); - var rotation = Quat.multiply(rightController.rotation, - Quat.inverse(rightController.oldRotation)); - rotation = Quat.multiply(rotation, - Models.getModelProperties(rightController.modelID).modelRotation); + var oldMiddle = Vec3.multiply(Vec3.sum(oldLeftPoint, oldRightPoint), 0.5); + var oldLength = Vec3.length(Vec3.subtract(oldLeftPoint, oldRightPoint)); - Models.editModel(rightController.modelID, { + + var leftPoint = Vec3.sum(leftController.palmPosition, Vec3.multiply(leftController.front, leftController.x)); + var rightPoint = Vec3.sum(rightController.palmPosition, Vec3.multiply(rightController.front, rightController.x)); + + var middle = Vec3.multiply(Vec3.sum(leftPoint, rightPoint), 0.5); + var length = Vec3.length(Vec3.subtract(leftPoint, rightPoint)); + + var ratio = length / oldLength; + + var newPosition = Vec3.sum(middle, + Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio)); + Vec3.print("Ratio : " + ratio + " New position: ", newPosition); + var rotation = Quat.multiply(leftController.rotation, + Quat.inverse(leftController.oldRotation)); + rotation = Quat.multiply(rotation, leftController.oldModelRotation); + + Models.editModel(leftController.modelID, { position: newPosition, - modelRotation: rotation + //modelRotation: rotation, + radius: leftController.oldModelRadius * ratio }); + + leftController.oldModelPosition = newPosition; + leftController.oldModelRotation = rotation; + leftController.oldModelRadius *= ratio; + return; } + + leftController.moveModel(); + rightController.moveModel(); } function checkController(deltaTime) { @@ -318,6 +351,8 @@ function checkController(deltaTime) { var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; + moveOverlays(); + // this is expected for hydras if (!(numberOfButtons==12 && numberOfTriggers == 2 && controllersPerTrigger == 2)) { //print("no hydra connected?"); @@ -329,14 +364,48 @@ function checkController(deltaTime) { moveModels(); } +function moveOverlays() { + windowDimensions = Controller.getViewportDimensions(); + + toolsX = windowDimensions.x - 8 - toolWidth; + toolsY = (windowDimensions.y - toolsHeight) / 2; + + Overlays.addOverlay(firstModel, { + x: toolsX, y: toolsY + ((toolHeight + toolVerticalSpacing) * 0), width: toolWidth, height: toolHeight, + }); +} + +function mousePressEvent(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + var url; + + if (clickedOverlay == firstModel) { + url = Window.prompt("Model url", modelURLs[Math.floor(Math.random() * modelURLs.length)]); + if (url == null) { + return; } + } else { + print("Didn't click on anything"); + return; + } + + var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); + Models.addModel({ position: position, + radius: radiusDefault, + modelURL: url + }); +} + function scriptEnding() { leftController.cleanup(); rightController.cleanup(); + + Overlays.deleteOverlay(firstModel); } Script.scriptEnding.connect(scriptEnding); // register the call back so it fires before each data send Script.update.connect(checkController); +Controller.mousePressEvent.connect(mousePressEvent); diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 317299be2d..76a78122ff 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -46,7 +46,7 @@ const uint16_t MODEL_PACKET_CONTAINS_MODEL_ROTATION = 2048; const float MODEL_DEFAULT_RADIUS = 0.1f / TREE_SCALE; const float MINIMUM_MODEL_ELEMENT_SIZE = (1.0f / 100000.0f) / TREE_SCALE; // smallest size container const QString MODEL_DEFAULT_MODEL_URL(""); -const glm::quat MODEL_DEFAULT_MODEL_ROTATION(0, 0, 0, 0); +const glm::quat MODEL_DEFAULT_MODEL_ROTATION; /// A collection of properties of a model item used in the scripting API. Translates between the actual properties of a model /// and a JavaScript style hash/QScriptValue storing a set of properties. Used in scripting to set/get the complete set of From 80ed8e7cf0332085b6ff610653a0af70ff4bde27 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 6 May 2014 14:56:16 -0700 Subject: [PATCH 12/43] disable environment gravity when not set in menu --- interface/src/avatar/MyAvatar.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 46357b1e76..e8782fa140 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -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)); From 353b9879b812141cc04a7900e060bee4a2536469 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 6 May 2014 15:15:42 -0700 Subject: [PATCH 13/43] Fix for exports from Sketchup. --- libraries/fbx/src/FBXReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index a21ed2627a..40a7d56c0d 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -817,7 +817,7 @@ ExtractedMesh extractMesh(const FBXNode& object) { while (endIndex < data.polygonIndices.size() && data.polygonIndices.at(endIndex++) >= 0); QPair 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); From cde583452ae8b46741d0b96ce99ac05e3089afcc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 6 May 2014 15:31:45 -0700 Subject: [PATCH 14/43] make model server not oversend data --- libraries/models/src/ModelTree.cpp | 117 +++++---- libraries/models/src/ModelTreeElement.cpp | 3 +- libraries/octree/src/Octree.cpp | 290 ++++++++++++---------- libraries/octree/src/Octree.h | 30 ++- 4 files changed, 241 insertions(+), 199 deletions(-) diff --git a/libraries/models/src/ModelTree.cpp b/libraries/models/src/ModelTree.cpp index 236138e2a8..b624b67016 100644 --- a/libraries/models/src/ModelTree.cpp +++ b/libraries/models/src/ModelTree.cpp @@ -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(extraData); +FindAndUpdateModelOperator::FindAndUpdateModelOperator(const ModelItem& searchModel) : + _searchModel(searchModel), + _found(false) { +}; + +bool FindAndUpdateModelOperator::PreRecursion(OctreeElement* element) { ModelTreeElement* modelTreeElement = static_cast(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,38 +126,47 @@ 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); +private: + const ModelItemID& _modelID; + const ModelItemProperties& _properties; + bool _found; }; -bool ModelTree::findAndUpdateWithIDandPropertiesOperation(OctreeElement* element, void* extraData) { - FindAndUpdateModelWithIDandPropertiesArgs* args = static_cast(extraData); +FindAndUpdateModelWithIDandPropertiesOperator::FindAndUpdateModelWithIDandPropertiesOperator(const ModelItemID& modelID, + const ModelItemProperties& properties) : + _modelID(modelID), + _properties(properties), + _found(false) { +}; + +bool FindAndUpdateModelWithIDandPropertiesOperator::PreRecursion(OctreeElement* element) { ModelTreeElement* modelTreeElement = static_cast(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) { - _isDirty = true; - } + // Look for the existing model in the tree.. + FindAndUpdateModelWithIDandPropertiesOperator theOperator(modelID, properties); + recurseTreeWithOperator(&theOperator); } void ModelTree::addModel(const ModelItemID& modelID, const ModelItemProperties& properties) { @@ -464,29 +490,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(); } diff --git a/libraries/models/src/ModelTreeElement.cpp b/libraries/models/src/ModelTreeElement.cpp index 687199827c..0327d8a0c4 100644 --- a/libraries/models/src/ModelTreeElement.cpp +++ b/libraries/models/src/ModelTreeElement.cpp @@ -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(); diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 266447e27e..7f5834fa6f 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -50,33 +50,33 @@ Octree::Octree(bool shouldReaverage) : } Octree::~Octree() { - // delete the children of the root node + // delete the children of the root element // this recursively deletes the tree delete _rootNode; } -// Recurses voxel tree calling the RecurseOctreeOperation function for each node. +// Recurses voxel tree calling the RecurseOctreeOperation function for each element. // stops recursion if operation function returns false. void Octree::recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData) { recurseNodeWithOperation(_rootNode, operation, extraData); } -// Recurses voxel tree calling the RecurseOctreePostFixOperation function for each node in post-fix order. +// Recurses voxel tree calling the RecurseOctreePostFixOperation function for each element in post-fix order. void Octree::recurseTreeWithPostOperation(RecurseOctreeOperation operation, void* extraData) { recurseNodeWithPostOperation(_rootNode, operation, extraData); } -// Recurses voxel node with an operation function -void Octree::recurseNodeWithOperation(OctreeElement* node, RecurseOctreeOperation operation, void* extraData, +// Recurses voxel element with an operation function +void Octree::recurseNodeWithOperation(OctreeElement* element, RecurseOctreeOperation operation, void* extraData, int recursionCount) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { qDebug() << "Octree::recurseNodeWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; return; } - if (operation(node, extraData)) { + if (operation(element, extraData)) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - OctreeElement* child = node->getChildAtIndex(i); + OctreeElement* child = element->getChildAtIndex(i); if (child) { recurseNodeWithOperation(child, operation, extraData, recursionCount+1); } @@ -84,8 +84,8 @@ void Octree::recurseNodeWithOperation(OctreeElement* node, RecurseOctreeOperatio } } -// Recurses voxel node with an operation function -void Octree::recurseNodeWithPostOperation(OctreeElement* node, RecurseOctreeOperation operation, void* extraData, +// Recurses voxel element with an operation function +void Octree::recurseNodeWithPostOperation(OctreeElement* element, RecurseOctreeOperation operation, void* extraData, int recursionCount) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { qDebug() << "Octree::recurseNodeWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!\n"; @@ -93,15 +93,15 @@ void Octree::recurseNodeWithPostOperation(OctreeElement* node, RecurseOctreeOper } for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - OctreeElement* child = node->getChildAtIndex(i); + OctreeElement* child = element->getChildAtIndex(i); if (child) { recurseNodeWithPostOperation(child, operation, extraData, recursionCount+1); } } - operation(node, extraData); + operation(element, extraData); } -// Recurses voxel tree calling the RecurseOctreeOperation function for each node. +// Recurses voxel tree calling the RecurseOctreeOperation function for each element. // stops recursion if operation function returns false. void Octree::recurseTreeWithOperationDistanceSorted(RecurseOctreeOperation operation, const glm::vec3& point, void* extraData) { @@ -109,8 +109,8 @@ void Octree::recurseTreeWithOperationDistanceSorted(RecurseOctreeOperation opera recurseNodeWithOperationDistanceSorted(_rootNode, operation, point, extraData); } -// Recurses voxel node with an operation function -void Octree::recurseNodeWithOperationDistanceSorted(OctreeElement* node, RecurseOctreeOperation operation, +// Recurses voxel element with an operation function +void Octree::recurseNodeWithOperationDistanceSorted(OctreeElement* element, RecurseOctreeOperation operation, const glm::vec3& point, void* extraData, int recursionCount) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { @@ -118,7 +118,7 @@ void Octree::recurseNodeWithOperationDistanceSorted(OctreeElement* node, Recurse return; } - if (operation(node, extraData)) { + if (operation(element, extraData)) { // determine the distance sorted order of our children OctreeElement* sortedChildren[NUMBER_OF_CHILDREN] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; float distancesToChildren[NUMBER_OF_CHILDREN] = { 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -126,7 +126,7 @@ void Octree::recurseNodeWithOperationDistanceSorted(OctreeElement* node, Recurse int currentCount = 0; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - OctreeElement* childNode = node->getChildAtIndex(i); + OctreeElement* childNode = element->getChildAtIndex(i); if (childNode) { // chance to optimize, doesn't need to be actual distance!! Could be distance squared float distanceSquared = childNode->distanceSquareToPoint(point); @@ -149,6 +149,30 @@ void Octree::recurseNodeWithOperationDistanceSorted(OctreeElement* node, Recurse } } +void Octree::recurseTreeWithOperator(RecurseOctreeOperator* operatorObject) { + recurseNodeWithOperator(_rootNode, operatorObject); +} + +bool Octree::recurseNodeWithOperator(OctreeElement* element, RecurseOctreeOperator* operatorObject, int recursionCount) { + if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { + qDebug() << "Octree::recurseNodeWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; + return false; + } + + if (operatorObject->PreRecursion(element)) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + OctreeElement* child = element->getChildAtIndex(i); + if (child) { + if (!recurseNodeWithOperator(child, operatorObject, recursionCount + 1)) { + break; // stop recursing if operator returns false... + } + } + } + } + + return operatorObject->PostRecursion(element); +} + OctreeElement* Octree::nodeForOctalCode(OctreeElement* ancestorNode, const unsigned char* needleCode, OctreeElement** parentOfFoundNode) const { @@ -170,8 +194,8 @@ OctreeElement* Octree::nodeForOctalCode(OctreeElement* ancestorNode, *parentOfFoundNode = ancestorNode; } // the fact that the number of sections is equivalent does not always guarantee - // that this is the same node, however due to the recursive traversal - // we know that this is our node + // that this is the same element, however due to the recursive traversal + // we know that this is our element return childNode; } else { // we need to go deeper @@ -180,15 +204,15 @@ OctreeElement* Octree::nodeForOctalCode(OctreeElement* ancestorNode, } } - // we've been given a code we don't have a node for - // return this node as the last created parent + // we've been given a code we don't have a element for + // return this element as the last created parent return ancestorNode; } -// returns the node created! +// returns the element created! OctreeElement* Octree::createMissingNode(OctreeElement* lastParentNode, const unsigned char* codeToReach) { int indexOfNewChild = branchIndexWithDescendant(lastParentNode->getOctalCode(), codeToReach); - // If this parent node is a leaf, then you know the child path doesn't exist, so deal with + // If this parent element is a leaf, then you know the child path doesn't exist, so deal with // breaking up the leaf first, which will also create a child path if (lastParentNode->requiresSplit()) { lastParentNode->splitChildren(); @@ -207,7 +231,7 @@ OctreeElement* Octree::createMissingNode(OctreeElement* lastParentNode, const un int Octree::readNodeData(OctreeElement* destinationNode, const unsigned char* nodeData, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { - // give this destination node the child mask from the packet + // give this destination element the child mask from the packet const unsigned char ALL_CHILDREN_ASSUMED_TO_EXIST = 0xFF; unsigned char colorInPacketMask = *nodeData; @@ -230,7 +254,7 @@ int Octree::readNodeData(OctreeElement* destinationNode, const unsigned char* no bytesRead += childNodeAt->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead, args); childNodeAt->setSourceUUID(args.sourceUUID); - // if we had a local version of the node already, it's possible that we have it already but + // if we had a local version of the element already, it's possible that we have it already but // with the same color data, so this won't count as a change. To address this we check the following if (!childNodeAt->isDirty() && childNodeAt->getShouldRender() && !childNodeAt->isRendered()) { childNodeAt->setDirtyBit(); // force dirty! @@ -244,7 +268,7 @@ int Octree::readNodeData(OctreeElement* destinationNode, const unsigned char* no } } - // give this destination node the child mask from the packet + // give this destination element the child mask from the packet unsigned char childrenInTreeMask = args.includeExistsBits ? *(nodeData + bytesRead) : ALL_CHILDREN_ASSUMED_TO_EXIST; unsigned char childMask = *(nodeData + bytesRead + (args.includeExistsBits ? sizeof(childrenInTreeMask) : 0)); @@ -274,7 +298,7 @@ int Octree::readNodeData(OctreeElement* destinationNode, const unsigned char* no if (args.includeExistsBits) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { // now also check the childrenInTreeMask, if the mask is missing the bit, then it means we need to delete this child - // subtree/node, because it shouldn't actually exist in the tree. + // subtree/element, because it shouldn't actually exist in the tree. if (!oneAtBit(childrenInTreeMask, i) && destinationNode->getChildAtIndex(i)) { destinationNode->safeDeepDeleteChildAtIndex(i); _isDirty = true; // by definition! @@ -289,7 +313,7 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long int bytesRead = 0; const unsigned char* bitstreamAt = bitstream; - // If destination node is not included, set it to root + // If destination element is not included, set it to root if (!args.destinationNode) { args.destinationNode = _rootNode; } @@ -304,7 +328,7 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long // if the octal code returned is not on the same level as // the code being searched for, we have OctreeElements to create - // Note: we need to create this node relative to root, because we're assuming that the bitstream for the initial + // Note: we need to create this element relative to root, because we're assuming that the bitstream for the initial // octal code is always relative to root! bitstreamRootNode = createMissingNode(args.destinationNode, (unsigned char*) bitstreamAt); if (bitstreamRootNode->isDirty()) { @@ -347,9 +371,9 @@ public: }; // Note: uses the codeColorBuffer format, but the color's are ignored, because -// this only finds and deletes the node from the tree. +// this only finds and deletes the element from the tree. void Octree::deleteOctalCodeFromTree(const unsigned char* codeBuffer, bool collapseEmptyTrees) { - // recurse the tree while decoding the codeBuffer, once you find the node in question, recurse + // recurse the tree while decoding the codeBuffer, once you find the element in question, recurse // back and implement color reaveraging, and marking of lastChanged DeleteOctalCodeFromTreeArgs args; args.collapseEmptyTrees = collapseEmptyTrees; @@ -358,18 +382,16 @@ void Octree::deleteOctalCodeFromTree(const unsigned char* codeBuffer, bool colla args.deleteLastChild = false; args.pathChanged = false; - OctreeElement* node = _rootNode; - - deleteOctalCodeFromTreeRecursion(node, &args); + deleteOctalCodeFromTreeRecursion(_rootNode, &args); } -void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* node, void* extraData) { +void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* element, void* extraData) { DeleteOctalCodeFromTreeArgs* args = (DeleteOctalCodeFromTreeArgs*)extraData; - int lengthOfNodeCode = numberOfThreeBitSectionsInCode(node->getOctalCode()); + int lengthOfNodeCode = numberOfThreeBitSectionsInCode(element->getOctalCode()); // Since we traverse the tree in code order, we know that if our code - // matches, then we've reached our target node. + // matches, then we've reached our target element. if (lengthOfNodeCode == args->lengthOfCode) { // we've reached our target, depending on how we're called we may be able to operate on it // it here, we need to recurse up, and delete it there. So we handle these cases the same to keep @@ -378,16 +400,16 @@ void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* node, void* extraDa return; } - // Ok, we know we haven't reached our target node yet, so keep looking - int childIndex = branchIndexWithDescendant(node->getOctalCode(), args->codeBuffer); - OctreeElement* childNode = node->getChildAtIndex(childIndex); + // Ok, we know we haven't reached our target element yet, so keep looking + int childIndex = branchIndexWithDescendant(element->getOctalCode(), args->codeBuffer); + OctreeElement* childNode = element->getChildAtIndex(childIndex); - // If there is no child at the target location, and the current parent node is a colored leaf, + // If there is no child at the target location, and the current parent element is a colored leaf, // then it means we were asked to delete a child out of a larger leaf voxel. // We support this by breaking up the parent voxel into smaller pieces. - if (!childNode && node->requiresSplit()) { + if (!childNode && element->requiresSplit()) { // we need to break up ancestors until we get to the right level - OctreeElement* ancestorNode = node; + OctreeElement* ancestorNode = element; while (true) { int index = branchIndexWithDescendant(ancestorNode->getOctalCode(), args->codeBuffer); @@ -425,7 +447,7 @@ void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* node, void* extraDa // If the lower level determined it needs to be deleted, then we should delete now. if (args->deleteLastChild) { - node->deleteChildAtIndex(childIndex); // note: this will track dirtiness and lastChanged for this node + element->deleteChildAtIndex(childIndex); // note: this will track dirtiness and lastChanged for this element // track our tree dirtiness _isDirty = true; @@ -433,11 +455,11 @@ void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* node, void* extraDa // track that path has changed args->pathChanged = true; - // If we're in collapseEmptyTrees mode, and this was the last child of this node, then we also want - // to delete this node. This will collapse the empty tree above us. - if (args->collapseEmptyTrees && node->getChildCount() == 0) { + // If we're in collapseEmptyTrees mode, and this was the last child of this element, then we also want + // to delete this element. This will collapse the empty tree above us. + if (args->collapseEmptyTrees && element->getChildCount() == 0) { // Can't delete the root this way. - if (node == _rootNode) { + if (element == _rootNode) { args->deleteLastChild = false; // reset so that further up the unwinding chain we don't do anything } } else { @@ -445,10 +467,10 @@ void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* node, void* extraDa } } - // If the lower level did some work, then we need to let this node know, so it can + // If the lower level did some work, then we need to let this element know, so it can // do any bookkeeping it wants to, like color re-averaging, time stamp marking, etc if (args->pathChanged) { - node->handleSubtreeChanged(this); + element->handleSubtreeChanged(this); } } @@ -529,30 +551,30 @@ void Octree::reaverageOctreeElements(OctreeElement* startNode) { OctreeElement* Octree::getOctreeElementAt(float x, float y, float z, float s) const { unsigned char* octalCode = pointToOctalCode(x,y,z,s); - OctreeElement* node = nodeForOctalCode(_rootNode, octalCode, NULL); - if (*node->getOctalCode() != *octalCode) { - node = NULL; + OctreeElement* element = nodeForOctalCode(_rootNode, octalCode, NULL); + if (*element->getOctalCode() != *octalCode) { + element = NULL; } delete[] octalCode; // cleanup memory #ifdef HAS_AUDIT_CHILDREN - if (node) { - node->auditChildren("Octree::getOctreeElementAt()"); + if (element) { + element->auditChildren("Octree::getOctreeElementAt()"); } #endif // def HAS_AUDIT_CHILDREN - return node; + return element; } OctreeElement* Octree::getOctreeEnclosingElementAt(float x, float y, float z, float s) const { unsigned char* octalCode = pointToOctalCode(x,y,z,s); - OctreeElement* node = nodeForOctalCode(_rootNode, octalCode, NULL); + OctreeElement* element = nodeForOctalCode(_rootNode, octalCode, NULL); delete[] octalCode; // cleanup memory #ifdef HAS_AUDIT_CHILDREN - if (node) { - node->auditChildren("Octree::getOctreeElementAt()"); + if (element) { + element->auditChildren("Octree::getOctreeElementAt()"); } #endif // def HAS_AUDIT_CHILDREN - return node; + return element; } @@ -566,26 +588,26 @@ class RayArgs { public: glm::vec3 origin; glm::vec3 direction; - OctreeElement*& node; + OctreeElement*& element; float& distance; BoxFace& face; bool found; }; -bool findRayIntersectionOp(OctreeElement* node, void* extraData) { +bool findRayIntersectionOp(OctreeElement* element, void* extraData) { RayArgs* args = static_cast(extraData); - AABox box = node->getAABox(); + AABox box = element->getAABox(); float distance; BoxFace face; if (!box.findRayIntersection(args->origin, args->direction, distance, face)) { return false; } - if (!node->isLeaf()) { + if (!element->isLeaf()) { return true; // recurse on children } distance *= TREE_SCALE; - if (node->hasContent() && (!args->found || distance < args->distance)) { - args->node = node; + if (element->hasContent() && (!args->found || distance < args->distance)) { + args->element = element; args->distance = distance; args->face = face; args->found = true; @@ -594,9 +616,9 @@ bool findRayIntersectionOp(OctreeElement* node, void* extraData) { } bool Octree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - OctreeElement*& node, float& distance, BoxFace& face, + OctreeElement*& element, float& distance, BoxFace& face, Octree::lockType lockType, bool* accurateResult) { - RayArgs args = { origin / (float)(TREE_SCALE), direction, node, distance, face, false}; + RayArgs args = { origin / (float)(TREE_SCALE), direction, element, distance, face, false}; bool gotLock = false; if (lockType == Octree::Lock) { @@ -712,18 +734,18 @@ public: bool found; }; -bool findCapsulePenetrationOp(OctreeElement* node, void* extraData) { +bool findCapsulePenetrationOp(OctreeElement* element, void* extraData) { CapsuleArgs* args = static_cast(extraData); // coarse check against bounds - const AABox& box = node->getAABox(); + const AABox& box = element->getAABox(); if (!box.expandedIntersectsSegment(args->start, args->end, args->radius)) { return false; } - if (!node->isLeaf()) { + if (!element->isLeaf()) { return true; // recurse on children } - if (node->hasContent()) { + if (element->hasContent()) { glm::vec3 nodePenetration; if (box.findCapsulePenetration(args->start, args->end, args->radius, nodePenetration)) { args->penetration = addPenetrations(args->penetration, nodePenetration * (float)(TREE_SCALE)); @@ -733,19 +755,19 @@ bool findCapsulePenetrationOp(OctreeElement* node, void* extraData) { return false; } -bool findShapeCollisionsOp(OctreeElement* node, void* extraData) { +bool findShapeCollisionsOp(OctreeElement* element, void* extraData) { ShapeArgs* args = static_cast(extraData); // coarse check against bounds - AABox cube = node->getAABox(); + AABox cube = element->getAABox(); cube.scale(TREE_SCALE); if (!cube.expandedContains(args->shape->getPosition(), args->shape->getBoundingRadius())) { return false; } - if (!node->isLeaf()) { + if (!element->isLeaf()) { return true; // recurse on children } - if (node->hasContent()) { + if (element->hasContent()) { if (ShapeCollider::collideShapeWithAACube(args->shape, cube.calcCenter(), cube.getScale(), args->collisions)) { args->found = true; return true; @@ -834,7 +856,7 @@ bool getElementEnclosingOperation(OctreeElement* element, void* extraData) { AABox elementBox = element->getAABox(); if (elementBox.contains(args->point)) { if (element->hasContent() && element->isLeaf()) { - // we've reached a solid leaf containing the point, return the node. + // we've reached a solid leaf containing the point, return the element. args->element = element; return false; } @@ -878,22 +900,22 @@ OctreeElement* Octree::getElementEnclosingPoint(const glm::vec3& point, Octree:: -int Octree::encodeTreeBitstream(OctreeElement* node, +int Octree::encodeTreeBitstream(OctreeElement* element, OctreePacketData* packetData, OctreeElementBag& bag, EncodeBitstreamParams& params) { // How many bytes have we written so far at this level; int bytesWritten = 0; - // you can't call this without a valid node - if (!node) { - qDebug("WARNING! encodeTreeBitstream() called with node=NULL"); + // you can't call this without a valid element + if (!element) { + qDebug("WARNING! encodeTreeBitstream() called with element=NULL"); params.stopReason = EncodeBitstreamParams::NULL_NODE; return bytesWritten; } - // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! - if (params.viewFrustum && !node->isInView(*params.viewFrustum)) { + // If we're at a element that is out of view, then we can return, because no nodes below us will be in view! + if (params.viewFrustum && !element->isInView(*params.viewFrustum)) { params.stopReason = EncodeBitstreamParams::OUT_OF_VIEW; return bytesWritten; } @@ -902,7 +924,7 @@ int Octree::encodeTreeBitstream(OctreeElement* node, bool roomForOctalCode = false; // assume the worst int codeLength = 1; // assume root if (params.chopLevels) { - unsigned char* newCode = chopOctalCode(node->getOctalCode(), params.chopLevels); + unsigned char* newCode = chopOctalCode(element->getOctalCode(), params.chopLevels); roomForOctalCode = packetData->startSubTree(newCode); if (newCode) { @@ -912,13 +934,13 @@ int Octree::encodeTreeBitstream(OctreeElement* node, codeLength = 1; } } else { - roomForOctalCode = packetData->startSubTree(node->getOctalCode()); - codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(node->getOctalCode())); + roomForOctalCode = packetData->startSubTree(element->getOctalCode()); + codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(element->getOctalCode())); } // If the octalcode couldn't fit, then we can return, because no nodes below us will fit... if (!roomForOctalCode) { - bag.insert(node); // add the node back to the bag so it will eventually get included + bag.insert(element); // add the element back to the bag so it will eventually get included params.stopReason = EncodeBitstreamParams::DIDNT_FIT; return bytesWritten; } @@ -927,15 +949,15 @@ int Octree::encodeTreeBitstream(OctreeElement* node, int currentEncodeLevel = 0; - // record some stats, this is the one node that we won't record below in the recursion function, so we need to + // record some stats, this is the one element that we won't record below in the recursion function, so we need to // track it here if (params.stats) { - params.stats->traversed(node); + params.stats->traversed(element); } ViewFrustum::location parentLocationThisView = ViewFrustum::INTERSECT; // assume parent is in view, but not fully - int childBytesWritten = encodeTreeBitstreamRecursion(node, packetData, bag, params, + int childBytesWritten = encodeTreeBitstreamRecursion(element, packetData, bag, params, currentEncodeLevel, parentLocationThisView); // if childBytesWritten == 1 then something went wrong... that's not possible @@ -966,16 +988,16 @@ int Octree::encodeTreeBitstream(OctreeElement* node, return bytesWritten; } -int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, +int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, OctreePacketData* packetData, OctreeElementBag& bag, EncodeBitstreamParams& params, int& currentEncodeLevel, const ViewFrustum::location& parentLocationThisView) const { // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; - // you can't call this without a valid node - if (!node) { - qDebug("WARNING! encodeTreeBitstreamRecursion() called with node=NULL"); + // you can't call this without a valid element + if (!element) { + qDebug("WARNING! encodeTreeBitstreamRecursion() called with element=NULL"); params.stopReason = EncodeBitstreamParams::NULL_NODE; return bytesAtThisLevel; } @@ -995,7 +1017,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, if (params.jurisdictionMap) { // here's how it works... if we're currently above our root jurisdiction, then we proceed normally. // but once we're in our own jurisdiction, then we need to make sure we're not below it. - if (JurisdictionMap::BELOW == params.jurisdictionMap->isMyJurisdiction(node->getOctalCode(), CHECK_NODE_ONLY)) { + if (JurisdictionMap::BELOW == params.jurisdictionMap->isMyJurisdiction(element->getOctalCode(), CHECK_NODE_ONLY)) { params.stopReason = EncodeBitstreamParams::OUT_OF_JURISDICTION; return bytesAtThisLevel; } @@ -1005,14 +1027,14 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, // caller can pass NULL as viewFrustum if they want everything if (params.viewFrustum) { - float distance = node->distanceToCamera(*params.viewFrustum); - float boundaryDistance = boundaryDistanceForRenderLevel(node->getLevel() + params.boundaryLevelAdjust, + float distance = element->distanceToCamera(*params.viewFrustum); + float boundaryDistance = boundaryDistanceForRenderLevel(element->getLevel() + params.boundaryLevelAdjust, params.octreeElementSizeScale); // If we're too far away for our render level, then just return if (distance >= boundaryDistance) { if (params.stats) { - params.stats->skippedDistance(node); + params.stats->skippedDistance(element); } params.stopReason = EncodeBitstreamParams::LOD_SKIP; return bytesAtThisLevel; @@ -1022,15 +1044,15 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, // if we are INSIDE, INTERSECT, or OUTSIDE if (parentLocationThisView != ViewFrustum::INSIDE) { assert(parentLocationThisView != ViewFrustum::OUTSIDE); // we shouldn't be here if our parent was OUTSIDE! - nodeLocationThisView = node->inFrustum(*params.viewFrustum); + nodeLocationThisView = element->inFrustum(*params.viewFrustum); } - // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! + // If we're at a element that is out of view, then we can return, because no nodes below us will be in view! // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if // we're out of view if (nodeLocationThisView == ViewFrustum::OUTSIDE) { if (params.stats) { - params.stats->skippedOutOfView(node); + params.stats->skippedOutOfView(element); } params.stopReason = EncodeBitstreamParams::OUT_OF_VIEW; return bytesAtThisLevel; @@ -1041,10 +1063,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, bool wasInView = false; if (params.deltaViewFrustum && params.lastViewFrustum) { - ViewFrustum::location location = node->inFrustum(*params.lastViewFrustum); + ViewFrustum::location location = element->inFrustum(*params.lastViewFrustum); // If we're a leaf, then either intersect or inside is considered "formerly in view" - if (node->isLeaf()) { + if (element->isLeaf()) { wasInView = location != ViewFrustum::OUTSIDE; } else { wasInView = location == ViewFrustum::INSIDE; @@ -1055,8 +1077,8 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, // to it, and so therefore it may now be visible from an LOD perspective, in which case we don't consider it // as "was in view"... if (wasInView) { - float distance = node->distanceToCamera(*params.lastViewFrustum); - float boundaryDistance = boundaryDistanceForRenderLevel(node->getLevel() + params.boundaryLevelAdjust, + float distance = element->distanceToCamera(*params.lastViewFrustum); + float boundaryDistance = boundaryDistanceForRenderLevel(element->getLevel() + params.boundaryLevelAdjust, params.octreeElementSizeScale); if (distance >= boundaryDistance) { // This would have been invisible... but now should be visible (we wouldn't be here otherwise)... @@ -1066,11 +1088,11 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, } // If we were previously in the view, then we normally will return out of here and stop recursing. But - // if we're in deltaViewFrustum mode, and this node has changed since it was last sent, then we do + // if we're in deltaViewFrustum mode, and this element has changed since it was last sent, then we do // need to send it. - if (wasInView && !(params.deltaViewFrustum && node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))) { + if (wasInView && !(params.deltaViewFrustum && element->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))) { if (params.stats) { - params.stats->skippedWasInView(node); + params.stats->skippedWasInView(element); } params.stopReason = EncodeBitstreamParams::WAS_IN_VIEW; return bytesAtThisLevel; @@ -1079,18 +1101,18 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, // If we're not in delta sending mode, and we weren't asked to do a force send, and the voxel hasn't changed, // then we can also bail early and save bits if (!params.forceSendScene && !params.deltaViewFrustum && - !node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE)) { + !element->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE)) { if (params.stats) { - params.stats->skippedNoChange(node); + params.stats->skippedNoChange(element); } params.stopReason = EncodeBitstreamParams::NO_CHANGE; return bytesAtThisLevel; } - // If the user also asked for occlusion culling, check if this node is occluded, but only if it's not a leaf. + // If the user also asked for occlusion culling, check if this element is occluded, but only if it's not a leaf. // leaf occlusion is handled down below when we check child nodes - if (params.wantOcclusionCulling && !node->isLeaf()) { - AABox voxelBox = node->getAABox(); + if (params.wantOcclusionCulling && !element->isLeaf()) { + AABox voxelBox = element->getAABox(); voxelBox.scale(TREE_SCALE); OctreeProjectedPolygon* voxelPolygon = new OctreeProjectedPolygon(params.viewFrustum->getProjectedPolygon(voxelBox)); @@ -1101,7 +1123,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, delete voxelPolygon; // cleanup if (result == OCCLUDED) { if (params.stats) { - params.stats->skippedOccluded(node); + params.stats->skippedOccluded(element); } params.stopReason = EncodeBitstreamParams::OCCLUDED; return bytesAtThisLevel; @@ -1138,14 +1160,14 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, int currentCount = 0; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - OctreeElement* childNode = node->getChildAtIndex(i); + OctreeElement* childNode = element->getChildAtIndex(i); // if the caller wants to include childExistsBits, then include them even if not in view, if however, // we're in a portion of the tree that's not our responsibility, then we assume the child nodes exist // even if they don't in our local tree bool notMyJurisdiction = false; if (params.jurisdictionMap) { - notMyJurisdiction = (JurisdictionMap::WITHIN != params.jurisdictionMap->isMyJurisdiction(node->getOctalCode(), i)); + notMyJurisdiction = (JurisdictionMap::WITHIN != params.jurisdictionMap->isMyJurisdiction(element->getOctalCode(), i)); } if (params.includeExistsBits) { // If the child is known to exist, OR, it's not my jurisdiction, then we mark the bit as existing @@ -1176,7 +1198,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, } } - // for each child node in Distance sorted order..., check to see if they exist, are colored, and in view, and if so + // for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children for (int i = 0; i < currentCount; i++) { OctreeElement* childNode = sortedChildren[i]; @@ -1218,7 +1240,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, bool childIsOccluded = false; // assume it's not occluded - // If the user also asked for occlusion culling, check if this node is occluded + // If the user also asked for occlusion culling, check if this element is occluded if (params.wantOcclusionCulling && childNode->isLeaf()) { // Don't check occlusion here, just add them to our distance ordered array... @@ -1282,7 +1304,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, } // If our child wasn't in view (or we're ignoring wasInView) then we add it to our sending items. - // Or if we were previously in the view, but this node has changed since it was last sent, then we do + // Or if we were previously in the view, but this element has changed since it was last sent, then we do // need to send it. if (!childWasInView || (params.deltaViewFrustum && @@ -1320,7 +1342,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, if (continueThisLevel && params.includeColor) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (oneAtBit(childrenColoredBits, i)) { - OctreeElement* childNode = node->getChildAtIndex(i); + OctreeElement* childNode = element->getChildAtIndex(i); if (childNode) { int bytesBeforeChild = packetData->getUncompressedSize(); continueThisLevel = childNode->appendElementData(packetData); @@ -1389,7 +1411,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, int firstRecursiveSliceOffset = packetData->getUncompressedByteOffset(); int allSlicesSize = 0; - // for each child node in Distance sorted order..., check to see if they exist, are colored, and in view, and if so + // for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children for (int indexByDistance = 0; indexByDistance < currentCount; indexByDistance++) { OctreeElement* childNode = sortedChildren[indexByDistance]; @@ -1431,7 +1453,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, // if the child tree wrote just 2 bytes, then it means: it had no colors and no child nodes, because... // if it had colors it would write 1 byte for the color mask, - // and at least a color's worth of bytes for the node of colors. + // and at least a color's worth of bytes for the element of colors. // if it had child trees (with something in them) then it would have the 1 byte for child mask // and some number of bytes of lower children... // so, if the child returns 2 bytes out, we can actually consider that an empty tree also!! @@ -1441,8 +1463,8 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees } // We used to try to collapse trees that didn't contain any data, but this does appear to create a problem - // in detecting node deletion. So, I've commented this out but left it in here as a warning to anyone else - // about not attempting to add this optimization back in, without solving the node deletion case. + // in detecting element deletion. So, I've commented this out but left it in here as a warning to anyone else + // about not attempting to add this optimization back in, without solving the element deletion case. // We need to send these bitMasks in case the exists in tree bitmask is indicating the deletion of a tree //if (params.includeColor && params.includeExistsBits && childTreeBytesOut == 3) { // childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees @@ -1508,7 +1530,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, qDebug(""); **/ - // if we were unable to fit this level in our packet, then rewind and add it to the node bag for + // if we were unable to fit this level in our packet, then rewind and add it to the element bag for // sending later... if (continueThisLevel) { continueThisLevel = packetData->endLevel(thisLevelKey); @@ -1517,11 +1539,11 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, } if (!continueThisLevel) { - bag.insert(node); + bag.insert(element); - // don't need to check node here, because we can't get here with no node + // don't need to check element here, because we can't get here with no element if (params.stats) { - params.stats->didntFit(node); + params.stats->didntFit(element); } params.stopReason = EncodeBitstreamParams::DIDNT_FIT; @@ -1591,7 +1613,7 @@ bool Octree::readFromSVOFile(const char* fileName) { return fileOk; } -void Octree::writeToSVOFile(const char* fileName, OctreeElement* node) { +void Octree::writeToSVOFile(const char* fileName, OctreeElement* element) { std::ofstream file(fileName, std::ios::out|std::ios::binary); @@ -1608,9 +1630,9 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* node) { } OctreeElementBag nodeBag; - // If we were given a specific node, start from there, otherwise start from root - if (node) { - nodeBag.insert(node); + // If we were given a specific element, start from there, otherwise start from root + if (element) { + nodeBag.insert(element); } else { nodeBag.insert(_rootNode); } @@ -1627,7 +1649,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* node) { bytesWritten = encodeTreeBitstream(subTree, &packetData, nodeBag, params); unlock(); - // if the subTree couldn't fit, and so we should reset the packet and reinsert the node in our bag and try again... + // if the subTree couldn't fit, and so we should reset the packet and reinsert the element in our bag and try again... if (bytesWritten == 0 && (params.stopReason == EncodeBitstreamParams::DIDNT_FIT)) { if (packetData.hasContent()) { file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize()); @@ -1654,7 +1676,7 @@ unsigned long Octree::getOctreeElementsCount() { return nodeCount; } -bool Octree::countOctreeElementsOperation(OctreeElement* node, void* extraData) { +bool Octree::countOctreeElementsOperation(OctreeElement* element, void* extraData) { (*(unsigned long*)extraData)++; return true; // keep going } @@ -1699,7 +1721,7 @@ void Octree::copySubTreeIntoNewTree(OctreeElement* startNode, Octree* destinatio void Octree::copyFromTreeIntoSubTree(Octree* sourceTree, OctreeElement* destinationNode) { OctreeElementBag nodeBag; - // If we were given a specific node, start from there, otherwise start from root + // If we were given a specific element, start from there, otherwise start from root nodeBag.insert(sourceTree->_rootNode); static OctreePacketData packetData; diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 56e8d9d08c..4c430bfe3a 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -36,8 +36,15 @@ class Shape; #include #include +/// 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; @@ -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,7 +276,7 @@ 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); @@ -279,17 +287,19 @@ public: bool getShouldReaverage() const { return _shouldReaverage; } - void recurseNodeWithOperation(OctreeElement* node, RecurseOctreeOperation operation, + void recurseNodeWithOperation(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 recurseNodeWithPostOperation(OctreeElement* element, RecurseOctreeOperation operation, void* extraData, int recursionCount = 0); - void recurseNodeWithOperationDistanceSorted(OctreeElement* node, RecurseOctreeOperation operation, + void recurseNodeWithOperationDistanceSorted(OctreeElement* element, RecurseOctreeOperation operation, const glm::vec3& point, void* extraData, int recursionCount = 0); + bool recurseNodeWithOperator(OctreeElement* element, RecurseOctreeOperator* operatorObject, int recursionCount = 0); + bool getIsViewing() const { return _isViewing; } void setIsViewing(bool isViewing) { _isViewing = isViewing; } @@ -302,14 +312,14 @@ 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); From 91e4a8957326eeb1f16564193e67632217a69151 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 6 May 2014 15:47:18 -0700 Subject: [PATCH 15/43] cleanup old references to node which are really elements --- interface/src/voxels/VoxelSystem.cpp | 4 +- libraries/models/src/ModelTree.cpp | 6 +- libraries/models/src/ModelTree.h | 2 +- libraries/octree/src/Octree.cpp | 322 +++++++++++------------ libraries/octree/src/Octree.h | 30 +-- libraries/particles/src/ParticleTree.cpp | 2 +- libraries/particles/src/ParticleTree.h | 2 +- libraries/voxels/src/VoxelTree.cpp | 6 +- libraries/voxels/src/VoxelTree.h | 2 +- 9 files changed, 182 insertions(+), 194 deletions(-) diff --git a/interface/src/voxels/VoxelSystem.cpp b/interface/src/voxels/VoxelSystem.cpp index 9a54a08619..0fac5a338c 100644 --- a/interface/src/voxels/VoxelSystem.cpp +++ b/interface/src/voxels/VoxelSystem.cpp @@ -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: { diff --git a/libraries/models/src/ModelTree.cpp b/libraries/models/src/ModelTree.cpp index b624b67016..cef38a9422 100644 --- a/libraries/models/src/ModelTree.cpp +++ b/libraries/models/src/ModelTree.cpp @@ -12,7 +12,7 @@ #include "ModelTree.h" ModelTree::ModelTree(bool shouldReaverage) : Octree(shouldReaverage) { - _rootNode = createNewElement(); + _rootElement = createNewElement(); } ModelTreeElement* ModelTree::createNewElement(unsigned char * octalCode) { @@ -132,6 +132,7 @@ public: 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; @@ -167,6 +168,9 @@ void ModelTree::updateModel(const ModelItemID& modelID, const ModelItemPropertie // Look for the existing model in the tree.. FindAndUpdateModelWithIDandPropertiesOperator theOperator(modelID, properties); recurseTreeWithOperator(&theOperator); + if (theOperator.wasFound()) { + _isDirty = true; + } } void ModelTree::addModel(const ModelItemID& modelID, const ModelItemProperties& properties) { diff --git a/libraries/models/src/ModelTree.h b/libraries/models/src/ModelTree.h index 02086ecd89..ac25cdc003 100644 --- a/libraries/models/src/ModelTree.h +++ b/libraries/models/src/ModelTree.h @@ -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(_rootElement); } // These methods will allow the OctreeServer to send your tree inbound edit packets of your diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 7f5834fa6f..8228249777 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -40,7 +40,7 @@ float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeSc } Octree::Octree(bool shouldReaverage) : - _rootNode(NULL), + _rootElement(NULL), _isDirty(true), _shouldReaverage(shouldReaverage), _stopImport(false), @@ -52,25 +52,25 @@ Octree::Octree(bool shouldReaverage) : Octree::~Octree() { // delete the children of the root element // this recursively deletes the tree - delete _rootNode; + delete _rootElement; } // Recurses voxel tree calling the RecurseOctreeOperation function for each element. // stops recursion if operation function returns false. void Octree::recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData) { - recurseNodeWithOperation(_rootNode, operation, extraData); + recurseElementWithOperation(_rootElement, operation, extraData); } // Recurses voxel tree calling the RecurseOctreePostFixOperation function for each element in post-fix order. void Octree::recurseTreeWithPostOperation(RecurseOctreeOperation operation, void* extraData) { - recurseNodeWithPostOperation(_rootNode, operation, extraData); + recurseElementWithPostOperation(_rootElement, operation, extraData); } // Recurses voxel element with an operation function -void Octree::recurseNodeWithOperation(OctreeElement* element, RecurseOctreeOperation operation, void* extraData, +void Octree::recurseElementWithOperation(OctreeElement* element, RecurseOctreeOperation operation, void* extraData, int recursionCount) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { - qDebug() << "Octree::recurseNodeWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; + qDebug() << "Octree::recurseElementWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; return; } @@ -78,24 +78,24 @@ void Octree::recurseNodeWithOperation(OctreeElement* element, RecurseOctreeOpera for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { OctreeElement* child = element->getChildAtIndex(i); if (child) { - recurseNodeWithOperation(child, operation, extraData, recursionCount+1); + recurseElementWithOperation(child, operation, extraData, recursionCount+1); } } } } // Recurses voxel element with an operation function -void Octree::recurseNodeWithPostOperation(OctreeElement* element, RecurseOctreeOperation operation, void* extraData, +void Octree::recurseElementWithPostOperation(OctreeElement* element, RecurseOctreeOperation operation, void* extraData, int recursionCount) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { - qDebug() << "Octree::recurseNodeWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!\n"; + qDebug() << "Octree::recurseElementWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!\n"; return; } for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { OctreeElement* child = element->getChildAtIndex(i); if (child) { - recurseNodeWithPostOperation(child, operation, extraData, recursionCount+1); + recurseElementWithPostOperation(child, operation, extraData, recursionCount+1); } } operation(element, extraData); @@ -106,15 +106,15 @@ void Octree::recurseNodeWithPostOperation(OctreeElement* element, RecurseOctreeO void Octree::recurseTreeWithOperationDistanceSorted(RecurseOctreeOperation operation, const glm::vec3& point, void* extraData) { - recurseNodeWithOperationDistanceSorted(_rootNode, operation, point, extraData); + recurseElementWithOperationDistanceSorted(_rootElement, operation, point, extraData); } // Recurses voxel element with an operation function -void Octree::recurseNodeWithOperationDistanceSorted(OctreeElement* element, RecurseOctreeOperation operation, +void Octree::recurseElementWithOperationDistanceSorted(OctreeElement* element, RecurseOctreeOperation operation, const glm::vec3& point, void* extraData, int recursionCount) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { - qDebug() << "Octree::recurseNodeWithOperationDistanceSorted() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; + qDebug() << "Octree::recurseElementWithOperationDistanceSorted() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; return; } @@ -126,36 +126,36 @@ void Octree::recurseNodeWithOperationDistanceSorted(OctreeElement* element, Recu int currentCount = 0; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - OctreeElement* childNode = element->getChildAtIndex(i); - if (childNode) { + OctreeElement* childElement = element->getChildAtIndex(i); + if (childElement) { // chance to optimize, doesn't need to be actual distance!! Could be distance squared - float distanceSquared = childNode->distanceSquareToPoint(point); - //qDebug("recurseNodeWithOperationDistanceSorted() CHECKING child[%d] point=%f,%f center=%f,%f distance=%f...\n", i, point.x, point.y, center.x, center.y, distance); - //childNode->printDebugDetails(""); - currentCount = insertIntoSortedArrays((void*)childNode, distanceSquared, i, + float distanceSquared = childElement->distanceSquareToPoint(point); + //qDebug("recurseElementWithOperationDistanceSorted() CHECKING child[%d] point=%f,%f center=%f,%f distance=%f...\n", i, point.x, point.y, center.x, center.y, distance); + //childElement->printDebugDetails(""); + currentCount = insertIntoSortedArrays((void*)childElement, distanceSquared, i, (void**)&sortedChildren, (float*)&distancesToChildren, (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); } } for (int i = 0; i < currentCount; i++) { - OctreeElement* childNode = sortedChildren[i]; - if (childNode) { - //qDebug("recurseNodeWithOperationDistanceSorted() PROCESSING child[%d] distance=%f...\n", i, distancesToChildren[i]); - //childNode->printDebugDetails(""); - recurseNodeWithOperationDistanceSorted(childNode, operation, point, extraData); + OctreeElement* childElement = sortedChildren[i]; + if (childElement) { + //qDebug("recurseElementWithOperationDistanceSorted() PROCESSING child[%d] distance=%f...\n", i, distancesToChildren[i]); + //childElement->printDebugDetails(""); + recurseElementWithOperationDistanceSorted(childElement, operation, point, extraData); } } } } void Octree::recurseTreeWithOperator(RecurseOctreeOperator* operatorObject) { - recurseNodeWithOperator(_rootNode, operatorObject); + recurseElementWithOperator(_rootElement, operatorObject); } -bool Octree::recurseNodeWithOperator(OctreeElement* element, RecurseOctreeOperator* operatorObject, int recursionCount) { +bool Octree::recurseElementWithOperator(OctreeElement* element, RecurseOctreeOperator* operatorObject, int recursionCount) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { - qDebug() << "Octree::recurseNodeWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; + qDebug() << "Octree::recurseElementWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; return false; } @@ -163,7 +163,7 @@ bool Octree::recurseNodeWithOperator(OctreeElement* element, RecurseOctreeOperat for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { OctreeElement* child = element->getChildAtIndex(i); if (child) { - if (!recurseNodeWithOperator(child, operatorObject, recursionCount + 1)) { + if (!recurseElementWithOperator(child, operatorObject, recursionCount + 1)) { break; // stop recursing if operator returns false... } } @@ -174,62 +174,62 @@ bool Octree::recurseNodeWithOperator(OctreeElement* element, RecurseOctreeOperat } -OctreeElement* Octree::nodeForOctalCode(OctreeElement* ancestorNode, - const unsigned char* needleCode, OctreeElement** parentOfFoundNode) const { +OctreeElement* Octree::nodeForOctalCode(OctreeElement* ancestorElement, + const unsigned char* needleCode, OctreeElement** parentOfFoundElement) const { // special case for NULL octcode if (!needleCode) { - return _rootNode; + return _rootElement; } - // find the appropriate branch index based on this ancestorNode + // find the appropriate branch index based on this ancestorElement if (*needleCode > 0) { - int branchForNeedle = branchIndexWithDescendant(ancestorNode->getOctalCode(), needleCode); - OctreeElement* childNode = ancestorNode->getChildAtIndex(branchForNeedle); + int branchForNeedle = branchIndexWithDescendant(ancestorElement->getOctalCode(), needleCode); + OctreeElement* childElement = ancestorElement->getChildAtIndex(branchForNeedle); - if (childNode) { - if (*childNode->getOctalCode() == *needleCode) { + if (childElement) { + if (*childElement->getOctalCode() == *needleCode) { // If the caller asked for the parent, then give them that too... - if (parentOfFoundNode) { - *parentOfFoundNode = ancestorNode; + if (parentOfFoundElement) { + *parentOfFoundElement = ancestorElement; } // the fact that the number of sections is equivalent does not always guarantee // that this is the same element, however due to the recursive traversal // we know that this is our element - return childNode; + return childElement; } else { // we need to go deeper - return nodeForOctalCode(childNode, needleCode, parentOfFoundNode); + return nodeForOctalCode(childElement, needleCode, parentOfFoundElement); } } } // we've been given a code we don't have a element for // return this element as the last created parent - return ancestorNode; + return ancestorElement; } // returns the element created! -OctreeElement* Octree::createMissingNode(OctreeElement* lastParentNode, const unsigned char* codeToReach) { - int indexOfNewChild = branchIndexWithDescendant(lastParentNode->getOctalCode(), codeToReach); +OctreeElement* Octree::createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach) { + int indexOfNewChild = branchIndexWithDescendant(lastParentElement->getOctalCode(), codeToReach); // If this parent element is a leaf, then you know the child path doesn't exist, so deal with // breaking up the leaf first, which will also create a child path - if (lastParentNode->requiresSplit()) { - lastParentNode->splitChildren(); - } else if (!lastParentNode->getChildAtIndex(indexOfNewChild)) { + if (lastParentElement->requiresSplit()) { + lastParentElement->splitChildren(); + } else if (!lastParentElement->getChildAtIndex(indexOfNewChild)) { // we could be coming down a branch that was already created, so don't stomp on it. - lastParentNode->addChildAtIndex(indexOfNewChild); + lastParentElement->addChildAtIndex(indexOfNewChild); } // This works because we know we traversed down the same tree so if the length is the same, then the whole code is the same - if (*lastParentNode->getChildAtIndex(indexOfNewChild)->getOctalCode() == *codeToReach) { - return lastParentNode->getChildAtIndex(indexOfNewChild); + if (*lastParentElement->getChildAtIndex(indexOfNewChild)->getOctalCode() == *codeToReach) { + return lastParentElement->getChildAtIndex(indexOfNewChild); } else { - return createMissingNode(lastParentNode->getChildAtIndex(indexOfNewChild), codeToReach); + return createMissingElement(lastParentElement->getChildAtIndex(indexOfNewChild), codeToReach); } } -int Octree::readNodeData(OctreeElement* destinationNode, const unsigned char* nodeData, int bytesLeftToRead, +int Octree::readElementData(OctreeElement* destinationElement, const unsigned char* nodeData, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { // give this destination element the child mask from the packet const unsigned char ALL_CHILDREN_ASSUMED_TO_EXIST = 0xFF; @@ -241,26 +241,26 @@ int Octree::readNodeData(OctreeElement* destinationNode, const unsigned char* no // check the colors mask to see if we have a child to color in if (oneAtBit(colorInPacketMask, i)) { // create the child if it doesn't exist - if (!destinationNode->getChildAtIndex(i)) { - destinationNode->addChildAtIndex(i); - if (destinationNode->isDirty()) { + if (!destinationElement->getChildAtIndex(i)) { + destinationElement->addChildAtIndex(i); + if (destinationElement->isDirty()) { _isDirty = true; } } - OctreeElement* childNodeAt = destinationNode->getChildAtIndex(i); + OctreeElement* childElementAt = destinationElement->getChildAtIndex(i); bool nodeIsDirty = false; - if (childNodeAt) { - bytesRead += childNodeAt->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead, args); - childNodeAt->setSourceUUID(args.sourceUUID); + if (childElementAt) { + bytesRead += childElementAt->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead, args); + childElementAt->setSourceUUID(args.sourceUUID); // if we had a local version of the element already, it's possible that we have it already but // with the same color data, so this won't count as a change. To address this we check the following - if (!childNodeAt->isDirty() && childNodeAt->getShouldRender() && !childNodeAt->isRendered()) { - childNodeAt->setDirtyBit(); // force dirty! + if (!childElementAt->isDirty() && childElementAt->getShouldRender() && !childElementAt->isRendered()) { + childElementAt->setDirtyBit(); // force dirty! } - nodeIsDirty = childNodeAt->isDirty(); + nodeIsDirty = childElementAt->isDirty(); } if (nodeIsDirty) { _isDirty = true; @@ -279,17 +279,17 @@ int Octree::readNodeData(OctreeElement* destinationNode, const unsigned char* no // check the exists mask to see if we have a child to traverse into if (oneAtBit(childMask, childIndex)) { - if (!destinationNode->getChildAtIndex(childIndex)) { + if (!destinationElement->getChildAtIndex(childIndex)) { // add a child at that index, if it doesn't exist - destinationNode->addChildAtIndex(childIndex); - bool nodeIsDirty = destinationNode->isDirty(); + destinationElement->addChildAtIndex(childIndex); + bool nodeIsDirty = destinationElement->isDirty(); if (nodeIsDirty) { _isDirty = true; } } // tell the child to read the subsequent data - bytesRead += readNodeData(destinationNode->getChildAtIndex(childIndex), + bytesRead += readElementData(destinationElement->getChildAtIndex(childIndex), nodeData + bytesRead, bytesLeftToRead - bytesRead, args); } childIndex++; @@ -299,8 +299,8 @@ int Octree::readNodeData(OctreeElement* destinationNode, const unsigned char* no for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { // now also check the childrenInTreeMask, if the mask is missing the bit, then it means we need to delete this child // subtree/element, because it shouldn't actually exist in the tree. - if (!oneAtBit(childrenInTreeMask, i) && destinationNode->getChildAtIndex(i)) { - destinationNode->safeDeepDeleteChildAtIndex(i); + if (!oneAtBit(childrenInTreeMask, i) && destinationElement->getChildAtIndex(i)) { + destinationElement->safeDeepDeleteChildAtIndex(i); _isDirty = true; // by definition! } } @@ -314,24 +314,24 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long const unsigned char* bitstreamAt = bitstream; // If destination element is not included, set it to root - if (!args.destinationNode) { - args.destinationNode = _rootNode; + if (!args.destinationElement) { + args.destinationElement = _rootElement; } - // Keep looping through the buffer calling readNodeData() this allows us to pack multiple root-relative Octal codes - // into a single network packet. readNodeData() basically goes down a tree from the root, and fills things in from there + // Keep looping through the buffer calling readElementData() this allows us to pack multiple root-relative Octal codes + // into a single network packet. readElementData() basically goes down a tree from the root, and fills things in from there // if there are more bytes after that, it's assumed to be another root relative tree while (bitstreamAt < bitstream + bufferSizeBytes) { - OctreeElement* bitstreamRootNode = nodeForOctalCode(args.destinationNode, (unsigned char *)bitstreamAt, NULL); - if (*bitstreamAt != *bitstreamRootNode->getOctalCode()) { + OctreeElement* bitstreamRootElement = nodeForOctalCode(args.destinationElement, (unsigned char *)bitstreamAt, NULL); + if (*bitstreamAt != *bitstreamRootElement->getOctalCode()) { // if the octal code returned is not on the same level as // the code being searched for, we have OctreeElements to create // Note: we need to create this element relative to root, because we're assuming that the bitstream for the initial // octal code is always relative to root! - bitstreamRootNode = createMissingNode(args.destinationNode, (unsigned char*) bitstreamAt); - if (bitstreamRootNode->isDirty()) { + bitstreamRootElement = createMissingElement(args.destinationElement, (unsigned char*) bitstreamAt); + if (bitstreamRootElement->isDirty()) { _isDirty = true; } } @@ -340,7 +340,7 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long int theseBytesRead = 0; theseBytesRead += octalCodeBytes; - theseBytesRead += readNodeData(bitstreamRootNode, bitstreamAt + octalCodeBytes, + theseBytesRead += readElementData(bitstreamRootElement, bitstreamAt + octalCodeBytes, bufferSizeBytes - (bytesRead + octalCodeBytes), args); // skip bitstream to new startPoint @@ -382,17 +382,17 @@ void Octree::deleteOctalCodeFromTree(const unsigned char* codeBuffer, bool colla args.deleteLastChild = false; args.pathChanged = false; - deleteOctalCodeFromTreeRecursion(_rootNode, &args); + deleteOctalCodeFromTreeRecursion(_rootElement, &args); } void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* element, void* extraData) { DeleteOctalCodeFromTreeArgs* args = (DeleteOctalCodeFromTreeArgs*)extraData; - int lengthOfNodeCode = numberOfThreeBitSectionsInCode(element->getOctalCode()); + int lengthOfElementCode = numberOfThreeBitSectionsInCode(element->getOctalCode()); // Since we traverse the tree in code order, we know that if our code // matches, then we've reached our target element. - if (lengthOfNodeCode == args->lengthOfCode) { + if (lengthOfElementCode == args->lengthOfCode) { // we've reached our target, depending on how we're called we may be able to operate on it // it here, we need to recurse up, and delete it there. So we handle these cases the same to keep // the logic consistent. @@ -402,30 +402,30 @@ void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* element, void* extr // Ok, we know we haven't reached our target element yet, so keep looking int childIndex = branchIndexWithDescendant(element->getOctalCode(), args->codeBuffer); - OctreeElement* childNode = element->getChildAtIndex(childIndex); + OctreeElement* childElement = element->getChildAtIndex(childIndex); // If there is no child at the target location, and the current parent element is a colored leaf, // then it means we were asked to delete a child out of a larger leaf voxel. // We support this by breaking up the parent voxel into smaller pieces. - if (!childNode && element->requiresSplit()) { + if (!childElement && element->requiresSplit()) { // we need to break up ancestors until we get to the right level - OctreeElement* ancestorNode = element; + OctreeElement* ancestorElement = element; while (true) { - int index = branchIndexWithDescendant(ancestorNode->getOctalCode(), args->codeBuffer); + int index = branchIndexWithDescendant(ancestorElement->getOctalCode(), args->codeBuffer); // we end up with all the children, even the one we want to delete - ancestorNode->splitChildren(); + ancestorElement->splitChildren(); - int lengthOfAncestorNode = numberOfThreeBitSectionsInCode(ancestorNode->getOctalCode()); + int lengthOfAncestorElement = numberOfThreeBitSectionsInCode(ancestorElement->getOctalCode()); // If we've reached the parent of the target, then stop breaking up children - if (lengthOfAncestorNode == (args->lengthOfCode - 1)) { + if (lengthOfAncestorElement == (args->lengthOfCode - 1)) { // since we created all the children when we split, we need to delete this target one - ancestorNode->deleteChildAtIndex(index); + ancestorElement->deleteChildAtIndex(index); break; } - ancestorNode = ancestorNode->getChildAtIndex(index); + ancestorElement = ancestorElement->getChildAtIndex(index); } _isDirty = true; args->pathChanged = true; @@ -437,13 +437,13 @@ void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* element, void* extr // if we don't have a child and we reach this point, then we actually know that the parent // isn't a colored leaf, and the child branch doesn't exist, so there's nothing to do below and // we can safely return, ending the recursion and unwinding - if (!childNode) { + if (!childElement) { return; } // If we got this far then we have a child for the branch we're looking for, but we're not there yet // recurse till we get there - deleteOctalCodeFromTreeRecursion(childNode, args); + deleteOctalCodeFromTreeRecursion(childElement, args); // If the lower level determined it needs to be deleted, then we should delete now. if (args->deleteLastChild) { @@ -459,7 +459,7 @@ void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* element, void* extr // to delete this element. This will collapse the empty tree above us. if (args->collapseEmptyTrees && element->getChildCount() == 0) { // Can't delete the root this way. - if (element == _rootNode) { + if (element == _rootElement) { args->deleteLastChild = false; // reset so that further up the unwinding chain we don't do anything } } else { @@ -475,8 +475,8 @@ void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* element, void* extr } void Octree::eraseAllOctreeElements() { - delete _rootNode; // this will recurse and delete all children - _rootNode = createNewElement(); + delete _rootElement; // this will recurse and delete all children + _rootElement = createNewElement(); _isDirty = true; } @@ -512,15 +512,15 @@ void Octree::processRemoveOctreeElementsBitstream(const unsigned char* bitstream } } -// Note: this is an expensive call. Don't call it unless you really need to reaverage the entire tree (from startNode) -void Octree::reaverageOctreeElements(OctreeElement* startNode) { - if (!startNode) { - startNode = getRoot(); +// Note: this is an expensive call. Don't call it unless you really need to reaverage the entire tree (from startElement) +void Octree::reaverageOctreeElements(OctreeElement* startElement) { + if (!startElement) { + startElement = getRoot(); } // if our tree is a reaveraging tree, then we do this, otherwise we don't do anything if (_shouldReaverage) { static int recursionCount; - if (startNode == _rootNode) { + if (startElement == _rootElement) { recursionCount = 0; } else { recursionCount++; @@ -534,16 +534,16 @@ void Octree::reaverageOctreeElements(OctreeElement* startNode) { bool hasChildren = false; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (startNode->getChildAtIndex(i)) { - reaverageOctreeElements(startNode->getChildAtIndex(i)); + if (startElement->getChildAtIndex(i)) { + reaverageOctreeElements(startElement->getChildAtIndex(i)); hasChildren = true; } } // collapseIdenticalLeaves() returns true if it collapses the leaves // in which case we don't need to set the average color - if (hasChildren && !startNode->collapseChildren()) { - startNode->calculateAverageFromChildren(); + if (hasChildren && !startElement->collapseChildren()) { + startElement->calculateAverageFromChildren(); } recursionCount--; } @@ -551,7 +551,7 @@ void Octree::reaverageOctreeElements(OctreeElement* startNode) { OctreeElement* Octree::getOctreeElementAt(float x, float y, float z, float s) const { unsigned char* octalCode = pointToOctalCode(x,y,z,s); - OctreeElement* element = nodeForOctalCode(_rootNode, octalCode, NULL); + OctreeElement* element = nodeForOctalCode(_rootElement, octalCode, NULL); if (*element->getOctalCode() != *octalCode) { element = NULL; } @@ -566,7 +566,7 @@ OctreeElement* Octree::getOctreeElementAt(float x, float y, float z, float s) co OctreeElement* Octree::getOctreeEnclosingElementAt(float x, float y, float z, float s) const { unsigned char* octalCode = pointToOctalCode(x,y,z,s); - OctreeElement* element = nodeForOctalCode(_rootNode, octalCode, NULL); + OctreeElement* element = nodeForOctalCode(_rootElement, octalCode, NULL); delete[] octalCode; // cleanup memory #ifdef HAS_AUDIT_CHILDREN @@ -1160,7 +1160,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, int currentCount = 0; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - OctreeElement* childNode = element->getChildAtIndex(i); + OctreeElement* childElement = element->getChildAtIndex(i); // if the caller wants to include childExistsBits, then include them even if not in view, if however, // we're in a portion of the tree that's not our responsibility, then we assume the child nodes exist @@ -1171,61 +1171,61 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, } if (params.includeExistsBits) { // If the child is known to exist, OR, it's not my jurisdiction, then we mark the bit as existing - if (childNode || notMyJurisdiction) { + if (childElement || notMyJurisdiction) { childrenExistInTreeBits += (1 << (7 - i)); } } if (params.wantOcclusionCulling) { - if (childNode) { - float distance = params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0; + if (childElement) { + float distance = params.viewFrustum ? childElement->distanceToCamera(*params.viewFrustum) : 0; - currentCount = insertIntoSortedArrays((void*)childNode, distance, i, + currentCount = insertIntoSortedArrays((void*)childElement, distance, i, (void**)&sortedChildren, (float*)&distancesToChildren, (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); } } else { - sortedChildren[i] = childNode; + sortedChildren[i] = childElement; indexOfChildren[i] = i; distancesToChildren[i] = 0.0f; currentCount++; } // track stats - // must check childNode here, because it could be we got here with no childNode - if (params.stats && childNode) { - params.stats->traversed(childNode); + // must check childElement here, because it could be we got here with no childElement + if (params.stats && childElement) { + params.stats->traversed(childElement); } } // for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children for (int i = 0; i < currentCount; i++) { - OctreeElement* childNode = sortedChildren[i]; + OctreeElement* childElement = sortedChildren[i]; int originalIndex = indexOfChildren[i]; - bool childIsInView = (childNode && + bool childIsInView = (childElement && ( !params.viewFrustum || // no view frustum was given, everything is assumed in view (nodeLocationThisView == ViewFrustum::INSIDE) || // the parent was fully in view, we can assume ALL children are - (nodeLocationThisView == ViewFrustum::INTERSECT && childNode->isInView(*params.viewFrustum)) // the parent intersects and the child is in view + (nodeLocationThisView == ViewFrustum::INTERSECT && childElement->isInView(*params.viewFrustum)) // the parent intersects and the child is in view )); if (!childIsInView) { - // must check childNode here, because it could be we got here because there was no childNode - if (params.stats && childNode) { - params.stats->skippedOutOfView(childNode); + // must check childElement here, because it could be we got here because there was no childElement + if (params.stats && childElement) { + params.stats->skippedOutOfView(childElement); } } else { // Before we determine consider this further, let's see if it's in our LOD scope... - float distance = distancesToChildren[i]; // params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0; + float distance = distancesToChildren[i]; // params.viewFrustum ? childElement->distanceToCamera(*params.viewFrustum) : 0; float boundaryDistance = !params.viewFrustum ? 1 : - boundaryDistanceForRenderLevel(childNode->getLevel() + params.boundaryLevelAdjust, + boundaryDistanceForRenderLevel(childElement->getLevel() + params.boundaryLevelAdjust, params.octreeElementSizeScale); if (!(distance < boundaryDistance)) { - // don't need to check childNode here, because we can't get here with no childNode + // don't need to check childElement here, because we can't get here with no childElement if (params.stats) { - params.stats->skippedDistance(childNode); + params.stats->skippedDistance(childElement); } } else { inViewCount++; @@ -1233,7 +1233,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, // track children in view as existing and not a leaf, if they're a leaf, // we don't care about recursing deeper on them, and we don't consider their // subtree to exist - if (!(childNode && childNode->isLeaf())) { + if (!(childElement && childElement->isLeaf())) { childrenExistInPacketBits += (1 << (7 - originalIndex)); inViewNotLeafCount++; } @@ -1241,10 +1241,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, bool childIsOccluded = false; // assume it's not occluded // If the user also asked for occlusion culling, check if this element is occluded - if (params.wantOcclusionCulling && childNode->isLeaf()) { + if (params.wantOcclusionCulling && childElement->isLeaf()) { // Don't check occlusion here, just add them to our distance ordered array... - AABox voxelBox = childNode->getAABox(); + AABox voxelBox = childElement->getAABox(); voxelBox.scale(TREE_SCALE); OctreeProjectedPolygon* voxelPolygon = new OctreeProjectedPolygon( params.viewFrustum->getProjectedPolygon(voxelBox)); @@ -1273,18 +1273,18 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, bool shouldRender = !params.viewFrustum ? true - : childNode->calculateShouldRender(params.viewFrustum, + : childElement->calculateShouldRender(params.viewFrustum, params.octreeElementSizeScale, params.boundaryLevelAdjust); // track some stats if (params.stats) { - // don't need to check childNode here, because we can't get here with no childNode - if (!shouldRender && childNode->isLeaf()) { - params.stats->skippedDistance(childNode); + // don't need to check childElement here, because we can't get here with no childElement + if (!shouldRender && childElement->isLeaf()) { + params.stats->skippedDistance(childElement); } - // don't need to check childNode here, because we can't get here with no childNode + // don't need to check childElement here, because we can't get here with no childElement if (childIsOccluded) { - params.stats->skippedOccluded(childNode); + params.stats->skippedOccluded(childElement); } } @@ -1292,11 +1292,11 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, if (shouldRender && !childIsOccluded) { bool childWasInView = false; - if (childNode && params.deltaViewFrustum && params.lastViewFrustum) { - ViewFrustum::location location = childNode->inFrustum(*params.lastViewFrustum); + if (childElement && params.deltaViewFrustum && params.lastViewFrustum) { + ViewFrustum::location location = childElement->inFrustum(*params.lastViewFrustum); // If we're a leaf, then either intersect or inside is considered "formerly in view" - if (childNode->isLeaf()) { + if (childElement->isLeaf()) { childWasInView = location != ViewFrustum::OUTSIDE; } else { childWasInView = location == ViewFrustum::INSIDE; @@ -1308,18 +1308,18 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, // need to send it. if (!childWasInView || (params.deltaViewFrustum && - childNode->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))){ + childElement->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))){ childrenColoredBits += (1 << (7 - originalIndex)); inViewWithColorCount++; } else { // otherwise just track stats of the items we discarded - // don't need to check childNode here, because we can't get here with no childNode + // don't need to check childElement here, because we can't get here with no childElement if (params.stats) { if (childWasInView) { - params.stats->skippedWasInView(childNode); + params.stats->skippedWasInView(childElement); } else { - params.stats->skippedNoChange(childNode); + params.stats->skippedNoChange(childElement); } } } @@ -1342,10 +1342,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, if (continueThisLevel && params.includeColor) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (oneAtBit(childrenColoredBits, i)) { - OctreeElement* childNode = element->getChildAtIndex(i); - if (childNode) { + OctreeElement* childElement = element->getChildAtIndex(i); + if (childElement) { int bytesBeforeChild = packetData->getUncompressedSize(); - continueThisLevel = childNode->appendElementData(packetData); + continueThisLevel = childElement->appendElementData(packetData); int bytesAfterChild = packetData->getUncompressedSize(); if (!continueThisLevel) { @@ -1354,9 +1354,9 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child - // don't need to check childNode here, because we can't get here with no childNode + // don't need to check childElement here, because we can't get here with no childElement if (params.stats) { - params.stats->colorSent(childNode); + params.stats->colorSent(childElement); } } } @@ -1414,7 +1414,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, // for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children for (int indexByDistance = 0; indexByDistance < currentCount; indexByDistance++) { - OctreeElement* childNode = sortedChildren[indexByDistance]; + OctreeElement* childElement = sortedChildren[indexByDistance]; int originalIndex = indexOfChildren[indexByDistance]; if (oneAtBit(childrenExistInPacketBits, originalIndex)) { @@ -1435,7 +1435,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, // This only applies in the view frustum case, in other cases, like file save and copy/past where // no viewFrustum was requested, we still want to recurse the child tree. if (!params.viewFrustum || !oneAtBit(childrenColoredBits, originalIndex)) { - childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, packetData, bag, params, + childTreeBytesOut = encodeTreeBitstreamRecursion(childElement, packetData, bag, params, thisLevel, nodeLocationThisView); } @@ -1634,7 +1634,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* element) { if (element) { nodeBag.insert(element); } else { - nodeBag.insert(_rootNode); + nodeBag.insert(_rootElement); } static OctreePacketData packetData; @@ -1681,12 +1681,12 @@ bool Octree::countOctreeElementsOperation(OctreeElement* element, void* extraDat return true; // keep going } -void Octree::copySubTreeIntoNewTree(OctreeElement* startNode, Octree* destinationTree, bool rebaseToRoot) { +void Octree::copySubTreeIntoNewTree(OctreeElement* startElement, Octree* destinationTree, bool rebaseToRoot) { OctreeElementBag nodeBag; - nodeBag.insert(startNode); + nodeBag.insert(startElement); int chopLevels = 0; if (rebaseToRoot) { - chopLevels = numberOfThreeBitSectionsInCode(startNode->getOctalCode()); + chopLevels = numberOfThreeBitSectionsInCode(startElement->getOctalCode()); } static OctreePacketData packetData; @@ -1701,28 +1701,12 @@ void Octree::copySubTreeIntoNewTree(OctreeElement* startNode, Octree* destinatio ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS); destinationTree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); } - - // XXXBHG - what is this trying to do? - // This code appears to be trying to set the color of the destination root - // of a copy operation. But that shouldn't be necessary. I think this code might - // have been a hack that Mark added when he was trying to solve the copy of a single - // voxel bug. But this won't solve that problem, and doesn't appear to be needed for - // a normal copy operation. I'm leaving this in for a little bit until we see if anything - // about copy/paste is broken. - // - //OctreeElement* destinationStartNode; - //if (rebaseToRoot) { - // destinationStartNode = destinationTree->_rootNode; - //} else { - // destinationStartNode = nodeForOctalCode(destinationTree->_rootNode, startNode->getOctalCode(), NULL); - //} - //destinationStartNode->setColor(startNode->getColor()); } -void Octree::copyFromTreeIntoSubTree(Octree* sourceTree, OctreeElement* destinationNode) { +void Octree::copyFromTreeIntoSubTree(Octree* sourceTree, OctreeElement* destinationElement) { OctreeElementBag nodeBag; // If we were given a specific element, start from there, otherwise start from root - nodeBag.insert(sourceTree->_rootNode); + nodeBag.insert(sourceTree->_rootElement); static OctreePacketData packetData; @@ -1737,7 +1721,7 @@ void Octree::copyFromTreeIntoSubTree(Octree* sourceTree, OctreeElement* destinat // ask destination tree to read the bitstream bool wantImportProgress = true; - ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationNode, 0, SharedNodePointer(), wantImportProgress); + ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationElement, 0, SharedNodePointer(), wantImportProgress); readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); } } diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 4c430bfe3a..6e0693dc23 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -166,7 +166,7 @@ class ReadBitstreamToTreeParams { public: bool includeColor; bool includeExistsBits; - OctreeElement* destinationNode; + OctreeElement* destinationElement; QUuid sourceUUID; SharedNodePointer sourceNode; bool wantImportProgress; @@ -174,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) @@ -207,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); @@ -282,23 +282,23 @@ public: 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* element, 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* element, RecurseOctreeOperation operation, + void recurseElementWithPostOperation(OctreeElement* element, RecurseOctreeOperation operation, void* extraData, int recursionCount = 0); - void recurseNodeWithOperationDistanceSorted(OctreeElement* element, RecurseOctreeOperation operation, + void recurseElementWithOperationDistanceSorted(OctreeElement* element, RecurseOctreeOperation operation, const glm::vec3& point, void* extraData, int recursionCount = 0); - bool recurseNodeWithOperator(OctreeElement* element, RecurseOctreeOperator* operatorObject, int recursionCount = 0); + bool recurseElementWithOperator(OctreeElement* element, RecurseOctreeOperator* operatorObject, int recursionCount = 0); bool getIsViewing() const { return _isViewing; } void setIsViewing(bool isViewing) { _isViewing = isViewing; } @@ -321,12 +321,12 @@ protected: 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; diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp index 09e034ccd1..dd8cb6e618 100644 --- a/libraries/particles/src/ParticleTree.cpp +++ b/libraries/particles/src/ParticleTree.cpp @@ -12,7 +12,7 @@ #include "ParticleTree.h" ParticleTree::ParticleTree(bool shouldReaverage) : Octree(shouldReaverage) { - _rootNode = createNewElement(); + _rootElement = createNewElement(); } ParticleTreeElement* ParticleTree::createNewElement(unsigned char * octalCode) { diff --git a/libraries/particles/src/ParticleTree.h b/libraries/particles/src/ParticleTree.h index 76b9926bdf..0a2ac285b7 100644 --- a/libraries/particles/src/ParticleTree.h +++ b/libraries/particles/src/ParticleTree.h @@ -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(_rootElement); } // These methods will allow the OctreeServer to send your tree inbound edit packets of your diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index b1ddf2e5b0..6372d7fd6d 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -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(_rootElement))->getVoxelSystem(); } VoxelTreeElement* newElement = new VoxelTreeElement(octalCode); newElement->setVoxelSystem(voxelSystem); diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index eb24c182b2..2915774fe3 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -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(_rootElement); } void deleteVoxelAt(float x, float y, float z, float s); From c3f6cc0ccbb11ec070617f99f4ffbecacd5bdf39 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 6 May 2014 15:50:54 -0700 Subject: [PATCH 16/43] code cleanup for style guide --- libraries/octree/src/Octree.cpp | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 8228249777..d308d007cd 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -130,8 +130,6 @@ void Octree::recurseElementWithOperationDistanceSorted(OctreeElement* element, R if (childElement) { // chance to optimize, doesn't need to be actual distance!! Could be distance squared float distanceSquared = childElement->distanceSquareToPoint(point); - //qDebug("recurseElementWithOperationDistanceSorted() CHECKING child[%d] point=%f,%f center=%f,%f distance=%f...\n", i, point.x, point.y, center.x, center.y, distance); - //childElement->printDebugDetails(""); currentCount = insertIntoSortedArrays((void*)childElement, distanceSquared, i, (void**)&sortedChildren, (float*)&distancesToChildren, (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); @@ -141,8 +139,6 @@ void Octree::recurseElementWithOperationDistanceSorted(OctreeElement* element, R for (int i = 0; i < currentCount; i++) { OctreeElement* childElement = sortedChildren[i]; if (childElement) { - //qDebug("recurseElementWithOperationDistanceSorted() PROCESSING child[%d] distance=%f...\n", i, distancesToChildren[i]); - //childElement->printDebugDetails(""); recurseElementWithOperationDistanceSorted(childElement, operation, point, extraData); } } @@ -1167,7 +1163,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, // even if they don't in our local tree bool notMyJurisdiction = false; if (params.jurisdictionMap) { - notMyJurisdiction = (JurisdictionMap::WITHIN != params.jurisdictionMap->isMyJurisdiction(element->getOctalCode(), i)); + notMyJurisdiction = JurisdictionMap::WITHIN != params.jurisdictionMap->isMyJurisdiction(element->getOctalCode(), i); } if (params.includeExistsBits) { // If the child is known to exist, OR, it's not my jurisdiction, then we mark the bit as existing @@ -1206,8 +1202,9 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, bool childIsInView = (childElement && ( !params.viewFrustum || // no view frustum was given, everything is assumed in view - (nodeLocationThisView == ViewFrustum::INSIDE) || // the parent was fully in view, we can assume ALL children are - (nodeLocationThisView == ViewFrustum::INTERSECT && childElement->isInView(*params.viewFrustum)) // the parent intersects and the child is in view + (nodeLocationThisView == ViewFrustum::INSIDE) || // parent was fully in view, we can assume ALL children are + (nodeLocationThisView == ViewFrustum::INTERSECT && + childElement->isInView(*params.viewFrustum)) // the parent intersects and the child is in view )); if (!childIsInView) { @@ -1217,7 +1214,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, } } else { // Before we determine consider this further, let's see if it's in our LOD scope... - float distance = distancesToChildren[i]; // params.viewFrustum ? childElement->distanceToCamera(*params.viewFrustum) : 0; + float distance = distancesToChildren[i]; float boundaryDistance = !params.viewFrustum ? 1 : boundaryDistanceForRenderLevel(childElement->getLevel() + params.boundaryLevelAdjust, params.octreeElementSizeScale); @@ -1249,7 +1246,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, OctreeProjectedPolygon* voxelPolygon = new OctreeProjectedPolygon( params.viewFrustum->getProjectedPolygon(voxelBox)); - // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we will ignore occlusion + // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we ignore occlusion // culling and proceed as normal if (voxelPolygon->getAllInView()) { CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, true); @@ -1649,7 +1646,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* element) { bytesWritten = encodeTreeBitstream(subTree, &packetData, nodeBag, params); unlock(); - // if the subTree couldn't fit, and so we should reset the packet and reinsert the element in our bag and try again... + // if the subTree couldn't fit, and so we should reset the packet and reinsert the element in our bag and try again if (bytesWritten == 0 && (params.stopReason == EncodeBitstreamParams::DIDNT_FIT)) { if (packetData.hasContent()) { file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize()); @@ -1721,20 +1718,12 @@ void Octree::copyFromTreeIntoSubTree(Octree* sourceTree, OctreeElement* destinat // ask destination tree to read the bitstream bool wantImportProgress = true; - ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationElement, 0, SharedNodePointer(), wantImportProgress); + ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationElement, + 0, SharedNodePointer(), wantImportProgress); readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); } } -void dumpSetContents(const char* name, std::set set) { - qDebug("set %s has %ld elements", name, set.size()); - /* - for (std::set::iterator i = set.begin(); i != set.end(); ++i) { - printOctalCode(*i); - } - */ -} - void Octree::cancelImport() { _stopImport = true; } From 911b8cd62334a3cb607cafd0254070939fcf9fbd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 6 May 2014 16:17:40 -0700 Subject: [PATCH 17/43] Update welcome screen --- .../html/interface-welcome-allsvg.html | 759 ++++++++++++++---- 1 file changed, 624 insertions(+), 135 deletions(-) diff --git a/interface/resources/html/interface-welcome-allsvg.html b/interface/resources/html/interface-welcome-allsvg.html index 0b45a4d717..d025f8059b 100644 --- a/interface/resources/html/interface-welcome-allsvg.html +++ b/interface/resources/html/interface-welcome-allsvg.html @@ -1,139 +1,628 @@ -
+
- - Welcome to Interface - Created with Sketch (http://www.bohemiancoding.com/sketch) - - - - What you can do with Hifi so far: - - - Move around. - - - Listen and talk. - - - Build something. - - - Connect devices. - - - Look around. - - - Move around with WASD - & fly up or down with E & C - - - Use your best headphones - and microphone for high fidelity - audio. Look for the blue balls - around the universe – walk up - to them (they become people - as you get closer) and talk! - - - Refer to the Tools menu for - available tools. Each tool is a - ‘mode’ that enables actions through - clicking. Press the V key to enter - voxel ‘add mode’ where you’ll be - able to click to add a voxel. - - - Have an Oculus Rift or a - Leap Motion? Gyros in your - headset? An Xbox Kinect? - We have experimental - features for them all. - - - Use two fingers to look - around via the trackpad - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A - - - C - - - D - - - S - - - WE - - - - - - path d="M41.277,11.18 L46.981,19.663 L35.579,19.663 L41.277,11.18" id="Fill-12" fill="#FFFFFF" sketch:type="MSShapeGroup"> - - - - + +Welcome to Interface +Created with Sketch (http://www.bohemiancoding.com/sketch) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Use your best headphones and microphone for high fidelity audio. Chat via text by pressing the Enter key. + +Use two fingers to look around. Turn this off by opening Running Scripts (Cmnd/Cntrl+J) and clicking the X next to lookWithTouch.js + +Move around with WASD & fly up or down with E & C.Cmnd/Cntrl+G will send you home. @ (Shift+2) will let you teleport to a user or location. + +Have an Oculus Rift, a Razer Hydra, or a PrimeSense 3D camera? We support them all. + +Use the editVoxels.js script to build with your mouse – use the tab key to toggle the tools on/off. + + + + + + + + + + + + + + + + + + +Write a script; we’re always adding new features. Cmnd/Cntrl+J will launch a Running Scripts dialog to help manage your scripts. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A + C + D + S + + W + + + + + + + + + E + + + + + + + + + + + + +
From 9c9556914e466f01fccfc9f6f62d1e77ec19c1d1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 6 May 2014 17:03:19 -0700 Subject: [PATCH 18/43] Slow down hydra move --- examples/hydraMove.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/hydraMove.js b/examples/hydraMove.js index b73f990446..ad0eeddfca 100644 --- a/examples/hydraMove.js +++ b/examples/hydraMove.js @@ -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; From d0537e7ead264c855f0bf948a924d2d59c732298 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 6 May 2014 17:32:10 -0700 Subject: [PATCH 19/43] Specular map support. --- .../shaders/model_normal_specular_map.frag | 47 ++++++++ .../resources/shaders/model_specular_map.frag | 35 ++++++ interface/src/ModelUploader.cpp | 8 ++ interface/src/renderer/GeometryCache.cpp | 17 ++- interface/src/renderer/GeometryCache.h | 1 + interface/src/renderer/Model.cpp | 114 +++++++++++++++--- interface/src/renderer/Model.h | 9 +- libraries/fbx/src/FBXReader.cpp | 22 ++++ libraries/fbx/src/FBXReader.h | 3 + 9 files changed, 235 insertions(+), 21 deletions(-) create mode 100644 interface/resources/shaders/model_normal_specular_map.frag create mode 100644 interface/resources/shaders/model_specular_map.frag diff --git a/interface/resources/shaders/model_normal_specular_map.frag b/interface/resources/shaders/model_normal_specular_map.frag new file mode 100644 index 0000000000..79761446b1 --- /dev/null +++ b/interface/resources/shaders/model_normal_specular_map.frag @@ -0,0 +1,47 @@ +#version 120 + +// +// model_normal_specular_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/6/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// the diffuse texture +uniform sampler2D diffuseMap; + +// the normal map texture +uniform sampler2D normalMap; + +// the specular map texture +uniform sampler2D specularMap; + +// the interpolated normal +varying vec4 interpolatedNormal; + +// the interpolated tangent +varying vec4 interpolatedTangent; + +void main(void) { + vec3 normalizedNormal = normalize(vec3(interpolatedNormal)); + vec3 normalizedTangent = normalize(vec3(interpolatedTangent)); + vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); + vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) * 2.0 - vec3(1.0, 1.0, 1.0); + + // compute the base color based on OpenGL lighting model + vec4 viewNormal = vec4(normalizedTangent * localNormal.x + + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * max(0.0, dot(viewNormal, gl_LightSource[0].position))); + + // compute the specular component (sans exponent) + float specular = max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), viewNormal)); + + // modulate texture by base color and add specular contribution + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + vec4(pow(specular, gl_FrontMaterial.shininess) * + gl_FrontLightProduct[0].specular.rgb * texture2D(specularMap, gl_TexCoord[0].st).rgb, 0.0); +} diff --git a/interface/resources/shaders/model_specular_map.frag b/interface/resources/shaders/model_specular_map.frag new file mode 100644 index 0000000000..972a8e2de6 --- /dev/null +++ b/interface/resources/shaders/model_specular_map.frag @@ -0,0 +1,35 @@ +#version 120 + +// +// model_specular_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/6/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// the diffuse texture +uniform sampler2D diffuseMap; + +// the specular texture +uniform sampler2D specularMap; + +// the interpolated normal +varying vec4 normal; + +void main(void) { + // compute the base color based on OpenGL lighting model + vec4 normalizedNormal = normalize(normal); + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * max(0.0, dot(normalizedNormal, gl_LightSource[0].position))); + + // compute the specular component (sans exponent) + float specular = max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), normalizedNormal)); + + // modulate texture by base color and add specular contribution + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + vec4(pow(specular, gl_FrontMaterial.shininess) * + gl_FrontLightProduct[0].specular.rgb * texture2D(specularMap, gl_TexCoord[0].st).rgb, 0.0); +} diff --git a/interface/src/ModelUploader.cpp b/interface/src/ModelUploader.cpp index bf6a868368..08719f0f25 100644 --- a/interface/src/ModelUploader.cpp +++ b/interface/src/ModelUploader.cpp @@ -443,6 +443,14 @@ bool ModelUploader::addTextures(const QString& texdir, const FBXGeometry& geomet } added.insert(part.normalTexture.filename); } + if (!part.specularTexture.filename.isEmpty() && part.specularTexture.content.isEmpty() && + !added.contains(part.specularTexture.filename)) { + if (!addPart(texdir + "/" + part.specularTexture.filename, + QString("texture%1").arg(++_texturesCount), true)) { + return false; + } + added.insert(part.specularTexture.filename); + } } } diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index 6e93fc77af..8d31cdce1d 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -342,7 +342,8 @@ bool NetworkGeometry::isLoadedWithTextures() const { foreach (const NetworkMesh& mesh, _meshes) { foreach (const NetworkMeshPart& part, mesh.parts) { if ((part.diffuseTexture && !part.diffuseTexture->isLoaded()) || - (part.normalTexture && !part.normalTexture->isLoaded())) { + (part.normalTexture && !part.normalTexture->isLoaded()) || + (part.specularTexture && !part.specularTexture->isLoaded())) { return false; } } @@ -416,6 +417,9 @@ void NetworkGeometry::setLoadPriority(const QPointer& owner, float prio if (part.normalTexture) { part.normalTexture->setLoadPriority(owner, priority); } + if (part.specularTexture) { + part.specularTexture->setLoadPriority(owner, priority); + } } } } @@ -433,6 +437,9 @@ void NetworkGeometry::setLoadPriorities(const QHash, float>& p if (part.normalTexture) { part.normalTexture->setLoadPriorities(priorities); } + if (part.specularTexture) { + part.specularTexture->setLoadPriorities(priorities); + } } } } @@ -450,6 +457,9 @@ void NetworkGeometry::clearLoadPriority(const QPointer& owner) { if (part.normalTexture) { part.normalTexture->clearLoadPriority(owner); } + if (part.specularTexture) { + part.specularTexture->clearLoadPriority(owner); + } } } } @@ -566,6 +576,11 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) { _textureBase.resolved(QUrl(part.normalTexture.filename)), true, false, part.normalTexture.content); networkPart.normalTexture->setLoadPriorities(_loadPriorities); } + if (!part.specularTexture.filename.isEmpty()) { + networkPart.specularTexture = Application::getInstance()->getTextureCache()->getTexture( + _textureBase.resolved(QUrl(part.specularTexture.filename)), true, false, part.specularTexture.content); + networkPart.specularTexture->setLoadPriorities(_loadPriorities); + } networkMesh.parts.append(networkPart); totalIndices += (part.quadIndices.size() + part.triangleIndices.size()); diff --git a/interface/src/renderer/GeometryCache.h b/interface/src/renderer/GeometryCache.h index 0ad4f73904..a9b274fedc 100644 --- a/interface/src/renderer/GeometryCache.h +++ b/interface/src/renderer/GeometryCache.h @@ -124,6 +124,7 @@ public: QSharedPointer diffuseTexture; QSharedPointer normalTexture; + QSharedPointer specularTexture; bool isTranslucent() const; }; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index b8b4f1f2a0..2a9a55abf0 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -56,13 +56,20 @@ Model::~Model() { ProgramObject Model::_program; ProgramObject Model::_normalMapProgram; +ProgramObject Model::_specularMapProgram; +ProgramObject Model::_normalSpecularMapProgram; ProgramObject Model::_shadowProgram; ProgramObject Model::_skinProgram; ProgramObject Model::_skinNormalMapProgram; +ProgramObject Model::_skinSpecularMapProgram; +ProgramObject Model::_skinNormalSpecularMapProgram; ProgramObject Model::_skinShadowProgram; int Model::_normalMapTangentLocation; +int Model::_normalSpecularMapTangentLocation; Model::SkinLocations Model::_skinLocations; Model::SkinLocations Model::_skinNormalMapLocations; +Model::SkinLocations Model::_skinSpecularMapLocations; +Model::SkinLocations Model::_skinNormalSpecularMapLocations; Model::SkinLocations Model::_skinShadowLocations; void Model::setScale(const glm::vec3& scale) { @@ -92,7 +99,7 @@ void Model::setOffset(const glm::vec3& offset) { } -void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations) { +void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations, int specularTextureUnit) { program.bind(); locations.clusterMatrices = program.uniformLocation("clusterMatrices"); locations.clusterIndices = program.attributeLocation("clusterIndices"); @@ -100,6 +107,7 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati locations.tangent = program.attributeLocation("tangent"); program.setUniformValue("diffuseMap", 0); program.setUniformValue("normalMap", 1); + program.setUniformValue("specularMap", specularTextureUnit); program.release(); } @@ -162,10 +170,10 @@ void Model::init() { _program.setUniformValue("texture", 0); _program.release(); - _normalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() - + "shaders/model_normal_map.vert"); - _normalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() - + "shaders/model_normal_map.frag"); + _normalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/model_normal_map.vert"); + _normalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_normal_map.frag"); _normalMapProgram.link(); _normalMapProgram.bind(); @@ -174,27 +182,65 @@ void Model::init() { _normalMapTangentLocation = _normalMapProgram.attributeLocation("tangent"); _normalMapProgram.release(); + _specularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/model.vert"); + _specularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_specular_map.frag"); + _specularMapProgram.link(); + + _specularMapProgram.bind(); + _specularMapProgram.setUniformValue("diffuseMap", 0); + _specularMapProgram.setUniformValue("specularMap", 1); + _specularMapProgram.release(); + + _normalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/model_normal_map.vert"); + _normalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_normal_specular_map.frag"); + _normalSpecularMapProgram.link(); + + _normalSpecularMapProgram.bind(); + _normalSpecularMapProgram.setUniformValue("diffuseMap", 0); + _normalSpecularMapProgram.setUniformValue("normalMap", 1); + _normalSpecularMapProgram.setUniformValue("specularMap", 2); + _normalSpecularMapTangentLocation = _normalMapProgram.attributeLocation("tangent"); + _normalSpecularMapProgram.release(); + _shadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_shadow.vert"); - _shadowProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + - "shaders/model_shadow.frag"); + _shadowProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_shadow.frag"); _shadowProgram.link(); - _skinProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() - + "shaders/skin_model.vert"); - _skinProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() - + "shaders/model.frag"); + _skinProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); + _skinProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model.frag"); _skinProgram.link(); initSkinProgram(_skinProgram, _skinLocations); - _skinNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() - + "shaders/skin_model_normal_map.vert"); - _skinNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() - + "shaders/model_normal_map.frag"); + _skinNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); + _skinNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_normal_map.frag"); _skinNormalMapProgram.link(); initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations); + _skinSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/skin_model.vert"); + _skinSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_specular_map.frag"); + _skinSpecularMapProgram.link(); + + initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations); + + _skinNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); + _skinNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_normal_specular_map.frag"); + _skinNormalSpecularMapProgram.link(); + + initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations, 2); + _skinShadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_shadow.vert"); _skinShadowProgram.addShaderFromSourceFile(QGLShader::Fragment, @@ -1331,15 +1377,29 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { ProgramObject* program = &_program; ProgramObject* skinProgram = &_skinProgram; SkinLocations* skinLocations = &_skinLocations; + GLenum specularTextureUnit = 0; if (mode == SHADOW_RENDER_MODE) { program = &_shadowProgram; skinProgram = &_skinShadowProgram; skinLocations = &_skinShadowLocations; } else if (!mesh.tangents.isEmpty()) { - program = &_normalMapProgram; - skinProgram = &_skinNormalMapProgram; - skinLocations = &_skinNormalMapLocations; + if (mesh.hasSpecularTexture()) { + program = &_normalSpecularMapProgram; + skinProgram = &_skinNormalSpecularMapProgram; + skinLocations = &_skinNormalSpecularMapLocations; + specularTextureUnit = GL_TEXTURE2; + + } else { + program = &_normalMapProgram; + skinProgram = &_skinNormalMapProgram; + skinLocations = &_skinNormalMapLocations; + } + } else if (mesh.hasSpecularTexture()) { + program = &_specularMapProgram; + skinProgram = &_skinSpecularMapProgram; + skinLocations = &_skinSpecularMapLocations; + specularTextureUnit = GL_TEXTURE1; } const MeshState& state = _meshStates.at(i); @@ -1427,13 +1487,23 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { glBindTexture(GL_TEXTURE_2D, !diffuseMap ? Application::getInstance()->getTextureCache()->getWhiteTextureID() : diffuseMap->getID()); + if (!mesh.tangents.isEmpty()) { + specularTextureUnit = GL_TEXTURE2; glActiveTexture(GL_TEXTURE1); Texture* normalMap = networkPart.normalTexture.data(); glBindTexture(GL_TEXTURE_2D, !normalMap ? Application::getInstance()->getTextureCache()->getBlueTextureID() : normalMap->getID()); glActiveTexture(GL_TEXTURE0); } + + if (specularTextureUnit) { + glActiveTexture(specularTextureUnit); + Texture* specularMap = networkPart.specularTexture.data(); + glBindTexture(GL_TEXTURE_2D, !specularMap ? + Application::getInstance()->getTextureCache()->getWhiteTextureID() : specularMap->getID()); + glActiveTexture(GL_TEXTURE0); + } } glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, part.quadIndices.size(), GL_UNSIGNED_INT, (void*)offset); offset += part.quadIndices.size() * sizeof(int); @@ -1456,7 +1526,13 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { activeProgram->disableAttributeArray(tangentLocation); } - + + if (specularTextureUnit) { + glActiveTexture(specularTextureUnit); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + } + if (state.clusterMatrices.size() > 1) { skinProgram->disableAttributeArray(skinLocations->clusterIndices); skinProgram->disableAttributeArray(skinLocations->clusterWeights); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 6a79772ca7..1a469c8122 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -318,12 +318,17 @@ private: static ProgramObject _program; static ProgramObject _normalMapProgram; + static ProgramObject _specularMapProgram; + static ProgramObject _normalSpecularMapProgram; static ProgramObject _shadowProgram; static ProgramObject _skinProgram; static ProgramObject _skinNormalMapProgram; + static ProgramObject _skinSpecularMapProgram; + static ProgramObject _skinNormalSpecularMapProgram; static ProgramObject _skinShadowProgram; static int _normalMapTangentLocation; + static int _normalSpecularMapTangentLocation; class SkinLocations { public: @@ -335,9 +340,11 @@ private: static SkinLocations _skinLocations; static SkinLocations _skinNormalMapLocations; + static SkinLocations _skinSpecularMapLocations; + static SkinLocations _skinNormalSpecularMapLocations; static SkinLocations _skinShadowLocations; - static void initSkinProgram(ProgramObject& program, SkinLocations& locations); + static void initSkinProgram(ProgramObject& program, SkinLocations& locations, int specularTextureUnit = 1); }; Q_DECLARE_METATYPE(QPointer) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 40a7d56c0d..d637526067 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -54,6 +54,15 @@ void Extents::addPoint(const glm::vec3& point) { maximum = glm::max(maximum, point); } +bool FBXMesh::hasSpecularTexture() const { + foreach (const FBXMeshPart& part, parts) { + if (!part.specularTexture.filename.isEmpty()) { + return true; + } + } + return false; +} + QStringList FBXGeometry::getJointNames() const { QStringList names; foreach (const FBXJoint& joint, joints) { @@ -976,6 +985,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) QHash materials; QHash diffuseTextures; QHash bumpTextures; + QHash specularTextures; QHash localRotations; QHash xComponents; QHash yComponents; @@ -1330,6 +1340,9 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } else if (type.contains("bump") || type.contains("normal")) { bumpTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); + } else if (type.contains("specular")) { + specularTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); + } else if (type == "lcl rotation") { localRotations.insert(getID(connection.properties, 2), getID(connection.properties, 1)); @@ -1546,6 +1559,12 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) generateTangents = true; } + FBXTexture specularTexture; + QString specularTextureID = specularTextures.value(childID); + if (!specularTextureID.isNull()) { + specularTexture = getTexture(specularTextureID, textureFilenames, textureContent); + } + for (int j = 0; j < extracted.partMaterialTextures.size(); j++) { if (extracted.partMaterialTextures.at(j).first == materialIndex) { FBXMeshPart& part = extracted.mesh.parts[j]; @@ -1558,6 +1577,9 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) if (!normalTexture.filename.isNull()) { part.normalTexture = normalTexture; } + if (!specularTexture.filename.isNull()) { + part.specularTexture = specularTexture; + } } } materialIndex++; diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index a4b04825ef..51e7380181 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -129,6 +129,7 @@ public: FBXTexture diffuseTexture; FBXTexture normalTexture; + FBXTexture specularTexture; }; /// A single mesh (with optional blendshapes) extracted from an FBX document. @@ -150,6 +151,8 @@ public: bool isEye; QVector blendshapes; + + bool hasSpecularTexture() const; }; /// A single animation frame extracted from an FBX document. From fc962749c02278dfffa30ba4781e4f3c6a0b8a4d Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 6 May 2014 22:41:08 -0700 Subject: [PATCH 20/43] Arrow keys adjust distance from camera in mirror mode, air guitar script --- examples/airGuitar.js | 96 ++++++++++++++++++++++++++++++++ examples/placeModelsWithHands.js | 3 +- interface/src/Application.cpp | 15 ++++- interface/src/Application.h | 2 + 4 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 examples/airGuitar.js diff --git a/examples/airGuitar.js b/examples/airGuitar.js new file mode 100644 index 0000000000..09080d71fd --- /dev/null +++ b/examples/airGuitar.js @@ -0,0 +1,96 @@ +// +// airGuitar.js +// examples +// +// Copyright 2014 High Fidelity, Inc. +// +// This example musical instrument script plays guitar chords based on a strum motion and hand position +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +function length(v) { + return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); +} + + +function printVector(v) { + print(v.x + ", " + v.y + ", " + v.z + "\n"); + return; +} + +function vMinus(a, b) { + var rval = { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z }; + return rval; +} + +// First, load two percussion sounds to be used on the sticks + +var chord1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+A.raw"); +var chord2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+B.raw"); +var chord3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+E.raw"); + +var whichChord = chord1; + +var leftHanded = false; +if (leftHanded) { + var strumHand = 0; + var chordHand = 1; +} else { + var strumHand = 1; + var chordHand = 0; +} + +// State Machine: +// 0 = not triggered +// 1 = triggered, waiting to stop to play sound +var state = new Array(); +state[0] = 0; +state[1] = 0; +var strokeSpeed = new Array(); +strokeSpeed[0] = 0.0; +strokeSpeed[1] = 0.0; +var lastPosition = { x: 0.0, + y: 0.0, + z: 0.0 }; + + +function checkHands(deltaTime) { + for (var palm = 0; palm < 2; palm++) { + var palmVelocity = Controller.getSpatialControlVelocity(palm * 2 + 1); + var speed = length(palmVelocity); + var position = Controller.getSpatialControlPosition(palm * 2 + 1); + var myPelvis = MyAvatar.position; + + if (palm == strumHand) { + + var STRUM_HEIGHT_ABOVE_PELVIS = 0.15; + var strumTriggerHeight = myPelvis.y + STRUM_HEIGHT_ABOVE_PELVIS; + //printVector(position); + if ((position.y < strumTriggerHeight) && (lastPosition.y >= strumTriggerHeight)) { + // If hand passes downward through guitar strings, play a chord! + var options = new AudioInjectionOptions(); + options.position = position; + if (speed > 1.0) { speed = 1.0; } + options.volume = speed; + Audio.playSound(whichChord, options); + } + lastPosition = Controller.getSpatialControlPosition(palm * 2 + 1); + } else { + // This is the chord controller + var distanceFromPelvis = Vec3.length(Vec3.subtract(position, myPelvis)); + //print(distanceFromPelvis); + if (distanceFromPelvis > 0.50) { + whichChord = chord3; + } else if (distanceFromPelvis > 0.35) { + whichChord = chord2; + } else { + whichChord = chord1; + } + } + } +} + +// Connect a call back that happens every frame +Script.update.connect(checkHands); \ No newline at end of file diff --git a/examples/placeModelsWithHands.js b/examples/placeModelsWithHands.js index 41d9d5dc86..e1ac151fe4 100644 --- a/examples/placeModelsWithHands.js +++ b/examples/placeModelsWithHands.js @@ -37,7 +37,7 @@ var radiusMinimum = 0.05; var radiusMaximum = 0.5; var modelURLs = [ - "https://s3-us-west-1.amazonaws.com/highfidelity-public/models/music/EVHFrankenstein.fbx", + "https://s3-us-west-1.amazonaws.com/highfidelity-public/models/attachments/topHat.fst", "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/Feisar_Ship.FBX", "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/birarda/birarda_head.fbx", "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/pug.fbx", @@ -72,7 +72,6 @@ function keyPressEvent(event) { } } else if (event.text == "m") { var URL = Window.prompt("Model URL", "Enter URL, e.g. http://foo.com/model.fbx"); - Window.alert("Your response was: " + prompt); var modelPosition = getNewVoxelPosition(); var properties = { position: { x: modelPosition.x, y: modelPosition.y, diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b50e9ef1dc..10f113ad11 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -151,6 +151,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _lastQueriedTime(usecTimestampNow()), _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)), _cameraPushback(0.0f), + _scaleMirror(1.0f), _mouseX(0), _mouseY(0), _lastMouseMove(usecTimestampNow()), @@ -570,7 +571,7 @@ void Application::paintGL() { _myCamera.setTightness(0.0f); glm::vec3 eyePosition = _myAvatar->getHead()->calculateAverageEyePosition(); float headHeight = eyePosition.y - _myAvatar->getPosition().y; - _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _myAvatar->getScale()); + _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _myAvatar->getScale() * _scaleMirror); _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight, 0)); _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f))); @@ -868,11 +869,19 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_Up: - _myAvatar->setDriveKeys(isShifted ? UP : FWD, 1.f); + if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + _scaleMirror *= 0.95; + } else { + _myAvatar->setDriveKeys(isShifted ? UP : FWD, 1.f); + } break; case Qt::Key_Down: - _myAvatar->setDriveKeys(isShifted ? DOWN : BACK, 1.f); + if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + _scaleMirror *= 1.05; + } else { + _myAvatar->setDriveKeys(isShifted ? DOWN : BACK, 1.f); + } break; case Qt::Key_Left: diff --git a/interface/src/Application.h b/interface/src/Application.h index a7073ac4e9..1d38a11357 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -455,6 +455,8 @@ private: glm::mat4 _untranslatedViewMatrix; glm::vec3 _viewMatrixTranslation; glm::mat4 _projectionMatrix; + + float _scaleMirror; glm::mat4 _shadowMatrix; From f6aaaad211232f16da7f97cb9e4e95604b9bc9cb Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 6 May 2014 22:44:36 -0700 Subject: [PATCH 21/43] removed some unneeded stuff --- examples/airGuitar.js | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/examples/airGuitar.js b/examples/airGuitar.js index 09080d71fd..a54ef82e7e 100644 --- a/examples/airGuitar.js +++ b/examples/airGuitar.js @@ -16,7 +16,7 @@ function length(v) { function printVector(v) { - print(v.x + ", " + v.y + ", " + v.z + "\n"); + print(v.x + ", " + v.y + ", " + v.z); return; } @@ -42,15 +42,6 @@ if (leftHanded) { var chordHand = 0; } -// State Machine: -// 0 = not triggered -// 1 = triggered, waiting to stop to play sound -var state = new Array(); -state[0] = 0; -state[1] = 0; -var strokeSpeed = new Array(); -strokeSpeed[0] = 0.0; -strokeSpeed[1] = 0.0; var lastPosition = { x: 0.0, y: 0.0, z: 0.0 }; From 37ca6efc7c30c68938992dbe0d115ed945cdb699 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 7 May 2014 11:48:32 -0700 Subject: [PATCH 22/43] correctly handle SHADOW_RENDER_MODE in a bunch of places that were drawing shadows when they shouldn't --- interface/src/Application.cpp | 4 +-- interface/src/Menu.cpp | 5 +++- interface/src/Menu.h | 2 ++ interface/src/avatar/Avatar.cpp | 16 +++++++----- interface/src/avatar/Hand.cpp | 8 +++--- interface/src/avatar/Hand.h | 3 ++- interface/src/avatar/Head.cpp | 2 +- interface/src/avatar/MyAvatar.cpp | 6 +++-- interface/src/models/ModelTreeRenderer.cpp | 11 ++++---- interface/src/models/ModelTreeRenderer.h | 2 +- .../src/particles/ParticleTreeRenderer.cpp | 10 +++++--- .../src/particles/ParticleTreeRenderer.h | 2 +- libraries/octree/src/OctreeHeadlessViewer.h | 2 +- libraries/octree/src/OctreeRenderer.cpp | 4 +-- libraries/octree/src/OctreeRenderer.h | 25 +++++++++++-------- 15 files changed, 62 insertions(+), 40 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b50e9ef1dc..b4853f54d5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2348,8 +2348,8 @@ void Application::updateShadowMap() { updateUntranslatedViewMatrix(); _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); - _particles.render(); - _models.render(); + _particles.render(OctreeRenderer::SHADOW_RENDER_MODE); + _models.render(OctreeRenderer::SHADOW_RENDER_MODE); glPopMatrix(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 13b72bcdb3..2a00e414df 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -291,7 +291,6 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::BuckyBalls, 0, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Particles, 0, true); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Models, 0, true); addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools())); QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxel Options"); @@ -308,6 +307,10 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontFadeOnVoxelServerChanges); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DisableAutoAdjustLOD); + QMenu* modelOptionsMenu = developerMenu->addMenu("Model Options"); + addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::Models, 0, true); + addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelProxies, 0, false); + QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options"); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 723d320905..d2d9ce7c7d 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -303,6 +303,7 @@ namespace MenuOption { const QString DisplayFrustum = "Display Frustum"; const QString DisplayHands = "Display Hands"; const QString DisplayHandTargets = "Display Hand Targets"; + const QString DisplayModelProxies = "Display Model Proxies"; const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; const QString EchoLocalAudio = "Echo Local Audio"; const QString EchoServerAudio = "Echo Server Audio"; @@ -337,6 +338,7 @@ namespace MenuOption { const QString Metavoxels = "Metavoxels"; const QString Mirror = "Mirror"; const QString Models = "Models"; + const QString ModelOptions = "Model Options"; const QString MoveWithLean = "Move with Lean"; const QString MuteAudio = "Mute Microphone"; const QString NameLocation = "Name this location"; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index f7bf4595d6..2e8deb4b0a 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -215,17 +215,20 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) { renderBody(renderMode, glowLevel); } - if (Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) { + if (renderMode != SHADOW_RENDER_MODE && + Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) { _skeletonModel.updateShapePositions(); _skeletonModel.renderJointCollisionShapes(0.7f); } - if (Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes)) { + if (renderMode != SHADOW_RENDER_MODE && + Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes)) { if (shouldRenderHead(cameraPosition, renderMode)) { getHead()->getFaceModel().updateShapePositions(); getHead()->getFaceModel().renderJointCollisionShapes(0.7f); } } - if (Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes)) { + if (renderMode != SHADOW_RENDER_MODE && + Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes)) { if (shouldRenderHead(cameraPosition, renderMode)) { getHead()->getFaceModel().updateShapePositions(); getHead()->getFaceModel().renderBoundingCollisionShapes(0.7f); @@ -234,7 +237,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { } } // If this is the avatar being looked at, render a little ball above their head - if (_isLookAtTarget) { + if (renderMode != SHADOW_RENDER_MODE &&_isLookAtTarget) { const float LOOK_AT_INDICATOR_RADIUS = 0.03f; const float LOOK_AT_INDICATOR_HEIGHT = 0.60f; const float LOOK_AT_INDICATOR_COLOR[] = { 0.8f, 0.0f, 0.0f, 0.5f }; @@ -340,7 +343,8 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { void Avatar::renderBody(RenderMode renderMode, float glowLevel) { Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? - Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + { Glower glower(glowLevel); @@ -351,7 +355,7 @@ void Avatar::renderBody(RenderMode renderMode, float glowLevel) { } _skeletonModel.render(1.0f, modelRenderMode); renderAttachments(modelRenderMode); - getHand()->render(false); + getHand()->render(false, modelRenderMode); } getHead()->render(1.0f, modelRenderMode); } diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index c925e452b2..320a8477c1 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -192,11 +192,11 @@ void Hand::calculateGeometry() { } } -void Hand::render(bool isMine) { - +void Hand::render(bool isMine, Model::RenderMode renderMode) { _renderAlpha = 1.0; - if (Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) { + if (renderMode != Model::SHADOW_RENDER_MODE && + Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) { // draw a green sphere at hand joint location, which is actually near the wrist) for (size_t i = 0; i < getNumPalms(); i++) { PalmData& palm = getPalms()[i]; @@ -212,7 +212,7 @@ void Hand::render(bool isMine) { } } - if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) { + if (renderMode != Model::SHADOW_RENDER_MODE && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) { renderLeapHands(isMine); } diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 65a7dcb74a..ff21e9f5b2 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -24,6 +24,7 @@ #include #include "InterfaceConfig.h" +#include "renderer/model.h" #include "world.h" @@ -52,7 +53,7 @@ public: void init(); void reset(); void simulate(float deltaTime, bool isMine); - void render(bool isMine); + void render(bool isMine, Model::RenderMode renderMode = Model::DEFAULT_RENDER_MODE); // getters const glm::vec3& getLeapFingerTipBallPosition (int ball) const { return _leapFingerTipBalls [ball].position;} diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 19aebba25c..9cb8ea3d9c 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -182,7 +182,7 @@ void Head::relaxLean(float deltaTime) { } void Head::render(float alpha, Model::RenderMode mode) { - if (_faceModel.render(alpha, mode) && _renderLookatVectors) { + if (_faceModel.render(alpha, mode) && _renderLookatVectors && mode != Model::SHADOW_RENDER_MODE) { renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition); } } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e8782fa140..36e2d64667 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -333,7 +333,9 @@ void MyAvatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { return; // exit early } Avatar::render(cameraPosition, renderMode); - if (Menu::getInstance()->isOptionChecked(MenuOption::ShowIKConstraints)) { + + // don't display IK constraints in shadow mode + if (Menu::getInstance()->isOptionChecked(MenuOption::ShowIKConstraints) && renderMode != SHADOW_RENDER_MODE) { _skeletonModel.renderIKConstraints(); } } @@ -582,7 +584,7 @@ void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) { if (shouldRenderHead(Application::getInstance()->getCamera()->getPosition(), renderMode)) { getHead()->render(1.0f, modelRenderMode); } - getHand()->render(true); + getHand()->render(true, modelRenderMode); } const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; diff --git a/interface/src/models/ModelTreeRenderer.cpp b/interface/src/models/ModelTreeRenderer.cpp index 9546c7d1c4..3ade46fc4a 100644 --- a/interface/src/models/ModelTreeRenderer.cpp +++ b/interface/src/models/ModelTreeRenderer.cpp @@ -39,8 +39,8 @@ void ModelTreeRenderer::update() { } } -void ModelTreeRenderer::render() { - OctreeRenderer::render(); +void ModelTreeRenderer::render(RenderMode renderMode) { + OctreeRenderer::render(renderMode); } Model* ModelTreeRenderer::getModel(const QString& url) { @@ -94,11 +94,12 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) // set the position model->setTranslation(position); - model->simulate(0.0f); - - model->render(alpha); // TODO: should we allow modelItems to have alpha on their models? + // TODO: should we allow modelItems to have alpha on their models? + Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE + ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + model->render(alpha, modelRenderMode); const bool wantDebugSphere = false; if (wantDebugSphere) { diff --git a/interface/src/models/ModelTreeRenderer.h b/interface/src/models/ModelTreeRenderer.h index 5ed4720391..7af5bbf317 100644 --- a/interface/src/models/ModelTreeRenderer.h +++ b/interface/src/models/ModelTreeRenderer.h @@ -46,7 +46,7 @@ public: void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode); virtual void init(); - virtual void render(); + virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE); protected: Model* getModel(const QString& url); diff --git a/interface/src/particles/ParticleTreeRenderer.cpp b/interface/src/particles/ParticleTreeRenderer.cpp index aa498082d9..2983093564 100644 --- a/interface/src/particles/ParticleTreeRenderer.cpp +++ b/interface/src/particles/ParticleTreeRenderer.cpp @@ -39,8 +39,8 @@ void ParticleTreeRenderer::update() { } } -void ParticleTreeRenderer::render() { - OctreeRenderer::render(); +void ParticleTreeRenderer::render(RenderMode renderMode) { + OctreeRenderer::render(renderMode); } Model* ParticleTreeRenderer::getModel(const QString& url) { @@ -102,7 +102,11 @@ void ParticleTreeRenderer::renderElement(OctreeElement* element, RenderArgs* arg model->setScale(scale * MODEL_SCALE * radius * modelScale); model->simulate(0.0f); - model->render(alpha); // TODO: should we allow particles to have alpha on their models? + + // TODO: should we allow particles to have alpha on their models? + Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE + ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + model->render(alpha, modelRenderMode); const bool wantDebugSphere = false; if (wantDebugSphere) { diff --git a/interface/src/particles/ParticleTreeRenderer.h b/interface/src/particles/ParticleTreeRenderer.h index ea52df3932..ccb8bfbdf3 100644 --- a/interface/src/particles/ParticleTreeRenderer.h +++ b/interface/src/particles/ParticleTreeRenderer.h @@ -43,7 +43,7 @@ public: void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode); virtual void init(); - virtual void render(); + virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE); protected: Model* getModel(const QString& url); diff --git a/libraries/octree/src/OctreeHeadlessViewer.h b/libraries/octree/src/OctreeHeadlessViewer.h index ebabf1dbad..3509713d50 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.h +++ b/libraries/octree/src/OctreeHeadlessViewer.h @@ -33,7 +33,7 @@ public: virtual void renderElement(OctreeElement* element, RenderArgs* args) { /* swallow these */ }; virtual void init(); - virtual void render() { /* swallow these */ }; + virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE) { /* swallow these */ }; void setJurisdictionListener(JurisdictionListener* jurisdictionListener) { _jurisdictionListener = jurisdictionListener; } diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index 5c5da2250f..c1ce3cb218 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -154,8 +154,8 @@ bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) { return false; } -void OctreeRenderer::render() { - RenderArgs args = { 0, this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust() }; +void OctreeRenderer::render(RenderMode renderMode) { + RenderArgs args = { 0, this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode }; if (_tree) { _tree->lockForRead(); _tree->recurseTreeWithOperation(renderOperation, &args); diff --git a/libraries/octree/src/OctreeRenderer.h b/libraries/octree/src/OctreeRenderer.h index 652f9d0399..73e26c97f6 100644 --- a/libraries/octree/src/OctreeRenderer.h +++ b/libraries/octree/src/OctreeRenderer.h @@ -25,15 +25,7 @@ #include "ViewFrustum.h" class OctreeRenderer; - -class RenderArgs { -public: - int _renderedItems; - OctreeRenderer* _renderer; - ViewFrustum* _viewFrustum; - float _sizeScale; - int _boundaryLevelAdjust; -}; +class RenderArgs; // Generic client side Octree renderer class. @@ -59,8 +51,10 @@ public: /// initialize and GPU/rendering related resources virtual void init(); + enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE }; + /// render the content of the octree - virtual void render(); + virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE); ViewFrustum* getViewFrustum() const { return _viewFrustum; } void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; } @@ -75,4 +69,15 @@ protected: ViewFrustum* _viewFrustum; }; +class RenderArgs { +public: + int _renderedItems; + OctreeRenderer* _renderer; + ViewFrustum* _viewFrustum; + float _sizeScale; + int _boundaryLevelAdjust; + OctreeRenderer::RenderMode _renderMode; +}; + + #endif // hifi_OctreeRenderer_h From 55b677dd02b40150869d782d8387b57d807ed295 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 7 May 2014 12:53:38 -0700 Subject: [PATCH 23/43] Provide options for model translation: by default, pivot about mesh bounds' center; allow numeric translation or pivot about joint position. --- interface/src/ModelUploader.cpp | 52 +++++++++++++++++++++++++++++++-- interface/src/ModelUploader.h | 7 +++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/interface/src/ModelUploader.cpp b/interface/src/ModelUploader.cpp index 08719f0f25..ce8691998d 100644 --- a/interface/src/ModelUploader.cpp +++ b/interface/src/ModelUploader.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include #include @@ -42,6 +43,9 @@ static const QString TEXDIR_FIELD = "texdir"; static const QString LOD_FIELD = "lod"; static const QString JOINT_INDEX_FIELD = "jointIndex"; static const QString SCALE_FIELD = "scale"; +static const QString TRANSLATION_X_FIELD = "tx"; +static const QString TRANSLATION_Y_FIELD = "ty"; +static const QString TRANSLATION_Z_FIELD = "tz"; static const QString JOINT_FIELD = "joint"; static const QString FREE_JOINT_FIELD = "freeJoint"; @@ -519,6 +523,14 @@ bool ModelUploader::addPart(const QFile& file, const QByteArray& contents, const return true; } +static QDoubleSpinBox* createTranslationBox() { + QDoubleSpinBox* box = new QDoubleSpinBox(); + const double MAX_TRANSLATION = 1000000.0; + box->setMinimum(-MAX_TRANSLATION); + box->setMaximum(MAX_TRANSLATION); + return box; +} + ModelPropertiesDialog::ModelPropertiesDialog(ModelType modelType, const QVariantHash& originalMapping, const QString& basePath, const FBXGeometry& geometry) : _modelType(modelType), @@ -540,7 +552,18 @@ ModelPropertiesDialog::ModelPropertiesDialog(ModelType modelType, const QVariant _scale->setMaximum(FLT_MAX); _scale->setSingleStep(0.01); - if (_modelType != ATTACHMENT_MODEL) { + if (_modelType == ATTACHMENT_MODEL) { + QHBoxLayout* translation = new QHBoxLayout(); + form->addRow("Translation:", translation); + translation->addWidget(_translationX = createTranslationBox()); + translation->addWidget(_translationY = createTranslationBox()); + translation->addWidget(_translationZ = createTranslationBox()); + form->addRow("Pivot About Center:", _pivotAboutCenter = new QCheckBox()); + form->addRow("Pivot Joint:", _pivotJoint = createJointBox()); + connect(_pivotAboutCenter, SIGNAL(toggled(bool)), SLOT(updatePivotJoint())); + _pivotAboutCenter->setChecked(true); + + } else { form->addRow("Left Eye Joint:", _leftEyeJoint = createJointBox()); form->addRow("Right Eye Joint:", _rightEyeJoint = createJointBox()); form->addRow("Neck Joint:", _neckJoint = createJointBox()); @@ -584,7 +607,19 @@ QVariantHash ModelPropertiesDialog::getMapping() const { mapping.insert(JOINT_INDEX_FIELD, jointIndices); QVariantHash joints = mapping.value(JOINT_FIELD).toHash(); - if (_modelType != ATTACHMENT_MODEL) { + if (_modelType == ATTACHMENT_MODEL) { + glm::vec3 pivot; + if (_pivotAboutCenter->isChecked()) { + pivot = (_geometry.meshExtents.minimum + _geometry.meshExtents.maximum) * 0.5f; + + } else if (_pivotJoint->currentIndex() != 0) { + pivot = extractTranslation(_geometry.joints.at(_pivotJoint->currentIndex() - 1).transform); + } + mapping.insert(TRANSLATION_X_FIELD, -pivot.x * _scale->value() + _translationX->value()); + mapping.insert(TRANSLATION_Y_FIELD, -pivot.y * _scale->value() + _translationY->value()); + mapping.insert(TRANSLATION_Z_FIELD, -pivot.z * _scale->value() + _translationZ->value()); + + } else { insertJointMapping(joints, "jointEyeLeft", _leftEyeJoint->currentText()); insertJointMapping(joints, "jointEyeRight", _rightEyeJoint->currentText()); insertJointMapping(joints, "jointNeck", _neckJoint->currentText()); @@ -617,7 +652,14 @@ void ModelPropertiesDialog::reset() { _scale->setValue(_originalMapping.value(SCALE_FIELD).toDouble()); QVariantHash jointHash = _originalMapping.value(JOINT_FIELD).toHash(); - if (_modelType != ATTACHMENT_MODEL) { + if (_modelType == ATTACHMENT_MODEL) { + _translationX->setValue(_originalMapping.value(TRANSLATION_X_FIELD).toDouble()); + _translationY->setValue(_originalMapping.value(TRANSLATION_Y_FIELD).toDouble()); + _translationZ->setValue(_originalMapping.value(TRANSLATION_Z_FIELD).toDouble()); + _pivotAboutCenter->setChecked(true); + _pivotJoint->setCurrentIndex(0); + + } else { setJointText(_leftEyeJoint, jointHash.value("jointEyeLeft").toString()); setJointText(_rightEyeJoint, jointHash.value("jointEyeRight").toString()); setJointText(_neckJoint, jointHash.value("jointNeck").toString()); @@ -654,6 +696,10 @@ void ModelPropertiesDialog::chooseTextureDirectory() { _textureDirectory->setText(directory.length() == _basePath.length() ? "." : directory.mid(_basePath.length() + 1)); } +void ModelPropertiesDialog::updatePivotJoint() { + _pivotJoint->setEnabled(!_pivotAboutCenter->isChecked()); +} + void ModelPropertiesDialog::createNewFreeJoint(const QString& joint) { QWidget* freeJoint = new QWidget(); QHBoxLayout* freeJointLayout = new QHBoxLayout(); diff --git a/interface/src/ModelUploader.h b/interface/src/ModelUploader.h index 499bfad03b..766bd55318 100644 --- a/interface/src/ModelUploader.h +++ b/interface/src/ModelUploader.h @@ -19,6 +19,7 @@ #include "ui/ModelsBrowser.h" +class QCheckBox; class QComboBox; class QDoubleSpinBox; class QFileInfo; @@ -83,6 +84,7 @@ public: private slots: void reset(); void chooseTextureDirectory(); + void updatePivotJoint(); void createNewFreeJoint(const QString& joint = QString()); private: @@ -96,6 +98,11 @@ private: QLineEdit* _name; QPushButton* _textureDirectory; QDoubleSpinBox* _scale; + QDoubleSpinBox* _translationX; + QDoubleSpinBox* _translationY; + QDoubleSpinBox* _translationZ; + QCheckBox* _pivotAboutCenter; + QComboBox* _pivotJoint; QComboBox* _leftEyeJoint; QComboBox* _rightEyeJoint; QComboBox* _neckJoint; From 40ed72989cecb380863ece849c28286e63aabea4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 7 May 2014 12:57:11 -0700 Subject: [PATCH 24/43] mute environment packet --- assignment-client/src/audio/AudioMixer.cpp | 10 ++++++++ interface/src/DatagramProcessor.cpp | 14 +++++++++++ interface/src/Menu.cpp | 28 ++++++++++++++++++++++ interface/src/Menu.h | 2 ++ libraries/networking/src/PacketHeaders.h | 2 +- 5 files changed, 55 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 63b2083aae..9007c55abb 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -348,6 +348,16 @@ void AudioMixer::readPendingDatagrams() { || mixerPacketType == PacketTypeSilentAudioFrame) { nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket); + } else if (mixerPacketType == PacketTypeMuteEnvironnement) { + QByteArray packet = receivedPacket; + populatePacketHeader(packet, PacketTypeMuteEnvironnement); + + foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { + if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != nodeList->sendingNodeForPacket(receivedPacket)) { + nodeList->writeDatagram(packet, packet.size(), node); + } + } + } else { // let processNodeData handle it. nodeList->processNodeData(senderSockAddr, receivedPacket); diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index 287744eba2..5251b5d8ee 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -131,6 +131,20 @@ void DatagramProcessor::processDatagrams() { break; } + case PacketTypeMuteEnvironnement: { + glm::vec3 position; + float radius; + + int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironnement); + memcpy(&position, incomingPacket.constData() + headerSize, sizeof(glm::vec3)); + memcpy(&radius, incomingPacket.constData() + headerSize + sizeof(glm::vec3), sizeof(float)); + + if (glm::distance(Application::getInstance()->getAvatar()->getPosition(), position) < radius + && !Application::getInstance()->getAudio()->getMuted()) { + Application::getInstance()->getAudio()->toggleMute(); + } + break; + } default: nodeList->processNodeData(senderSockAddr, incomingPacket); break; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 13b72bcdb3..ec9c47ecbf 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -68,6 +68,7 @@ const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f; const int ONE_SECOND_OF_FRAMES = 60; const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; +const float MUTE_RADIUS = 10; Menu::Menu() : _actionHash(), @@ -397,6 +398,11 @@ Menu::Menu() : false, appInstance->getAudio(), SLOT(toggleMute())); + addActionToQMenuAndActionHash(audioDebugMenu, + MenuOption::MuteEnvironment, + 0, + this, + SLOT(muteEnvironment())); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioToneInjection, 0, false, @@ -1000,6 +1006,28 @@ void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJson disconnect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision); } +void Menu::muteEnvironment() { + int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironnement); + int packetSize = headerSize + sizeof(glm::vec3) + sizeof(float); + + glm::vec3 position = Application::getInstance()->getAvatar()->getPosition(); + + char packet[packetSize]; + populatePacketHeader(packet, PacketTypeMuteEnvironnement); + memcpy(packet + headerSize, &position, sizeof(glm::vec3)); + memcpy(packet + headerSize + sizeof(glm::vec3), &MUTE_RADIUS, sizeof(float)); + + QByteArray mutePacket(packet, packetSize); + + // grab our audio mixer from the NodeList, if it exists + SharedNodePointer audioMixer = NodeList::getInstance()->soloNodeOfType(NodeType::AudioMixer); + + if (audioMixer) { + // send off this mute packet + NodeList::getInstance()->writeDatagram(mutePacket, audioMixer); + } +} + void Menu::goToLocation() { MyAvatar* myAvatar = Application::getInstance()->getAvatar(); glm::vec3 avatarPos = myAvatar->getPosition(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 723d320905..d1097929f7 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -191,6 +191,7 @@ private slots: void audioMuteToggled(); void namedLocationCreated(LocationManager::NamedLocationCreateResponse response); void multipleDestinationsDecision(const QJsonObject& userData, const QJsonObject& placeData); + void muteEnvironment(); private: static Menu* _instance; @@ -339,6 +340,7 @@ namespace MenuOption { const QString Models = "Models"; const QString MoveWithLean = "Move with Lean"; const QString MuteAudio = "Mute Microphone"; + const QString MuteEnvironment = "Mute Environment"; const QString NameLocation = "Name this location"; const QString NewVoxelCullingMode = "New Voxel Culling Mode"; const QString OctreeStats = "Voxel and Particle Statistics"; diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 844fce77fe..ac8a187034 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -39,7 +39,7 @@ enum PacketType { PacketTypeRequestAssignment, PacketTypeCreateAssignment, PacketTypeDomainOAuthRequest, - PacketTypeDataServerGet, // reusable + PacketTypeMuteEnvironnement, PacketTypeDataServerSend, // reusable PacketTypeDataServerConfirm, PacketTypeVoxelQuery, From 6308c39aab3112848e83b52d09466f51d5140441 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 7 May 2014 14:03:30 -0700 Subject: [PATCH 25/43] Fix for windows --- interface/src/Menu.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index ec9c47ecbf..b98bd985e2 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1012,7 +1012,7 @@ void Menu::muteEnvironment() { glm::vec3 position = Application::getInstance()->getAvatar()->getPosition(); - char packet[packetSize]; + char* packet = (char*)malloc(packetSize); populatePacketHeader(packet, PacketTypeMuteEnvironnement); memcpy(packet + headerSize, &position, sizeof(glm::vec3)); memcpy(packet + headerSize + sizeof(glm::vec3), &MUTE_RADIUS, sizeof(float)); @@ -1026,6 +1026,8 @@ void Menu::muteEnvironment() { // send off this mute packet NodeList::getInstance()->writeDatagram(mutePacket, audioMixer); } + + free(packet); } void Menu::goToLocation() { From 31aedb4aa8779dda51714c6a856bb8a10a448ec1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 7 May 2014 14:39:26 -0700 Subject: [PATCH 26/43] fixed overlay not moving on resize in editModels.js --- examples/editModels.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/editModels.js b/examples/editModels.js index ecf398edfa..384d2f75a8 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -370,7 +370,7 @@ function moveOverlays() { toolsX = windowDimensions.x - 8 - toolWidth; toolsY = (windowDimensions.y - toolsHeight) / 2; - Overlays.addOverlay(firstModel, { + Overlays.editOverlay(firstModel, { x: toolsX, y: toolsY + ((toolHeight + toolVerticalSpacing) * 0), width: toolWidth, height: toolHeight, }); } From 03faff359f1772cd587ea37360981409c46fa968 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 7 May 2014 14:48:25 -0700 Subject: [PATCH 27/43] Fix for certain models with textures not parented to materials. --- libraries/fbx/src/FBXReader.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index d637526067..1fc03ceb66 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -826,7 +826,7 @@ ExtractedMesh extractMesh(const FBXNode& object) { while (endIndex < data.polygonIndices.size() && data.polygonIndices.at(endIndex++) >= 0); QPair materialTexture((polygonIndex < materials.size()) ? materials.at(polygonIndex) : 0, - (polygonIndex < textures.size()) ? textures.at(polygonIndex) : -1); + (polygonIndex < textures.size()) ? textures.at(polygonIndex) : 0); int& partIndex = materialTextureParts[materialTexture]; if (partIndex == 0) { data.extracted.partMaterialTextures.append(materialTexture); @@ -972,6 +972,18 @@ FBXTexture getTexture(const QString& textureID, const QHash return texture; } +bool checkMaterialsHaveTextures(const QHash& materials, + const QHash& textureFilenames, const QMultiHash& childMap) { + foreach (const QString& materialID, materials.keys()) { + foreach (const QString& childID, childMap.values(materialID)) { + if (textureFilenames.contains(childID)) { + return true; + } + } + } + return false; +} + FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) { QHash meshes; QVector blendshapes; @@ -1515,6 +1527,9 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) geometry.bindExtents.reset(); geometry.meshExtents.reset(); + // see if any materials have texture children + bool materialsHaveTextures = checkMaterialsHaveTextures(materials, textureFilenames, childMap); + for (QHash::iterator it = meshes.begin(); it != meshes.end(); it++) { ExtractedMesh& extracted = it.value(); @@ -1587,7 +1602,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } else if (textureFilenames.contains(childID)) { FBXTexture texture = getTexture(childID, textureFilenames, textureContent); for (int j = 0; j < extracted.partMaterialTextures.size(); j++) { - if (extracted.partMaterialTextures.at(j).second == textureIndex) { + int partTexture = extracted.partMaterialTextures.at(j).second; + if (partTexture == textureIndex && !(partTexture == 0 && materialsHaveTextures)) { extracted.mesh.parts[j].diffuseTexture = texture; } } From fd1f6befffb942d0e9b2c9e8557c2fc75cbce9cc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 7 May 2014 15:19:32 -0700 Subject: [PATCH 28/43] CR --- assignment-client/src/audio/AudioMixer.cpp | 4 ++-- interface/src/DatagramProcessor.cpp | 4 ++-- interface/src/Menu.cpp | 6 +++--- libraries/networking/src/PacketHeaders.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 9007c55abb..158eabe27b 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -348,9 +348,9 @@ void AudioMixer::readPendingDatagrams() { || mixerPacketType == PacketTypeSilentAudioFrame) { nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket); - } else if (mixerPacketType == PacketTypeMuteEnvironnement) { + } else if (mixerPacketType == PacketTypeMuteEnvironment) { QByteArray packet = receivedPacket; - populatePacketHeader(packet, PacketTypeMuteEnvironnement); + populatePacketHeader(packet, PacketTypeMuteEnvironment); foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != nodeList->sendingNodeForPacket(receivedPacket)) { diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index 5251b5d8ee..56078c1a8d 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -131,11 +131,11 @@ void DatagramProcessor::processDatagrams() { break; } - case PacketTypeMuteEnvironnement: { + case PacketTypeMuteEnvironment: { glm::vec3 position; float radius; - int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironnement); + int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironment); memcpy(&position, incomingPacket.constData() + headerSize, sizeof(glm::vec3)); memcpy(&radius, incomingPacket.constData() + headerSize + sizeof(glm::vec3), sizeof(float)); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index b98bd985e2..0587e979f6 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -68,7 +68,7 @@ const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f; const int ONE_SECOND_OF_FRAMES = 60; const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; -const float MUTE_RADIUS = 10; +const float MUTE_RADIUS = 50; Menu::Menu() : _actionHash(), @@ -1007,13 +1007,13 @@ void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJson } void Menu::muteEnvironment() { - int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironnement); + int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironment); int packetSize = headerSize + sizeof(glm::vec3) + sizeof(float); glm::vec3 position = Application::getInstance()->getAvatar()->getPosition(); char* packet = (char*)malloc(packetSize); - populatePacketHeader(packet, PacketTypeMuteEnvironnement); + populatePacketHeader(packet, PacketTypeMuteEnvironment); memcpy(packet + headerSize, &position, sizeof(glm::vec3)); memcpy(packet + headerSize + sizeof(glm::vec3), &MUTE_RADIUS, sizeof(float)); diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index ac8a187034..d5b1e8301c 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -39,7 +39,7 @@ enum PacketType { PacketTypeRequestAssignment, PacketTypeCreateAssignment, PacketTypeDomainOAuthRequest, - PacketTypeMuteEnvironnement, + PacketTypeMuteEnvironment, PacketTypeDataServerSend, // reusable PacketTypeDataServerConfirm, PacketTypeVoxelQuery, From 5e9036b3fec64b282cda0e58e06c55ce61edbaab Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 7 May 2014 15:37:41 -0700 Subject: [PATCH 29/43] tweak audio constants to be less agressive on cutoff --- assignment-client/src/audio/AudioMixer.cpp | 2 +- libraries/audio/src/PositionalAudioRingBuffer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 63b2083aae..6ee044a709 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -54,7 +54,7 @@ const short JITTER_BUFFER_MSECS = 12; const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_MSECS * (SAMPLE_RATE / 1000.0); -const float LOUDNESS_TO_DISTANCE_RATIO = 0.00305f; +const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f; const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer"; diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index 70da363267..6fc16c57a9 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -89,7 +89,7 @@ void PositionalAudioRingBuffer::updateNextOutputTrailingLoudness() { const int TRAILING_AVERAGE_FRAMES = 100; const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; - const float LOUDNESS_EPSILON = 0.01f; + const float LOUDNESS_EPSILON = 0.000001f; if (nextLoudness >= _nextOutputTrailingLoudness) { _nextOutputTrailingLoudness = nextLoudness; From 99ee6ae8af86874170a04c6598a2b04a51712621 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 7 May 2014 16:26:32 -0700 Subject: [PATCH 30/43] return an injector from playSound and allow user to stop it --- libraries/audio/src/AudioInjector.cpp | 8 +++++++- libraries/audio/src/AudioInjector.h | 13 +++++++++---- libraries/audio/src/AudioScriptingInterface.cpp | 4 +++- libraries/audio/src/AudioScriptingInterface.h | 2 +- libraries/script-engine/src/ScriptEngine.cpp | 11 +++++++++++ 5 files changed, 31 insertions(+), 7 deletions(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index eed41ac849..364d14cfbb 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -21,6 +21,12 @@ #include "AudioInjector.h" +AudioInjector::AudioInjector(QObject* parent) : + QObject(parent) +{ + +} + AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions) : _sound(sound), _options(injectorOptions) @@ -80,7 +86,7 @@ void AudioInjector::injectAudio() { int numPreAudioDataBytes = injectAudioPacket.size(); // loop to send off our audio in NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL byte chunks - while (currentSendPosition < soundByteArray.size()) { + while (currentSendPosition < soundByteArray.size() && !_shouldStop) { int bytesToCopy = std::min(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, soundByteArray.size() - currentSendPosition); diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index abaa804fb0..08fe544255 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -24,14 +24,19 @@ class AudioInjector : public QObject { Q_OBJECT public: + AudioInjector(QObject* parent); AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions); +public slots: + void injectAudio(); + void stop() { _shouldStop = true; } +signals: + void finished(); private: Sound* _sound; AudioInjectorOptions _options; -public slots: - void injectAudio(); -signals: - void finished(); + bool _shouldStop; }; +Q_DECLARE_METATYPE(AudioInjector*) + #endif // hifi_AudioInjector_h diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index 0d76a42757..944ae49adf 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -11,7 +11,7 @@ #include "AudioScriptingInterface.h" -void AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions* injectorOptions) { +AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions* injectorOptions) { AudioInjector* injector = new AudioInjector(sound, *injectorOptions); @@ -28,6 +28,8 @@ void AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions connect(injectorThread, SIGNAL(finished()), injectorThread, SLOT(deleteLater())); injectorThread->start(); + + return injector; } void AudioScriptingInterface::startDrumSound(float volume, float frequency, float duration, float decay, diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index f2e9b02e9a..de8e57090a 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -20,7 +20,7 @@ const AudioInjectorOptions DEFAULT_INJECTOR_OPTIONS; class AudioScriptingInterface : public QObject { Q_OBJECT public slots: - static void playSound(Sound* sound, const AudioInjectorOptions* injectorOptions = NULL); + static AudioInjector* playSound(Sound* sound, const AudioInjectorOptions* injectorOptions = NULL); static void startDrumSound(float volume, float frequency, float duration, float decay, const AudioInjectorOptions* injectorOptions = NULL); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 402f1a2885..9be2cb5252 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -52,6 +53,14 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ return QScriptValue(); } +QScriptValue injectorToScriptValue(QScriptEngine *engine, AudioInjector* const &in) { + return engine->newQObject(in); +} + +void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out) { + out = qobject_cast(object.toQObject()); +} + ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, AbstractControllerScriptingInterface* controllerScriptingInterface) : @@ -226,6 +235,8 @@ void ScriptEngine::init() { QScriptValue localVoxelsValue = _engine.scriptValueFromQMetaObject(); _engine.globalObject().setProperty("LocalVoxels", localVoxelsValue); + + qScriptRegisterMetaType(&_engine, injectorToScriptValue, injectorFromScriptValue); registerGlobalObject("Script", this); registerGlobalObject("Audio", &_audioScriptingInterface); From e6a8c79f9fde066c95c3fd3137f139bfee93c31c Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 7 May 2014 16:51:22 -0700 Subject: [PATCH 31/43] Added more arrow controls to move camera when in mirror mode, new guitar chords. --- examples/airGuitar.js | 21 +++++++++++++++------ interface/src/Application.cpp | 28 ++++++++++++++++++++++------ interface/src/Application.h | 2 ++ 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/examples/airGuitar.js b/examples/airGuitar.js index a54ef82e7e..08898579a7 100644 --- a/examples/airGuitar.js +++ b/examples/airGuitar.js @@ -27,9 +27,18 @@ function vMinus(a, b) { // First, load two percussion sounds to be used on the sticks -var chord1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+A.raw"); -var chord2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+B.raw"); -var chord3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+E.raw"); +var guitarType = 2; + +if (guitarType == 1) { + var chord1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+A.raw"); + var chord2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+B.raw"); + var chord3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+E.raw"); +} else { + var chord1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Metal+A+short.raw"); + var chord2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Metal+B+short.raw"); + var chord3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Metal+E+short.raw"); +} + var whichChord = chord1; @@ -56,7 +65,7 @@ function checkHands(deltaTime) { if (palm == strumHand) { - var STRUM_HEIGHT_ABOVE_PELVIS = 0.15; + var STRUM_HEIGHT_ABOVE_PELVIS = -0.30; var strumTriggerHeight = myPelvis.y + STRUM_HEIGHT_ABOVE_PELVIS; //printVector(position); if ((position.y < strumTriggerHeight) && (lastPosition.y >= strumTriggerHeight)) { @@ -72,9 +81,9 @@ function checkHands(deltaTime) { // This is the chord controller var distanceFromPelvis = Vec3.length(Vec3.subtract(position, myPelvis)); //print(distanceFromPelvis); - if (distanceFromPelvis > 0.50) { + if (distanceFromPelvis > 0.63) { whichChord = chord3; - } else if (distanceFromPelvis > 0.35) { + } else if (distanceFromPelvis > 0.55) { whichChord = chord2; } else { whichChord = chord1; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 10f113ad11..e4adb38cd4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -572,8 +572,8 @@ void Application::paintGL() { glm::vec3 eyePosition = _myAvatar->getHead()->calculateAverageEyePosition(); float headHeight = eyePosition.y - _myAvatar->getPosition().y; _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _myAvatar->getScale() * _scaleMirror); - _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight, 0)); - _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f))); + _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight + (_raiseMirror * _myAvatar->getScale()), 0)); + _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); // if the head would intersect the near clip plane, we must push the camera out glm::vec3 relativePosition = glm::inverse(_myCamera.getTargetRotation()) * @@ -870,7 +870,11 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_Up: if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - _scaleMirror *= 0.95; + if (!isShifted) { + _scaleMirror *= 0.95f; + } else { + _raiseMirror += 0.05f; + } } else { _myAvatar->setDriveKeys(isShifted ? UP : FWD, 1.f); } @@ -878,18 +882,30 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_Down: if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - _scaleMirror *= 1.05; + if (!isShifted) { + _scaleMirror *= 1.05f; + } else { + _raiseMirror -= 0.05f; + } } else { _myAvatar->setDriveKeys(isShifted ? DOWN : BACK, 1.f); } break; case Qt::Key_Left: - _myAvatar->setDriveKeys(isShifted ? LEFT : ROT_LEFT, 1.f); + if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + _rotateMirror += PI / 20.f; + } else { + _myAvatar->setDriveKeys(isShifted ? LEFT : ROT_LEFT, 1.f); + } break; case Qt::Key_Right: - _myAvatar->setDriveKeys(isShifted ? RIGHT : ROT_RIGHT, 1.f); + if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + _rotateMirror -= PI / 20.f; + } else { + _myAvatar->setDriveKeys(isShifted ? RIGHT : ROT_RIGHT, 1.f); + } break; case Qt::Key_I: diff --git a/interface/src/Application.h b/interface/src/Application.h index 1d38a11357..54e6bcdcac 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -457,6 +457,8 @@ private: glm::mat4 _projectionMatrix; float _scaleMirror; + float _rotateMirror; + float _raiseMirror; glm::mat4 _shadowMatrix; From 128e4a13de641cd1a85dfee9772d56465bb1bf06 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 7 May 2014 17:32:51 -0700 Subject: [PATCH 32/43] place models in proper containing voxel --- interface/src/Menu.cpp | 4 +- interface/src/Menu.h | 4 +- interface/src/models/ModelTreeRenderer.cpp | 145 +++++++++++++----- libraries/models/src/ModelItem.h | 12 ++ libraries/models/src/ModelTree.cpp | 34 ++-- libraries/models/src/ModelTreeElement.cpp | 56 +++++-- libraries/models/src/ModelTreeElement.h | 5 +- libraries/octree/src/Octree.cpp | 8 +- libraries/octree/src/Octree.h | 1 + libraries/octree/src/OctreeElement.cpp | 87 +++++++++++ libraries/octree/src/OctreeElement.h | 8 +- .../particles/src/ParticleTreeElement.cpp | 2 +- libraries/particles/src/ParticleTreeElement.h | 2 +- libraries/voxels/src/VoxelTreeElement.cpp | 2 +- libraries/voxels/src/VoxelTreeElement.h | 2 +- 15 files changed, 303 insertions(+), 69 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 2a00e414df..4bc6bea107 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -309,7 +309,9 @@ Menu::Menu() : QMenu* modelOptionsMenu = developerMenu->addMenu("Model Options"); addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::Models, 0, true); - addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelProxies, 0, false); + addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelBounds, 0, false); + addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelElementProxy, 0, false); + addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelElementChildProxies, 0, false); QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index d2d9ce7c7d..3667674f80 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -303,7 +303,9 @@ namespace MenuOption { const QString DisplayFrustum = "Display Frustum"; const QString DisplayHands = "Display Hands"; const QString DisplayHandTargets = "Display Hand Targets"; - const QString DisplayModelProxies = "Display Model Proxies"; + const QString DisplayModelBounds = "Display Model Bounds"; + const QString DisplayModelElementProxy = "Display Model Element Bounds"; + const QString DisplayModelElementChildProxies = "Display Model Element Children"; const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; const QString EchoLocalAudio = "Echo Local Audio"; const QString EchoServerAudio = "Echo Server Audio"; diff --git a/interface/src/models/ModelTreeRenderer.cpp b/interface/src/models/ModelTreeRenderer.cpp index 3ade46fc4a..c762182290 100644 --- a/interface/src/models/ModelTreeRenderer.cpp +++ b/interface/src/models/ModelTreeRenderer.cpp @@ -66,55 +66,130 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) const QList& modelItems = modelTreeElement->getModels(); uint16_t numberOfModels = modelItems.size(); + + bool isShadowMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE; + + bool displayModelBounds = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelBounds); + bool displayElementProxy = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelElementProxy); + bool displayElementChildProxies = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelElementChildProxies); + + + if (!isShadowMode && displayElementProxy && numberOfModels > 0) { + glm::vec3 elementCenter = modelTreeElement->getAABox().calcCenter() * (float)TREE_SCALE; + float elementSize = modelTreeElement->getScale() * (float)TREE_SCALE; + glColor3f(1.0f, 0.0f, 0.0f); + glPushMatrix(); + glTranslatef(elementCenter.x, elementCenter.y, elementCenter.z); + glutWireCube(elementSize); + glPopMatrix(); + + if (displayElementChildProxies) { + // draw the children + float halfSize = elementSize / 2.0f; + float quarterSize = elementSize / 4.0f; + glColor3f(1.0f, 1.0f, 0.0f); + glPushMatrix(); + glTranslatef(elementCenter.x - quarterSize, elementCenter.y - quarterSize, elementCenter.z - quarterSize); + glutWireCube(halfSize); + glPopMatrix(); + + glColor3f(1.0f, 0.0f, 1.0f); + glPushMatrix(); + glTranslatef(elementCenter.x + quarterSize, elementCenter.y - quarterSize, elementCenter.z - quarterSize); + glutWireCube(halfSize); + glPopMatrix(); + + glColor3f(0.0f, 1.0f, 0.0f); + glPushMatrix(); + glTranslatef(elementCenter.x - quarterSize, elementCenter.y + quarterSize, elementCenter.z - quarterSize); + glutWireCube(halfSize); + glPopMatrix(); + + glColor3f(0.0f, 0.0f, 1.0f); + glPushMatrix(); + glTranslatef(elementCenter.x - quarterSize, elementCenter.y - quarterSize, elementCenter.z + quarterSize); + glutWireCube(halfSize); + glPopMatrix(); + + glColor3f(1.0f, 1.0f, 1.0f); + glPushMatrix(); + glTranslatef(elementCenter.x + quarterSize, elementCenter.y + quarterSize, elementCenter.z + quarterSize); + glutWireCube(halfSize); + glPopMatrix(); + + glColor3f(0.0f, 0.5f, 0.5f); + glPushMatrix(); + glTranslatef(elementCenter.x - quarterSize, elementCenter.y + quarterSize, elementCenter.z + quarterSize); + glutWireCube(halfSize); + glPopMatrix(); + + glColor3f(0.5f, 0.0f, 0.0f); + glPushMatrix(); + glTranslatef(elementCenter.x + quarterSize, elementCenter.y - quarterSize, elementCenter.z + quarterSize); + glutWireCube(halfSize); + glPopMatrix(); + + glColor3f(0.0f, 0.5f, 0.0f); + glPushMatrix(); + glTranslatef(elementCenter.x + quarterSize, elementCenter.y + quarterSize, elementCenter.z - quarterSize); + glutWireCube(halfSize); + glPopMatrix(); + } + + } for (uint16_t i = 0; i < numberOfModels; i++) { const ModelItem& modelItem = modelItems[i]; // render modelItem aspoints - glm::vec3 position = modelItem.getPosition() * (float)TREE_SCALE; - glColor3ub(modelItem.getColor()[RED_INDEX],modelItem.getColor()[GREEN_INDEX],modelItem.getColor()[BLUE_INDEX]); - float radius = modelItem.getRadius() * (float)TREE_SCALE; - //glm::vec3 center = position + glm::vec3(radius, radius, radius); // center it around the position + AABox modelBox = modelItem.getAABox(); + modelBox.scale(TREE_SCALE); + if (args->_viewFrustum->boxInFrustum(modelBox) != ViewFrustum::OUTSIDE) { + glm::vec3 position = modelItem.getPosition() * (float)TREE_SCALE; + float radius = modelItem.getRadius() * (float)TREE_SCALE; + float size = modelItem.getSize() * (float)TREE_SCALE; - bool drawAsModel = modelItem.hasModel(); + bool drawAsModel = modelItem.hasModel(); - args->_renderedItems++; + args->_renderedItems++; - if (drawAsModel) { - glPushMatrix(); - const float alpha = 1.0f; + if (drawAsModel) { + glPushMatrix(); + const float alpha = 1.0f; - Model* model = getModel(modelItem.getModelURL()); + Model* model = getModel(modelItem.getModelURL()); - model->setScaleToFit(true, radius * 2.0f); - model->setSnapModelToCenter(true); + model->setScaleToFit(true, radius * 2.0f); + model->setSnapModelToCenter(true); - // set the rotation - glm::quat rotation = modelItem.getModelRotation(); - model->setRotation(rotation); + // set the rotation + glm::quat rotation = modelItem.getModelRotation(); + model->setRotation(rotation); - // set the position - model->setTranslation(position); - model->simulate(0.0f); + // set the position + model->setTranslation(position); + model->simulate(0.0f); - // TODO: should we allow modelItems to have alpha on their models? - Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE - ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; - model->render(alpha, modelRenderMode); + // TODO: should we allow modelItems to have alpha on their models? + Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE + ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + model->render(alpha, modelRenderMode); - const bool wantDebugSphere = false; - if (wantDebugSphere) { - glPushMatrix(); - glTranslatef(position.x, position.y, position.z); - glutWireSphere(radius, 15, 15); - glPopMatrix(); - } + if (!isShadowMode && displayModelBounds) { + glColor3f(0.0f, 1.0f, 0.0f); + glPushMatrix(); + glTranslatef(position.x, position.y, position.z); + glutWireCube(size); + glPopMatrix(); + } - glPopMatrix(); - } else { - glPushMatrix(); - glTranslatef(position.x, position.y, position.z); - glutSolidSphere(radius, 15, 15); - glPopMatrix(); + glPopMatrix(); + } else { + glColor3ub(modelItem.getColor()[RED_INDEX],modelItem.getColor()[GREEN_INDEX],modelItem.getColor()[BLUE_INDEX]); + glPushMatrix(); + glTranslatef(position.x, position.y, position.z); + glutSolidSphere(radius, 15, 15); + glPopMatrix(); + } } } } diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 76a78122ff..9edcf482c0 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -85,6 +85,9 @@ public: /// used by ModelScriptingInterface to return ModelItemProperties for unknown models void setIsUnknownID() { _id = UNKNOWN_MODEL_ID; _idSet = true; } + + glm::vec3 getMinimumPoint() const { return _position - glm::vec3(_radius, _radius, _radius); } + glm::vec3 getMaximumPoint() const { return _position + glm::vec3(_radius, _radius, _radius); } private: glm::vec3 _position; @@ -156,11 +159,20 @@ public: /// get position in domain scale units (0.0 - 1.0) const glm::vec3& getPosition() const { return _position; } + glm::vec3 getMinimumPoint() const { return _position - glm::vec3(_radius, _radius, _radius); } + glm::vec3 getMaximumPoint() const { return _position + glm::vec3(_radius, _radius, _radius); } + const rgbColor& getColor() const { return _color; } xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; } /// get radius in domain scale units (0.0 - 1.0) float getRadius() const { return _radius; } + + /// get maximum dimension in domain scale units (0.0 - 1.0) + float getSize() const { return _radius * 2.0f; } + + /// get maximum dimension in domain scale units (0.0 - 1.0) + AABox getAABox() const { return AABox(getMinimumPoint(), getSize()); } // model related properties bool hasModel() const { return !_modelURL.isEmpty(); } diff --git a/libraries/models/src/ModelTree.cpp b/libraries/models/src/ModelTree.cpp index cef38a9422..45694b081d 100644 --- a/libraries/models/src/ModelTree.cpp +++ b/libraries/models/src/ModelTree.cpp @@ -113,13 +113,10 @@ void ModelTree::storeModel(const ModelItem& model, const SharedNodePointer& send FindAndUpdateModelOperator theOperator(model); recurseTreeWithOperator(&theOperator); - // if we didn't find it in the tree, then store it... if (!theOperator.wasFound()) { - glm::vec3 position = model.getPosition(); - float size = std::max(MINIMUM_MODEL_ELEMENT_SIZE, model.getRadius()); - - ModelTreeElement* element = (ModelTreeElement*)getOrCreateChildElementAt(position.x, position.y, position.z, size); + AABox modelBox = model.getAABox(); + ModelTreeElement* element = (ModelTreeElement*)getOrCreateChildElementContaining(model.getAABox()); element->storeModel(model); } // what else do we need to do here to get reaveraging to work @@ -494,12 +491,29 @@ void ModelTree::update() { lockForWrite(); _isDirty = true; - // 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); + ModelTreeUpdateArgs args = { }; + recurseTreeWithOperation(updateOperation, &args); - // Now is a reasonable time to prune the tree... + // now add back any of the particles that moved elements.... + int movingModels = args._movingModels.size(); + for (int i = 0; i < movingModels; i++) { + bool shouldDie = args._movingModels[i].getShouldDie(); + + // if the particle 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 modelItemID = args._movingModels[i].getID(); + quint64 deletedAt = usecTimestampNow(); + _recentlyDeletedModelsLock.lockForWrite(); + _recentlyDeletedModelItemIDs.insert(deletedAt, modelItemID); + _recentlyDeletedModelsLock.unlock(); + } + } + + // prune the tree... recurseTreeWithOperation(pruneOperation, NULL); unlock(); } diff --git a/libraries/models/src/ModelTreeElement.cpp b/libraries/models/src/ModelTreeElement.cpp index 0327d8a0c4..5c5d5100cf 100644 --- a/libraries/models/src/ModelTreeElement.cpp +++ b/libraries/models/src/ModelTreeElement.cpp @@ -47,15 +47,32 @@ ModelTreeElement* ModelTreeElement::addChildAtIndex(int index) { } -bool ModelTreeElement::appendElementData(OctreePacketData* packetData) const { +bool ModelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const { bool success = true; // assume the best... - // write our models out... - uint16_t numberOfModels = _modelItems->size(); + // write our models out... first determine which of the models are in view based on our params + uint16_t numberOfModels = 0; + QVector indexesOfModelsToInclude; + + for (uint16_t i = 0; i < _modelItems->size(); i++) { + if (params.viewFrustum) { + const ModelItem& model = (*_modelItems)[i]; + AABox modelBox = model.getAABox(); + modelBox.scale(TREE_SCALE); + if (params.viewFrustum->boxInFrustum(modelBox) != ViewFrustum::OUTSIDE) { + indexesOfModelsToInclude << i; + numberOfModels++; + } + } else { + indexesOfModelsToInclude << i; + numberOfModels++; + } + } + success = packetData->appendValue(numberOfModels); if (success) { - for (uint16_t i = 0; i < numberOfModels; i++) { + foreach (uint16_t i, indexesOfModelsToInclude) { const ModelItem& model = (*_modelItems)[i]; success = model.appendModelData(packetData); if (!success) { @@ -66,10 +83,25 @@ bool ModelTreeElement::appendElementData(OctreePacketData* packetData) const { return success; } -void ModelTreeElement::update(ModelTreeUpdateArgs& args) { - markWithChangedTime(); - // TODO: early exit when _modelItems is empty +bool ModelTreeElement::containsModelBounds(const ModelItem& model) const { + return _box.contains(model.getMinimumPoint()) && _box.contains(model.getMaximumPoint()); +} +bool ModelTreeElement::bestFitModelBounds(const ModelItem& model) const { + if (_box.contains(model.getMinimumPoint()) && _box.contains(model.getMaximumPoint())) { + int childForMinimumPoint = getMyChildContainingPoint(model.getMinimumPoint()); + int childForMaximumPoint = getMyChildContainingPoint(model.getMaximumPoint()); + + // If I contain both the minimum and maximum point, but two different children of mine + // contain those points, then I am the best fit for that model + if (childForMinimumPoint != childForMaximumPoint) { + return true; + } + } + return false; +} + +void ModelTreeElement::update(ModelTreeUpdateArgs& args) { // update our contained models QList::iterator modelItr = _modelItems->begin(); while(modelItr != _modelItems->end()) { @@ -78,19 +110,18 @@ void ModelTreeElement::update(ModelTreeUpdateArgs& args) { // If the model wants to die, or if it's left our bounding box, then move it // into the arguments moving models. These will be added back or deleted completely - if (model.getShouldDie() || !_box.contains(model.getPosition())) { + if (model.getShouldDie() || !bestFitModelBounds(model)) { args._movingModels.push_back(model); // erase this model modelItr = _modelItems->erase(modelItr); + + // this element has changed so mark it... + markWithChangedTime(); } else { ++modelItr; } } - // TODO: if _modelItems is empty after while loop consider freeing memory in _modelItems if - // internal array is too big (QList internal array does not decrease size except in dtor and - // assignment operator). Otherwise _modelItems could become a "resource leak" for large - // roaming piles of models. } bool ModelTreeElement::findSpherePenetration(const glm::vec3& center, float radius, @@ -136,6 +167,7 @@ bool ModelTreeElement::updateModel(const ModelItem& model) { (localOlder ? "OLDER" : "NEWER"), difference, debug::valueOf(model.isNewlyCreated()) ); } + thisModel.copyChangedProperties(model); markWithChangedTime(); } else { diff --git a/libraries/models/src/ModelTreeElement.h b/libraries/models/src/ModelTreeElement.h index ce03d50065..ce9e2dec7e 100644 --- a/libraries/models/src/ModelTreeElement.h +++ b/libraries/models/src/ModelTreeElement.h @@ -74,7 +74,7 @@ public: virtual bool requiresSplit() const { return false; } /// Override to serialize the state of this element. This is used for persistance and for transmission across the network. - virtual bool appendElementData(OctreePacketData* packetData) const; + virtual bool appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const; /// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading /// from the network. @@ -118,6 +118,9 @@ public: bool removeModelWithID(uint32_t id); + bool containsModelBounds(const ModelItem& model) const; + bool bestFitModelBounds(const ModelItem& model) const; + protected: virtual void init(unsigned char * octalCode); diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index d308d007cd..5b766ecdd7 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -578,6 +578,10 @@ OctreeElement* Octree::getOrCreateChildElementAt(float x, float y, float z, floa return getRoot()->getOrCreateChildElementAt(x, y, z, s); } +OctreeElement* Octree::getOrCreateChildElementContaining(const AABox& box) { + return getRoot()->getOrCreateChildElementContaining(box); +} + // combines the ray cast arguments into a single object class RayArgs { @@ -1001,7 +1005,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, // Keep track of how deep we've encoded. currentEncodeLevel++; - params.maxLevelReached = std::max(currentEncodeLevel,params.maxLevelReached); + params.maxLevelReached = std::max(currentEncodeLevel, params.maxLevelReached); // If we've reached our max Search Level, then stop searching. if (currentEncodeLevel >= params.maxEncodeLevel) { @@ -1342,7 +1346,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, OctreeElement* childElement = element->getChildAtIndex(i); if (childElement) { int bytesBeforeChild = packetData->getUncompressedSize(); - continueThisLevel = childElement->appendElementData(packetData); + continueThisLevel = childElement->appendElementData(packetData, params); int bytesAfterChild = packetData->getUncompressedSize(); if (!continueThisLevel) { diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 6e0693dc23..4a17cb3c1d 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -227,6 +227,7 @@ public: OctreeElement* getOctreeEnclosingElementAt(float x, float y, float z, float s) const; OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s); + OctreeElement* getOrCreateChildElementContaining(const AABox& box); void recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData = NULL); void recurseTreeWithPostOperation(RecurseOctreeOperation operation, void* extraData = NULL); diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index d54f7aa94b..edba26f2a7 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1379,3 +1379,90 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float // Now that we have the child to recurse down, let it answer the original question... return child->getOrCreateChildElementAt(x, y, z, s); } + + +OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AABox& box) { + OctreeElement* child = NULL; + + float ourScale = getScale(); + float boxScale = box.getScale(); + + if(boxScale > ourScale) { + qDebug("UNEXPECTED -- OctreeElement::getOrCreateChildElementContaining() " + "boxScale=[%f] > ourScale=[%f] ", boxScale, ourScale); + } + + // Determine which of our children the minimum and maximum corners of the box live in... + glm::vec3 boxCornerMinimum = box.getCorner(); + glm::vec3 boxCornerMaximum = box.calcTopFarLeft(); + + int childIndexBoxMinimum = getMyChildContainingPoint(boxCornerMinimum); + int childIndexBoxMaximum = getMyChildContainingPoint(boxCornerMaximum); + + // If the minimum and maximum corners of the box are in two different children's boxes, then we are the containing element + if (childIndexBoxMinimum != childIndexBoxMaximum) { + return this; + } + + // otherwise, they are the same and that child should be considered as the correct element + int childIndex = childIndexBoxMinimum; // both the same... + + // Now, check if we have a child at that location + child = getChildAtIndex(childIndex); + if (!child) { + child = addChildAtIndex(childIndex); + } + + // Now that we have the child to recurse down, let it answer the original question... + return child->getOrCreateChildElementContaining(box); +} + +int OctreeElement::getMyChildContainingPoint(const glm::vec3& point) const { + glm::vec3 ourCenter = _box.calcCenter(); + int childIndex = CHILD_UNKNOWN; + // left half + if (point.x > ourCenter.x) { + if (point.y > ourCenter.y) { + // top left + if (point.z > ourCenter.z) { + // top left far + childIndex = CHILD_TOP_LEFT_FAR; + } else { + // top left near + childIndex = CHILD_TOP_LEFT_NEAR; + } + } else { + // bottom left + if (point.z > ourCenter.z) { + // bottom left far + childIndex = CHILD_BOTTOM_LEFT_FAR; + } else { + // bottom left near + childIndex = CHILD_BOTTOM_LEFT_NEAR; + } + } + } else { + // right half + if (point.y > ourCenter.y) { + // top right + if (point.z > ourCenter.z) { + // top right far + childIndex = CHILD_TOP_RIGHT_FAR; + } else { + // top right near + childIndex = CHILD_TOP_RIGHT_NEAR; + } + } else { + // bottom right + if (point.z > ourCenter.z) { + // bottom right far + childIndex = CHILD_BOTTOM_RIGHT_FAR; + } else { + // bottom right near + childIndex = CHILD_BOTTOM_RIGHT_NEAR; + } + } + } + return childIndex; +} + diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index c5eec1c9e2..42c9abad46 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -23,14 +23,14 @@ #include "AABox.h" #include "ViewFrustum.h" #include "OctreeConstants.h" -//#include "Octree.h" +class EncodeBitstreamParams; class Octree; class OctreeElement; class OctreeElementDeleteHook; class OctreePacketData; -class VoxelSystem; class ReadBitstreamToTreeParams; +class VoxelSystem; // Callers who want delete hook callbacks should implement this class class OctreeElementDeleteHook { @@ -81,7 +81,7 @@ public: virtual bool requiresSplit() const { return false; } /// Override to serialize the state of this element. This is used for persistance and for transmission across the network. - virtual bool appendElementData(OctreePacketData* packetData) const { return true; } + virtual bool appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const { return true; } /// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading /// from the network. @@ -217,6 +217,8 @@ public: OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s); + OctreeElement* getOrCreateChildElementContaining(const AABox& box); + int getMyChildContainingPoint(const glm::vec3& point) const; protected: diff --git a/libraries/particles/src/ParticleTreeElement.cpp b/libraries/particles/src/ParticleTreeElement.cpp index d28ccf2f5e..b6e59eb0ab 100644 --- a/libraries/particles/src/ParticleTreeElement.cpp +++ b/libraries/particles/src/ParticleTreeElement.cpp @@ -47,7 +47,7 @@ ParticleTreeElement* ParticleTreeElement::addChildAtIndex(int index) { } -bool ParticleTreeElement::appendElementData(OctreePacketData* packetData) const { +bool ParticleTreeElement::appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const { bool success = true; // assume the best... // write our particles out... diff --git a/libraries/particles/src/ParticleTreeElement.h b/libraries/particles/src/ParticleTreeElement.h index 59f80d588a..4381cdd777 100644 --- a/libraries/particles/src/ParticleTreeElement.h +++ b/libraries/particles/src/ParticleTreeElement.h @@ -76,7 +76,7 @@ public: virtual bool requiresSplit() const { return false; } /// Override to serialize the state of this element. This is used for persistance and for transmission across the network. - virtual bool appendElementData(OctreePacketData* packetData) const; + virtual bool appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const; /// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading /// from the network. diff --git a/libraries/voxels/src/VoxelTreeElement.cpp b/libraries/voxels/src/VoxelTreeElement.cpp index 2582980816..f72e628b74 100644 --- a/libraries/voxels/src/VoxelTreeElement.cpp +++ b/libraries/voxels/src/VoxelTreeElement.cpp @@ -65,7 +65,7 @@ void VoxelTreeElement::splitChildren() { } } -bool VoxelTreeElement::appendElementData(OctreePacketData* packetData) const { +bool VoxelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const { return packetData->appendColor(getColor()); } diff --git a/libraries/voxels/src/VoxelTreeElement.h b/libraries/voxels/src/VoxelTreeElement.h index 8733987df4..788a728f6f 100644 --- a/libraries/voxels/src/VoxelTreeElement.h +++ b/libraries/voxels/src/VoxelTreeElement.h @@ -43,7 +43,7 @@ public: virtual bool hasContent() const { return isColored(); } virtual void splitChildren(); virtual bool requiresSplit() const; - virtual bool appendElementData(OctreePacketData* packetData) const; + virtual bool appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const; virtual int readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); virtual void calculateAverageFromChildren(); virtual bool collapseChildren(); From f78c81e073e3dd2cf247beb794c3f39734602e60 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 7 May 2014 17:48:01 -0700 Subject: [PATCH 33/43] add interface to Audio to stop injector and see if playing --- libraries/audio/src/AudioScriptingInterface.cpp | 10 ++++++++++ libraries/audio/src/AudioScriptingInterface.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index 944ae49adf..fa0d3a9565 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -32,6 +32,16 @@ AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjec return injector; } +void AudioScriptingInterface::stopInjector(AudioInjector* injector) { + if (injector) { + injector->stop(); + } +} + +bool AudioScriptingInterface::isInjectorPlaying(AudioInjector* injector) { + return (injector != NULL); +} + void AudioScriptingInterface::startDrumSound(float volume, float frequency, float duration, float decay, const AudioInjectorOptions* injectorOptions) { diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index de8e57090a..343eac304c 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -21,6 +21,8 @@ class AudioScriptingInterface : public QObject { Q_OBJECT public slots: static AudioInjector* playSound(Sound* sound, const AudioInjectorOptions* injectorOptions = NULL); + static void stopInjector(AudioInjector* injector); + static bool isInjectorPlaying(AudioInjector* injector); static void startDrumSound(float volume, float frequency, float duration, float decay, const AudioInjectorOptions* injectorOptions = NULL); From c56f0accec5895625ed45235883a42d0c231d81c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 7 May 2014 20:01:02 -0700 Subject: [PATCH 34/43] fix unix build buster --- interface/src/avatar/Hand.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index ff21e9f5b2..757a74db29 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -24,7 +24,7 @@ #include #include "InterfaceConfig.h" -#include "renderer/model.h" +#include "renderer/Model.h" #include "world.h" From 01e5b009eee25fb0d9cb891d8c279a1ee035990b Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 7 May 2014 20:43:23 -0700 Subject: [PATCH 35/43] scope menus better, pause hotkey, no stay paused, remove menu for shared face culling ops --- interface/src/Audio.cpp | 1 + interface/src/Menu.cpp | 22 ++++--------------- interface/src/Menu.h | 2 -- interface/src/voxels/VoxelSystem.cpp | 32 ---------------------------- interface/src/voxels/VoxelSystem.h | 4 +--- 5 files changed, 6 insertions(+), 55 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 68e38615bf..bef6f4c2da 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1068,6 +1068,7 @@ void Audio::toggleScope() { memset(_scopeInput.data(), 0, width * sizeof(int16_t)); memset(_scopeOutputLeft.data(), 0, width * sizeof(int16_t)); memset(_scopeOutputRight.data(), 0, width * sizeof(int16_t)); + _scopeEnabledPause = false; } } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0587e979f6..eecc18534c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -272,9 +272,6 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true); addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails())); addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, this, SLOT(octreeStatsDetails())); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::AudioScope, 0, false, - appInstance->getAudio(), - SLOT(toggleScope())); QMenu* developerMenu = addMenu("Developer"); @@ -371,20 +368,6 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings); addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::SuppressShortTimings); - addCheckableActionToQMenuAndActionHash(renderDebugMenu, - MenuOption::CullSharedFaces, - Qt::CTRL | Qt::SHIFT | Qt::Key_C, - false, - appInstance->getVoxels(), - SLOT(cullSharedFaces())); - - addCheckableActionToQMenuAndActionHash(renderDebugMenu, - MenuOption::ShowCulledSharedFaces, - 0, - false, - appInstance->getVoxels(), - SLOT(showCulledSharedFaces())); - QMenu* audioDebugMenu = developerMenu->addMenu("Audio Debugging Tools"); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioNoiseReduction, 0, @@ -408,8 +391,11 @@ Menu::Menu() : false, appInstance->getAudio(), SLOT(toggleToneInjection())); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScope, Qt::CTRL | Qt::Key_P, false, + appInstance->getAudio(), + SLOT(toggleScope())); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScopePause, - Qt::CTRL | Qt::Key_P, + Qt::CTRL | Qt::SHIFT | Qt::Key_P , false, appInstance->getAudio(), SLOT(toggleScopePause())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index d1097929f7..1e13d5ff2a 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -297,7 +297,6 @@ namespace MenuOption { const QString CollideWithParticles = "Collide With Particles"; const QString CollideWithVoxels = "Collide With Voxels"; const QString Collisions = "Collisions"; - const QString CullSharedFaces = "Cull Shared Voxel Faces"; const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD"; @@ -363,7 +362,6 @@ namespace MenuOption { const QString SettingsExport = "Export Settings"; const QString SettingsImport = "Import Settings"; const QString Shadows = "Shadows"; - const QString ShowCulledSharedFaces = "Show Culled Shared Voxel Faces"; const QString ShowIKConstraints = "Show IK Constraints"; const QString Stars = "Stars"; const QString Stats = "Stats"; diff --git a/interface/src/voxels/VoxelSystem.cpp b/interface/src/voxels/VoxelSystem.cpp index 0fac5a338c..8937cef7dd 100644 --- a/interface/src/voxels/VoxelSystem.cpp +++ b/interface/src/voxels/VoxelSystem.cpp @@ -1711,38 +1711,6 @@ bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element, return true; } - -void VoxelSystem::cullSharedFaces() { - - if (Menu::getInstance()->isOptionChecked(MenuOption::CullSharedFaces)) { - _useVoxelShader = false; - _usePrimitiveRenderer = true; - inspectForOcclusions(); - } else { - _usePrimitiveRenderer = false; - clearAllNodesBufferIndex(); - } - _writeRenderFullVBO = true; - _tree->setDirtyBit(); - setupNewVoxelsForDrawing(); -} - -void VoxelSystem::showCulledSharedFaces() { - - _tree->lockForRead(); - if (Menu::getInstance()->isOptionChecked(MenuOption::ShowCulledSharedFaces)) { - _showCulledSharedFaces = true; - } else { - _showCulledSharedFaces = false; - } - _tree->unlock(); - if (Menu::getInstance()->isOptionChecked(MenuOption::CullSharedFaces)) { - _writeRenderFullVBO = true; - _tree->setDirtyBit(); - setupNewVoxelsForDrawing(); - } -} - void VoxelSystem::inspectForOcclusions() { if (_inOcclusions) { diff --git a/interface/src/voxels/VoxelSystem.h b/interface/src/voxels/VoxelSystem.h index b134fe1539..15e2b20a75 100644 --- a/interface/src/voxels/VoxelSystem.h +++ b/interface/src/voxels/VoxelSystem.h @@ -95,9 +95,7 @@ public slots: // Methods that recurse tree void forceRedrawEntireTree(); void clearAllNodesBufferIndex(); - void cullSharedFaces(); - void showCulledSharedFaces(); - + void setDisableFastVoxelPipeline(bool disableFastVoxelPipeline); void setUseVoxelShader(bool useVoxelShader); void setVoxelsAsPoints(bool voxelsAsPoints); From 8f4fb04021c192b3fdb078ed0fd0ac3148f3dc90 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 7 May 2014 22:24:05 -0700 Subject: [PATCH 36/43] clearer visualization of controller hand target, remove hand paddles --- interface/src/avatar/Hand.cpp | 29 ++++++++++++++++++++++------- interface/src/avatar/Hand.h | 2 +- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 320a8477c1..a6cd7ff10e 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -213,7 +213,7 @@ void Hand::render(bool isMine, Model::RenderMode renderMode) { } if (renderMode != Model::SHADOW_RENDER_MODE && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) { - renderLeapHands(isMine); + renderHandTargets(isMine); } glEnable(GL_DEPTH_TEST); @@ -221,11 +221,11 @@ void Hand::render(bool isMine, Model::RenderMode renderMode) { } -void Hand::renderLeapHands(bool isMine) { +void Hand::renderHandTargets(bool isMine) { const float alpha = 1.0f; - const glm::vec3 handColor(1.0, 0.84, 0.66); // use the skin color + const glm::vec3 handColor(1.0, 0.0, 0.0); // Color the hand targets red to be different than skin glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); @@ -262,23 +262,37 @@ void Hand::renderLeapHands(bool isMine) { glPopMatrix(); } } - - // Draw the finger root cones + + const float PALM_BALL_RADIUS = 0.03f; + const float PALM_DISK_RADIUS = 0.06f; + const float PALM_DISK_THICKNESS = 0.01f; + const float PALM_FINGER_ROD_RADIUS = 0.003f; + + // Draw the palm ball and disk for (size_t i = 0; i < getNumPalms(); ++i) { PalmData& palm = getPalms()[i]; if (palm.isActive()) { for (size_t f = 0; f < palm.getNumFingers(); ++f) { FingerData& finger = palm.getFingers()[f]; if (finger.isActive()) { - glColor4f(handColor.r, handColor.g, handColor.b, 0.5); + glColor4f(handColor.r, handColor.g, handColor.b, alpha); glm::vec3 tip = finger.getTipPosition(); glm::vec3 root = finger.getRootPosition(); - Avatar::renderJointConnectingCone(root, tip, 0.001f, 0.003f); + Avatar::renderJointConnectingCone(root, tip, PALM_FINGER_ROD_RADIUS, PALM_FINGER_ROD_RADIUS); + // Render sphere at palm/finger root + glm::vec3 palmNormal = root + palm.getNormal() * PALM_DISK_THICKNESS; + Avatar::renderJointConnectingCone(root, palmNormal, PALM_DISK_RADIUS, 0.0f); + glPushMatrix(); + glTranslatef(root.x, root.y, root.z); + glutSolidSphere(PALM_BALL_RADIUS, 20.0f, 20.0f); + glPopMatrix(); + } } } } + /* // Draw the hand paddles int MAX_NUM_PADDLES = 2; // one for left and one for right glColor4f(handColor.r, handColor.g, handColor.b, 0.3f); @@ -309,6 +323,7 @@ void Hand::renderLeapHands(bool isMine) { Avatar::renderJointConnectingCone(root, tip, HAND_PADDLE_RADIUS, 0.f); } } + */ glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 757a74db29..9c2bc2c2c0 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -76,7 +76,7 @@ private: std::vector _leapFingerTipBalls; std::vector _leapFingerRootBalls; - void renderLeapHands(bool isMine); + void renderHandTargets(bool isMine); void renderLeapFingerTrails(); void calculateGeometry(); From e439694d72b5c791346a255af10178fe31ec424f Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 7 May 2014 22:56:06 -0700 Subject: [PATCH 37/43] =?UTF-8?q?reset=20only=20pitch=20and=20roll=20on=20?= =?UTF-8?q?spacebar=20so=20that=20you=20don=E2=80=99t=20turn=20away=20from?= =?UTF-8?q?=20someone?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- interface/src/avatar/MyAvatar.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1655a17f08..f320a2759d 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -99,7 +99,11 @@ void MyAvatar::reset() { setVelocity(glm::vec3(0.0f)); setThrust(glm::vec3(0.0f)); - setOrientation(glm::quat(glm::vec3(0.0f))); + // Reset the pitch and roll components of the avatar's orientation, preserve yaw direction + glm::vec3 eulers = safeEulerAngles(getOrientation()); + eulers.x = 0.f; + eulers.z = 0.f; + setOrientation(glm::quat(eulers)); } void MyAvatar::update(float deltaTime) { From 1e276f6dae1d87c8eeb526b74022fbba342916da Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 7 May 2014 23:41:58 -0700 Subject: [PATCH 38/43] Improved hydra idle detection by tracking total distance moved, fixed NaN in starting velocities --- interface/src/devices/SixenseManager.cpp | 24 ++++++++++++++++++------ interface/src/devices/SixenseManager.h | 1 + 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index f7c00411c1..0435519124 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -30,6 +30,7 @@ const float NECK_Z = 300.f; // millimeters SixenseManager::SixenseManager() { #ifdef HAVE_SIXENSE _lastMovement = 0; + _amountMoved = glm::vec3(0.0f); _calibrationState = CALIBRATION_STATE_IDLE; // By default we assume the _neckBase (in orb frame) is as high above the orb @@ -122,14 +123,21 @@ void SixenseManager::update(float deltaTime) { palm->setRawRotation(rotation); // Compute current velocity from position change - glm::vec3 rawVelocity = (position - palm->getRawPosition()) / deltaTime / 1000.f; + glm::vec3 rawVelocity; + if (deltaTime > 0.f) { + rawVelocity = (position - palm->getRawPosition()) / deltaTime / 1000.f; + } else { + rawVelocity = glm::vec3(0.0f); + } palm->setRawVelocity(rawVelocity); // meters/sec palm->setRawPosition(position); // use the velocity to determine whether there's any movement (if the hand isn't new) - const float MOVEMENT_SPEED_THRESHOLD = 0.05f; - if (glm::length(rawVelocity) > MOVEMENT_SPEED_THRESHOLD && foundHand) { + const float MOVEMENT_DISTANCE_THRESHOLD = 0.003f; + _amountMoved += rawVelocity * deltaTime; + if (glm::length(_amountMoved) > MOVEMENT_DISTANCE_THRESHOLD && foundHand) { _lastMovement = usecTimestampNow(); + _amountMoved = glm::vec3(0.0f); } // initialize the "finger" based on the direction @@ -143,7 +151,11 @@ void SixenseManager::update(float deltaTime) { // Store the one fingertip in the palm structure so we can track velocity glm::vec3 oldTipPosition = palm->getTipRawPosition(); - palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime / 1000.f); + if (deltaTime > 0.f) { + palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime / 1000.f); + } else { + palm->setTipVelocity(glm::vec3(0.f)); + } palm->setTipPosition(newTipPosition); // three fingers indicates to the skeleton that we have enough data to determine direction @@ -158,8 +170,8 @@ void SixenseManager::update(float deltaTime) { } // if the controllers haven't been moved in a while, disable - const unsigned int MOVEMENT_DISABLE_DURATION = 30 * 1000 * 1000; - if (usecTimestampNow() - _lastMovement > MOVEMENT_DISABLE_DURATION) { + const unsigned int MOVEMENT_DISABLE_SECONDS = 3; + if (usecTimestampNow() - _lastMovement > (MOVEMENT_DISABLE_SECONDS * 1000 * 1000)) { for (std::vector::iterator it = hand->getPalms().begin(); it != hand->getPalms().end(); it++) { it->setActive(false); } diff --git a/interface/src/devices/SixenseManager.h b/interface/src/devices/SixenseManager.h index 2fc6b3dcb3..a98d4c0e4e 100644 --- a/interface/src/devices/SixenseManager.h +++ b/interface/src/devices/SixenseManager.h @@ -64,6 +64,7 @@ private: #endif quint64 _lastMovement; + glm::vec3 _amountMoved; }; #endif // hifi_SixenseManager_h From 2797d0ab3b4d4498d4981800764874e25f70cf10 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 8 May 2014 00:09:07 -0700 Subject: [PATCH 39/43] removed hand trying to follow mouse and other cruft --- interface/src/Application.cpp | 38 +-------------------------- interface/src/Application.h | 6 ----- interface/src/avatar/MyAvatar.cpp | 43 ++++++------------------------- interface/src/avatar/MyAvatar.h | 1 - 4 files changed, 9 insertions(+), 79 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fb414311ef..61666ccdeb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1217,10 +1217,6 @@ void Application::touchBeginEvent(QTouchEvent* event) { return; } - // put any application specific touch behavior below here.. - _lastTouchAvgX = _touchAvgX; - _lastTouchAvgY = _touchAvgY; - } void Application::touchEndEvent(QTouchEvent* event) { @@ -1875,34 +1871,6 @@ void Application::updateMyAvatarLookAtPosition() { _myAvatar->getHead()->setLookAtPosition(lookAtSpot); } -void Application::updateHandAndTouch(float deltaTime) { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateHandAndTouch()"); - - // Update from Touch - if (_isTouchPressed) { - _lastTouchAvgX = _touchAvgX; - _lastTouchAvgY = _touchAvgY; - } -} - -void Application::updateLeap(float deltaTime) { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateLeap()"); -} - -void Application::updateSixense(float deltaTime) { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateSixense()"); - - _sixenseManager.update(deltaTime); -} - -void Application::updateSerialDevices(float deltaTime) { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateSerialDevices()"); -} - void Application::updateThreads(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateThreads()"); @@ -2016,11 +1984,7 @@ void Application::update(float deltaTime) { updateVisage(); _myAvatar->updateLookAtTargetAvatar(); updateMyAvatarLookAtPosition(); - - updateHandAndTouch(deltaTime); // Update state for touch sensors - updateLeap(deltaTime); // Leap finger-sensing device - updateSixense(deltaTime); // Razer Hydra controllers - updateSerialDevices(deltaTime); // Read serial port interface devices + _sixenseManager.update(deltaTime); updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... _avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them... diff --git a/interface/src/Application.h b/interface/src/Application.h index 54e6bcdcac..91a7ebd29b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -343,10 +343,6 @@ private: void updateFaceshift(); void updateVisage(); void updateMyAvatarLookAtPosition(); - void updateHandAndTouch(float deltaTime); - void updateLeap(float deltaTime); - void updateSixense(float deltaTime); - void updateSerialDevices(float deltaTime); void updateThreads(float deltaTime); void updateMetavoxels(float deltaTime); void updateCamera(float deltaTime); @@ -477,8 +473,6 @@ private: float _touchAvgX; float _touchAvgY; - float _lastTouchAvgX; - float _lastTouchAvgY; float _touchDragStartedAvgX; float _touchDragStartedAvgY; bool _isTouchPressed; // true if multitouch has been pressed (clear when finished) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f320a2759d..2f931b0a54 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -136,7 +136,14 @@ void MyAvatar::simulate(float deltaTime) { } // update the movement of the hand and process handshaking with other avatars... - updateHandMovementAndTouching(deltaTime); + bool pointing = false; + if (_mousePressed) { + _handState = HAND_STATE_GRASPING; + } else if (pointing) { + _handState = HAND_STATE_POINTING; + } else { + _handState = HAND_STATE_NULL; + } updateOrientation(deltaTime); @@ -915,40 +922,6 @@ void MyAvatar::updateThrust(float deltaTime) { } */ -void MyAvatar::updateHandMovementAndTouching(float deltaTime) { - glm::quat orientation = getOrientation(); - - // reset hand and arm positions according to hand movement - glm::vec3 up = orientation * IDENTITY_UP; - - bool pointing = false; - if (glm::length(_mouseRayDirection) > EPSILON && !Application::getInstance()->isMouseHidden()) { - // confine to the approximate shoulder plane - glm::vec3 pointDirection = _mouseRayDirection; - if (glm::dot(_mouseRayDirection, up) > 0.0f) { - glm::vec3 projectedVector = glm::cross(up, glm::cross(_mouseRayDirection, up)); - if (glm::length(projectedVector) > EPSILON) { - pointDirection = glm::normalize(projectedVector); - } - } - glm::vec3 shoulderPosition; - if (_skeletonModel.getRightShoulderPosition(shoulderPosition)) { - glm::vec3 farVector = _mouseRayOrigin + pointDirection * (float)TREE_SCALE - shoulderPosition; - const float ARM_RETRACTION = 0.75f; - float retractedLength = _skeletonModel.getRightArmLength() * ARM_RETRACTION; - setHandPosition(shoulderPosition + glm::normalize(farVector) * retractedLength); - pointing = true; - } - } - - if (_mousePressed) { - _handState = HAND_STATE_GRASPING; - } else if (pointing) { - _handState = HAND_STATE_POINTING; - } else { - _handState = HAND_STATE_NULL; - } -} void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) { glm::vec3 up = getBodyUpDirection(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 1c80d3b969..f715a37db4 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -147,7 +147,6 @@ private: float computeMotorTimescale(); void applyMotor(float deltaTime); void applyThrust(float deltaTime); - void updateHandMovementAndTouching(float deltaTime); void updateCollisionWithAvatars(float deltaTime); void updateCollisionWithEnvironment(float deltaTime, float radius); void updateCollisionWithVoxels(float deltaTime, float radius); From 2c6c57eec2875823fadd14c0f5d4028ce26bc17d Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 8 May 2014 00:28:02 -0700 Subject: [PATCH 40/43] increase hand restoration rate, improve function name clarity --- interface/src/avatar/MyAvatar.cpp | 4 ++-- interface/src/avatar/MyAvatar.h | 2 +- interface/src/avatar/SkeletonModel.cpp | 9 ++++----- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 2f931b0a54..c3591862d1 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -109,7 +109,7 @@ void MyAvatar::reset() { void MyAvatar::update(float deltaTime) { Head* head = getHead(); head->relaxLean(deltaTime); - updateFromGyros(deltaTime); + updateFromFaceTracker(deltaTime); if (Menu::getInstance()->isOptionChecked(MenuOption::MoveWithLean)) { // Faceshift drive is enabled, set the avatar drive based on the head position moveWithLean(); @@ -239,7 +239,7 @@ void MyAvatar::simulate(float deltaTime) { } // Update avatar head rotation with sensor data -void MyAvatar::updateFromGyros(float deltaTime) { +void MyAvatar::updateFromFaceTracker(float deltaTime) { glm::vec3 estimatedPosition, estimatedRotation; FaceTracker* tracker = Application::getInstance()->getActiveFaceTracker(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f715a37db4..c07c27033c 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -38,7 +38,7 @@ public: void reset(); void update(float deltaTime); void simulate(float deltaTime); - void updateFromGyros(float deltaTime); + void updateFromFaceTracker(float deltaTime); void moveWithLean(); void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index e4c796d3ce..8c21a3240f 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -38,24 +38,23 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { Hand* hand = _owningAvatar->getHand(); hand->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex); - const float HAND_RESTORATION_PERIOD = 1.f; // seconds - float handRestorePercent = glm::clamp(deltaTime / HAND_RESTORATION_PERIOD, 0.f, 1.f); + const float HAND_RESTORATION_RATE = 0.25f; const FBXGeometry& geometry = _geometry->getFBXGeometry(); if (leftPalmIndex == -1) { // no Leap data; set hands from mouse if (_owningAvatar->getHandState() == HAND_STATE_NULL) { - restoreRightHandPosition(handRestorePercent); + restoreRightHandPosition(HAND_RESTORATION_RATE); } else { applyHandPosition(geometry.rightHandJointIndex, _owningAvatar->getHandPosition()); } - restoreLeftHandPosition(handRestorePercent); + restoreLeftHandPosition(HAND_RESTORATION_RATE); } else if (leftPalmIndex == rightPalmIndex) { // right hand only applyPalmData(geometry.rightHandJointIndex, geometry.rightFingerJointIndices, geometry.rightFingertipJointIndices, hand->getPalms()[leftPalmIndex]); - restoreLeftHandPosition(handRestorePercent); + restoreLeftHandPosition(HAND_RESTORATION_RATE); } else { applyPalmData(geometry.leftHandJointIndex, geometry.leftFingerJointIndices, geometry.leftFingertipJointIndices, From 4185faa82ad72aa632baacee17e40ab652f9f1a1 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 8 May 2014 01:06:26 -0700 Subject: [PATCH 41/43] Tweaks to improve mouth and brow appearance when just audio driven --- interface/src/avatar/Head.cpp | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 9cb8ea3d9c..ce02bb8e55 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -106,15 +106,10 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { const float BROW_LIFT_THRESHOLD = 100.0f; if (_audioAttack > BROW_LIFT_THRESHOLD) { - _browAudioLift += sqrtf(_audioAttack) * 0.00005f; + _browAudioLift += sqrtf(_audioAttack) * 0.01f; } - - const float CLAMP = 0.01f; - if (_browAudioLift > CLAMP) { - _browAudioLift = CLAMP; - } - - _browAudioLift *= 0.7f; + _browAudioLift = glm::clamp(_browAudioLift *= 0.7f, 0.0f, 1.0f); + qDebug() << _browAudioLift; const float BLINK_SPEED = 10.0f; const float FULLY_OPEN = 0.0f; @@ -147,12 +142,12 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { } // use data to update fake Faceshift blendshape coefficients - const float BROW_LIFT_SCALE = 500.0f; - const float JAW_OPEN_SCALE = 0.01f; - const float JAW_OPEN_DEAD_ZONE = 0.75f; - Application::getInstance()->getFaceshift()->updateFakeCoefficients(_leftEyeBlink, _rightEyeBlink, - min(1.0f, _browAudioLift * BROW_LIFT_SCALE), glm::clamp(sqrt(_averageLoudness * JAW_OPEN_SCALE) - - JAW_OPEN_DEAD_ZONE, 0.0f, 1.0f), _blendshapeCoefficients); + const float JAW_OPEN_SCALE = 10.f; + Application::getInstance()->getFaceshift()->updateFakeCoefficients(_leftEyeBlink, + _rightEyeBlink, + _browAudioLift, + glm::clamp(log(_averageLoudness) / JAW_OPEN_SCALE, 0.0f, 1.0f), + _blendshapeCoefficients); } if (!isMine) { From 71789b65e71bd5c2f836ab0a7e6a7221d6b1f603 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 8 May 2014 11:02:35 -0700 Subject: [PATCH 42/43] remove debug --- interface/src/avatar/Head.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index ce02bb8e55..2d0599b31f 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -109,8 +109,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { _browAudioLift += sqrtf(_audioAttack) * 0.01f; } _browAudioLift = glm::clamp(_browAudioLift *= 0.7f, 0.0f, 1.0f); - qDebug() << _browAudioLift; - + const float BLINK_SPEED = 10.0f; const float FULLY_OPEN = 0.0f; const float FULLY_CLOSED = 1.0f; From a8a53e35dd4762e7567aa9d27d68706ca235fbbc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 8 May 2014 11:12:16 -0700 Subject: [PATCH 43/43] make sure shouldStop for injector defaults to false --- libraries/audio/src/AudioInjector.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 364d14cfbb..1fe9f1336f 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -22,14 +22,18 @@ #include "AudioInjector.h" AudioInjector::AudioInjector(QObject* parent) : - QObject(parent) + QObject(parent), + _sound(NULL), + _options(), + _shouldStop(false) { } AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions) : _sound(sound), - _options(injectorOptions) + _options(injectorOptions), + _shouldStop(false) { }