From 874b542c0cd5797301a6b6668b35696f534fb662 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Jul 2014 04:13:53 -0700 Subject: [PATCH 001/407] Add import/export/paste model functionality to editModels.js --- examples/editModels.js | 427 +++++++++++++++++- interface/src/Application.cpp | 38 ++ interface/src/Application.h | 5 + .../scripting/ClipboardScriptingInterface.cpp | 13 + .../scripting/ClipboardScriptingInterface.h | 4 + .../scripting/WindowScriptingInterface.cpp | 24 +- .../src/scripting/WindowScriptingInterface.h | 4 +- 7 files changed, 510 insertions(+), 5 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 64c203534c..6cde543e55 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -61,6 +61,398 @@ var jointList = MyAvatar.getJointNames(); var mode = 0; +var exportMenu = null; + +var ExportMenu = function(opts) { + var self = this; + + var windowDimensions = Controller.getViewportDimensions(); + var pos = { x: windowDimensions.x / 2, y: windowDimensions.y - 100 }; + + this._onClose = opts.onClose || function() {}; + this._position = { x: 0.0, y: 0.0, z: 0.0 }; + this._scale = 1.0; + + var minScale = 1; + var maxScale = 32768; + var titleWidth = 120; + var locationWidth = 100; + var scaleWidth = 144; + var exportWidth = 100; + var cancelWidth = 100; + var margin = 4; + var height = 30; + var outerHeight = height + (2 * margin); + var buttonColor = { red: 128, green: 128, blue: 128}; + + var SCALE_MINUS = scaleWidth * 40.0 / 100.0; + var SCALE_PLUS = scaleWidth * 63.0 / 100.0; + + var fullWidth = locationWidth + scaleWidth + exportWidth + cancelWidth + (2 * margin); + var offset = fullWidth / 2; + pos.x -= offset; + + var background= Overlays.addOverlay("text", { + x: pos.x, + y: pos.y, + opacity: 1, + width: fullWidth, + height: outerHeight, + backgroundColor: { red: 200, green: 200, blue: 200 }, + text: "", + }); + + var titleText = Overlays.addOverlay("text", { + x: pos.x, + y: pos.y - height, + font: { size: 14 }, + width: titleWidth, + height: height, + backgroundColor: { red: 255, green: 255, blue: 255 }, + color: { red: 255, green: 255, blue: 255 }, + text: "Export Models" + }); + + var locationButton = Overlays.addOverlay("text", { + x: pos.x + margin, + y: pos.y + margin, + width: locationWidth, + height: height, + color: { red: 255, green: 255, blue: 255 }, + text: "0, 0, 0", + }); + var scaleOverlay = Overlays.addOverlay("image", { + x: pos.x + margin + locationWidth, + y: pos.y + margin, + width: scaleWidth, + height: height, + subImage: { x: 0, y: 3, width: 144, height: height}, + imageURL: toolIconUrl + "voxel-size-selector.svg", + alpha: 0.9, + }); + var scaleViewWidth = 40; + var scaleView = Overlays.addOverlay("text", { + x: pos.x + margin + locationWidth + SCALE_MINUS, + y: pos.y + margin, + width: scaleViewWidth, + height: height, + alpha: 0.0, + color: { red: 255, green: 255, blue: 255 }, + text: "1" + }); + var exportButton = Overlays.addOverlay("text", { + x: pos.x + margin + locationWidth + scaleWidth, + y: pos.y + margin, + width: exportWidth, + height: height, + color: { red: 0, green: 255, blue: 255 }, + text: "Export" + }); + var cancelButton = Overlays.addOverlay("text", { + x: pos.x + margin + locationWidth + scaleWidth + exportWidth, + y: pos.y + margin, + width: cancelWidth, + height: height, + color: { red: 255, green: 255, blue: 255 }, + text: "Cancel" + }); + + var voxelPreview = Overlays.addOverlay("cube", { + position: { x: 0, y: 0, z: 0}, + size: this._scale, + color: { red: 255, green: 255, blue: 0}, + alpha: 1, + solid: false, + visible: true, + lineWidth: 4 + }); + + this.parsePosition = function(str) { + var parts = str.split(','); + if (parts.length == 3) { + var x = parseFloat(parts[0]); + var y = parseFloat(parts[1]); + var z = parseFloat(parts[2]); + if (isFinite(x) && isFinite(y) && isFinite(z)) { + return { x: x, y: y, z: z }; + } + } + return null; + }; + + this.showPositionPrompt = function() { + var positionStr = self._position.x + ", " + self._position.y + ", " + self._position.z; + while (1) { + positionStr = Window.prompt("Position to export form:", positionStr); + if (positionStr == null) { + break; + } + print("position: " + position); + var position = self.parsePosition(positionStr); + if (position != null) { + self.setPosition(position.x, position.y, position.z); + break; + } + Window.alert("The position you entered was invalid."); + } + }; + + this.setScale = function(scale) { + self._scale = Math.min(maxScale, Math.max(minScale, scale)); + Overlays.editOverlay(scaleView, { text: self._scale }); + Overlays.editOverlay(voxelPreview, { size: self._scale }); + } + + this.decreaseScale = function() { + self.setScale(self._scale /= 2); + } + + this.increaseScale = function() { + self.setScale(self._scale *= 2); + } + + this.exportModels = function() { + var x = self._position.x; + var y = self._position.y; + var z = self._position.z; + var s = self._scale; + var filename = "models__" + Window.location.hostname + "__" + x + "_" + y + "_" + z + "_" + s + "__.svo"; + filename = Window.save("Select where to save", filename, "*.svo") + Clipboard.exportModels(filename, x, y, z, s); + self.close(); + }; + + this.getPosition = function() { + return self._position; + }; + + this.setPosition = function(x, y, z) { + self._position = { x: x, y: y, z: z }; + var positionStr = x + ", " + y + ", " + z; + Overlays.editOverlay(locationButton, { text: positionStr }); + Overlays.editOverlay(voxelPreview, { position: self._position }); + + }; + + this.mousePressEvent = function(event) { + print("Mouse press"); + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + }; + + this.mouseReleaseEvent = function(event) { + print("Mouse release"); + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + + if (clickedOverlay == locationButton) { + self.showPositionPrompt(); + } else if (clickedOverlay == exportButton) { + self.exportModels(); + } else if (clickedOverlay == cancelButton) { + self.close(); + } else if (clickedOverlay == scaleOverlay) { + var x = event.x - pos.x - margin - locationWidth; + print(x); + if (x < SCALE_MINUS) { + self.decreaseScale(); + } else if (x > SCALE_PLUS) { + self.increaseScale(); + } + } + }; + + this.close = function() { + this.cleanup(); + this._onClose(); + }; + + this.cleanup = function() { + Overlays.deleteOverlay(background); + Overlays.deleteOverlay(titleText); + Overlays.deleteOverlay(locationButton); + Overlays.deleteOverlay(exportButton); + Overlays.deleteOverlay(cancelButton); + Overlays.deleteOverlay(voxelPreview); + Overlays.deleteOverlay(scaleOverlay); + Overlays.deleteOverlay(scaleView); + }; + + print("CONNECTING!"); + Controller.mousePressEvent.connect(this.mousePressEvent); + Controller.mouseReleaseEvent.connect(this.mouseReleaseEvent); +}; + +var ModelImporter = function(opts) { + var self = this; + + var height = 30; + var margin = 4; + var outerHeight = height + (2 * margin); + var titleWidth = 120; + var cancelWidth = 100; + var fullWidth = titleWidth + cancelWidth + (2 * margin); + + // TODO: Show import preview + var importBoundaries = Overlays.addOverlay("cube", { + position: { x: 0, y: 0, z: 0 }, + size: 1, + color: { red: 128, blue: 128, green: 128 }, + lineWidth: 4, + solid: false, + visible: false + }); + + var pos = { x: windowDimensions.x / 2 - (fullWidth / 2), y: windowDimensions.y - 100 }; + + var background= Overlays.addOverlay("text", { + x: pos.x, + y: pos.y, + opacity: 1, + width: fullWidth, + height: outerHeight, + backgroundColor: { red: 200, green: 200, blue: 200 }, + visible: false, + text: "", + }); + + var titleText = Overlays.addOverlay("text", { + x: pos.x + margin, + y: pos.y + margin, + font: { size: 14 }, + width: titleWidth, + height: height, + backgroundColor: { red: 255, green: 255, blue: 255 }, + color: { red: 255, green: 255, blue: 255 }, + visible: false, + text: "Import Models" + }); + var cancelButton = Overlays.addOverlay("text", { + x: pos.x + margin + titleWidth, + y: pos.y + margin, + width: cancelWidth, + height: height, + color: { red: 255, green: 255, blue: 255 }, + visible: false, + text: "Cancel" + }); + this._importing = false; + + this.setImportVisible = function(visible) { + Overlays.editOverlay(importBoundaries, { visible: visible }); + Overlays.editOverlay(cancelButton, { visible: visible }); + Overlays.editOverlay(titleText, { visible: visible }); + Overlays.editOverlay(background, { visible: visible }); + }; + + var importPosition = { x: 0, y: 0, z: 0 }; + this.moveImport = function(position) { + importPosition = position; + // TODO: Show import preview + Overlays.editOverlay(importBoundaries, { + position: { x: importPosition.x, y: importPosition.y, z: importPosition.z } + }); + } + + this.mouseMoveEvent = function(event) { + if (self._importing) { + var pickRay = Camera.computePickRay(event.x, event.y); + var intersection = Voxels.findRayIntersection(pickRay); + + var distance = 2;// * self._scale; + + if (false) {//intersection.intersects) { + var intersectionDistance = Vec3.length(Vec3.subtract(pickRay.origin, intersection.intersection)); + if (intersectionDistance < distance) { + distance = intersectionDistance * 0.99; + } + + } + + var targetPosition = { + x: pickRay.origin.x + (pickRay.direction.x * distance), + y: pickRay.origin.y + (pickRay.direction.y * distance), + z: pickRay.origin.z + (pickRay.direction.z * distance) + }; + + if (targetPosition.x < 0) targetPosition.x = 0; + if (targetPosition.y < 0) targetPosition.y = 0; + if (targetPosition.z < 0) targetPosition.z = 0; + + var nudgeFactor = 1; + var newPosition = { + x: Math.floor(targetPosition.x / nudgeFactor) * nudgeFactor, + y: Math.floor(targetPosition.y / nudgeFactor) * nudgeFactor, + z: Math.floor(targetPosition.z / nudgeFactor) * nudgeFactor + } + + self.moveImport(newPosition); + } + } + + this.mouseReleaseEvent = function(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + + if (clickedOverlay == cancelButton) { + self._importing = false; + self.setImportVisible(false); + } + }; + + // Would prefer to use {4} for the coords, but it would only capture the last digit. + var fileRegex = /__(.+)__(\d+(?:\.\d+)?)_(\d+(?:\.\d+)?)_(\d+(?:\.\d+)?)_(\d+(?:\.\d+)?)__/; + this.doImport = function() { + print("IMPORTING "); + if (!self._importing) { + var filename = Window.browse("Select models to import", "", "*.svo") + if (filename) { + parts = fileRegex.exec(filename); + if (parts == null) { + Window.alert("The file you selected does not contain source domain or location information"); + } else { + var hostname = parts[1]; + var x = parts[2]; + var y = parts[3]; + var z = parts[4]; + var s = parts[5]; + if (hostname != location.hostname) { + if (!Window.confirm(("These models were not originally exported from this domain. Continue?"))) { + return; + } + } else { + if (Window.confirm(("Would you like to import back to the source location?"))) { + Window.alert("(TODO) Importing backing to source location"); + Clipboard.importModels(filename); + return; + } + } + } + Clipboard.importModels(filename); + self._importing = true; + self.setImportVisible(true); + } + } + } + + this.paste = function() { + if (self._importing) { + self._importing = false; + self.setImportVisible(false); + Clipboard.pasteModels(); + } + } + + this.cleanup = function() { + Overlays.deleteOverlay(importBoundaries); + Overlays.deleteOverlay(cancelButton); + Overlays.deleteOverlay(titleText); + Overlays.deleteOverlay(background); + } + + Controller.mouseReleaseEvent.connect(this.mouseReleaseEvent); + Controller.mouseMoveEvent.connect(this.mouseMoveEvent); +}; + +var modelImporter = new ModelImporter(); + function isLocked(properties) { // special case to lock the ground plane model in hq. if (location.hostname == "hq.highfidelity.io" && @@ -1045,7 +1437,7 @@ function mouseReleaseEvent(event) { var modelMenuAddedDelete = false; function setupModelMenus() { print("setupModelMenus()"); - // add our menuitems + // adj our menuitems Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Edit Properties...", shortcutKeyEvent: { text: "`" }, afterItem: "Models" }); @@ -1057,6 +1449,12 @@ function setupModelMenus() { } else { print("delete exists... don't add ours"); } + + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." }); + + Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" }); + Menu.addMenuItem({ menuName: "File", menuItemName: "Export Models", shortcutKey: "CTRL+META+E", afterItem: "Models" }); + Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" }); } function cleanupModelMenus() { @@ -1066,6 +1464,12 @@ function cleanupModelMenus() { // delete our menuitems Menu.removeMenuItem("Edit", "Delete"); } + + Menu.removeMenuItem("Edit", "Paste Models"); + + Menu.removeSeparator("File", "Models"); + Menu.removeMenuItem("File", "Export Models"); + Menu.removeMenuItem("File", "Import Models"); } function scriptEnding() { @@ -1074,6 +1478,10 @@ function scriptEnding() { toolBar.cleanup(); cleanupModelMenus(); tooltip.cleanup(); + modelImporter.cleanup(); + if (exportMenu) { + exportMenu.close(); + } } Script.scriptEnding.connect(scriptEnding); @@ -1128,6 +1536,21 @@ function handeMenuEvent(menuItem){ Models.editModel(editModelID, properties); } } + } else if (menuItem == "Paste Models") { + modelImporter.paste(); + } else if (menuItem == "Export Models") { + if (!exportMenu) { + // if (modelImporter) { + // modelImporter.close(); + // } + exportMenu = new ExportMenu({ + onClose: function() { + exportMenu = null; + } + }); + } + } else if (menuItem == "Import Models") { + modelImporter.doImport(); } tooltip.show(false); } @@ -1173,4 +1596,4 @@ Controller.keyReleaseEvent.connect(function(event) { if (event.text == "BACKSPACE") { handeMenuEvent("Delete"); } -}); \ No newline at end of file +}); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3e121bc2ee..2c097318e4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -141,6 +141,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _voxelImporter(NULL), _importSucceded(false), _sharedVoxelSystem(TREE_SCALE, DEFAULT_MAX_VOXELS_PER_SYSTEM, &_clipboard), + _modelClipboardRenderer(), + _modelClipboard(), _wantToKillLocalVoxels(false), _viewFrustum(), _lastQueriedViewFrustum(), @@ -1483,6 +1485,21 @@ struct SendVoxelsOperationArgs { const unsigned char* newBaseOctCode; }; +void Application::exportModels(const QString& filename, float x, float y, float z, float scale) { + ModelTreeElement* selectedNode = _models.getTree()->getModelAt(x, y, z, scale); + if (selectedNode) { + qDebug() << "Exporting models doing it!" << filename; + ModelTree exportTree; + _models.getTree()->copySubTreeIntoNewTree(selectedNode, &exportTree, true); + exportTree.writeToSVOFile(filename.toLocal8Bit().constData()); + } else { + qDebug() << "No models were selected"; + } + + // restore the main window's active state + _window->activateWindow(); +} + bool Application::sendVoxelsOperation(OctreeElement* element, void* extraData) { VoxelTreeElement* voxel = (VoxelTreeElement*)element; SendVoxelsOperationArgs* args = (SendVoxelsOperationArgs*)extraData; @@ -1564,6 +1581,20 @@ void Application::importVoxels() { emit importDone(); } +void Application::importModels(const QString& filename) { + _importSucceded = false; + + + _models.getTree()->readFromSVOFile(filename.toLocal8Bit().constData()); + _models.getTree()->reaverageOctreeElements(); + + + // restore the main window's active state + _window->activateWindow(); + + emit importDone(); +} + void Application::cutVoxels(const VoxelDetail& sourceVoxel) { copyVoxels(sourceVoxel); deleteVoxelAt(sourceVoxel); @@ -1719,6 +1750,10 @@ void Application::init() { _models.init(); _models.setViewFrustum(getViewFrustum()); + _modelClipboardRenderer.init(); + _modelClipboardRenderer.setViewFrustum(getViewFrustum()); + _modelClipboardRenderer.setTree(&_modelClipboard); + _metavoxels.init(); _particleCollisionSystem.init(&_particleEditSender, _particles.getTree(), _voxels.getTree(), &_audio, &_avatarManager); @@ -2083,6 +2118,7 @@ void Application::update(float deltaTime) { { PerformanceTimer perfTimer("idle/update/_models"); _models.update(); // update the models... + _modelClipboardRenderer.update(); } { @@ -2566,6 +2602,7 @@ void Application::updateShadowMap() { _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); _particles.render(OctreeRenderer::SHADOW_RENDER_MODE); _models.render(OctreeRenderer::SHADOW_RENDER_MODE); + _modelClipboardRenderer.render(OctreeRenderer::SHADOW_RENDER_MODE); glDisable(GL_POLYGON_OFFSET_FILL); @@ -2767,6 +2804,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... models..."); _models.render(); + _modelClipboardRenderer.render(); } // render the ambient occlusion effect if enabled diff --git a/interface/src/Application.h b/interface/src/Application.h index 11f406abf0..c2f21f3738 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -308,6 +308,9 @@ public slots: void nodeKilled(SharedNodePointer node); void packetSent(quint64 length); + void exportModels(const QString& filename, float x, float y, float z, float scale); + void importModels(const QString& filename); + void importVoxels(); // doesn't include source voxel because it goes to clipboard void cutVoxels(const VoxelDetail& sourceVoxel); void copyVoxels(const VoxelDetail& sourceVoxel); @@ -452,6 +455,8 @@ private: ParticleCollisionSystem _particleCollisionSystem; ModelTreeRenderer _models; + ModelTreeRenderer _modelClipboardRenderer; + ModelTree _modelClipboard; QByteArray _voxelsFilename; bool _wantToKillLocalVoxels; diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp index e8fb545343..39b5db9418 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.cpp +++ b/interface/src/scripting/ClipboardScriptingInterface.cpp @@ -100,3 +100,16 @@ void ClipboardScriptingInterface::nudgeVoxel(float x, float y, float z, float s, Application::getInstance()->nudgeVoxelsByVector(sourceVoxel, nudgeVecInTreeSpace); } + + +void ClipboardScriptingInterface::exportModels(const QString& filename, float x, float y, float z, float s) { + Application::getInstance()->exportModels(filename, x / TREE_SCALE, y / TREE_SCALE, z / TREE_SCALE, s / TREE_SCALE); +} + +void ClipboardScriptingInterface::importModels(const QString& filename) { + Application::getInstance()->importModels(filename); +} + +void ClipboardScriptingInterface::pasteModels() { + // TODO +} diff --git a/interface/src/scripting/ClipboardScriptingInterface.h b/interface/src/scripting/ClipboardScriptingInterface.h index f0258b0cc7..2ff287b29f 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.h +++ b/interface/src/scripting/ClipboardScriptingInterface.h @@ -42,6 +42,10 @@ public slots: void nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec); void nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec); + + void importModels(const QString& filename); + void exportModels(const QString& filename, float x, float y, float z, float s); + void pasteModels(); }; #endif // hifi_ClipboardScriptingInterface_h diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index e10197d488..84ccdc9d7e 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -53,6 +53,15 @@ QScriptValue WindowScriptingInterface::browse(const QString& title, const QStrin return retVal; } +QScriptValue WindowScriptingInterface::save(const QString& title, const QString& directory, const QString& nameFilter) { + QScriptValue retVal; + QMetaObject::invokeMethod(this, "showBrowse", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QScriptValue, retVal), + Q_ARG(const QString&, title), Q_ARG(const QString&, directory), Q_ARG(const QString&, nameFilter), + Q_ARG(QFileDialog::AcceptMode, QFileDialog::AcceptSave)); + return retVal; +} + /// Display an alert box /// \param const QString& message message to display /// \return QScriptValue::UndefinedValue @@ -93,18 +102,29 @@ QScriptValue WindowScriptingInterface::showPrompt(const QString& message, const /// \param const QString& directory directory to start the file browser at /// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog` /// \return QScriptValue file path as a string if one was selected, otherwise `QScriptValue::NullValue` -QScriptValue WindowScriptingInterface::showBrowse(const QString& title, const QString& directory, const QString& nameFilter) { +QScriptValue WindowScriptingInterface::showBrowse(const QString& title, const QString& directory, const QString& nameFilter, + QFileDialog::AcceptMode acceptMode) { // On OS X `directory` does not work as expected unless a file is included in the path, so we append a bogus // filename if the directory is valid. QString path = ""; QFileInfo fileInfo = QFileInfo(directory); + qDebug() << "File: " << directory << fileInfo.isFile(); if (fileInfo.isDir()) { fileInfo.setFile(directory, "__HIFI_INVALID_FILE__"); path = fileInfo.filePath(); } QFileDialog fileDialog(Application::getInstance()->getWindow(), title, path, nameFilter); - fileDialog.setFileMode(QFileDialog::ExistingFile); + // fileDialog.setFileMode(QFileDialog::ExistingFile); + fileDialog.setAcceptMode(acceptMode); + qDebug() << "Opening!"; + QUrl fileUrl(directory); + if (acceptMode == QFileDialog::AcceptSave) { + fileDialog.setFileMode(QFileDialog::Directory); + fileDialog.selectFile(fileUrl.fileName()); + // qDebug() << "Setting filename!"; + // fileDialog.setLabelText(QFileDialog::FileName, fileUrl.fileName()); + } if (fileDialog.exec()) { return QScriptValue(fileDialog.selectedFiles().first()); } diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index b97113af9c..3fb0974b4f 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -31,12 +31,14 @@ public slots: QScriptValue confirm(const QString& message = ""); QScriptValue prompt(const QString& message = "", const QString& defaultText = ""); QScriptValue browse(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); + QScriptValue save(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); private slots: QScriptValue showAlert(const QString& message); QScriptValue showConfirm(const QString& message); QScriptValue showPrompt(const QString& message, const QString& defaultText); - QScriptValue showBrowse(const QString& title, const QString& directory, const QString& nameFilter); + QScriptValue showBrowse(const QString& title, const QString& directory, const QString& nameFilter, + QFileDialog::AcceptMode acceptMode = QFileDialog::AcceptOpen); }; #endif // hifi_WindowScriptingInterface_h From ade1903595c1be26ea15d5b99a9bb475c2dfca66 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Jul 2014 04:14:47 -0700 Subject: [PATCH 002/407] Add ModelTree::getModelAt --- libraries/models/src/ModelTree.cpp | 5 +++++ libraries/models/src/ModelTree.h | 1 + 2 files changed, 6 insertions(+) diff --git a/libraries/models/src/ModelTree.cpp b/libraries/models/src/ModelTree.cpp index 763f0a969e..1489f4db19 100644 --- a/libraries/models/src/ModelTree.cpp +++ b/libraries/models/src/ModelTree.cpp @@ -108,6 +108,11 @@ bool FindAndUpdateModelOperator::PostRecursion(OctreeElement* element) { return !_found; // if we haven't yet found it, keep looking } + +ModelTreeElement* ModelTree::getModelAt(float x, float y, float z, float s) const { + return static_cast(getOctreeElementAt(x, y, z, s)); +} + // TODO: improve this to not use multiple recursions void ModelTree::storeModel(const ModelItem& model, const SharedNodePointer& senderNode) { // First, look for the existing model in the tree.. diff --git a/libraries/models/src/ModelTree.h b/libraries/models/src/ModelTree.h index a2a3c9cd28..9ab081f46c 100644 --- a/libraries/models/src/ModelTree.h +++ b/libraries/models/src/ModelTree.h @@ -36,6 +36,7 @@ public: /// Type safe version of getRoot() ModelTreeElement* getRoot() { return static_cast(_rootElement); } + ModelTreeElement* getModelAt(float x, float y, float z, float s) const; // These methods will allow the OctreeServer to send your tree inbound edit packets of your // own definition. Implement these to allow your octree based server to support editing From 2fea3c58cdc99249dee7cfbd0eacbc6a9a64555e Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Thu, 17 Jul 2014 15:25:54 -0700 Subject: [PATCH 003/407] Added working rockPaperScissors.js that works for multiple ACs --- examples/rockPaperScissorsCells.js | 225 +++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 examples/rockPaperScissorsCells.js diff --git a/examples/rockPaperScissorsCells.js b/examples/rockPaperScissorsCells.js new file mode 100644 index 0000000000..9227278455 --- /dev/null +++ b/examples/rockPaperScissorsCells.js @@ -0,0 +1,225 @@ +// rockPaperScissorsCells.js +// examples +// +// Created by Ben Arnold on 7/16/14. +// Copyright 2014 High Fidelity, Inc. +// +// This sample script creates a voxel wall that simulates the Rock Paper Scissors cellular +// automata. http://www.gamedev.net/blog/844/entry-2249737-another-cellular-automaton-video/ +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var NUMBER_OF_CELLS_EACH_DIMENSION = 64; +var NUMBER_OF_CELLS_REGION_EACH_DIMESION = 16; +var REGIONS_EACH_DIMENSION = NUMBER_OF_CELLS_EACH_DIMENSION / NUMBER_OF_CELLS_REGION_EACH_DIMESION; + +var currentCells = []; +var nextCells = []; + +var cornerPosition = {x: 100, y: 0, z: 0 } +var position = {x: 0, y: 0, z: 0 }; + +var METER_LENGTH = 1; +var cellScale = (NUMBER_OF_CELLS_EACH_DIMENSION * METER_LENGTH) / NUMBER_OF_CELLS_EACH_DIMENSION; + +//Feel free to add new cell types here. It can be more than three. +var cellTypes = []; +cellTypes[0] = { r: 255, g: 0, b: 0 }; +cellTypes[1] = { r: 0, g: 255, b: 0 }; +cellTypes[2] = { r: 0, g:0, b: 255 }; +cellTypes[3] = { r: 255, g: 255, b: 255 }; +cellTypes[4] = { r: 255, g: 0, b: 255 }; +cellTypes[5] = { r: 0, g: 255, b: 255 }; + +//Check for free region for AC +var regionMarkerX = -1; +var regionMarkerY = -1; +var regionMarkerI = -1; +var regionMarkerJ = -1; + +var regionMarkerColor = {r: 255, g: 0, b: 255}; + +for (var i = 0; i < REGIONS_EACH_DIMENSION; i++) { + for (var j = 0; j < REGIONS_EACH_DIMENSION; j++) { + var x = cornerPosition.x + (j) * cellScale; + var y = cornerPosition.y + (i + NUMBER_OF_CELLS_EACH_DIMENSION) * cellScale; + var z = cornerPosition.z; + var voxel = Voxels.getVoxelAt(x, y, z, cellScale); + if (voxel.x != x || voxel.y != y || voxel.z != z || voxel.s != cellScale || + voxel.red != regionMarkerColor.r || voxel.green != regionMarkerColor.g || voxel.blue != regionMarkerColor.b) { + regionMarkerX = x; + regionMarkerY = y; + regionMarkerI = i; + regionMarkerJ = j; + i = REGIONS_EACH_DIMENSION; //force quit loop + break; + } + } +} + +if (regionMarkerX == -1) { + print("No available Cellular Automata regions found!") + Script.stop(); +} + +position.x = cornerPosition.x + regionMarkerJ * NUMBER_OF_CELLS_REGION_EACH_DIMESION * cellScale; +position.y = cornerPosition.y + regionMarkerI * NUMBER_OF_CELLS_REGION_EACH_DIMESION * cellScale; +position.z = cornerPosition.z; + +Voxels.setVoxel(regionMarkerX, regionMarkerY, position.z, cellScale, regionMarkerColor.r, regionMarkerColor.g, regionMarkerColor.b); + +// randomly populate the cell start values +for (var i = 0; i < NUMBER_OF_CELLS_REGION_EACH_DIMESION; i++) { + // create the array to hold this row + currentCells[i] = []; + + // create the array to hold this row in the nextCells array + nextCells[i] = []; + + for (var j = 0; j < NUMBER_OF_CELLS_REGION_EACH_DIMESION; j++) { + currentCells[i][j] = { changed: true, type: Math.floor(Math.random() * cellTypes.length) }; + + // put the same value in the nextCells array for first board draw + nextCells[i][j] = currentCells[i][j]; + } +} + +function updateCells() { + var i = 0; + var j = 0; + var cell; + var y = 0; + var x = 0; + + for (i = 0; i < NUMBER_OF_CELLS_REGION_EACH_DIMESION; i++) { + for (j = 0; j < NUMBER_OF_CELLS_REGION_EACH_DIMESION; j++) { + + cell = currentCells[i][j]; + + var r = Math.floor(Math.random() * 8); + + switch (r){ + case 0: + y = i - 1; + x = j - 1; + break; + case 1: + y = i; + x = j-1; + break; + case 2: + y = i + 1; + x = j - 1; + break; + case 3: + y = i + 1; + x = j; + break; + case 4: + y = i + 1; + x = j + 1; + break; + case 5: + y = i; + x = j + 1; + break; + case 6: + y = i - 1; + x = j + 1; + break; + case 7: + y = i - 1; + x = j; + break; + default: + continue; + + } + + //check the voxel grid instead of local array when on the edge + if (x == -1 || x == NUMBER_OF_CELLS_REGION_EACH_DIMESION || + y == -1 || y == NUMBER_OF_CELLS_REGION_EACH_DIMESION) { + + var voxel = Voxels.getVoxelAt(position.x + x * cellScale, position.y + y * cellScale, position.z, cellScale); + var predatorCellType = ((cell.type + 1) % cellTypes.length); + var predatorCellColor = cellTypes[predatorCellType]; + if (voxel.red == predatorCellColor.r && voxel.green == predatorCellColor.g && voxel.blue == predatorCellColor.b) { + nextCells[i][j].type = predatorCellType; + nextCells[i][j].changed = true; + } + } else { + + if (currentCells[y][x].type == ((cell.type + 1) % cellTypes.length)) { + nextCells[i][j] = currentCells[y][x]; + nextCells[i][j].changed = true; + } else { + //indicate no update + nextCells[i][j].changed = true; + } + } + } + } + + for (i = 0; i < NUMBER_OF_CELLS_REGION_EACH_DIMESION; i++) { + for (j = 0; j < NUMBER_OF_CELLS_REGION_EACH_DIMESION; j++) { + if (nextCells[i][j].changed == true) { + // there has been a change to this cell, change the value in the currentCells array + currentCells[i][j] = nextCells[i][j]; + } + } + } +} + +function sendNextCells() { + for (var i = 0; i < NUMBER_OF_CELLS_REGION_EACH_DIMESION; i++) { + for (var j = 0; j < NUMBER_OF_CELLS_REGION_EACH_DIMESION; j++) { + if (nextCells[i][j].changed == true) { + // there has been a change to the state of this cell, send it + + // find the x and y position for this voxel, z = 0 + var x = j * cellScale; + var y = i * cellScale; + var type = nextCells[i][j].type; + + // queue a packet to add a voxel for the new cell + Voxels.setVoxel(position.x + x, position.y + y, position.z, cellScale, cellTypes[type].r, cellTypes[type].g, cellTypes[type].b); + } + } + } +} + +var sentFirstBoard = false; + +var UPDATES_PER_SECOND = 3.0; +var frameIndex = 1.0; +var oldFrameIndex = 0; + +function step(deltaTime) { + frameIndex += deltaTime * UPDATES_PER_SECOND; + if (Math.floor(frameIndex) == oldFrameIndex) { + return; + } + oldFrameIndex++; + + if (sentFirstBoard) { + // we've already sent the first full board, perform a step in time + updateCells(); + } else { + // this will be our first board send + sentFirstBoard = true; + } + + sendNextCells(); +} + +function scriptEnding() { + Voxels.eraseVoxel(regionMarkerX, regionMarkerY, position.z, cellScale); +} + +Script.scriptEnding.connect(scriptEnding); + +Script.update.connect(step); +//Voxels.setMaxPacketSize(1); //this is needed or a bug occurs :( +Voxels.setPacketsPerSecond(2000); From 592c571fcb6d3c9d71916dd4fd3d82c3c2fdc8a2 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Thu, 17 Jul 2014 18:15:34 -0700 Subject: [PATCH 004/407] Fixed crash bug in voxelScriptingInterface --- examples/rockPaperScissorsCells.js | 10 ++++------ libraries/voxels/src/VoxelsScriptingInterface.cpp | 6 ++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/examples/rockPaperScissorsCells.js b/examples/rockPaperScissorsCells.js index 9227278455..4f6de888a1 100644 --- a/examples/rockPaperScissorsCells.js +++ b/examples/rockPaperScissorsCells.js @@ -29,9 +29,7 @@ var cellTypes = []; cellTypes[0] = { r: 255, g: 0, b: 0 }; cellTypes[1] = { r: 0, g: 255, b: 0 }; cellTypes[2] = { r: 0, g:0, b: 255 }; -cellTypes[3] = { r: 255, g: 255, b: 255 }; -cellTypes[4] = { r: 255, g: 0, b: 255 }; -cellTypes[5] = { r: 0, g: 255, b: 255 }; + //Check for free region for AC var regionMarkerX = -1; @@ -152,11 +150,11 @@ function updateCells() { } else { if (currentCells[y][x].type == ((cell.type + 1) % cellTypes.length)) { - nextCells[i][j] = currentCells[y][x]; + nextCells[i][j].type = currentCells[y][x].type; nextCells[i][j].changed = true; } else { //indicate no update - nextCells[i][j].changed = true; + nextCells[i][j].changed = false; } } } @@ -192,7 +190,7 @@ function sendNextCells() { var sentFirstBoard = false; -var UPDATES_PER_SECOND = 3.0; +var UPDATES_PER_SECOND = 6.0; var frameIndex = 1.0; var oldFrameIndex = 0; diff --git a/libraries/voxels/src/VoxelsScriptingInterface.cpp b/libraries/voxels/src/VoxelsScriptingInterface.cpp index e877f99760..ba1c3d72de 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.cpp +++ b/libraries/voxels/src/VoxelsScriptingInterface.cpp @@ -81,11 +81,17 @@ void VoxelsScriptingInterface::setVoxel(float x, float y, float z, float scale, DeleteVoxelCommand* deleteCommand = new DeleteVoxelCommand(_tree, addVoxelDetail, getVoxelPacketSender()); + static QMutex mutex; + mutex.lock(); + _undoStack->beginMacro(addCommand->text()); // As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves. _undoStack->push(deleteCommand); _undoStack->push(addCommand); _undoStack->endMacro(); + + //Unlock the mutex + mutex.unlock(); } else { // queue the destructive add queueVoxelAdd(PacketTypeVoxelSetDestructive, addVoxelDetail); From 814dd0fcb6408ed9b07fdf4be9ea5d22c5a1fcbb Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Fri, 18 Jul 2014 11:37:13 -0700 Subject: [PATCH 005/407] Fixed another crash relating to undo stack. Made script support the VoxelViewer --- examples/rockPaperScissorsCells.js | 31 +++++++++++++++++++--- libraries/networking/src/ResourceCache.cpp | 9 +++++++ libraries/networking/src/ResourceCache.h | 2 +- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/examples/rockPaperScissorsCells.js b/examples/rockPaperScissorsCells.js index 4f6de888a1..aa7d4ef040 100644 --- a/examples/rockPaperScissorsCells.js +++ b/examples/rockPaperScissorsCells.js @@ -11,10 +11,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var NUMBER_OF_CELLS_EACH_DIMENSION = 64; +var NUMBER_OF_CELLS_EACH_DIMENSION = 48; var NUMBER_OF_CELLS_REGION_EACH_DIMESION = 16; var REGIONS_EACH_DIMENSION = NUMBER_OF_CELLS_EACH_DIMENSION / NUMBER_OF_CELLS_REGION_EACH_DIMESION; +var isLocal = false; + var currentCells = []; var nextCells = []; @@ -24,11 +26,20 @@ var position = {x: 0, y: 0, z: 0 }; var METER_LENGTH = 1; var cellScale = (NUMBER_OF_CELLS_EACH_DIMENSION * METER_LENGTH) / NUMBER_OF_CELLS_EACH_DIMENSION; +var viewerPosition = {x: cornerPosition.x + (NUMBER_OF_CELLS_EACH_DIMENSION / 2) * cellScale, y: cornerPosition.y + (NUMBER_OF_CELLS_EACH_DIMENSION / 2) * cellScale, z: cornerPosition.z }; + +viewerPosition.z += 50; +var yaw = 0; +var orientation = Quat.fromPitchYawRollDegrees(0, yaw, 0); + //Feel free to add new cell types here. It can be more than three. var cellTypes = []; cellTypes[0] = { r: 255, g: 0, b: 0 }; cellTypes[1] = { r: 0, g: 255, b: 0 }; cellTypes[2] = { r: 0, g:0, b: 255 }; +cellTypes[3] = { r: 0, g:255, b: 255 }; +cellTypes[4] = { r: 255, g:0, b: 255 }; +//cellTypes[5] = { r: 255, g:255, b: 255 }; //Check for free region for AC @@ -76,8 +87,10 @@ for (var i = 0; i < NUMBER_OF_CELLS_REGION_EACH_DIMESION; i++) { // create the array to hold this row in the nextCells array nextCells[i] = []; + var randomColor = Math.floor(Math.random() * cellTypes.length); + for (var j = 0; j < NUMBER_OF_CELLS_REGION_EACH_DIMESION; j++) { - currentCells[i][j] = { changed: true, type: Math.floor(Math.random() * cellTypes.length) }; + currentCells[i][j] = { changed: true, type: randomColor }; // put the same value in the nextCells array for first board draw nextCells[i][j] = currentCells[i][j]; @@ -207,6 +220,15 @@ function step(deltaTime) { } else { // this will be our first board send sentFirstBoard = true; + + print("AHHHH"); + print(viewerPosition.x + " " + viewerPosition.y + " " + viewerPosition.z); + + if (isLocal == false) { + VoxelViewer.setPosition(viewerPosition); + VoxelViewer.setOrientation(orientation); + VoxelViewer.queryOctree(); + } } sendNextCells(); @@ -219,5 +241,8 @@ function scriptEnding() { Script.scriptEnding.connect(scriptEnding); Script.update.connect(step); -//Voxels.setMaxPacketSize(1); //this is needed or a bug occurs :( Voxels.setPacketsPerSecond(2000); + +// test for local... +Menu.isOptionChecked("Voxels"); +isLocal = true; // will only get here on local client \ No newline at end of file diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index a183e2f9a1..73c01ef582 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -40,6 +40,15 @@ void ResourceCache::refresh(const QUrl& url) { } QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& fallback, bool delayLoad, void* extra) { + + if (QThread::currentThread() != thread()) { + QSharedPointer result; + QMetaObject::invokeMethod(this, "getResource", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QSharedPointer, result), Q_ARG(const QUrl&, url), Q_ARG(const QUrl&, fallback), + Q_ARG(bool, delayLoad), Q_ARG(void*, extra)); + return result; + } + if (!url.isValid() && !url.isEmpty() && fallback.isValid()) { return getResource(fallback, QUrl(), delayLoad); } diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 1593ad45fc..c3a5974da7 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -52,7 +52,7 @@ protected: /// \param fallback a fallback URL to load if the desired one is unavailable /// \param delayLoad if true, don't load the resource immediately; wait until load is first requested /// \param extra extra data to pass to the creator, if appropriate - QSharedPointer getResource(const QUrl& url, const QUrl& fallback = QUrl(), + Q_INVOKABLE QSharedPointer getResource(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false, void* extra = NULL); /// Creates a new resource. From 4410411d9d4c2f32eeaafca369e572a1c37e8d86 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Fri, 18 Jul 2014 14:51:53 -0700 Subject: [PATCH 006/407] Script improvements for AC --- examples/rockPaperScissorsCells.js | 118 ++++++++++-------- .../voxels/src/VoxelsScriptingInterface.cpp | 5 + 2 files changed, 68 insertions(+), 55 deletions(-) diff --git a/examples/rockPaperScissorsCells.js b/examples/rockPaperScissorsCells.js index aa7d4ef040..d7101ce4c7 100644 --- a/examples/rockPaperScissorsCells.js +++ b/examples/rockPaperScissorsCells.js @@ -11,7 +11,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var NUMBER_OF_CELLS_EACH_DIMENSION = 48; +var NUMBER_OF_CELLS_EACH_DIMENSION = 64; var NUMBER_OF_CELLS_REGION_EACH_DIMESION = 16; var REGIONS_EACH_DIMENSION = NUMBER_OF_CELLS_EACH_DIMENSION / NUMBER_OF_CELLS_REGION_EACH_DIMESION; @@ -37,8 +37,8 @@ var cellTypes = []; cellTypes[0] = { r: 255, g: 0, b: 0 }; cellTypes[1] = { r: 0, g: 255, b: 0 }; cellTypes[2] = { r: 0, g:0, b: 255 }; -cellTypes[3] = { r: 0, g:255, b: 255 }; -cellTypes[4] = { r: 255, g:0, b: 255 }; +cellTypes[3] = { r: 0, g: 255, b: 255 }; +//cellTypes[4] = { r: 255, g:0, b: 255 }; //cellTypes[5] = { r: 255, g:255, b: 255 }; @@ -50,51 +50,45 @@ var regionMarkerJ = -1; var regionMarkerColor = {r: 255, g: 0, b: 255}; -for (var i = 0; i < REGIONS_EACH_DIMENSION; i++) { - for (var j = 0; j < REGIONS_EACH_DIMENSION; j++) { - var x = cornerPosition.x + (j) * cellScale; - var y = cornerPosition.y + (i + NUMBER_OF_CELLS_EACH_DIMENSION) * cellScale; - var z = cornerPosition.z; - var voxel = Voxels.getVoxelAt(x, y, z, cellScale); - if (voxel.x != x || voxel.y != y || voxel.z != z || voxel.s != cellScale || - voxel.red != regionMarkerColor.r || voxel.green != regionMarkerColor.g || voxel.blue != regionMarkerColor.b) { - regionMarkerX = x; - regionMarkerY = y; - regionMarkerI = i; - regionMarkerJ = j; - i = REGIONS_EACH_DIMENSION; //force quit loop - break; + +function init() { + + for (var i = 0; i < REGIONS_EACH_DIMENSION; i++) { + for (var j = 0; j < REGIONS_EACH_DIMENSION; j++) { + var x = cornerPosition.x + (j) * cellScale; + var y = cornerPosition.y + (i + NUMBER_OF_CELLS_EACH_DIMENSION) * cellScale; + var z = cornerPosition.z; + var voxel = Voxels.getVoxelAt(x, y, z, cellScale); + if (voxel.x != x || voxel.y != y || voxel.z != z || voxel.s != cellScale || + voxel.red != regionMarkerColor.r || voxel.green != regionMarkerColor.g || voxel.blue != regionMarkerColor.b) { + regionMarkerX = x; + regionMarkerY = y; + regionMarkerI = i; + regionMarkerJ = j; + i = REGIONS_EACH_DIMENSION; //force quit loop + break; + } } } -} + + Voxels.setVoxel(regionMarkerX, regionMarkerY, position.z, cellScale, regionMarkerColor.r, regionMarkerColor.g, regionMarkerColor.b); -if (regionMarkerX == -1) { - print("No available Cellular Automata regions found!") - Script.stop(); -} - -position.x = cornerPosition.x + regionMarkerJ * NUMBER_OF_CELLS_REGION_EACH_DIMESION * cellScale; -position.y = cornerPosition.y + regionMarkerI * NUMBER_OF_CELLS_REGION_EACH_DIMESION * cellScale; -position.z = cornerPosition.z; - -Voxels.setVoxel(regionMarkerX, regionMarkerY, position.z, cellScale, regionMarkerColor.r, regionMarkerColor.g, regionMarkerColor.b); - -// randomly populate the cell start values -for (var i = 0; i < NUMBER_OF_CELLS_REGION_EACH_DIMESION; i++) { - // create the array to hold this row - currentCells[i] = []; - - // create the array to hold this row in the nextCells array - nextCells[i] = []; - - var randomColor = Math.floor(Math.random() * cellTypes.length); - - for (var j = 0; j < NUMBER_OF_CELLS_REGION_EACH_DIMESION; j++) { - currentCells[i][j] = { changed: true, type: randomColor }; - - // put the same value in the nextCells array for first board draw - nextCells[i][j] = currentCells[i][j]; - } + // randomly populate the cell start values + var randomColor = Math.floor(Math.random() * cellTypes.length); + for (var i = 0; i < NUMBER_OF_CELLS_REGION_EACH_DIMESION; i++) { + // create the array to hold this row + currentCells[i] = []; + + // create the array to hold this row in the nextCells array + nextCells[i] = []; + + for (var j = 0; j < NUMBER_OF_CELLS_REGION_EACH_DIMESION; j++) { + currentCells[i][j] = { changed: true, type: randomColor }; + + // put the same value in the nextCells array for first board draw + nextCells[i][j] = currentCells[i][j]; + } + } } function updateCells() { @@ -202,35 +196,49 @@ function sendNextCells() { } var sentFirstBoard = false; +var voxelViewerInit = false; var UPDATES_PER_SECOND = 6.0; var frameIndex = 1.0; var oldFrameIndex = 0; +var framesToWait = UPDATES_PER_SECOND; + function step(deltaTime) { + + if (isLocal == false) { + if (voxelViewerInit == false) { + VoxelViewer.setPosition(viewerPosition); + VoxelViewer.setOrientation(orientation); + voxelViewerInit = true; + } + VoxelViewer.queryOctree(); + } + frameIndex += deltaTime * UPDATES_PER_SECOND; if (Math.floor(frameIndex) == oldFrameIndex) { return; } oldFrameIndex++; + + if (frameIndex <= framesToWait) { + return; + } + print("UPDATE"); + if (sentFirstBoard) { // we've already sent the first full board, perform a step in time updateCells(); } else { // this will be our first board send sentFirstBoard = true; - - print("AHHHH"); - print(viewerPosition.x + " " + viewerPosition.y + " " + viewerPosition.z); - - if (isLocal == false) { - VoxelViewer.setPosition(viewerPosition); - VoxelViewer.setOrientation(orientation); - VoxelViewer.queryOctree(); - } + init(); + } + + if (isLocal == false) { + VoxelViewer.queryOctree(); } - sendNextCells(); } diff --git a/libraries/voxels/src/VoxelsScriptingInterface.cpp b/libraries/voxels/src/VoxelsScriptingInterface.cpp index ba1c3d72de..093d736720 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.cpp +++ b/libraries/voxels/src/VoxelsScriptingInterface.cpp @@ -116,11 +116,16 @@ void VoxelsScriptingInterface::eraseVoxel(float x, float y, float z, float scale } if (_undoStack) { + DeleteVoxelCommand* command = new DeleteVoxelCommand(_tree, deleteVoxelDetail, getVoxelPacketSender()); + + static QMutex mutex; + mutex.lock(); // As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves. _undoStack->push(command); + mutex.unlock(); } else { getVoxelPacketSender()->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &deleteVoxelDetail); _tree->deleteVoxelAt(deleteVoxelDetail.x, deleteVoxelDetail.y, deleteVoxelDetail.z, deleteVoxelDetail.s); From f16eb0fd896879165e8fbc203e1f352d47291ee6 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 19 Jul 2014 14:33:48 -0700 Subject: [PATCH 007/407] Encapsulate and lint "new model" toolbar --- examples/editModels.js | 204 +++++++++++++++++++++++------------------ 1 file changed, 114 insertions(+), 90 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 458ddf7b4a..0c6ac8b426 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -9,12 +9,12 @@ // // If using the hydras : // grab grab models with the triggers, you can then move the models around or scale them with both hands. -// You can switch mode using the bumpers so that you can move models roud more easily. +// You can switch mode using the bumpers so that you can move models around more easily. // // If using the mouse : // - left click lets you move the model in the plane facing you. -// If pressing shift, it will move on the horizontale plane it's in. -// - right click lets you rotate the model. z and x give you access to more axix of rotation while shift allows for finer control. +// If pressing shift, it will move on the horizontal plane it's in. +// - right click lets you rotate the model. z and x give access to more axes of rotation while shift provides finer control. // - left + right click lets you scale the model. // - you can press r while holding the model to reset its rotation // @@ -39,27 +39,122 @@ var MAX_ANGULAR_SIZE = 45; var LEFT = 0; var RIGHT = 1; - var SPAWN_DISTANCE = 1; -var radiusDefault = 0.10; +var DEFAULT_RADIUS = 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 toolBar; + "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 jointList = MyAvatar.getJointNames(); var mode = 0; + +var toolBar = (function () { + var that = {}, + toolBar, + newModelButton, + browseModelsButton; + + function initialize() { + toolBar = new ToolBar(0, 0, ToolBar.VERTICAL); + newModelButton = toolBar.addTool({ + imageURL: toolIconUrl + "add-model-tool.svg", + subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: toolWidth, + height: toolHeight, + visible: true, + alpha: 0.9 + }); + browseModelsButton = toolBar.addTool({ + imageURL: toolIconUrl + "list-icon.png", + width: toolWidth, + height: toolHeight, + visible: true, + alpha: 0.7 + }); + } + + function addModel(url) { + var position; + + position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); + + if (position.x > 0 && position.y > 0 && position.z > 0) { + Models.addModel({ + position: position, + radius: DEFAULT_RADIUS, + modelURL: url + }); + } else { + print("Can't create model: Model would be out of bounds."); + } + } + + that.move = function () { + var newViewPort, + toolsX, + toolsY; + + newViewPort = Controller.getViewportDimensions(); + + if (toolBar === undefined) { + initialize(); + + } else if (windowDimensions.x === newViewPort.x && + windowDimensions.y === newViewPort.y) { + return; + } + + windowDimensions = newViewPort; + toolsX = windowDimensions.x - 8 - toolBar.width; + toolsY = (windowDimensions.y - toolBar.height) / 2; + + toolBar.move(toolsX, toolsY); + }; + + that.mousePressEvent = function (event) { + var clickedOverlay, + url, + position; + + clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); + + if (newModelButton === toolBar.clicked(clickedOverlay)) { + url = Window.prompt("Model url", modelURLs[Math.floor(Math.random() * modelURLs.length)]); + if (url !== null && url !== "") { + addModel(url); + } + return true; + } + + if (browseModelsButton === toolBar.clicked(clickedOverlay)) { + url = Window.s3Browse(); + if (url !== null && url !== "") { + addModel(url); + } + return true; + } + + return false; + }; + + that.cleanup = function () { + toolBar.cleanup(); + }; + + return that; +}()); + + function isLocked(properties) { // special case to lock the ground plane model in hq. if (location.hostname == "hq.highfidelity.io" && @@ -663,45 +758,7 @@ function checkController(deltaTime) { } } - moveOverlays(); -} -var newModel; -var browser; -function initToolBar() { - toolBar = new ToolBar(0, 0, ToolBar.VERTICAL); - // New Model - newModel = toolBar.addTool({ - imageURL: toolIconUrl + "add-model-tool.svg", - subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: toolWidth, height: toolHeight, - visible: true, - alpha: 0.9 - }); - browser = toolBar.addTool({ - imageURL: toolIconUrl + "list-icon.png", - width: toolWidth, height: toolHeight, - visible: true, - alpha: 0.7 - }); -} - -function moveOverlays() { - var newViewPort = Controller.getViewportDimensions(); - - if (typeof(toolBar) === 'undefined') { - initToolBar(); - - } else if (windowDimensions.x == newViewPort.x && - windowDimensions.y == newViewPort.y) { - return; - } - - - windowDimensions = newViewPort; - var toolsX = windowDimensions.x - 8 - toolBar.width; - var toolsY = (windowDimensions.y - toolBar.height) / 2; - - toolBar.move(toolsX, toolsY); + toolBar.move(); } @@ -784,42 +841,9 @@ function mousePressEvent(event) { mouseLastPosition = { x: event.x, y: event.y }; modelSelected = false; - var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - if (newModel == toolBar.clicked(clickedOverlay)) { - var url = Window.prompt("Model URL", modelURLs[Math.floor(Math.random() * modelURLs.length)]); - if (url == null || url == "") { - return; - } - - var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); - - if (position.x > 0 && position.y > 0 && position.z > 0) { - Models.addModel({ position: position, - radius: radiusDefault, - modelURL: url - }); - } else { - print("Can't create model: Model would be out of bounds."); - } - - } else if (browser == toolBar.clicked(clickedOverlay)) { - var url = Window.s3Browse(); - if (url == null || url == "") { - return; - } - - var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); - - if (position.x > 0 && position.y > 0 && position.z > 0) { - Models.addModel({ position: position, - radius: radiusDefault, - modelURL: url - }); - } else { - print("Can't create model: Model would be out of bounds."); - } - + if (toolBar.mousePressEvent(event)) { + // Event handled; do nothing. } else { var pickRay = Camera.computePickRay(event.x, event.y); Vec3.print("[Mouse] Looking at: ", pickRay.origin); From c5faeadd818ce6a545cdc61cc760add0befb8f47 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 19 Jul 2014 15:27:41 -0700 Subject: [PATCH 008/407] Add button menu options for loading model from URL or file --- examples/editModels.js | 77 ++++++++++++++++++++++++++++++++++++++---- examples/toolBars.js | 8 +++++ 2 files changed, 79 insertions(+), 6 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 0c6ac8b426..721878c656 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -62,25 +62,72 @@ var toolBar = (function () { var that = {}, toolBar, newModelButton, - browseModelsButton; + browseModelsButton, + loadURLMenuItem, + loadFileMenuItem, + menuItemWidth = 90, + menuItemOffset = 2, + menuItemHeight = Tool.IMAGE_HEIGHT / 2 - menuItemOffset, + menuItemMargin = 5, + menuTextColor = { red: 255, green: 255, blue: 255 }, + menuBackgoundColor = { red: 18, green: 66, blue: 66 }; function initialize() { toolBar = new ToolBar(0, 0, ToolBar.VERTICAL); + newModelButton = toolBar.addTool({ imageURL: toolIconUrl + "add-model-tool.svg", subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, width: toolWidth, height: toolHeight, - visible: true, - alpha: 0.9 - }); + alpha: 0.9, + visible: true + }, true); + browseModelsButton = toolBar.addTool({ imageURL: toolIconUrl + "list-icon.png", width: toolWidth, height: toolHeight, - visible: true, - alpha: 0.7 + alpha: 0.7, + visible: true }); + + loadURLMenuItem = Overlays.addOverlay("text", { + x: newModelButton.x - menuItemWidth, + y: newModelButton.y + menuItemOffset, + width: menuItemWidth, + height: menuItemHeight, + backgroundColor: menuBackgoundColor, + topMargin: menuItemMargin, + text: "Model URL", + alpha: 0.9, + visible: false + }); + + loadFileMenuItem = Overlays.addOverlay("text", { + x: newModelButton.x - menuItemWidth, + y: newModelButton.y + menuItemOffset + menuItemHeight, + width: menuItemWidth, + height: menuItemHeight, + backgroundColor: menuBackgoundColor, + topMargin: menuItemMargin, + text: "Model File", + alpha: 0.9, + visible: false + }); + } + + function toggleToolbar(active) { + if (active === undefined) { + print("active === undefine"); + active = toolBar.toolSelected(newModelButton); + } else { + print("active !== undefine"); + toolBar.selectTool(newModelButton, active); + } + + Overlays.editOverlay(loadURLMenuItem, { visible: active }); + Overlays.editOverlay(loadFileMenuItem, { visible: active }); } function addModel(url) { @@ -119,6 +166,9 @@ var toolBar = (function () { toolsY = (windowDimensions.y - toolBar.height) / 2; toolBar.move(toolsX, toolsY); + + Overlays.editOverlay(loadURLMenuItem, { x: toolsX - menuItemWidth, y: toolsY + menuItemOffset }); + Overlays.editOverlay(loadFileMenuItem, { x: toolsX - menuItemWidth, y: toolsY + menuItemOffset + menuItemHeight }); }; that.mousePressEvent = function (event) { @@ -129,6 +179,12 @@ var toolBar = (function () { clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); if (newModelButton === toolBar.clicked(clickedOverlay)) { + toggleToolbar(); + return true; + } + + if (clickedOverlay === loadURLMenuItem) { + toggleToolbar(false); url = Window.prompt("Model url", modelURLs[Math.floor(Math.random() * modelURLs.length)]); if (url !== null && url !== "") { addModel(url); @@ -136,7 +192,14 @@ var toolBar = (function () { return true; } + if (clickedOverlay === loadFileMenuItem) { + toggleToolbar(false); + print("TODO: Upload model file"); + return true; + } + if (browseModelsButton === toolBar.clicked(clickedOverlay)) { + toggleToolbar(false); url = Window.s3Browse(); if (url !== null && url !== "") { addModel(url); @@ -149,6 +212,8 @@ var toolBar = (function () { that.cleanup = function () { toolBar.cleanup(); + Overlays.deleteOverlay(loadURLMenuItem); + Overlays.deleteOverlay(loadFileMenuItem); }; return that; diff --git a/examples/toolBars.js b/examples/toolBars.js index 1a464b4e4f..ede3b80062 100644 --- a/examples/toolBars.js +++ b/examples/toolBars.js @@ -186,6 +186,14 @@ ToolBar = function(x, y, direction) { return this.tools.length; } + this.selectTool = function (tool, select) { + this.tools[tool].select(select); + } + + this.toolSelected = function (tool) { + return this.tools[tool].selected(); + } + this.cleanup = function() { for(var tool in this.tools) { this.tools[tool].cleanup(); From 6027f4dad1bd0133cce90f8a53a190ade4c40ffd Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 19 Jul 2014 15:33:54 -0700 Subject: [PATCH 009/407] Add model file selection dialog box --- examples/editModels.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 721878c656..71a4050176 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -174,6 +174,7 @@ var toolBar = (function () { that.mousePressEvent = function (event) { var clickedOverlay, url, + file, position; clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); @@ -185,7 +186,7 @@ var toolBar = (function () { if (clickedOverlay === loadURLMenuItem) { toggleToolbar(false); - url = Window.prompt("Model url", modelURLs[Math.floor(Math.random() * modelURLs.length)]); + url = Window.prompt("Model URL", modelURLs[Math.floor(Math.random() * modelURLs.length)]); if (url !== null && url !== "") { addModel(url); } @@ -194,7 +195,10 @@ var toolBar = (function () { if (clickedOverlay === loadFileMenuItem) { toggleToolbar(false); - print("TODO: Upload model file"); + file = Window.browse("Model File", "", "FST, FBX, or SVO files (*.fst *.fbx *.svo)"); + if (file !== null) { + print("TODO: Upload model file: " + file); + } return true; } From 33ffed71359c74346e45b2254e13a03f4ff0f5d2 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 19 Jul 2014 15:47:06 -0700 Subject: [PATCH 010/407] Add GET of local files to JavaScript XMLHttpRequest --- examples/Test.js | 7 + examples/testXMLHttpRequest.js | 95 +++++++++++++ .../script-engine/src/XMLHttpRequestClass.cpp | 125 +++++++++++++++--- .../script-engine/src/XMLHttpRequestClass.h | 2 + 4 files changed, 211 insertions(+), 18 deletions(-) diff --git a/examples/Test.js b/examples/Test.js index 36dee7bd90..612c56d10b 100644 --- a/examples/Test.js +++ b/examples/Test.js @@ -59,6 +59,13 @@ UnitTest.prototype.assertEquals = function(expected, actual, message) { } }; +UnitTest.prototype.assertContains = function (expected, actual, message) { + this.numAssertions++; + if (actual.indexOf(expected) == -1) { + throw new AssertionException(expected, actual, message); + } +}; + UnitTest.prototype.assertHasProperty = function(property, actual, message) { this.numAssertions++; if (actual[property] === undefined) { diff --git a/examples/testXMLHttpRequest.js b/examples/testXMLHttpRequest.js index 421eb458e4..ec5bcf6c4c 100644 --- a/examples/testXMLHttpRequest.js +++ b/examples/testXMLHttpRequest.js @@ -145,3 +145,98 @@ test("Test timeout", function() { this.assertEquals(0, req.status, "status should be `0`"); this.assertEquals(4, req.errorCode, "4 is the timeout error code for QNetworkReply::NetworkError"); }); + + +var localFile = Window.browse("Find defaultScripts.js file ...", "", "defaultScripts.js (defaultScripts.js)"); + +if (localFile !== null) { + + localFile = "file:///" + localFile; + + test("Test GET local file synchronously", function () { + var req = new XMLHttpRequest(); + + var statesVisited = [true, false, false, false, false] + req.onreadystatechange = function () { + statesVisited[req.readyState] = true; + }; + + req.open("GET", localFile, false); + req.send(); + + this.assertEquals(req.DONE, req.readyState, "readyState should be DONE"); + this.assertEquals(200, req.status, "status should be `200`"); + this.assertEquals("OK", req.statusText, "statusText should be `OK`"); + this.assertEquals(0, req.errorCode); + this.assertEquals("", req.getAllResponseHeaders(), "headers should be null"); + this.assertContains("High Fidelity", req.response.substring(0, 100), "expected text not found in response") + + for (var i = 0; i <= req.DONE; i++) { + this.assertEquals(true, statesVisited[i], i + " should be set"); + } + }); + + test("Test GET nonexistent local file", function () { + var nonexistentFile = localFile.replace(".js", "NoExist.js"); + + var req = new XMLHttpRequest(); + req.open("GET", nonexistentFile, false); + req.send(); + + this.assertEquals(req.DONE, req.readyState, "readyState should be DONE"); + this.assertEquals(404, req.status, "status should be `404`"); + this.assertEquals("Not Found", req.statusText, "statusText should be `Not Found`"); + this.assertNotEquals(0, req.errorCode); + }); + + test("Test GET local file already open", function () { + // Can't open file exclusively in order to test. + }); + + test("Test GET local file with data not implemented", function () { + var req = new XMLHttpRequest(); + req.open("GET", localFile, true); + req.send("data"); + + this.assertEquals(req.DONE, req.readyState, "readyState should be DONE"); + this.assertEquals(501, req.status, "status should be `501`"); + this.assertEquals("Not Implemented", req.statusText, "statusText should be `Not Implemented`"); + this.assertNotEquals(0, req.errorCode); + }); + + test("Test GET local file asynchronously not implemented", function () { + var req = new XMLHttpRequest(); + req.open("GET", localFile, true); + req.send(); + + this.assertEquals(req.DONE, req.readyState, "readyState should be DONE"); + this.assertEquals(501, req.status, "status should be `501`"); + this.assertEquals("Not Implemented", req.statusText, "statusText should be `Not Implemented`"); + this.assertNotEquals(0, req.errorCode); + }); + + test("Test POST local file not implemented", function () { + var req = new XMLHttpRequest(); + req.open("POST", localFile, false); + req.send(); + + this.assertEquals(req.DONE, req.readyState, "readyState should be DONE"); + this.assertEquals(501, req.status, "status should be `501`"); + this.assertEquals("Not Implemented", req.statusText, "statusText should be `Not Implemented`"); + this.assertNotEquals(0, req.errorCode); + }); + + test("Test local file username and password not implemented", function () { + var req = new XMLHttpRequest(); + req.open("GET", localFile, false, "username", "password"); + req.send(); + + this.assertEquals(req.DONE, req.readyState, "readyState should be DONE"); + this.assertEquals(501, req.status, "status should be `501`"); + this.assertEquals("Not Implemented", req.statusText, "statusText should be `Not Implemented`"); + this.assertNotEquals(0, req.errorCode); + }); + +} else { + print("Local file operation not tested"); +} diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index d9b7312bf4..6355b689ea 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -13,6 +13,7 @@ // #include +#include #include @@ -33,6 +34,7 @@ XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) : _onReadyStateChange(QScriptValue::NullValue), _readyState(XMLHttpRequestClass::UNSENT), _errorCode(QNetworkReply::NoError), + _file(NULL), _timeout(0), _timer(this), _numRedirects(0) { @@ -52,6 +54,19 @@ QScriptValue XMLHttpRequestClass::constructor(QScriptContext* context, QScriptEn QScriptValue XMLHttpRequestClass::getStatus() const { if (_reply) { return QScriptValue(_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()); + } else if(_url.isLocalFile()) { + switch (_errorCode) { + case QNetworkReply::NoError: + return QScriptValue(200); + case QNetworkReply::ContentNotFoundError: + return QScriptValue(404); + case QNetworkReply::ContentAccessDenied: + return QScriptValue(409); + case QNetworkReply::TimeoutError: + return QScriptValue(408); + case QNetworkReply::ContentOperationNotPermittedError: + return QScriptValue(501); + } } return QScriptValue(0); } @@ -59,6 +74,19 @@ QScriptValue XMLHttpRequestClass::getStatus() const { QString XMLHttpRequestClass::getStatusText() const { if (_reply) { return _reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(); + } else if (_url.isLocalFile()) { + switch (_errorCode) { + case QNetworkReply::NoError: + return "OK"; + case QNetworkReply::ContentNotFoundError: + return "Not Found"; + case QNetworkReply::ContentAccessDenied: + return "Conflict"; + case QNetworkReply::TimeoutError: + return "Timeout"; + case QNetworkReply::ContentOperationNotPermittedError: + return "Not Implemented"; + } } return ""; } @@ -126,17 +154,42 @@ void XMLHttpRequestClass::setReadyState(ReadyState readyState) { void XMLHttpRequestClass::open(const QString& method, const QString& url, bool async, const QString& username, const QString& password) { if (_readyState == UNSENT) { - _async = async; - _url.setUrl(url); - if (!username.isEmpty()) { - _url.setUserName(username); - } - if (!password.isEmpty()) { - _url.setPassword(password); - } - _request.setUrl(_url); _method = method; - setReadyState(OPENED); + _url.setUrl(url); + _async = async; + + if (_url.isLocalFile()) { + if (_method.toUpper() == "GET" && !_async && username.isEmpty() && password.isEmpty()) { + _file = new QFile(_url.toLocalFile()); + if (!_file->exists()) { + qDebug() << "Can't find file " << _url.fileName(); + abortRequest(); + _errorCode = QNetworkReply::ContentNotFoundError; + setReadyState(DONE); + emit requestComplete(); + } else if (!_file->open(QIODevice::ReadOnly)) { + qDebug() << "Can't open file " << _url.fileName(); + abortRequest(); + //_errorCode = QNetworkReply::ContentConflictError; // TODO: Use this status when update to Qt 5.3 + _errorCode = QNetworkReply::ContentAccessDenied; + setReadyState(DONE); + emit requestComplete(); + } else { + setReadyState(OPENED); + } + } else { + notImplemented(); + } + } else { + if (!username.isEmpty()) { + _url.setUserName(username); + } + if (!password.isEmpty()) { + _url.setPassword(password); + } + _request.setUrl(_url); + setReadyState(OPENED); + } } } @@ -147,13 +200,18 @@ void XMLHttpRequestClass::send() { void XMLHttpRequestClass::send(const QString& data) { if (_readyState == OPENED && !_reply) { if (!data.isNull()) { - _sendData = new QBuffer(this); - _sendData->setData(data.toUtf8()); + if (_url.isLocalFile()) { + notImplemented(); + return; + } else { + _sendData = new QBuffer(this); + _sendData->setData(data.toUtf8()); + } } doSend(); - if (!_async) { + if (!_async && !_url.isLocalFile()) { QEventLoop loop; connect(this, SIGNAL(requestComplete()), &loop, SLOT(quit())); loop.exec(); @@ -162,14 +220,24 @@ void XMLHttpRequestClass::send(const QString& data) { } void XMLHttpRequestClass::doSend() { - _reply = NetworkAccessManager::getInstance().sendCustomRequest(_request, _method.toLatin1(), _sendData); - - connectToReply(_reply); + + if (!_url.isLocalFile()) { + _reply = NetworkAccessManager::getInstance().sendCustomRequest(_request, _method.toLatin1(), _sendData); + connectToReply(_reply); + } if (_timeout > 0) { _timer.start(_timeout); connect(&_timer, SIGNAL(timeout()), this, SLOT(requestTimeout())); } + + if (_url.isLocalFile()) { + setReadyState(HEADERS_RECEIVED); + setReadyState(LOADING); + _rawResponseData = _file->readAll(); + _file->close(); + requestFinished(); + } } void XMLHttpRequestClass::requestTimeout() { @@ -188,9 +256,16 @@ void XMLHttpRequestClass::requestError(QNetworkReply::NetworkError code) { void XMLHttpRequestClass::requestFinished() { disconnect(&_timer, SIGNAL(timeout()), this, SLOT(requestTimeout())); - _errorCode = _reply->error(); + if (!_url.isLocalFile()) { + _errorCode = _reply->error(); + } else { + _errorCode = QNetworkReply::NoError; + } + if (_errorCode == QNetworkReply::NoError) { - _rawResponseData.append(_reply->readAll()); + if (!_url.isLocalFile()) { + _rawResponseData.append(_reply->readAll()); + } if (_responseType == "json") { _responseData = _engine->evaluate("(" + QString(_rawResponseData.data()) + ")"); @@ -204,6 +279,7 @@ void XMLHttpRequestClass::requestFinished() { _responseData = QScriptValue(QString(_rawResponseData.data())); } } + setReadyState(DONE); emit requestComplete(); } @@ -217,6 +293,19 @@ void XMLHttpRequestClass::abortRequest() { delete _reply; _reply = NULL; } + + if (_file != NULL) { + _file->close(); + _file = NULL; + } +} + +void XMLHttpRequestClass::notImplemented() { + abortRequest(); + //_errorCode = QNetworkReply::OperationNotImplementedError; TODO: Use this status code when update to Qt 5.3 + _errorCode = QNetworkReply::ContentOperationNotPermittedError; + setReadyState(DONE); + emit requestComplete(); } void XMLHttpRequestClass::connectToReply(QNetworkReply* reply) { diff --git a/libraries/script-engine/src/XMLHttpRequestClass.h b/libraries/script-engine/src/XMLHttpRequestClass.h index 48f1a596e1..9052a627b7 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.h +++ b/libraries/script-engine/src/XMLHttpRequestClass.h @@ -97,6 +97,7 @@ private: void connectToReply(QNetworkReply* reply); void disconnectFromReply(QNetworkReply* reply); void abortRequest(); + void notImplemented(); QScriptEngine* _engine; bool _async; @@ -112,6 +113,7 @@ private: QScriptValue _onReadyStateChange; ReadyState _readyState; QNetworkReply::NetworkError _errorCode; + QFile* _file; int _timeout; QTimer _timer; int _numRedirects; From d05435db91664f7dee5b96c716c562ee1f31bd4d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 19 Jul 2014 23:27:36 -0700 Subject: [PATCH 011/407] Add arraybuffer binary data handling in JavaScript XMLHttpRequest --- libraries/script-engine/src/XMLHttpRequestClass.cpp | 13 +++++++++---- libraries/script-engine/src/XMLHttpRequestClass.h | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index 6355b689ea..84e49f2364 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -194,10 +194,10 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a } void XMLHttpRequestClass::send() { - send(QString::Null()); + send(QString()); } -void XMLHttpRequestClass::send(const QString& data) { +void XMLHttpRequestClass::send(const QVariant& data) { if (_readyState == OPENED && !_reply) { if (!data.isNull()) { if (_url.isLocalFile()) { @@ -205,7 +205,12 @@ void XMLHttpRequestClass::send(const QString& data) { return; } else { _sendData = new QBuffer(this); - _sendData->setData(data.toUtf8()); + if (_responseType == "arraybuffer") { + QByteArray ba = qvariant_cast(data); + _sendData->setData(ba); + } else { + _sendData->setData(data.toString().toUtf8()); + } } } @@ -274,7 +279,7 @@ void XMLHttpRequestClass::requestFinished() { _responseData = QScriptValue::NullValue; } } else if (_responseType == "arraybuffer") { - _responseData = QScriptValue(_rawResponseData.data()); + _responseData = _engine->newVariant(QVariant::fromValue(_rawResponseData)); } else { _responseData = QScriptValue(QString(_rawResponseData.data())); } diff --git a/libraries/script-engine/src/XMLHttpRequestClass.h b/libraries/script-engine/src/XMLHttpRequestClass.h index 9052a627b7..e482e57077 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.h +++ b/libraries/script-engine/src/XMLHttpRequestClass.h @@ -84,7 +84,7 @@ public slots: void open(const QString& method, const QString& url, bool async = true, const QString& username = "", const QString& password = ""); void send(); - void send(const QString& data); + void send(const QVariant& data); QScriptValue getAllResponseHeaders() const; QScriptValue getResponseHeader(const QString& name) const; From ed1b058cb14fdde8f810ba90ed4cf5aa2ab76657 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 20 Jul 2014 13:55:26 -0700 Subject: [PATCH 012/407] Upload selected model file directly to public folder for starters --- examples/editModels.js | 54 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 71a4050176..9304afbc49 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -58,6 +58,51 @@ var jointList = MyAvatar.getJointNames(); var mode = 0; +var modelUploader = (function () { + var that = {}, + urlBase = "http://public.highfidelity.io/meshes/"; + + that.upload = function (file, callback) { + var url, + reqRead, + reqSend; + + // Read model content ... + url = "file:///" + file; + print("Reading model from " + url); + reqRead = new XMLHttpRequest(); + reqRead.open("GET", url, false); + reqRead.responseType = "arraybuffer"; + reqRead.send(); + if (reqRead.status !== 200) { + print("Error reading file: " + reqRead.status + " " + reqRead.statusText); + Window.alert("Could not read file " + reqRead.status + " " + reqRead.statusText); + return; + } + + // Upload to High Fidelity ... + url = urlBase + file.replace(/^(.*[\/\\])*/, ""); + print("Uploading model to " + url); + reqSend = new XMLHttpRequest(); + reqSend.open("PUT", url, true); + reqSend.responseType = "arraybuffer"; + reqSend.onreadystatechange = function () { + if (reqSend.readyState === reqSend.DONE) { + if (reqSend.status === 200) { + print("Uploaded model"); + callback(url); + } else { + print("Error uploading file: " + reqSend.status + " " + reqSend.statusText); + Window.alert("Could not upload file: " + reqSend.status + " " + reqSend.statusText); + } + } + }; + reqSend.send(reqRead.response); + }; + + return that; +}()); + var toolBar = (function () { var that = {}, toolBar, @@ -119,10 +164,8 @@ var toolBar = (function () { function toggleToolbar(active) { if (active === undefined) { - print("active === undefine"); active = toolBar.toolSelected(newModelButton); } else { - print("active !== undefine"); toolBar.selectTool(newModelButton, active); } @@ -174,8 +217,7 @@ var toolBar = (function () { that.mousePressEvent = function (event) { var clickedOverlay, url, - file, - position; + file; clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); @@ -195,9 +237,9 @@ var toolBar = (function () { if (clickedOverlay === loadFileMenuItem) { toggleToolbar(false); - file = Window.browse("Model File", "", "FST, FBX, or SVO files (*.fst *.fbx *.svo)"); + file = Window.browse("Select your model file ...", "", "Model files (*.fst *.fbx *.svo)"); if (file !== null) { - print("TODO: Upload model file: " + file); + modelUploader.upload(file, addModel); } return true; } From 2be03ada9c86a390243a3cf1e37e9721d1af7442 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 20 Jul 2014 15:14:48 -0700 Subject: [PATCH 013/407] Prepare for reading and processing model file content --- examples/editModels.js | 90 +++++++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 27 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 9304afbc49..a7fe76abdf 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -60,44 +60,80 @@ var mode = 0; var modelUploader = (function () { var that = {}, - urlBase = "http://public.highfidelity.io/meshes/"; + urlBase = "http://public.highfidelity.io/meshes/", + model; - that.upload = function (file, callback) { + function readModel(file) { var url, - reqRead, - reqSend; + req; + + print("Reading model from " + file); - // Read model content ... url = "file:///" + file; - print("Reading model from " + url); - reqRead = new XMLHttpRequest(); - reqRead.open("GET", url, false); - reqRead.responseType = "arraybuffer"; - reqRead.send(); - if (reqRead.status !== 200) { - print("Error reading file: " + reqRead.status + " " + reqRead.statusText); - Window.alert("Could not read file " + reqRead.status + " " + reqRead.statusText); - return; + req = new XMLHttpRequest(); + req.open("GET", url, false); + req.responseType = "arraybuffer"; + req.send(); + if (req.status !== 200) { + print("Error reading file: " + req.status + " " + req.statusText); + Window.alert("Could not read file " + req.status + " " + req.statusText); + return false; } + model = req.response; - // Upload to High Fidelity ... - url = urlBase + file.replace(/^(.*[\/\\])*/, ""); - print("Uploading model to " + url); - reqSend = new XMLHttpRequest(); - reqSend.open("PUT", url, true); - reqSend.responseType = "arraybuffer"; - reqSend.onreadystatechange = function () { - if (reqSend.readyState === reqSend.DONE) { - if (reqSend.status === 200) { - print("Uploaded model"); + return true; + } + + function setProperties() { + print("Setting model properties"); + return true; + } + + function createHttpMessage() { + print("Putting model into HTTP message"); + return true; + } + + function sendToHighFidelity(url, callback) { + var req; + + print("Sending model to High Fidelity"); + + req = new XMLHttpRequest(); + req.open("PUT", url, true); + req.responseType = "arraybuffer"; + req.onreadystatechange = function () { + if (req.readyState === req.DONE) { + if (req.status === 200) { + print("Uploaded model: " + url); callback(url); } else { - print("Error uploading file: " + reqSend.status + " " + reqSend.statusText); - Window.alert("Could not upload file: " + reqSend.status + " " + reqSend.statusText); + print("Error uploading file: " + req.status + " " + req.statusText); + Window.alert("Could not upload file: " + req.status + " " + req.statusText); } } }; - reqSend.send(reqRead.response); + req.send(model); + } + + that.upload = function (file, callback) { + var url = urlBase + file.replace(/^(.*[\/\\])*/, ""), + ok; + + // Read model content ... + ok = readModel(file); + if (!ok) { return; } + + // Set model properties ... + ok = setProperties(); + if (!ok) { return; } + + // Put model in HTTP message ... + ok = createHttpMessage(); + if (!ok) { return; } + + // Send model to High Fidelity ... + sendToHighFidelity(url, callback); }; return that; From 3f24f61180dee38114919a817a1bdc7cca6d00c0 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 20 Jul 2014 22:45:19 -0700 Subject: [PATCH 014/407] Provide Content-Type and -Length headers when reading local files --- examples/testXMLHttpRequest.js | 2 +- .../script-engine/src/XMLHttpRequestClass.cpp | 21 +++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/examples/testXMLHttpRequest.js b/examples/testXMLHttpRequest.js index ec5bcf6c4c..79d2842464 100644 --- a/examples/testXMLHttpRequest.js +++ b/examples/testXMLHttpRequest.js @@ -168,7 +168,7 @@ if (localFile !== null) { this.assertEquals(200, req.status, "status should be `200`"); this.assertEquals("OK", req.statusText, "statusText should be `OK`"); this.assertEquals(0, req.errorCode); - this.assertEquals("", req.getAllResponseHeaders(), "headers should be null"); + this.assertNotEquals("", req.getAllResponseHeaders(), "headers should not be null"); this.assertContains("High Fidelity", req.response.substring(0, 100), "expected text not found in response") for (var i = 0; i <= req.DONE; i++) { diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index 84e49f2364..8e48682ea0 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -54,7 +54,8 @@ QScriptValue XMLHttpRequestClass::constructor(QScriptContext* context, QScriptEn QScriptValue XMLHttpRequestClass::getStatus() const { if (_reply) { return QScriptValue(_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()); - } else if(_url.isLocalFile()) { + } + if(_url.isLocalFile()) { switch (_errorCode) { case QNetworkReply::NoError: return QScriptValue(200); @@ -74,7 +75,8 @@ QScriptValue XMLHttpRequestClass::getStatus() const { QString XMLHttpRequestClass::getStatusText() const { if (_reply) { return _reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(); - } else if (_url.isLocalFile()) { + } + if (_url.isLocalFile()) { switch (_errorCode) { case QNetworkReply::NoError: return "OK"; @@ -132,6 +134,13 @@ QScriptValue XMLHttpRequestClass::getAllResponseHeaders() const { } return QString(headers.data()); } + if (_url.isLocalFile()) { + QString headers = QString("Content-Type: application/octet-stream\n"); + headers.append("Content-Length: "); + headers.append(QString("%1").arg(_rawResponseData.length())); + headers.append("\n"); + return headers; + } return QScriptValue(""); } @@ -139,6 +148,14 @@ QScriptValue XMLHttpRequestClass::getResponseHeader(const QString& name) const { if (_reply && _reply->hasRawHeader(name.toLatin1())) { return QScriptValue(QString(_reply->rawHeader(name.toLatin1()))); } + if (_url.isLocalFile()) { + if (name.toLower() == "content-type") { + return QString("application/octet-stream"); + } + if (name.toLower() == "content-length") { + return QString("%1").arg(_rawResponseData.length()); + } + } return QScriptValue::NullValue; } From ab0ec9f4746be7f047dba960547aa4e8b294362c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 20 Jul 2014 22:55:07 -0700 Subject: [PATCH 015/407] Read raw data of different model file types --- examples/editModels.js | 136 +++++++++++++++++++++++++++++++++++------ 1 file changed, 116 insertions(+), 20 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index a7fe76abdf..54cf014dfe 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -58,28 +58,115 @@ var jointList = MyAvatar.getJointNames(); var mode = 0; +if (typeof String.prototype.fileName !== 'function') { + String.prototype.fileName = function (str) { + return this.replace(/^(.*[\/\\])*/, ""); + }; +} + +if (typeof String.prototype.path !== 'function') { + String.prototype.path = function (str) { + return this.replace(/[\\\/][^\\\/]*$/, ""); + }; +} + + var modelUploader = (function () { var that = {}, urlBase = "http://public.highfidelity.io/meshes/", - model; + fstBuffer, + fbxBuffer, + svoBuffer, + mapping = {}, + NAME_FIELD = "name", + SCALE_FIELD = "scale", + FILENAME_FIELD = "filename", + TEXDIR_FIELD = "texdir", + fbxDataView; - function readModel(file) { - var url, - req; + function error(message) { + Window.alert(message); + print(message); + } - print("Reading model from " + file); + function readFile(filename, buffer, length) { + var url = "file:///" + filename, + req = new XMLHttpRequest(); - url = "file:///" + file; - req = new XMLHttpRequest(); req.open("GET", url, false); req.responseType = "arraybuffer"; req.send(); if (req.status !== 200) { - print("Error reading file: " + req.status + " " + req.statusText); - Window.alert("Could not read file " + req.status + " " + req.statusText); - return false; + error("Could not read file: " + filename + " : " + req.status + " " + req.statusText); + return null; + } + + return { + buffer: req.response, + length: parseInt(req.getResponseHeader("Content-Length"), 10) + }; + } + + function readMapping(buffer) { + return {}; // DJRTODO + } + + function readGeometry(buffer) { + return {}; // DJRTODO + } + + function readModel(filename) { + var url, + req, + fbxFilename, + geometry; + + if (filename.toLowerCase().slice(-4) === ".svo") { + svoBuffer = readFile(filename); + if (svoBuffer === null) { + return false; + } + + } else { + + if (filename.toLowerCase().slice(-4) === ".fst") { + fstBuffer = readFile(filename); + if (fstBuffer === null) { + return false; + } + mapping = readMapping(fstBuffer); + fbxFilename = filename.path() + "\\" + mapping[FILENAME_FIELD]; + + } else if (filename.toLowerCase().slice(-4) === ".fbx") { + fbxFilename = filename; + mapping[FILENAME_FIELD] = filename.fileName(); + + } else { + error("Unrecognized file type: " + filename); + return false; + } + + fbxBuffer = readFile(fbxFilename); + if (fbxBuffer === null) { + return false; + } + + geometry = readGeometry(fbxBuffer); + if (!mapping.hasOwnProperty(SCALE_FIELD)) { + mapping[SCALE_FIELD] = (geometry.author === "www.makehuman.org" ? 150.0 : 15.0); + } + } + + // Add any missing basic mappings + if (!mapping.hasOwnProperty(NAME_FIELD)) { + mapping[NAME_FIELD] = filename.fileName().slice(0, -4); + } + if (!mapping.hasOwnProperty(TEXDIR_FIELD)) { + mapping[TEXDIR_FIELD] = "."; + } + if (!mapping.hasOwnProperty(SCALE_FIELD)) { + mapping[SCALE_FIELD] = 0.2; // For SVO models. } - model = req.response; return true; } @@ -99,6 +186,8 @@ var modelUploader = (function () { print("Sending model to High Fidelity"); + // DJRTODO + req = new XMLHttpRequest(); req.open("PUT", url, true); req.responseType = "arraybuffer"; @@ -113,24 +202,31 @@ var modelUploader = (function () { } } }; - req.send(model); + + if (fbxBuffer !== null) { + req.send(fbxBuffer.buffer); + } else { + req.send(svoBuffer.buffer); + } } that.upload = function (file, callback) { - var url = urlBase + file.replace(/^(.*[\/\\])*/, ""), - ok; + var url = urlBase + file.fileName(); // Read model content ... - ok = readModel(file); - if (!ok) { return; } + if (!readModel(file)) { + return; + } // Set model properties ... - ok = setProperties(); - if (!ok) { return; } + if (!setProperties()) { + return; + } // Put model in HTTP message ... - ok = createHttpMessage(); - if (!ok) { return; } + if (!createHttpMessage()) { + return; + } // Send model to High Fidelity ... sendToHighFidelity(url, callback); From d0070796174b64b43348f13f770487e4658953cb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 21 Jul 2014 10:30:11 -0700 Subject: [PATCH 016/407] associate username with agent nodes in domain-server --- domain-server/src/DomainServer.cpp | 33 +++++++++++++++++----- domain-server/src/DomainServer.h | 2 +- domain-server/src/DomainServerNodeData.cpp | 1 + domain-server/src/DomainServerNodeData.h | 4 +++ 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 366a5016f9..b57f3ac383 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -426,11 +426,14 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock } } + + QString connectedUsername; if (!isAssignment && !_oauthProviderURL.isEmpty() && _argumentVariantMap.contains(ALLOWED_ROLES_CONFIG_KEY)) { // this is an Agent, and we require authentication so we can compare the user's roles to our list of allowed ones if (_sessionAuthenticationHash.contains(packetUUID)) { - if (!_sessionAuthenticationHash.value(packetUUID)) { + connectedUsername = _sessionAuthenticationHash.take(packetUUID); + if (connectedUsername.isEmpty()) { // we've decided this is a user that isn't allowed in, return out // TODO: provide information to the user so they know why they can't connect return; @@ -473,6 +476,9 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock // now that we've pulled the wallet UUID and added the node to our list, delete the pending assignee data delete pendingAssigneeData; } + + // if we have a username from an OAuth connect request, set it on the DomainServerNodeData + nodeData->setUsername(connectedUsername); nodeData->setSendingSockAddr(senderSockAddr); @@ -860,6 +866,7 @@ const char JSON_KEY_LOCAL_SOCKET[] = "local"; const char JSON_KEY_POOL[] = "pool"; const char JSON_KEY_PENDING_CREDITS[] = "pending_credits"; const char JSON_KEY_WAKE_TIMESTAMP[] = "wake_timestamp"; +const char JSON_KEY_USERNAME[] = "username"; QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { QJsonObject nodeJson; @@ -884,6 +891,10 @@ QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { // if the node has pool information, add it DomainServerNodeData* nodeData = reinterpret_cast(node->getLinkedData()); + + // add the node username, if it exists + nodeJson[JSON_KEY_USERNAME] = nodeData->getUsername(); + SharedAssignmentPointer matchingAssignment = _allAssignments.value(nodeData->getAssignmentUUID()); if (matchingAssignment) { nodeJson[JSON_KEY_POOL] = matchingAssignment->getPool(); @@ -1254,22 +1265,30 @@ void DomainServer::handleProfileRequestFinished() { QJsonArray allowedRolesArray = _argumentVariantMap.value(ALLOWED_ROLES_CONFIG_KEY).toJsonValue().toArray(); - bool shouldAllowUserToConnect = false; + QString connectableUsername; + QString profileUsername = profileJSON.object()["data"].toObject()["user"].toObject()["username"].toString(); foreach(const QJsonValue& roleValue, userRolesArray) { if (allowedRolesArray.contains(roleValue)) { // the user has a role that lets them in // set the bool to true and break - shouldAllowUserToConnect = true; + connectableUsername = profileUsername; break; } } - - qDebug() << "Confirmed authentication state for user" << uuidStringWithoutCurlyBraces(matchingSessionUUID) - << "-" << shouldAllowUserToConnect; + + if (connectableUsername.isEmpty()) { + qDebug() << "User" << profileUsername << "with session UUID" + << uuidStringWithoutCurlyBraces(matchingSessionUUID) + << "does not have an allowable role. Refusing connection."; + } else { + qDebug() << "User" << profileUsername << "with session UUID" + << uuidStringWithoutCurlyBraces(matchingSessionUUID) + << "has an allowable role. Can connect."; + } // insert this UUID and a flag that indicates if they are allowed to connect - _sessionAuthenticationHash.insert(matchingSessionUUID, shouldAllowUserToConnect); + _sessionAuthenticationHash.insert(matchingSessionUUID, connectableUsername); } } } diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index cc44bd95a8..e15e277aaf 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -108,7 +108,7 @@ private: QString _oauthClientSecret; QString _hostname; QMap _networkReplyUUIDMap; - QHash _sessionAuthenticationHash; + QHash _sessionAuthenticationHash; DomainServerSettingsManager _settingsManager; }; diff --git a/domain-server/src/DomainServerNodeData.cpp b/domain-server/src/DomainServerNodeData.cpp index 68903cc106..fd95ea9a67 100644 --- a/domain-server/src/DomainServerNodeData.cpp +++ b/domain-server/src/DomainServerNodeData.cpp @@ -21,6 +21,7 @@ DomainServerNodeData::DomainServerNodeData() : _sessionSecretHash(), _assignmentUUID(), _walletUUID(), + _username(), _paymentIntervalTimer(), _statsJSONObject(), _sendingSockAddr(), diff --git a/domain-server/src/DomainServerNodeData.h b/domain-server/src/DomainServerNodeData.h index a7d7233874..366ee8c730 100644 --- a/domain-server/src/DomainServerNodeData.h +++ b/domain-server/src/DomainServerNodeData.h @@ -35,6 +35,9 @@ public: void setWalletUUID(const QUuid& walletUUID) { _walletUUID = walletUUID; } const QUuid& getWalletUUID() const { return _walletUUID; } + void setUsername(const QString& username) { _username = username; } + const QString& getUsername() const { return _username; } + QElapsedTimer& getPaymentIntervalTimer() { return _paymentIntervalTimer; } void setSendingSockAddr(const HifiSockAddr& sendingSockAddr) { _sendingSockAddr = sendingSockAddr; } @@ -50,6 +53,7 @@ private: QHash _sessionSecretHash; QUuid _assignmentUUID; QUuid _walletUUID; + QString _username; QElapsedTimer _paymentIntervalTimer; QJsonObject _statsJSONObject; HifiSockAddr _sendingSockAddr; From 624bb33b1d2294932961958b5aadc67481f73a36 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 21 Jul 2014 10:34:12 -0700 Subject: [PATCH 017/407] display the node's username in underscore template --- domain-server/resources/web/index.shtml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/domain-server/resources/web/index.shtml b/domain-server/resources/web/index.shtml index f0315a113f..7d9f3c80c5 100644 --- a/domain-server/resources/web/index.shtml +++ b/domain-server/resources/web/index.shtml @@ -10,6 +10,7 @@ Type UUID Pool + Username Public Local Uptime (s) @@ -24,6 +25,7 @@ <%- node.type %> <%- node.uuid %> <%- node.pool %> + <%- node.username %> <%- node.public.ip %><%- node.public.port %> <%- node.local.ip %><%- node.local.port %> <%- ((Date.now() - node.wake_timestamp) / 1000).toLocaleString() %> From a77e49d2abc0a7015cacd38f71bb8bdbfa239a86 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 21 Jul 2014 10:47:07 -0700 Subject: [PATCH 018/407] add back missing colon for node port --- domain-server/resources/web/index.shtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain-server/resources/web/index.shtml b/domain-server/resources/web/index.shtml index 7d9f3c80c5..2f83172d4a 100644 --- a/domain-server/resources/web/index.shtml +++ b/domain-server/resources/web/index.shtml @@ -26,8 +26,8 @@ <%- node.uuid %> <%- node.pool %> <%- node.username %> - <%- node.public.ip %><%- node.public.port %> - <%- node.local.ip %><%- node.local.port %> + <%- node.public.ip %>:<%- node.public.port %> + <%- node.local.ip %>:<%- node.local.port %> <%- ((Date.now() - node.wake_timestamp) / 1000).toLocaleString() %> <%- (typeof node.pending_credits == 'number' ? node.pending_credits.toLocaleString() : 'N/A') %> From f87a83f79e69664556a827dfa44ebb115d4e87ab Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 21 Jul 2014 12:55:25 -0700 Subject: [PATCH 019/407] Read mappings from FST file --- examples/editModels.js | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/examples/editModels.js b/examples/editModels.js index 54cf014dfe..b8ebcd8a6c 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -108,7 +108,32 @@ var modelUploader = (function () { } function readMapping(buffer) { - return {}; // DJRTODO + var mapping = {}, + lines, + line, + values, + name, + i; + + // Simplified to target values relevant to model uploading. + lines = String(buffer.buffer).split(/\r\n|\r|\n/); + for (i = 0; i < lines.length; i += 1) { + line = lines[i].trim(); + if (line.length > 0 && line[0] !== "#") { + values = line.split(/\s*=\s*/); + name = values[0].toLowerCase(); + if (values.length === 2) { + mapping[name] = values[1]; + } else if (values.length === 3 && name === "lod") { + if (mapping[name] === undefined) { + mapping[name] = {}; + } + mapping[name][values[1]] = values[2]; + } + } + } + + return mapping; } function readGeometry(buffer) { @@ -121,6 +146,8 @@ var modelUploader = (function () { fbxFilename, geometry; + print("Reading model file: " + filename); + if (filename.toLowerCase().slice(-4) === ".svo") { svoBuffer = readFile(filename); if (svoBuffer === null) { From f45a50950891f1cf6eb188a8d7e0f0a4d71d92f5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 21 Jul 2014 16:54:27 -0700 Subject: [PATCH 020/407] initial hook-in of OAuth authentication for DS web pages --- domain-server/src/DomainServer.cpp | 177 +++++++++++++++--- domain-server/src/DomainServer.h | 7 + .../embedded-webserver/src/HTTPConnection.cpp | 1 + .../embedded-webserver/src/HTTPConnection.h | 1 + 4 files changed, 162 insertions(+), 24 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index b57f3ac383..b0248d3b57 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -42,6 +42,8 @@ DomainServer::DomainServer(int argc, char* argv[]) : _hostname(), _networkReplyUUIDMap(), _sessionAuthenticationHash(), + _webAuthenticationStateSet(), + _cookieProfileJSONHash(), _settingsManager() { setOrganizationName("High Fidelity"); @@ -932,7 +934,13 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url const QString URI_NODES = "/nodes"; const QString UUID_REGEX_STRING = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"; - + + if (!isAuthenticatedRequest(connection, url)) { + // this is not an authenticated request + // return true from the handler since it was handled with a 401 or re-direct to auth + return true; + } + if (connection->requestOperation() == QNetworkAccessManager::GetOperation) { if (url.path() == "/assignments.json") { // user is asking for json list of assignments @@ -1176,6 +1184,8 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url return _settingsManager.handleHTTPRequest(connection, url); } +const QString HIFI_SESSION_COOKIE_KEY = "DS_WEB_SESSION_UUID"; + bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &url) { const QString URI_OAUTH = "/oauth"; qDebug() << "HTTPS request received at" << url.toString(); @@ -1189,7 +1199,6 @@ bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &u const QString STATE_QUERY_KEY = "state"; QUuid stateUUID = QUuid(codeURLQuery.queryItemValue(STATE_QUERY_KEY)); - if (!authorizationCode.isEmpty() && !stateUUID.isNull()) { // fire off a request with this code and state to get an access token for the user @@ -1204,15 +1213,45 @@ bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &u QNetworkRequest tokenRequest(tokenRequestUrl); tokenRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); - + QNetworkReply* tokenReply = NetworkAccessManager::getInstance().post(tokenRequest, tokenPostBody.toLocal8Bit()); - - qDebug() << "Requesting a token for user with session UUID" << uuidStringWithoutCurlyBraces(stateUUID); - - // insert this to our pending token replies so we can associate the returned access token with the right UUID - _networkReplyUUIDMap.insert(tokenReply, stateUUID); - - connect(tokenReply, &QNetworkReply::finished, this, &DomainServer::handleTokenRequestFinished); + + if (_webAuthenticationStateSet.remove(stateUUID)) { + // this is a web user who wants to auth to access web interface + // we hold the response back to them until we get their profile information + // and can decide if they are let in or not + + QEventLoop loop; + connect(tokenReply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + + // start the loop for the token request + loop.exec(); + + QNetworkReply* profileReply = profileRequestGivenTokenReply(tokenReply); + + // stop the loop once the profileReply is complete + connect(profileReply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + + // restart the loop for the profile request + loop.exec(); + + // call helper method to get cookieHeaders + Headers cookieHeaders = setupCookieHeadersFromProfileReply(profileReply); + + connection->respond(HTTPConnection::StatusCode302, QByteArray(), + HTTPConnection::DefaultContentType, cookieHeaders); + + // we've redirected the user back to our homepage + return true; + + } else { + qDebug() << "Requesting a token for user with session UUID" << uuidStringWithoutCurlyBraces(stateUUID); + + // insert this to our pending token replies so we can associate the returned access token with the right UUID + _networkReplyUUIDMap.insert(tokenReply, stateUUID); + + connect(tokenReply, &QNetworkReply::finished, this, &DomainServer::handleTokenRequestFinished); + } } // respond with a 200 code indicating that login is complete @@ -1224,6 +1263,65 @@ bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &u } } +bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl& url) { + + const QByteArray HTTP_COOKIE_HEADER_KEY = "Cookie"; + const QString ADMIN_USERS_CONFIG_KEY = "admin-users"; + const QString ADMIN_ROLES_CONFIG_KEY = "admin-roles"; + + if (!_oauthProviderURL.isEmpty() + && (_argumentVariantMap.contains(ADMIN_USERS_CONFIG_KEY) || _argumentVariantMap.contains(ADMIN_ROLES_CONFIG_KEY))) { + QString cookieString = connection->requestHeaders().value(HTTP_COOKIE_HEADER_KEY); + + const QString COOKIE_UUID_REGEX_STRING = HIFI_SESSION_COOKIE_KEY + "=([\\d\\w-]+)($|;)"; + QRegExp cookieUUIDRegex(COOKIE_UUID_REGEX_STRING); + + QUuid cookieUUID; + if (cookieString.indexOf(cookieUUIDRegex) != -1) { + cookieUUID = cookieUUIDRegex.cap(1); + } + + if (!cookieUUID.isNull() && _cookieProfileJSONHash.contains(cookieUUID)) { + // pull the QJSONObject for the user with this cookie UUID + QJsonObject profileObject = _cookieProfileJSONHash.value(cookieUUID); + QString profileUsername = profileObject.value("username").toString(); + + if (_argumentVariantMap.value(ADMIN_USERS_CONFIG_KEY).toJsonValue().toArray().contains(profileUsername)) { + // this is an authenticated user + return true; + } else { + QString unauthenticatedRequest = "You do not have permission to access this domain-server."; + connection->respond(HTTPConnection::StatusCode401, unauthenticatedRequest.toUtf8()); + + // the user does not have allowed username or role, return 401 + return false; + } + } else { + // re-direct this user to OAuth page + + // generate a random state UUID to use + QUuid stateUUID = QUuid::createUuid(); + + // add it to the set so we can handle the callback from the OAuth provider + _webAuthenticationStateSet.insert(stateUUID); + + QUrl oauthRedirectURL = oauthAuthorizationURL(stateUUID); + + Headers redirectHeaders; + redirectHeaders.insert("Location", oauthRedirectURL.toEncoded()); + + connection->respond(HTTPConnection::StatusCode302, + QByteArray(), HTTPConnection::DefaultContentType, redirectHeaders); + + // we don't know about this user yet, so they are not yet authenticated + return false; + } + } else { + // we don't have an OAuth URL + admin roles/usernames, so all users are authenticated + return true; + } +} + const QString OAUTH_JSON_ACCESS_TOKEN_KEY = "access_token"; void DomainServer::handleTokenRequestFinished() { @@ -1231,20 +1329,11 @@ void DomainServer::handleTokenRequestFinished() { QUuid matchingSessionUUID = _networkReplyUUIDMap.take(networkReply); if (!matchingSessionUUID.isNull() && networkReply->error() == QNetworkReply::NoError) { - // pull the access token from the returned JSON and store it with the matching session UUID - QJsonDocument returnedJSON = QJsonDocument::fromJson(networkReply->readAll()); - QString accessToken = returnedJSON.object()[OAUTH_JSON_ACCESS_TOKEN_KEY].toString(); - - qDebug() << "Received access token for user with UUID" << uuidStringWithoutCurlyBraces(matchingSessionUUID); - - // fire off a request to get this user's identity so we can see if we will let them in - QUrl profileURL = _oauthProviderURL; - profileURL.setPath("/api/v1/users/profile"); - profileURL.setQuery(QString("%1=%2").arg(OAUTH_JSON_ACCESS_TOKEN_KEY, accessToken)); - - QNetworkReply* profileReply = NetworkAccessManager::getInstance().get(QNetworkRequest(profileURL)); - - qDebug() << "Requesting access token for user with session UUID" << uuidStringWithoutCurlyBraces(matchingSessionUUID); + + qDebug() << "Received access token for user with UUID" << uuidStringWithoutCurlyBraces(matchingSessionUUID) + << "-" << "requesting profile."; + + QNetworkReply* profileReply = profileRequestGivenTokenReply(networkReply); connect(profileReply, &QNetworkReply::finished, this, &DomainServer::handleProfileRequestFinished); @@ -1252,6 +1341,19 @@ void DomainServer::handleTokenRequestFinished() { } } +QNetworkReply* DomainServer::profileRequestGivenTokenReply(QNetworkReply* tokenReply) { + // pull the access token from the returned JSON and store it with the matching session UUID + QJsonDocument returnedJSON = QJsonDocument::fromJson(tokenReply->readAll()); + QString accessToken = returnedJSON.object()[OAUTH_JSON_ACCESS_TOKEN_KEY].toString(); + + // fire off a request to get this user's identity so we can see if we will let them in + QUrl profileURL = _oauthProviderURL; + profileURL.setPath("/api/v1/users/profile"); + profileURL.setQuery(QString("%1=%2").arg(OAUTH_JSON_ACCESS_TOKEN_KEY, accessToken)); + + return NetworkAccessManager::getInstance().get(QNetworkRequest(profileURL)); +} + void DomainServer::handleProfileRequestFinished() { QNetworkReply* networkReply = reinterpret_cast(sender()); QUuid matchingSessionUUID = _networkReplyUUIDMap.take(networkReply); @@ -1293,6 +1395,33 @@ void DomainServer::handleProfileRequestFinished() { } } +Headers DomainServer::setupCookieHeadersFromProfileReply(QNetworkReply* profileReply) { + Headers cookieHeaders; + + // create a UUID for this cookie + QUuid cookieUUID = QUuid::createUuid(); + + QJsonDocument profileDocument = QJsonDocument::fromJson(profileReply->readAll()); + + // add the profile to our in-memory data structure so we know who the user is when they send us their cookie + _cookieProfileJSONHash.insert(cookieUUID, profileDocument.object()["data"].toObject()["user"].toObject()); + + // setup expiry for cookie to 1 month from today + QDateTime cookieExpiry = QDateTime::currentDateTimeUtc().addMonths(1); + + QString cookieString = HIFI_SESSION_COOKIE_KEY + "=" + uuidStringWithoutCurlyBraces(cookieUUID.toString()); + cookieString += "; expires=" + cookieExpiry.toString("ddd, dd MMM yyyy HH:mm:ss") + " GMT"; + cookieString += "; domain=" + _hostname + "; path=/"; + + cookieHeaders.insert("Set-Cookie", cookieString.toUtf8()); + + // redirect the user back to the homepage so they can present their cookie and be authenticated + QString redirectString = "http://" + _hostname + ":" + QString::number(_httpManager.serverPort()); + cookieHeaders.insert("Location", redirectString.toUtf8()); + + return cookieHeaders; +} + void DomainServer::refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& assignment) { QUuid oldUUID = assignment->getUUID(); assignment->resetUUID(); diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index e15e277aaf..98e5b96f25 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -85,8 +85,12 @@ private: QUrl oauthRedirectURL(); QUrl oauthAuthorizationURL(const QUuid& stateUUID = QUuid::createUuid()); + bool isAuthenticatedRequest(HTTPConnection* connection, const QUrl& url); + void handleTokenRequestFinished(); + QNetworkReply* profileRequestGivenTokenReply(QNetworkReply* tokenReply); void handleProfileRequestFinished(); + Headers setupCookieHeadersFromProfileReply(QNetworkReply* profileReply); QJsonObject jsonForSocket(const HifiSockAddr& socket); QJsonObject jsonObjectForNode(const SharedNodePointer& node); @@ -110,6 +114,9 @@ private: QMap _networkReplyUUIDMap; QHash _sessionAuthenticationHash; + QSet _webAuthenticationStateSet; + QHash _cookieProfileJSONHash; + DomainServerSettingsManager _settingsManager; }; diff --git a/libraries/embedded-webserver/src/HTTPConnection.cpp b/libraries/embedded-webserver/src/HTTPConnection.cpp index beb107c4cf..7112a90825 100755 --- a/libraries/embedded-webserver/src/HTTPConnection.cpp +++ b/libraries/embedded-webserver/src/HTTPConnection.cpp @@ -21,6 +21,7 @@ const char* HTTPConnection::StatusCode200 = "200 OK"; const char* HTTPConnection::StatusCode301 = "301 Moved Permanently"; const char* HTTPConnection::StatusCode302 = "302 Found"; const char* HTTPConnection::StatusCode400 = "400 Bad Request"; +const char* HTTPConnection::StatusCode401 = "401 Unauthorized"; const char* HTTPConnection::StatusCode404 = "404 Not Found"; const char* HTTPConnection::DefaultContentType = "text/plain; charset=ISO-8859-1"; diff --git a/libraries/embedded-webserver/src/HTTPConnection.h b/libraries/embedded-webserver/src/HTTPConnection.h index e2352ed250..c981537c15 100644 --- a/libraries/embedded-webserver/src/HTTPConnection.h +++ b/libraries/embedded-webserver/src/HTTPConnection.h @@ -46,6 +46,7 @@ public: static const char* StatusCode301; static const char* StatusCode302; static const char* StatusCode400; + static const char* StatusCode401; static const char* StatusCode404; static const char* DefaultContentType; From 1903fff45c29f5200d37f5112896a084667fa7ea Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 21 Jul 2014 17:03:09 -0700 Subject: [PATCH 021/407] hide remote socket closed error message in HTTPConnection --- libraries/embedded-webserver/src/HTTPConnection.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/embedded-webserver/src/HTTPConnection.cpp b/libraries/embedded-webserver/src/HTTPConnection.cpp index 7112a90825..82d3d7eba6 100755 --- a/libraries/embedded-webserver/src/HTTPConnection.cpp +++ b/libraries/embedded-webserver/src/HTTPConnection.cpp @@ -43,7 +43,8 @@ HTTPConnection::HTTPConnection (QTcpSocket* socket, HTTPManager* parentManager) HTTPConnection::~HTTPConnection() { // log the destruction - if (_socket->error() != QAbstractSocket::UnknownSocketError) { + if (_socket->error() != QAbstractSocket::UnknownSocketError + && _socket->error() != QAbstractSocket::RemoteHostClosedError) { qDebug() << _socket->errorString() << "-" << _socket->error(); } } From e75ed2c4fa8982468da9fd0d05897f40c5279013 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 21 Jul 2014 17:23:57 -0700 Subject: [PATCH 022/407] add a class to hold web session data --- .../src/DomainServerWebSessionData.cpp | 26 ++++++++++++++++ .../src/DomainServerWebSessionData.h | 31 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 domain-server/src/DomainServerWebSessionData.cpp create mode 100644 domain-server/src/DomainServerWebSessionData.h diff --git a/domain-server/src/DomainServerWebSessionData.cpp b/domain-server/src/DomainServerWebSessionData.cpp new file mode 100644 index 0000000000..e59f255822 --- /dev/null +++ b/domain-server/src/DomainServerWebSessionData.cpp @@ -0,0 +1,26 @@ +// +// DomainServerWebSessionData.cpp +// domain-server/src +// +// Created by Stephen Birarda on 2014-07-21. +// 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 +// + +#include +#include + +#include "DomainServerWebSessionData.h" + +DomainServerWebSessionData::DomainServerWebSessionData(const QJsonDocument& profileDocument) : + _roles() +{ + _username = profileDocument.object()["user"].toObject()["username"].toString(); + + // pull each of the roles and throw them into our set + foreach(const QJsonValue& rolesValue, profileDocument.object()["user"].toObject()["roles"].toObject()) { + _roles.insert(rolesValue.toString()); + } +} \ No newline at end of file diff --git a/domain-server/src/DomainServerWebSessionData.h b/domain-server/src/DomainServerWebSessionData.h new file mode 100644 index 0000000000..80088c9362 --- /dev/null +++ b/domain-server/src/DomainServerWebSessionData.h @@ -0,0 +1,31 @@ +// +// DomainServerWebSessionData.h +// domain-server/src +// +// Created by Stephen Birarda on 2014-07-21. +// 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 +// + +#ifndef hifi_DomainServerWebSessionData_h +#define hifi_DomainServerWebSessionData_h + +#include +#include + +class DomainServerWebSessionData : public QObject { + Q_OBJECT +public: + DomainServerWebSessionData(const QJsonDocument& profileDocument); + + const QString& getUsername() const { return _username; } + const QSet& getRoles() const { return _roles; } + +private: + QString _username; + QSet _roles; +}; + +#endif // hifi_DomainServerWebSessionData_h \ No newline at end of file From f78a1f703374dcde09826d78b6a800d06d48fdd4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 21 Jul 2014 17:32:38 -0700 Subject: [PATCH 023/407] hook domain-server to user DomainServerWebSessionData class --- domain-server/src/DomainServer.cpp | 10 +++---- domain-server/src/DomainServer.h | 3 +- .../src/DomainServerWebSessionData.cpp | 28 ++++++++++++++++++- .../src/DomainServerWebSessionData.h | 5 ++++ 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index b0248d3b57..3c0a088869 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -43,7 +43,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : _networkReplyUUIDMap(), _sessionAuthenticationHash(), _webAuthenticationStateSet(), - _cookieProfileJSONHash(), + _cookieSessionHash(), _settingsManager() { setOrganizationName("High Fidelity"); @@ -1281,10 +1281,10 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl cookieUUID = cookieUUIDRegex.cap(1); } - if (!cookieUUID.isNull() && _cookieProfileJSONHash.contains(cookieUUID)) { + if (!cookieUUID.isNull() && _cookieSessionHash.contains(cookieUUID)) { // pull the QJSONObject for the user with this cookie UUID - QJsonObject profileObject = _cookieProfileJSONHash.value(cookieUUID); - QString profileUsername = profileObject.value("username").toString(); + DomainServerWebSessionData sessionData = _cookieSessionHash.value(cookieUUID); + QString profileUsername = sessionData.getUsername(); if (_argumentVariantMap.value(ADMIN_USERS_CONFIG_KEY).toJsonValue().toArray().contains(profileUsername)) { // this is an authenticated user @@ -1404,7 +1404,7 @@ Headers DomainServer::setupCookieHeadersFromProfileReply(QNetworkReply* profileR QJsonDocument profileDocument = QJsonDocument::fromJson(profileReply->readAll()); // add the profile to our in-memory data structure so we know who the user is when they send us their cookie - _cookieProfileJSONHash.insert(cookieUUID, profileDocument.object()["data"].toObject()["user"].toObject()); + _cookieSessionHash.insert(cookieUUID, DomainServerWebSessionData(profileDocument)); // setup expiry for cookie to 1 month from today QDateTime cookieExpiry = QDateTime::currentDateTimeUtc().addMonths(1); diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 98e5b96f25..f8daa9a529 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -25,6 +25,7 @@ #include #include "DomainServerSettingsManager.h" +#include "DomainServerWebSessionData.h" #include "WalletTransaction.h" #include "PendingAssignedNodeData.h" @@ -115,7 +116,7 @@ private: QHash _sessionAuthenticationHash; QSet _webAuthenticationStateSet; - QHash _cookieProfileJSONHash; + QHash _cookieSessionHash; DomainServerSettingsManager _settingsManager; }; diff --git a/domain-server/src/DomainServerWebSessionData.cpp b/domain-server/src/DomainServerWebSessionData.cpp index e59f255822..de73ca77dd 100644 --- a/domain-server/src/DomainServerWebSessionData.cpp +++ b/domain-server/src/DomainServerWebSessionData.cpp @@ -14,6 +14,13 @@ #include "DomainServerWebSessionData.h" +DomainServerWebSessionData::DomainServerWebSessionData() : + _username(), + _roles() +{ + +} + DomainServerWebSessionData::DomainServerWebSessionData(const QJsonDocument& profileDocument) : _roles() { @@ -23,4 +30,23 @@ DomainServerWebSessionData::DomainServerWebSessionData(const QJsonDocument& prof foreach(const QJsonValue& rolesValue, profileDocument.object()["user"].toObject()["roles"].toObject()) { _roles.insert(rolesValue.toString()); } -} \ No newline at end of file +} + +DomainServerWebSessionData::DomainServerWebSessionData(const DomainServerWebSessionData& otherSessionData) { + _username = otherSessionData._username; + _roles = otherSessionData._roles; +} + +DomainServerWebSessionData& DomainServerWebSessionData::operator=(const DomainServerWebSessionData& otherSessionData) { + DomainServerWebSessionData temp(otherSessionData); + swap(temp); + return *this; +} + +void DomainServerWebSessionData::swap(DomainServerWebSessionData& otherSessionData) { + using std::swap; + + swap(_username, otherSessionData._username); + swap(_roles, otherSessionData._roles); +} + diff --git a/domain-server/src/DomainServerWebSessionData.h b/domain-server/src/DomainServerWebSessionData.h index 80088c9362..cd2410cf66 100644 --- a/domain-server/src/DomainServerWebSessionData.h +++ b/domain-server/src/DomainServerWebSessionData.h @@ -18,12 +18,17 @@ class DomainServerWebSessionData : public QObject { Q_OBJECT public: + DomainServerWebSessionData(); DomainServerWebSessionData(const QJsonDocument& profileDocument); + DomainServerWebSessionData(const DomainServerWebSessionData& otherSessionData); + DomainServerWebSessionData& operator=(const DomainServerWebSessionData& otherSessionData); const QString& getUsername() const { return _username; } const QSet& getRoles() const { return _roles; } private: + void swap(DomainServerWebSessionData& otherSessionData); + QString _username; QSet _roles; }; From 8082e2f88b08c263cb4603099562b4249df7c7ae Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 21 Jul 2014 17:41:22 -0700 Subject: [PATCH 024/407] allow a user to be let into domain-server based on role --- domain-server/src/DomainServer.cpp | 27 ++++++++++++++----- .../src/DomainServerWebSessionData.cpp | 9 ++++--- .../src/DomainServerWebSessionData.h | 2 +- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 3c0a088869..52da966d46 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1289,13 +1289,25 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl if (_argumentVariantMap.value(ADMIN_USERS_CONFIG_KEY).toJsonValue().toArray().contains(profileUsername)) { // this is an authenticated user return true; - } else { - QString unauthenticatedRequest = "You do not have permission to access this domain-server."; - connection->respond(HTTPConnection::StatusCode401, unauthenticatedRequest.toUtf8()); - - // the user does not have allowed username or role, return 401 - return false; } + + // loop the roles of this user and see if they are in the admin-roles array + QJsonArray adminRolesArray = _argumentVariantMap.value(ADMIN_ROLES_CONFIG_KEY).toJsonValue().toArray(); + + if (!adminRolesArray.isEmpty()) { + foreach(const QString& userRole, sessionData.getRoles()) { + if (adminRolesArray.contains(userRole)) { + // this user has a role that allows them to administer the domain-server + return true; + } + } + } + + QString unauthenticatedRequest = "You do not have permission to access this domain-server."; + connection->respond(HTTPConnection::StatusCode401, unauthenticatedRequest.toUtf8()); + + // the user does not have allowed username or role, return 401 + return false; } else { // re-direct this user to OAuth page @@ -1402,9 +1414,10 @@ Headers DomainServer::setupCookieHeadersFromProfileReply(QNetworkReply* profileR QUuid cookieUUID = QUuid::createUuid(); QJsonDocument profileDocument = QJsonDocument::fromJson(profileReply->readAll()); + QJsonObject userObject = profileDocument.object()["data"].toObject()["user"].toObject(); // add the profile to our in-memory data structure so we know who the user is when they send us their cookie - _cookieSessionHash.insert(cookieUUID, DomainServerWebSessionData(profileDocument)); + _cookieSessionHash.insert(cookieUUID, DomainServerWebSessionData(userObject)); // setup expiry for cookie to 1 month from today QDateTime cookieExpiry = QDateTime::currentDateTimeUtc().addMonths(1); diff --git a/domain-server/src/DomainServerWebSessionData.cpp b/domain-server/src/DomainServerWebSessionData.cpp index de73ca77dd..b0c56cc59e 100644 --- a/domain-server/src/DomainServerWebSessionData.cpp +++ b/domain-server/src/DomainServerWebSessionData.cpp @@ -9,7 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include +#include #include #include "DomainServerWebSessionData.h" @@ -21,13 +22,13 @@ DomainServerWebSessionData::DomainServerWebSessionData() : } -DomainServerWebSessionData::DomainServerWebSessionData(const QJsonDocument& profileDocument) : +DomainServerWebSessionData::DomainServerWebSessionData(const QJsonObject& userObject) : _roles() { - _username = profileDocument.object()["user"].toObject()["username"].toString(); + _username = userObject["username"].toString(); // pull each of the roles and throw them into our set - foreach(const QJsonValue& rolesValue, profileDocument.object()["user"].toObject()["roles"].toObject()) { + foreach(const QJsonValue& rolesValue, userObject["roles"].toArray()) { _roles.insert(rolesValue.toString()); } } diff --git a/domain-server/src/DomainServerWebSessionData.h b/domain-server/src/DomainServerWebSessionData.h index cd2410cf66..15e4171b57 100644 --- a/domain-server/src/DomainServerWebSessionData.h +++ b/domain-server/src/DomainServerWebSessionData.h @@ -19,7 +19,7 @@ class DomainServerWebSessionData : public QObject { Q_OBJECT public: DomainServerWebSessionData(); - DomainServerWebSessionData(const QJsonDocument& profileDocument); + DomainServerWebSessionData(const QJsonObject& userObject); DomainServerWebSessionData(const DomainServerWebSessionData& otherSessionData); DomainServerWebSessionData& operator=(const DomainServerWebSessionData& otherSessionData); From ef8ce8ad7d1848976cbaa8c0ad0d59d26a2696a5 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 21 Jul 2014 21:39:52 -0700 Subject: [PATCH 025/407] Remember location of model file last selected --- examples/editModels.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/editModels.js b/examples/editModels.js index b8ebcd8a6c..0363f29b05 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -396,8 +396,11 @@ var toolBar = (function () { if (clickedOverlay === loadFileMenuItem) { toggleToolbar(false); - file = Window.browse("Select your model file ...", "", "Model files (*.fst *.fbx *.svo)"); + file = Window.browse("Select your model file ...", + Settings.getValue("LastModelUploadLocation").path(), + "Model files (*.fst *.fbx *.svo)"); if (file !== null) { + Settings.setValue("LastModelUploadLocation", file); modelUploader.upload(file, addModel); } return true; From 09d52251ef04d1f9d9d1ad4c5868a22c5b4c27cf Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 22 Jul 2014 20:38:44 -0700 Subject: [PATCH 026/407] Fix merge --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8b00bface7..02f4842e88 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3628,7 +3628,7 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript scriptEngine->getModelsScriptingInterface()->setModelTree(_models.getTree()); // model has some custom types - Model::registerMetaTypes(scriptEngine->getEngine()); + Model::registerMetaTypes(scriptEngine); // hook our avatar object into this script engine scriptEngine->setAvatarData(_myAvatar, "MyAvatar"); // leave it as a MyAvatar class to expose thrust features From ed7bd9317e3d1cd4aef678828cc1bec2e7300276 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 22 Jul 2014 21:48:48 -0700 Subject: [PATCH 027/407] Make XMLHttpRequest return an ArrayBuffer object when requested --- libraries/script-engine/src/XMLHttpRequestClass.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index 8e48682ea0..563e268222 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -18,6 +18,7 @@ #include #include "XMLHttpRequestClass.h" +#include "ScriptEngine.h" XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) : _engine(engine), @@ -296,7 +297,8 @@ void XMLHttpRequestClass::requestFinished() { _responseData = QScriptValue::NullValue; } } else if (_responseType == "arraybuffer") { - _responseData = _engine->newVariant(QVariant::fromValue(_rawResponseData)); + QScriptValue data = _engine->newVariant(QVariant::fromValue(_rawResponseData)); + _responseData = _engine->newObject(reinterpret_cast(_engine)->getArrayBufferClass(), data); } else { _responseData = QScriptValue(QString(_rawResponseData.data())); } From 1a13fbb437b5d79fa66793d7170d8defc399b555 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 23 Jul 2014 10:54:55 -0700 Subject: [PATCH 028/407] add a setting section for voxel costs --- .../resources/web/settings/describe.json | 20 +++++++++++++++++++ .../resources/web/settings/index.shtml | 18 +++++++++++------ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/domain-server/resources/web/settings/describe.json b/domain-server/resources/web/settings/describe.json index 227b6bf0cd..97280bfd32 100644 --- a/domain-server/resources/web/settings/describe.json +++ b/domain-server/resources/web/settings/describe.json @@ -16,5 +16,25 @@ "default": false } } + }, + "voxels": { + "label": "Voxels", + "assignment-types": [3], + "settings": { + "per-voxel-cost": { + "label": "Per Voxel Cost", + "help": "Credit cost to change each voxel", + "placeholder": "0.00001", + "default": "0.00001", + "input_addon": "₵" + }, + "volume-cost": { + "label": "Volume Cost", + "help": "Credit cost to change each cubed meter of voxel space", + "placeholder": "0.0005", + "default": "0.0005", + "input_addon": "₵" + } + } } } \ No newline at end of file diff --git a/domain-server/resources/web/settings/index.shtml b/domain-server/resources/web/settings/index.shtml index 3bb669b32e..73e3cdbea2 100644 --- a/domain-server/resources/web/settings/index.shtml +++ b/domain-server/resources/web/settings/index.shtml @@ -16,16 +16,22 @@ <% var setting_id = group_key + "." + setting_key %>
- <% if(setting.type) %> - <% if (setting.type === "checkbox") { %> - <% var checked_box = (values[group_key] || {})[setting_key] || setting.default %> - > - <% } else { %> + <% if (setting.type === "checkbox") { %> + <% var checked_box = (values[group_key] || {})[setting_key] || setting.default %> + > + <% } else { %> + <% if (setting.input_addon) { %> +
+
<%- setting.input_addon %>
+ <% } %> + + <% if (setting.input_addon) { %> +
+ <% } %> <% } %> -

<%- setting.help %>

From ebf5379275a5376d23839a722b96bded3e267836 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 23 Jul 2014 11:13:12 -0700 Subject: [PATCH 029/407] default voxel costs to free, add a wallet ID for voxel change payments --- domain-server/resources/web/settings/describe.json | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/domain-server/resources/web/settings/describe.json b/domain-server/resources/web/settings/describe.json index 97280bfd32..0ab647734b 100644 --- a/domain-server/resources/web/settings/describe.json +++ b/domain-server/resources/web/settings/describe.json @@ -21,18 +21,24 @@ "label": "Voxels", "assignment-types": [3], "settings": { + "voxel-wallet": { + "label": "Destination Wallet ID", + "help": "Wallet to be paid for voxel changes", + "placeholder": "00000000-0000-0000-0000-000000000000", + "default": "" + }, "per-voxel-cost": { "label": "Per Voxel Cost", "help": "Credit cost to change each voxel", - "placeholder": "0.00001", - "default": "0.00001", + "placeholder": "0.0", + "default": "0.0", "input_addon": "₵" }, "volume-cost": { "label": "Volume Cost", "help": "Credit cost to change each cubed meter of voxel space", - "placeholder": "0.0005", - "default": "0.0005", + "placeholder": "0.0", + "default": "0.0", "input_addon": "₵" } } From 74d17a094f0a190c3aa080143e02c4f5ad6b0434 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 23 Jul 2014 11:47:56 -0700 Subject: [PATCH 030/407] tweaks to string default handling in DomainServerSettingsManager --- .../src/DomainServerSettingsManager.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index f9996aa0e7..0520426ea8 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -145,7 +145,12 @@ void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ // we don't continue if this key is not present in our descriptionObject if (descriptionObject.contains(key)) { if (rootValue.isString()) { - settingsVariant[key] = rootValue.toString(); + if (rootValue.toString().isEmpty()) { + // this is an empty value, clear it in settings variant so the default is sent + settingsVariant.remove(key); + } else { + settingsVariant[key] = rootValue.toString(); + } } else if (rootValue.isBool()) { settingsVariant[key] = rootValue.toBool(); } else if (rootValue.isObject()) { @@ -158,9 +163,16 @@ void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ settingsVariant[key] = QVariantMap(); } + QVariantMap& thisMap = *reinterpret_cast(settingsVariant[key].data()); + recurseJSONObjectAndOverwriteSettings(rootValue.toObject(), - *reinterpret_cast(settingsVariant[key].data()), + thisMap, nextDescriptionObject[DESCRIPTION_SETTINGS_KEY].toObject()); + + if (thisMap.isEmpty()) { + // we've cleared all of the settings below this value, so remove this one too + settingsVariant.remove(key); + } } } } From ec8b82bf6e5c9ffd69d864da1ada45741d12f42d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 23 Jul 2014 12:27:52 -0700 Subject: [PATCH 031/407] Read author and texture filenames from binary FBX files --- examples/editModels.js | 95 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 91 insertions(+), 4 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 0363f29b05..51757f81bb 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -58,18 +58,62 @@ var jointList = MyAvatar.getJointNames(); var mode = 0; -if (typeof String.prototype.fileName !== 'function') { +if (typeof String.prototype.fileName !== "function") { String.prototype.fileName = function (str) { return this.replace(/^(.*[\/\\])*/, ""); }; } -if (typeof String.prototype.path !== 'function') { +if (typeof String.prototype.path !== "function") { String.prototype.path = function (str) { return this.replace(/[\\\/][^\\\/]*$/, ""); }; } +if (typeof DataView.prototype.indexOf !== "function") { + DataView.prototype.indexOf = function (searchString, position) { + var searchLength = searchString.length, + byteArrayLength = this.byteLength, + maxSearchIndex = byteArrayLength - searchLength, + searchCharCodes = [], + found, + i, + j; + + searchCharCodes[searchLength] = 0; + for (j = 0; j < searchLength; j += 1) { + searchCharCodes[j] = searchString.charCodeAt(j); + } + + i = position; + found = false; + while (i < maxSearchIndex && !found) { + j = 0; + while (j < searchLength && this.getUint8(i + j) === searchCharCodes[j]) { + j += 1; + } + found = (j === searchLength); + i += 1; + } + + return found ? i - 1 : -1; + }; +} + +if (typeof DataView.prototype.string !== "function") { + DataView.prototype.string = function (i, length) { + var charCodes = [], + end = i + length, + j; + + for (j = i; j < end; j += 1) { + charCodes.push(this.getUint8(j)); + } + + return String.fromCharCode.apply(String, charCodes); + }; +} + var modelUploader = (function () { var that = {}, @@ -136,8 +180,51 @@ var modelUploader = (function () { return mapping; } - function readGeometry(buffer) { - return {}; // DJRTODO + function readGeometry(fbxBuffer) { + var dv = new DataView(fbxBuffer.buffer), + geometry = {}, + pathLength, + filename, + author, + i; + + // Simple direct search of FBX file for relevant texture filenames (excl. paths) instead of interpreting FBX format. + // - "RelativeFilename" Record type + // - char Subtype + // - Uint8 Length of path string + // - 00 00 00 3 null chars + // - Path and name of texture file + geometry.textures = []; + i = 0; + while (i !== -1) { + i = dv.indexOf("RelativeFilename", i); + if (i !== -1) { + i += 17; // Record type and subtype + pathLength = dv.getUint8(i); + i += 4; // Path length and null chars + filename = dv.string(i, pathLength).fileName(); + geometry.textures.push(filename); + i += pathLength; + } + } + + // Simple direct search of FBX file for the first author record. + // - "Author" Record type + // - char Subtype + // - Uint8 Length of path string + // - 00 00 00 3 null chars + // - Path and name of texture file + i = dv.indexOf("Author", 0); + if (i !== -1) { + i += 7; + pathLength = dv.getUint8(i); + if (pathLength > 0) { + author = dv.string(i, pathLength); + geometry.author = author; + } + } + + return geometry; } function readModel(filename) { From 6b72274d219a69371d2df1e5792724becdfefa83 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 23 Jul 2014 16:05:34 -0700 Subject: [PATCH 032/407] Read author and texture filenames from text FBX files --- examples/editModels.js | 51 +++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 51757f81bb..bcfa0176cc 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -183,43 +183,68 @@ var modelUploader = (function () { function readGeometry(fbxBuffer) { var dv = new DataView(fbxBuffer.buffer), geometry = {}, - pathLength, + binary, + stringLength, filename, author, i; + binary = (dv.string(0, 18) === "Kaydara FBX Binary"); + // Simple direct search of FBX file for relevant texture filenames (excl. paths) instead of interpreting FBX format. - // - "RelativeFilename" Record type + // Binary format: + // - 'RelativeFilename' Record type // - char Subtype // - Uint8 Length of path string // - 00 00 00 3 null chars // - Path and name of texture file + // Text format: + // - 'RelativeFilename' Record type + // - ': " ' Pre-string colon and quote + // - Path and name of texture file + // - '"' End-of-string quote geometry.textures = []; i = 0; while (i !== -1) { i = dv.indexOf("RelativeFilename", i); if (i !== -1) { - i += 17; // Record type and subtype - pathLength = dv.getUint8(i); - i += 4; // Path length and null chars - filename = dv.string(i, pathLength).fileName(); + if (binary) { + i += 17; + stringLength = dv.getUint8(i); + i += 4; + } else { + i = dv.indexOf("\"", i) + 1; + stringLength = dv.indexOf("\"", i) - i; + } + filename = dv.string(i, stringLength).fileName(); geometry.textures.push(filename); - i += pathLength; + i += stringLength; } } // Simple direct search of FBX file for the first author record. - // - "Author" Record type + // Binary format: + // - 'Author' Record type // - char Subtype // - Uint8 Length of path string // - 00 00 00 3 null chars - // - Path and name of texture file + // - Author name + // Text format: + // - 'Author' Record type + // - ': "' Pre-string colon and quote + // - Author name; may be empty + // - '"' End-of-string quote i = dv.indexOf("Author", 0); if (i !== -1) { - i += 7; - pathLength = dv.getUint8(i); - if (pathLength > 0) { - author = dv.string(i, pathLength); + if (binary) { + i += 7; + stringLength = dv.getUint8(i); + } else { + i = dv.indexOf("\"", i) + 1; + stringLength = dv.indexOf("\"", i) - i; + } + if (stringLength > 0) { + author = dv.string(i, stringLength); geometry.author = author; } } From 401326ddd7c140ce932b6e852695006c83347f64 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 23 Jul 2014 16:59:52 -0700 Subject: [PATCH 033/407] Fix FST file processing after ArrayBuffer change --- examples/editModels.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index bcfa0176cc..917f9ad7fd 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -151,8 +151,9 @@ var modelUploader = (function () { }; } - function readMapping(buffer) { - var mapping = {}, + function readMapping(fstBuffer) { + var dv = new DataView(fstBuffer.buffer), + mapping = {}, lines, line, values, @@ -160,7 +161,7 @@ var modelUploader = (function () { i; // Simplified to target values relevant to model uploading. - lines = String(buffer.buffer).split(/\r\n|\r|\n/); + lines = dv.string(0, dv.byteLength).split(/\r\n|\r|\n/); for (i = 0; i < lines.length; i += 1) { line = lines[i].trim(); if (line.length > 0 && line[0] !== "#") { From 7c6f1ff414d819e9d3b21b13b0d57d8286865923 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 23 Jul 2014 17:09:40 -0700 Subject: [PATCH 034/407] Handle FBX file name not found in FST file more gracefully --- examples/editModels.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/editModels.js b/examples/editModels.js index 917f9ad7fd..1498cff6d0 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -275,7 +275,12 @@ var modelUploader = (function () { return false; } mapping = readMapping(fstBuffer); - fbxFilename = filename.path() + "\\" + mapping[FILENAME_FIELD]; + if (mapping.hasOwnProperty(FILENAME_FIELD)) { + fbxFilename = filename.path() + "\\" + mapping[FILENAME_FIELD]; + } else { + error("FBX file name not found in FST file!"); + return false; + } } else if (filename.toLowerCase().slice(-4) === ".fbx") { fbxFilename = filename; From 2e5dc2320d65d16df83afbca64717f7d34d5e767 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 24 Jul 2014 11:09:09 -0700 Subject: [PATCH 035/407] don't flip order on node socket, HifiSockAddr is handling --- domain-server/src/DomainServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 52da966d46..4261b5033b 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -856,7 +856,7 @@ QJsonObject DomainServer::jsonForSocket(const HifiSockAddr& socket) { QJsonObject socketJSON; socketJSON["ip"] = socket.getAddress().toString(); - socketJSON["port"] = ntohs(socket.getPort()); + socketJSON["port"] = socket.getPort(); return socketJSON; } From 040254a119ad8d651c642401ee31d0459b5f1929 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 24 Jul 2014 17:04:02 -0700 Subject: [PATCH 036/407] Add optional Cancel button to JavaScript Window.form() --- .../scripting/WindowScriptingInterface.cpp | 63 ++++++++++++------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 827f66c8d5..a36d149a86 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -94,11 +94,14 @@ QScriptValue WindowScriptingInterface::showConfirm(const QString& message) { /// Display a form layout with an edit box /// \param const QString& title title to display /// \param const QScriptValue form to display (array containing labels and values) -/// \return QScriptValue result form (unchanged is dialog canceled) +/// \return QScriptValue `true` if 'OK' was clicked, `false` otherwise QScriptValue WindowScriptingInterface::showForm(const QString& title, QScriptValue form) { + if (form.isArray() && form.property("length").toInt32() > 0) { QDialog* editDialog = new QDialog(Application::getInstance()->getWindow()); editDialog->setWindowTitle(title); + + bool cancelButton = false; QVBoxLayout* layout = new QVBoxLayout(); editDialog->setLayout(layout); @@ -120,42 +123,60 @@ QScriptValue WindowScriptingInterface::showForm(const QString& title, QScriptVal QVector edits; for (int i = 0; i < form.property("length").toInt32(); ++i) { QScriptValue item = form.property(i); - edits.push_back(new QLineEdit(item.property("value").toString())); - formLayout->addRow(item.property("label").toString(), edits.back()); + + if (item.property("button").toString() != "") { + cancelButton = cancelButton || item.property("button").toString().toLower() == "cancel"; + } else { + edits.push_back(new QLineEdit(item.property("value").toString())); + formLayout->addRow(item.property("label").toString(), edits.back()); + } } - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok); + + QDialogButtonBox* buttons = new QDialogButtonBox( + QDialogButtonBox::Ok + | (cancelButton ? QDialogButtonBox::Cancel : QDialogButtonBox::NoButton) + ); connect(buttons, SIGNAL(accepted()), editDialog, SLOT(accept())); + connect(buttons, SIGNAL(rejected()), editDialog, SLOT(reject())); layout->addWidget(buttons); - if (editDialog->exec() == QDialog::Accepted) { + int result = editDialog->exec(); + if (result == QDialog::Accepted) { + int j = -1; for (int i = 0; i < form.property("length").toInt32(); ++i) { QScriptValue item = form.property(i); QScriptValue value = item.property("value"); bool ok = true; - if (value.isNumber()) { - value = edits.at(i)->text().toDouble(&ok); - } else if (value.isString()) { - value = edits.at(i)->text(); - } else if (value.isBool()) { - if (edits.at(i)->text() == "true") { - value = true; - } else if (edits.at(i)->text() == "false") { - value = false; - } else { - ok = false; + qDebug() << "item.property(""button"").toString() = " << item.property("button").toString(); + if (item.property("button").toString() == "") { + j += 1; + if (value.isNumber()) { + value = edits.at(j)->text().toDouble(&ok); + } else if (value.isString()) { + value = edits.at(j)->text(); + } else if (value.isBool()) { + if (edits.at(j)->text() == "true") { + value = true; + } else if (edits.at(j)->text() == "false") { + value = false; + } else { + ok = false; + } + } + if (ok) { + item.setProperty("value", value); + form.setProperty(i, item); } - } - if (ok) { - item.setProperty("value", value); - form.setProperty(i, item); } } } delete editDialog; + + return (result == QDialog::Accepted); } - return form; + return false; } /// Display a prompt with a text box From 005a3c7c1239b156f7df2cd8e6d8efd107717f64 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 24 Jul 2014 17:17:57 -0700 Subject: [PATCH 037/407] persist and recall domain-server web sessions from ini settings --- domain-server/src/DomainServer.cpp | 28 ++++++++++++++++++- domain-server/src/DomainServer.h | 2 ++ .../src/DomainServerWebSessionData.cpp | 10 +++++++ .../src/DomainServerWebSessionData.h | 5 ++++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 4261b5033b..e462e05aa6 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -50,6 +50,9 @@ DomainServer::DomainServer(int argc, char* argv[]) : setOrganizationDomain("highfidelity.io"); setApplicationName("domain-server"); QSettings::setDefaultFormat(QSettings::IniFormat); + + qRegisterMetaType("DomainServerWebSessionData"); + qRegisterMetaTypeStreamOperators("DomainServerWebSessionData"); _argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments()); @@ -59,6 +62,8 @@ DomainServer::DomainServer(int argc, char* argv[]) : qDebug() << "Setting up LimitedNodeList and assignments."; setupNodeListAndAssignments(); + + loadExistingSessionsFromSettings(); } } @@ -1407,6 +1412,9 @@ void DomainServer::handleProfileRequestFinished() { } } + +const QString DS_SETTINGS_SESSIONS_GROUP = "web-sessions"; + Headers DomainServer::setupCookieHeadersFromProfileReply(QNetworkReply* profileReply) { Headers cookieHeaders; @@ -1417,7 +1425,14 @@ Headers DomainServer::setupCookieHeadersFromProfileReply(QNetworkReply* profileR QJsonObject userObject = profileDocument.object()["data"].toObject()["user"].toObject(); // add the profile to our in-memory data structure so we know who the user is when they send us their cookie - _cookieSessionHash.insert(cookieUUID, DomainServerWebSessionData(userObject)); + DomainServerWebSessionData sessionData(userObject); + _cookieSessionHash.insert(cookieUUID, sessionData); + + // persist the cookie to settings file so we can get it back on DS relaunch + QSettings localSettings; + localSettings.beginGroup(DS_SETTINGS_SESSIONS_GROUP); + QVariant sessionVariant = QVariant::fromValue(sessionData); + localSettings.setValue(cookieUUID.toString(), QVariant::fromValue(sessionData)); // setup expiry for cookie to 1 month from today QDateTime cookieExpiry = QDateTime::currentDateTimeUtc().addMonths(1); @@ -1435,6 +1450,17 @@ Headers DomainServer::setupCookieHeadersFromProfileReply(QNetworkReply* profileR return cookieHeaders; } +void DomainServer::loadExistingSessionsFromSettings() { + // read data for existing web sessions into memory so existing sessions can be leveraged + QSettings domainServerSettings; + domainServerSettings.beginGroup(DS_SETTINGS_SESSIONS_GROUP); + + foreach(const QString& uuidKey, domainServerSettings.childKeys()) { + _cookieSessionHash.insert(QUuid(uuidKey), domainServerSettings.value(uuidKey).value()); + qDebug() << "Pulled web session from settings - cookie UUID is" << uuidKey; + } +} + void DomainServer::refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& assignment) { QUuid oldUUID = assignment->getUUID(); assignment->resetUUID(); diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index f8daa9a529..666994c818 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -93,6 +93,8 @@ private: void handleProfileRequestFinished(); Headers setupCookieHeadersFromProfileReply(QNetworkReply* profileReply); + void loadExistingSessionsFromSettings(); + QJsonObject jsonForSocket(const HifiSockAddr& socket); QJsonObject jsonObjectForNode(const SharedNodePointer& node); diff --git a/domain-server/src/DomainServerWebSessionData.cpp b/domain-server/src/DomainServerWebSessionData.cpp index b0c56cc59e..ee32a17570 100644 --- a/domain-server/src/DomainServerWebSessionData.cpp +++ b/domain-server/src/DomainServerWebSessionData.cpp @@ -51,3 +51,13 @@ void DomainServerWebSessionData::swap(DomainServerWebSessionData& otherSessionDa swap(_roles, otherSessionData._roles); } +QDataStream& operator<<(QDataStream &out, const DomainServerWebSessionData& session) { + out << session._username << session._roles; + return out; +} + +QDataStream& operator>>(QDataStream &in, DomainServerWebSessionData& session) { + in >> session._username >> session._roles; + return in; +} + diff --git a/domain-server/src/DomainServerWebSessionData.h b/domain-server/src/DomainServerWebSessionData.h index 15e4171b57..450bc13a9b 100644 --- a/domain-server/src/DomainServerWebSessionData.h +++ b/domain-server/src/DomainServerWebSessionData.h @@ -26,6 +26,9 @@ public: const QString& getUsername() const { return _username; } const QSet& getRoles() const { return _roles; } + friend QDataStream& operator<<(QDataStream &out, const DomainServerWebSessionData& session); + friend QDataStream& operator>>(QDataStream &in, DomainServerWebSessionData& session); + private: void swap(DomainServerWebSessionData& otherSessionData); @@ -33,4 +36,6 @@ private: QSet _roles; }; +Q_DECLARE_METATYPE(DomainServerWebSessionData) + #endif // hifi_DomainServerWebSessionData_h \ No newline at end of file From eecdc2dc7b942df35bfed245e3b513423915d268 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 24 Jul 2014 19:00:41 -0700 Subject: [PATCH 038/407] Increase initial width of the edit fields in JavaScript Window.form() --- interface/src/scripting/WindowScriptingInterface.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index a36d149a86..1889b283f8 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -127,8 +127,10 @@ QScriptValue WindowScriptingInterface::showForm(const QString& title, QScriptVal if (item.property("button").toString() != "") { cancelButton = cancelButton || item.property("button").toString().toLower() == "cancel"; } else { - edits.push_back(new QLineEdit(item.property("value").toString())); - formLayout->addRow(item.property("label").toString(), edits.back()); + QLineEdit* edit = new QLineEdit(item.property("value").toString()); + edit->setMinimumWidth(200); + edits.push_back(edit); + formLayout->addRow(new QLabel(item.property("label").toString()), edit); } } From 49e0d07ac8123eba72dae92e41f1fb9cd14fd10a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 25 Jul 2014 20:32:44 -0700 Subject: [PATCH 039/407] Add directory picker button option to JavaScript Window.form() --- .../scripting/WindowScriptingInterface.cpp | 94 +++++++++++++++++-- .../src/scripting/WindowScriptingInterface.h | 3 + 2 files changed, 87 insertions(+), 10 deletions(-) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 1889b283f8..19e2ba8194 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -91,9 +91,44 @@ QScriptValue WindowScriptingInterface::showConfirm(const QString& message) { return QScriptValue(response == QMessageBox::Yes); } +void WindowScriptingInterface::chooseDirectory() { + QPushButton* button = reinterpret_cast(sender()); + + QString title = button->property("title").toString(); + QString path = button->property("path").toString(); + QRegExp displayAs = button->property("displayAs").toRegExp(); + QRegExp validateAs = button->property("validateAs").toRegExp(); + QString errorMessage = button->property("errorMessage").toString(); + + QString directory = QFileDialog::getExistingDirectory(button, title, path); + if (directory.isEmpty()) { + return; + } + + if (!validateAs.exactMatch(directory)) { + QMessageBox::warning(NULL, "Invalid Directory", errorMessage); + return; + } + + button->setProperty("path", directory); + + displayAs.indexIn(directory); + QString buttonText = displayAs.cap(1) != "" ? displayAs.cap(1) : "."; + button->setText(buttonText); +} + +QString WindowScriptingInterface::jsRegExp2QtRegExp(QString string) { + // Converts string representation of RegExp from JavaScript format to Qt format. + return string.mid(1, string.length() - 2) // No enclosing slashes. + .replace("\\/", "/"); // No escaping of forward slash. +} + /// Display a form layout with an edit box /// \param const QString& title title to display -/// \param const QScriptValue form to display (array containing labels and values) +/// \param const QScriptValue form to display as an array of objects: +/// - label, value +/// - label, directory, title, display regexp, validate regexp, error message +/// - button ("Cancel") /// \return QScriptValue `true` if 'OK' was clicked, `false` otherwise QScriptValue WindowScriptingInterface::showForm(const QString& title, QScriptValue form) { @@ -121,11 +156,42 @@ QScriptValue WindowScriptingInterface::showForm(const QString& title, QScriptVal area->setWidget(container); QVector edits; + QVector directories; for (int i = 0; i < form.property("length").toInt32(); ++i) { QScriptValue item = form.property(i); if (item.property("button").toString() != "") { cancelButton = cancelButton || item.property("button").toString().toLower() == "cancel"; + + } else if (item.property("directory").toString() != "") { + QString path = item.property("directory").toString(); + QString title = item.property("title").toString(); + if (title == "") { + title = "Choose Directory"; + } + QString displayAsString = item.property("displayAs").toString(); + QRegExp displayAs = QRegExp(displayAsString != "" ? jsRegExp2QtRegExp(displayAsString) : "^(.*)$"); + QString validateAsString = item.property("validateAs").toString(); + QRegExp validateAs = QRegExp(validateAsString != "" ? jsRegExp2QtRegExp(validateAsString) : ".*"); + QString errorMessage = item.property("errorMessage").toString(); + if (errorMessage == "") { + errorMessage = "Invalid directory"; + } + + QPushButton* directory = new QPushButton(displayAs.cap(1)); + directory->setProperty("title", title); + directory->setProperty("path", path); + directory->setProperty("displayAs", displayAs); + directory->setProperty("validateAs", validateAs); + directory->setProperty("errorMessage", errorMessage); + directory->setText(displayAs.cap(1) != "" ? displayAs.cap(1) : "."); + + directory->setMinimumWidth(200); + directories.push_back(directory); + + formLayout->addRow(new QLabel(item.property("label").toString()), directory); + connect(directory, SIGNAL(clicked(bool)), SLOT(chooseDirectory())); + } else { QLineEdit* edit = new QLineEdit(item.property("value").toString()); edit->setMinimumWidth(200); @@ -144,22 +210,30 @@ QScriptValue WindowScriptingInterface::showForm(const QString& title, QScriptVal int result = editDialog->exec(); if (result == QDialog::Accepted) { - int j = -1; + int e = -1; + int d = -1; for (int i = 0; i < form.property("length").toInt32(); ++i) { QScriptValue item = form.property(i); QScriptValue value = item.property("value"); - bool ok = true; - qDebug() << "item.property(""button"").toString() = " << item.property("button").toString(); - if (item.property("button").toString() == "") { - j += 1; + + if (item.property("button").toString() != "") { + // Nothing to do + } else if (item.property("directory").toString() != "") { + d += 1; + value = directories.at(d)->property("path").toString(); + item.setProperty("directory", value); + form.setProperty(i, item); + } else { + e += 1; + bool ok = true; if (value.isNumber()) { - value = edits.at(j)->text().toDouble(&ok); + value = edits.at(e)->text().toDouble(&ok); } else if (value.isString()) { - value = edits.at(j)->text(); + value = edits.at(e)->text(); } else if (value.isBool()) { - if (edits.at(j)->text() == "true") { + if (edits.at(e)->text() == "true") { value = true; - } else if (edits.at(j)->text() == "false") { + } else if (edits.at(e)->text() == "false") { value = false; } else { ok = false; diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 654b048b24..025ee06ed7 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -40,9 +40,12 @@ private slots: QScriptValue showPrompt(const QString& message, const QString& defaultText); QScriptValue showBrowse(const QString& title, const QString& directory, const QString& nameFilter); QScriptValue showS3Browse(const QString& nameFilter); + void chooseDirectory(); private: WindowScriptingInterface(); + + QString jsRegExp2QtRegExp(QString string); }; #endif // hifi_WindowScriptingInterface_h From fcfaf6a9beb366c763bc8a79de83a14dff7000c0 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 26 Jul 2014 08:49:42 -0700 Subject: [PATCH 040/407] Add Set Model Properties dialog for model uploading --- examples/editModels.js | 85 +++++++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 18 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 1498cff6d0..58855f24cd 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -118,14 +118,19 @@ if (typeof DataView.prototype.string !== "function") { var modelUploader = (function () { var that = {}, urlBase = "http://public.highfidelity.io/meshes/", + modelFile, fstBuffer, fbxBuffer, svoBuffer, - mapping = {}, + mapping, NAME_FIELD = "name", SCALE_FIELD = "scale", FILENAME_FIELD = "filename", TEXDIR_FIELD = "texdir", + ANIMATION_URL_FIELD = "animationurl", + PITCH_FIELD = "pitch", + YAW_FIELD = "yaw", + ROLL_FIELD = "roll", fbxDataView; function error(message) { @@ -253,41 +258,41 @@ var modelUploader = (function () { return geometry; } - function readModel(filename) { - var url, - req, - fbxFilename, + function readModel() { + var fbxFilename, geometry; - print("Reading model file: " + filename); + print("Reading model file: " + modelFile); - if (filename.toLowerCase().slice(-4) === ".svo") { - svoBuffer = readFile(filename); + mapping = {}; + + if (modelFile.toLowerCase().slice(-4) === ".svo") { + svoBuffer = readFile(modelFile); if (svoBuffer === null) { return false; } } else { - if (filename.toLowerCase().slice(-4) === ".fst") { - fstBuffer = readFile(filename); + if (modelFile.toLowerCase().slice(-4) === ".fst") { + fstBuffer = readFile(modelFile); if (fstBuffer === null) { return false; } mapping = readMapping(fstBuffer); if (mapping.hasOwnProperty(FILENAME_FIELD)) { - fbxFilename = filename.path() + "\\" + mapping[FILENAME_FIELD]; + fbxFilename = modelFile.path() + "\\" + mapping[FILENAME_FIELD]; } else { error("FBX file name not found in FST file!"); return false; } - } else if (filename.toLowerCase().slice(-4) === ".fbx") { - fbxFilename = filename; - mapping[FILENAME_FIELD] = filename.fileName(); + } else if (modelFile.toLowerCase().slice(-4) === ".fbx") { + fbxFilename = modelFile; + mapping[FILENAME_FIELD] = modelFile.fileName(); } else { - error("Unrecognized file type: " + filename); + error("Unrecognized file type: " + modelFile); return false; } @@ -304,7 +309,7 @@ var modelUploader = (function () { // Add any missing basic mappings if (!mapping.hasOwnProperty(NAME_FIELD)) { - mapping[NAME_FIELD] = filename.fileName().slice(0, -4); + mapping[NAME_FIELD] = modelFile.fileName().slice(0, -4); } if (!mapping.hasOwnProperty(TEXDIR_FIELD)) { mapping[TEXDIR_FIELD] = "."; @@ -317,7 +322,50 @@ var modelUploader = (function () { } function setProperties() { - print("Setting model properties"); + var form = [], + decimals = 3, + directory, + displayAs, + validateAs; + + form.push({ label: "Name:", value: mapping[NAME_FIELD] }); + + directory = modelFile.path() + "/" + mapping[TEXDIR_FIELD]; + displayAs = new RegExp("^" + modelFile.path().replace(/[\\\\\\\/]/, "[\\\\\\\/]") + "[\\\\\\\/](.*)"); + validateAs = new RegExp("^" + modelFile.path().replace(/[\\\\\\\/]/, "[\\\\\\\/]") + "([\\\\\\\/].*)?"); + + form.push({ + label: "Texture directory:", + directory: modelFile.path() + "/" + mapping[TEXDIR_FIELD], + title: "Choose Texture Directory", + displayAs: displayAs, + validateAs: validateAs, + errorMessage: "Texture directory must be subdirectory of model directory." + }); + + form.push({ label: "Animation URL:", value: "" }); + form.push({ label: "Pitch:", value: (0).toFixed(decimals) }); + form.push({ label: "Yaw:", value: (0).toFixed(decimals) }); + form.push({ label: "Roll:", value: (0).toFixed(decimals) }); + form.push({ label: "Scale:", value: mapping[SCALE_FIELD].toFixed(decimals) }); + form.push({ button: "Cancel" }); + + if (!Window.form("Set Model Properties", form)) { + print("User cancelled uploading model"); + return false; + } + + mapping[NAME_FIELD] = form[0].value; + mapping[TEXDIR_FIELD] = form[1].directory.slice(modelFile.path().length + 1); + if (mapping[TEXDIR_FIELD] === "") { + mapping[TEXDIR_FIELD] = "."; + } + mapping[ANIMATION_URL_FIELD] = form[2].value; + mapping[PITCH_FIELD] = form[3].value; + mapping[YAW_FIELD] = form[4].value; + mapping[ROLL_FIELD] = form[5].value; + mapping[SCALE_FIELD] = form[6].value; + return true; } @@ -356,10 +404,11 @@ var modelUploader = (function () { } that.upload = function (file, callback) { + modelFile = file; var url = urlBase + file.fileName(); // Read model content ... - if (!readModel(file)) { + if (!readModel()) { return; } From f602f42189b8a22b3a084c4315f0054e3f79c57d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 26 Jul 2014 09:22:44 -0700 Subject: [PATCH 041/407] Add Cancel button to model editing dialog --- examples/editModels.js | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 58855f24cd..2b1aa190c6 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -1618,23 +1618,25 @@ function handeMenuEvent(menuItem){ array.push({ label: "Yaw:", value: angles.y.toFixed(decimals) }); array.push({ label: "Roll:", value: angles.z.toFixed(decimals) }); array.push({ label: "Scale:", value: 2 * selectedModelProperties.radius.toFixed(decimals) }); - - var propertyName = Window.form("Edit Properties", array); - modelSelected = false; - - selectedModelProperties.modelURL = array[0].value; - selectedModelProperties.animationURL = array[1].value; - selectedModelProperties.position.x = array[2].value; - selectedModelProperties.position.y = array[3].value; - selectedModelProperties.position.z = array[4].value; - angles.x = array[5].value; - angles.y = array[6].value; - angles.z = array[7].value; - selectedModelProperties.modelRotation = Quat.fromVec3Degrees(angles); - selectedModelProperties.radius = array[8].value / 2; - print(selectedModelProperties.radius); + array.push({ button: "Cancel" }); - Models.editModel(selectedModelID, selectedModelProperties); + if (Window.form("Edit Properties", array)) { + selectedModelProperties.modelURL = array[0].value; + selectedModelProperties.animationURL = array[1].value; + selectedModelProperties.position.x = array[2].value; + selectedModelProperties.position.y = array[3].value; + selectedModelProperties.position.z = array[4].value; + angles.x = array[5].value; + angles.y = array[6].value; + angles.z = array[7].value; + selectedModelProperties.modelRotation = Quat.fromVec3Degrees(angles); + selectedModelProperties.radius = array[8].value / 2; + print(selectedModelProperties.radius); + + Models.editModel(selectedModelID, selectedModelProperties); + } + + modelSelected = false; } } tooltip.show(false); From 61bb21cc00477865cde342c6330e3bfd4d227583 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 27 Jul 2014 22:05:18 -0700 Subject: [PATCH 042/407] Prepare multipart/form-date message with model file and attributes --- examples/editModels.js | 242 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 223 insertions(+), 19 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 2b1aa190c6..c5a8c5c1e8 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -70,6 +70,39 @@ if (typeof String.prototype.path !== "function") { }; } +if (typeof String.prototype.toArrayBuffer !== "function") { + String.prototype.toArrayBuffer = function () { + var length, + buffer, + view, + charCode, + charCodes, + i; + + charCodes = []; + + length = this.length; + for (i = 0; i < length; i += 1) { + charCode = this.charCodeAt(i); + if (i <= 255) { + charCodes.push(charCode); + } else { + charCodes.push(charCode / 256); + charCodes.push(charCode % 256); + } + } + + length = charCodes.length; + buffer = new ArrayBuffer(length); + view = new Uint8Array(buffer); + for (i = 0; i < length; i += 1) { + view[i] = charCodes[i]; + } + + return buffer; + }; +} + if (typeof DataView.prototype.indexOf !== "function") { DataView.prototype.indexOf = function (searchString, position) { var searchLength = searchString.length, @@ -101,19 +134,139 @@ if (typeof DataView.prototype.indexOf !== "function") { } if (typeof DataView.prototype.string !== "function") { - DataView.prototype.string = function (i, length) { + DataView.prototype.string = function (start, length) { var charCodes = [], - end = i + length, - j; + end, + i; - for (j = i; j < end; j += 1) { - charCodes.push(this.getUint8(j)); + if (start === undefined) { + start = 0; + } + if (length === undefined) { + length = this.length; + } + + end = start + length; + for (i = start; i < end; i += 1) { + charCodes.push(this.getUint8(i)); } return String.fromCharCode.apply(String, charCodes); }; } +var httpMultiPart = (function () { + var that = {}, + parts, + byteLength, + boundaryString, + crlf; + + function clear() { + boundaryString = "--boundary_" + Uuid.generate() + "="; + parts = []; + byteLength = 0; + crlf = ""; + } + that.clear = clear; + + function boundary() { + return boundaryString.slice(2); + } + that.boundary = boundary; + + function length() { + return byteLength; + } + that.length = length; + + function add(object) { + // - name, string + // - name, buffer + var buffer, + stringBuffer, + string, + length; + + if (object.name === undefined) { + + throw new Error("Item to add to HttpMultiPart must have a name"); + + } else if (object.string !== undefined) { + //--= + //Content-Disposition: form-data; name="model_name" + // + // + + string = crlf + boundaryString + "\r\n" + + "Content-Disposition: form-data; name=\"" + object.name + "\"\r\n" + + "\r\n" + + object.string; + buffer = string.toArrayBuffer(); + + } else if (object.buffer !== undefined) { + //--= + //Content-Disposition: form-data; name="fbx"; filename="" + //Content-Type: application/octet-stream + // + // + + string = crlf + boundaryString + "\r\n" + + "Content-Disposition: form-data; name=\"" + object.name + + "\"; filename=\"" + object.buffer.filename + "\"\r\n" + + "Content-Type: application/octet-stream\r\n" + + "\r\n"; + stringBuffer = string.toArrayBuffer(); + + buffer = new Uint8Array(stringBuffer.byteLength + object.buffer.buffer.byteLength); + buffer.set(new Uint8Array(stringBuffer)); + buffer.set(new Uint8Array(object.buffer.buffer), stringBuffer.byteLength); + + } else { + + throw new Error("Item to add to HttpMultiPart not recognized"); + } + + byteLength += buffer.byteLength; + parts.push(buffer); + + crlf = "\r\n"; + + return true; + } + that.add = add; + + function response() { + var buffer, + view, + charCodes, + str, + i, + j; + + str = crlf + boundaryString + "--\r\n"; + buffer = str.toArrayBuffer(); + byteLength += buffer.byteLength; + parts.push(buffer); + + charCodes = []; + for (i = 0; i < parts.length; i += 1) { + view = new Uint8Array(parts[i]); + for (j = 0; j < view.length; j += 1) { + charCodes.push(view[j]); + } + } + str = String.fromCharCode.apply(String, charCodes); + + return str; + } + that.response = response; + + clear(); + + return that; +}()); + var modelUploader = (function () { var that = {}, @@ -151,8 +304,8 @@ var modelUploader = (function () { } return { + filename: filename.fileName(), buffer: req.response, - length: parseInt(req.getResponseHeader("Content-Length"), 10) }; } @@ -259,8 +412,8 @@ var modelUploader = (function () { } function readModel() { - var fbxFilename, - geometry; + var geometry, + fbxFilename; print("Reading model file: " + modelFile); @@ -328,6 +481,8 @@ var modelUploader = (function () { displayAs, validateAs; + print("Setting model properties"); + form.push({ label: "Name:", value: mapping[NAME_FIELD] }); directory = modelFile.path() + "/" + mapping[TEXDIR_FIELD]; @@ -370,7 +525,60 @@ var modelUploader = (function () { } function createHttpMessage() { - print("Putting model into HTTP message"); + var i; + + print("Preparing to send model"); + + httpMultiPart.clear(); + + // Model name + if (mapping.hasOwnProperty(NAME_FIELD)) { + httpMultiPart.add({ + name : "model_name", + string : mapping[NAME_FIELD] + }); + } else { + error("Model name is missing"); + httpMultiPart.clear(); + return false; + } + + // FST file + if (fstBuffer) { + httpMultiPart.add({ + name : "fst", + buffer: fstBuffer + }); + } + + // FBX file + if (fbxBuffer) { + httpMultiPart.add({ + name : "fbx", + buffer: fbxBuffer + }); + } + + // SVO file + if (svoBuffer) { + httpMultiPart.add({ + name : "svo", + buffer: svoBuffer + }); + } + + // LOD files + // DJRTODO + + // Textures + // DJRTODO + + // Model category + httpMultiPart.add({ + name : "model_category", + string : "item" // DJRTODO: What model category to use? + }); + return true; } @@ -379,11 +587,10 @@ var modelUploader = (function () { print("Sending model to High Fidelity"); - // DJRTODO - req = new XMLHttpRequest(); - req.open("PUT", url, true); - req.responseType = "arraybuffer"; + req.open("POST", url, true); + req.setRequestHeader("Content-Type", "multipart/form-data; boundary=\"" + httpMultiPart.boundary() + "\""); + req.onreadystatechange = function () { if (req.readyState === req.DONE) { if (req.status === 200) { @@ -396,17 +603,14 @@ var modelUploader = (function () { } }; - if (fbxBuffer !== null) { - req.send(fbxBuffer.buffer); - } else { - req.send(svoBuffer.buffer); - } + req.send(httpMultiPart.response()); } that.upload = function (file, callback) { - modelFile = file; var url = urlBase + file.fileName(); + modelFile = file; + // Read model content ... if (!readModel()) { return; From 6334116070369afbffcd4ef4f88b17efe7bc7fdd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 28 Jul 2014 12:07:19 -0700 Subject: [PATCH 043/407] request domain settings after successful connection to domain --- libraries/networking/src/DomainHandler.cpp | 60 +++++++++++++++++++++- libraries/networking/src/DomainHandler.h | 8 +++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index f603d21240..286909279b 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "NodeList.h" #include "PacketHeaders.h" #include "UserActivityLogger.h" @@ -21,7 +23,9 @@ DomainHandler::DomainHandler(QObject* parent) : _sockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)), _assignmentUUID(), _isConnected(false), - _handshakeTimer(NULL) + _handshakeTimer(NULL), + _settingsObject(), + _failedSettingsRequests(0) { } @@ -37,8 +41,14 @@ void DomainHandler::clearConnectionInfo() { } } +void DomainHandler::clearSettings() { + _settingsObject = QJsonObject(); + _failedSettingsRequests = 0; +} + void DomainHandler::reset() { clearConnectionInfo(); + clearSettings(); _hostname = QString(); _sockAddr.setAddress(QHostAddress::Null); } @@ -109,10 +119,58 @@ void DomainHandler::setIsConnected(bool isConnected) { if (_isConnected) { emit connectedToDomain(_hostname); + + // we've connected to new domain - time to ask it for global settings + requestDomainSettings(); } } } +void DomainHandler::requestDomainSettings() const { + + // setup the URL required to grab settings JSON + QUrl settingsJSONURL; + settingsJSONURL.setScheme("http"); + settingsJSONURL.setHost(_hostname); + settingsJSONURL.setPort(DOMAIN_SERVER_HTTP_PORT); + settingsJSONURL.setPath("/settings.json"); + settingsJSONURL.setQuery(QString("type=%1").arg(NodeList::getInstance()->getOwnerType())); + + qDebug() << settingsJSONURL; + + QNetworkReply* reply = NetworkAccessManager::getInstance().get(QNetworkRequest(settingsJSONURL)); + connect(reply, &QNetworkReply::finished, this, &DomainHandler::settingsRequestFinished); +} + +const int MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS = 5; + +void DomainHandler::settingsRequestFinished() { + QNetworkReply* settingsReply = reinterpret_cast(sender()); + + if (settingsReply->error() == QNetworkReply::NoError) { + // parse the JSON to a QJsonObject and save it + _settingsObject = QJsonDocument::fromJson(settingsReply->readAll()).object(); + + qDebug() << settingsReply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + qDebug() << "Received domain settings."; + + // reset failed settings requests to 0, we got them + _failedSettingsRequests = 0; + } else { + // error grabbing the settings - in some cases this means we are stuck + // so we should retry until we get it + qDebug() << "Error getting domain settings -" << settingsReply->errorString() << "- retrying"; + + if (++_failedSettingsRequests >= MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS) { + qDebug() << "Failed to retreive domain-server settings" << MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS << "times. Re-setting connection to domain."; + clearSettings(); + clearConnectionInfo(); + } + + requestDomainSettings(); + } +} + void DomainHandler::parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket) { // figure out the port that the DS wants us to use for us to talk to them with DTLS int numBytesPacketHeader = numBytesForPacketHeader(dtlsRequirementPacket); diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 782332f06a..6761b8eb84 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -12,6 +12,7 @@ #ifndef hifi_DomainHandler_h #define hifi_DomainHandler_h +#include #include #include #include @@ -33,6 +34,7 @@ public: DomainHandler(QObject* parent = 0); void clearConnectionInfo(); + void clearSettings(); const QUuid& getUUID() const { return _uuid; } void setUUID(const QUuid& uuid) { _uuid = uuid; } @@ -54,10 +56,14 @@ public: bool isConnected() const { return _isConnected; } void setIsConnected(bool isConnected); + bool hasSettings() const { return !_settingsObject.isEmpty(); } + void requestDomainSettings() const; + void parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket); private slots: void completedHostnameLookup(const QHostInfo& hostInfo); + void settingsRequestFinished(); signals: void hostnameChanged(const QString& hostname); void connectedToDomain(const QString& hostname); @@ -71,6 +77,8 @@ private: QUuid _assignmentUUID; bool _isConnected; QTimer* _handshakeTimer; + QJsonObject _settingsObject; + int _failedSettingsRequests; }; #endif // hifi_DomainHandler_h From dbf41c8a422b90aed2bfe1ec1194f3b452330943 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 28 Jul 2014 14:56:26 -0700 Subject: [PATCH 044/407] allow domain-server to serve settings publicly, fix retry in DomainHandler --- domain-server/src/DomainServer.cpp | 8 +++- .../src/DomainServerSettingsManager.cpp | 42 +++++++++++-------- .../src/DomainServerSettingsManager.h | 5 ++- libraries/networking/src/DomainHandler.cpp | 19 +++++---- 4 files changed, 44 insertions(+), 30 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index e462e05aa6..2ea66c2ee3 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -940,6 +940,12 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url const QString UUID_REGEX_STRING = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"; + // allow sub-handlers to handle requests that do not require authentication + if (_settingsManager.handlePublicHTTPRequest(connection, url)) { + return true; + } + + // all requests below require a cookie to prove authentication so check that first if (!isAuthenticatedRequest(connection, url)) { // this is not an authenticated request // return true from the handler since it was handled with a 401 or re-direct to auth @@ -1186,7 +1192,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url } // didn't process the request, let our DomainServerSettingsManager or HTTPManager handle - return _settingsManager.handleHTTPRequest(connection, url); + return _settingsManager.handleAuthenticatedHTTPRequest(connection, url); } const QString HIFI_SESSION_COOKIE_KEY = "DS_WEB_SESSION_UUID"; diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 0520426ea8..4ec88996a6 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -47,24 +47,8 @@ DomainServerSettingsManager::DomainServerSettingsManager() : const QString DESCRIPTION_SETTINGS_KEY = "settings"; const QString SETTING_DEFAULT_KEY = "default"; -bool DomainServerSettingsManager::handleHTTPRequest(HTTPConnection* connection, const QUrl &url) { - if (connection->requestOperation() == QNetworkAccessManager::PostOperation && url.path() == "/settings.json") { - // this is a POST operation to change one or more settings - QJsonDocument postedDocument = QJsonDocument::fromJson(connection->requestContent()); - QJsonObject postedObject = postedDocument.object(); - - // we recurse one level deep below each group for the appropriate setting - recurseJSONObjectAndOverwriteSettings(postedObject, _settingsMap, _descriptionObject); - - // store whatever the current _settingsMap is to file - persistToFile(); - - // return success to the caller - QString jsonSuccess = "{\"status\": \"success\"}"; - connection->respond(HTTPConnection::StatusCode200, jsonSuccess.toUtf8(), "application/json"); - - return true; - } else if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == "/settings.json") { +bool DomainServerSettingsManager::handlePublicHTTPRequest(HTTPConnection* connection, const QUrl &url) { + if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == "/settings.json") { // this is a GET operation for our settings // check if there is a query parameter for settings affecting a particular type of assignment @@ -135,6 +119,28 @@ bool DomainServerSettingsManager::handleHTTPRequest(HTTPConnection* connection, return false; } +bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection *connection, const QUrl &url) { + if (connection->requestOperation() == QNetworkAccessManager::PostOperation && url.path() == "/settings.json") { + // this is a POST operation to change one or more settings + QJsonDocument postedDocument = QJsonDocument::fromJson(connection->requestContent()); + QJsonObject postedObject = postedDocument.object(); + + // we recurse one level deep below each group for the appropriate setting + recurseJSONObjectAndOverwriteSettings(postedObject, _settingsMap, _descriptionObject); + + // store whatever the current _settingsMap is to file + persistToFile(); + + // return success to the caller + QString jsonSuccess = "{\"status\": \"success\"}"; + connection->respond(HTTPConnection::StatusCode200, jsonSuccess.toUtf8(), "application/json"); + + return true; + } + + return false; +} + void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, QVariantMap& settingsVariant, QJsonObject descriptionObject) { diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index 8b80cad280..26bfe57ab4 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -16,11 +16,12 @@ #include -class DomainServerSettingsManager : public QObject, HTTPRequestHandler { +class DomainServerSettingsManager : public QObject { Q_OBJECT public: DomainServerSettingsManager(); - bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url); + bool handlePublicHTTPRequest(HTTPConnection* connection, const QUrl& url); + bool handleAuthenticatedHTTPRequest(HTTPConnection* connection, const QUrl& url); QByteArray getJSONSettingsMap() const; private: diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 286909279b..ce6a264b34 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -11,6 +11,7 @@ #include +#include "Assignment.h" #include "NodeList.h" #include "PacketHeaders.h" #include "UserActivityLogger.h" @@ -133,10 +134,9 @@ void DomainHandler::requestDomainSettings() const { settingsJSONURL.setScheme("http"); settingsJSONURL.setHost(_hostname); settingsJSONURL.setPort(DOMAIN_SERVER_HTTP_PORT); - settingsJSONURL.setPath("/settings.json"); - settingsJSONURL.setQuery(QString("type=%1").arg(NodeList::getInstance()->getOwnerType())); - - qDebug() << settingsJSONURL; + settingsJSONURL.setPath("/settingz.json/"); + Assignment::Type assignmentType = Assignment::typeForNodeType(NodeList::getInstance()->getOwnerType()); + settingsJSONURL.setQuery(QString("type=%1").arg(assignmentType)); QNetworkReply* reply = NetworkAccessManager::getInstance().get(QNetworkRequest(settingsJSONURL)); connect(reply, &QNetworkReply::finished, this, &DomainHandler::settingsRequestFinished); @@ -147,11 +147,12 @@ const int MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS = 5; void DomainHandler::settingsRequestFinished() { QNetworkReply* settingsReply = reinterpret_cast(sender()); - if (settingsReply->error() == QNetworkReply::NoError) { + int replyCode = settingsReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (settingsReply->error() == QNetworkReply::NoError && replyCode != 301 && replyCode != 302) { // parse the JSON to a QJsonObject and save it _settingsObject = QJsonDocument::fromJson(settingsReply->readAll()).object(); - qDebug() << settingsReply->attribute(QNetworkRequest::HttpStatusCodeAttribute); qDebug() << "Received domain settings."; // reset failed settings requests to 0, we got them @@ -165,9 +166,9 @@ void DomainHandler::settingsRequestFinished() { qDebug() << "Failed to retreive domain-server settings" << MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS << "times. Re-setting connection to domain."; clearSettings(); clearConnectionInfo(); - } - - requestDomainSettings(); + } else { + requestDomainSettings(); + } } } From 84b86c17b7d75a76d6afc1d4e6a03b7e537058b9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 28 Jul 2014 15:16:59 -0700 Subject: [PATCH 045/407] use common settings retreival code to block before run in AudioMixer --- assignment-client/src/audio/AudioMixer.cpp | 43 +++++++--------------- libraries/networking/src/DomainHandler.cpp | 29 +++++++++------ libraries/networking/src/DomainHandler.h | 3 ++ 3 files changed, 33 insertions(+), 42 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index ad4787b407..91ecee76e2 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -408,41 +408,24 @@ void AudioMixer::run() { nodeList->linkedDataCreateCallback = attachNewBufferToNode; - // setup a NetworkAccessManager to ask the domain-server for our settings - NetworkAccessManager& networkManager = NetworkAccessManager::getInstance(); + // wait until we have the domain-server settings, otherwise we bail + DomainHandler& domainHandler = nodeList->getDomainHandler(); - QUrl settingsJSONURL; - settingsJSONURL.setScheme("http"); - settingsJSONURL.setHost(nodeList->getDomainHandler().getHostname()); - settingsJSONURL.setPort(DOMAIN_SERVER_HTTP_PORT); - settingsJSONURL.setPath("/settings.json"); - settingsJSONURL.setQuery(QString("type=%1").arg(_type)); + qDebug() << "Waiting for domain settings from domain-server."; - QNetworkReply *reply = NULL; + // block until we get the settingsRequestComplete signal + QEventLoop loop; + loop.connect(&domainHandler, &DomainHandler::settingsRequestComplete, &loop, &QEventLoop::quit); + domainHandler.requestDomainSettings(); + loop.exec(); - int failedAttempts = 0; - const int MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS = 5; - - qDebug() << "Requesting settings for assignment from domain-server at" << settingsJSONURL.toString(); - - while (!reply || reply->error() != QNetworkReply::NoError) { - reply = networkManager.get(QNetworkRequest(settingsJSONURL)); - - QEventLoop loop; - QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); - - loop.exec(); - - ++failedAttempts; - - if (failedAttempts == MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS) { - qDebug() << "Failed to get settings from domain-server. Bailing on assignment."; - setFinished(true); - return; - } + if (domainHandler.getSettingsObject().isEmpty()) { + qDebug() << "Failed to retreive settings object from domain-server. Bailing on assignment."; + setFinished(true); + return; } - QJsonObject settingsObject = QJsonDocument::fromJson(reply->readAll()).object(); + const QJsonObject& settingsObject = domainHandler.getSettingsObject(); // check the settings object to see if we have anything we can parse out const QString AUDIO_GROUP_KEY = "audio"; diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index ce6a264b34..0f37160512 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -128,18 +128,21 @@ void DomainHandler::setIsConnected(bool isConnected) { } void DomainHandler::requestDomainSettings() const { - - // setup the URL required to grab settings JSON - QUrl settingsJSONURL; - settingsJSONURL.setScheme("http"); - settingsJSONURL.setHost(_hostname); - settingsJSONURL.setPort(DOMAIN_SERVER_HTTP_PORT); - settingsJSONURL.setPath("/settingz.json/"); - Assignment::Type assignmentType = Assignment::typeForNodeType(NodeList::getInstance()->getOwnerType()); - settingsJSONURL.setQuery(QString("type=%1").arg(assignmentType)); - - QNetworkReply* reply = NetworkAccessManager::getInstance().get(QNetworkRequest(settingsJSONURL)); - connect(reply, &QNetworkReply::finished, this, &DomainHandler::settingsRequestFinished); + if (_settingsObject.isEmpty()) { + // setup the URL required to grab settings JSON + QUrl settingsJSONURL; + settingsJSONURL.setScheme("http"); + settingsJSONURL.setHost(_hostname); + settingsJSONURL.setPort(DOMAIN_SERVER_HTTP_PORT); + settingsJSONURL.setPath("/settings.json"); + Assignment::Type assignmentType = Assignment::typeForNodeType(NodeList::getInstance()->getOwnerType()); + settingsJSONURL.setQuery(QString("type=%1").arg(assignmentType)); + + qDebug() << "Requesting domain-server settings at" << settingsJSONURL.toString(); + + QNetworkReply* reply = NetworkAccessManager::getInstance().get(QNetworkRequest(settingsJSONURL)); + connect(reply, &QNetworkReply::finished, this, &DomainHandler::settingsRequestFinished); + } } const int MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS = 5; @@ -154,6 +157,7 @@ void DomainHandler::settingsRequestFinished() { _settingsObject = QJsonDocument::fromJson(settingsReply->readAll()).object(); qDebug() << "Received domain settings."; + emit settingsRequestComplete(true); // reset failed settings requests to 0, we got them _failedSettingsRequests = 0; @@ -166,6 +170,7 @@ void DomainHandler::settingsRequestFinished() { qDebug() << "Failed to retreive domain-server settings" << MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS << "times. Re-setting connection to domain."; clearSettings(); clearConnectionInfo(); + emit settingsRequestComplete(false); } else { requestDomainSettings(); } diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 6761b8eb84..67edd64172 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -58,6 +58,7 @@ public: bool hasSettings() const { return !_settingsObject.isEmpty(); } void requestDomainSettings() const; + const QJsonObject& getSettingsObject() const { return _settingsObject; } void parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket); @@ -68,6 +69,8 @@ signals: void hostnameChanged(const QString& hostname); void connectedToDomain(const QString& hostname); + void settingsRequestComplete(bool wasSuccessful); + private: void reset(); From aeee3692868aabc99b39e68f635d957032d69794 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 28 Jul 2014 19:10:59 -0700 Subject: [PATCH 046/407] Working on heightfield implementation. --- .../shaders/metavoxel_heightfield.frag | 16 ++ .../shaders/metavoxel_heightfield.vert | 16 ++ interface/src/MetavoxelSystem.cpp | 250 ++++++++++++------ interface/src/MetavoxelSystem.h | 53 +++- .../metavoxels/src/AttributeRegistry.cpp | 28 +- libraries/metavoxels/src/AttributeRegistry.h | 45 ++++ libraries/metavoxels/src/MetavoxelData.cpp | 15 +- libraries/metavoxels/src/MetavoxelData.h | 7 +- 8 files changed, 337 insertions(+), 93 deletions(-) create mode 100644 interface/resources/shaders/metavoxel_heightfield.frag create mode 100644 interface/resources/shaders/metavoxel_heightfield.vert diff --git a/interface/resources/shaders/metavoxel_heightfield.frag b/interface/resources/shaders/metavoxel_heightfield.frag new file mode 100644 index 0000000000..de520d57ac --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield.frag @@ -0,0 +1,16 @@ +#version 120 + +// +// metavoxel_heightfield.frag +// fragment shader +// +// Created by Andrzej Kapolka on 7/28/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 +// + +void main(void) { + gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); +} diff --git a/interface/resources/shaders/metavoxel_heightfield.vert b/interface/resources/shaders/metavoxel_heightfield.vert new file mode 100644 index 0000000000..6b90bdc44d --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield.vert @@ -0,0 +1,16 @@ +#version 120 + +// +// metavoxel_heighfield.vert +// vertex shader +// +// Created by Andrzej Kapolka on 7/28/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 +// + +void main(void) { + gl_Position = ftransform(); +} diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 00d69c8c25..318bf65614 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -25,7 +25,7 @@ #include "MetavoxelSystem.h" #include "renderer/Model.h" -REGISTER_META_OBJECT(PointMetavoxelRendererImplementation) +REGISTER_META_OBJECT(DefaultMetavoxelRendererImplementation) REGISTER_META_OBJECT(SphereRenderer) REGISTER_META_OBJECT(StaticModelRenderer) @@ -33,8 +33,10 @@ static int bufferPointVectorMetaTypeId = qRegisterMetaType(); void MetavoxelSystem::init() { MetavoxelClientManager::init(); - PointMetavoxelRendererImplementation::init(); - _pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new PointBufferAttribute()); + DefaultMetavoxelRendererImplementation::init(); + _pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new BufferDataAttribute("pointBuffer")); + _heightfieldBufferAttribute = AttributeRegistry::getInstance()->registerAttribute( + new BufferDataAttribute("heightfieldBuffer")); } MetavoxelLOD MetavoxelSystem::getLOD() { @@ -42,28 +44,31 @@ MetavoxelLOD MetavoxelSystem::getLOD() { return _lod; } -class SpannerSimulateVisitor : public SpannerVisitor { +class SimulateVisitor : public MetavoxelVisitor { public: - SpannerSimulateVisitor(float deltaTime); + SimulateVisitor(float deltaTime, const MetavoxelLOD& lod); - virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize); + virtual int visit(MetavoxelInfo& info); private: float _deltaTime; }; -SpannerSimulateVisitor::SpannerSimulateVisitor(float deltaTime) : - SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), - QVector(), QVector(), QVector(), - Application::getInstance()->getMetavoxels()->getLOD()), +SimulateVisitor::SimulateVisitor(float deltaTime, const MetavoxelLOD& lod) : + MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getRendererAttribute(), + QVector(), lod), _deltaTime(deltaTime) { } -bool SpannerSimulateVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) { - spanner->getRenderer()->simulate(_deltaTime); - return true; +int SimulateVisitor::visit(MetavoxelInfo& info) { + if (!info.isLeaf) { + return DEFAULT_ORDER; + } + static_cast(info.inputValues.at(0).getInlineValue< + SharedObjectPointer>().data())->getImplementation()->simulate(*_data, _deltaTime, info, _lod); + return STOP_RECURSION; } void MetavoxelSystem::simulate(float deltaTime) { @@ -76,28 +81,8 @@ void MetavoxelSystem::simulate(float deltaTime) { BASE_LOD_THRESHOLD * Menu::getInstance()->getAvatarLODDistanceMultiplier()); } - SpannerSimulateVisitor spannerSimulateVisitor(deltaTime); - guide(spannerSimulateVisitor); -} - -class SpannerRenderVisitor : public SpannerVisitor { -public: - - SpannerRenderVisitor(); - - virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize); -}; - -SpannerRenderVisitor::SpannerRenderVisitor() : - SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), - QVector(), QVector(), QVector(), - Application::getInstance()->getMetavoxels()->getLOD(), - encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())) { -} - -bool SpannerRenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) { - spanner->getRenderer()->render(1.0f, SpannerRenderer::DEFAULT_MODE, clipMinimum, clipSize); - return true; + SimulateVisitor simulateVisitor(deltaTime, getLOD()); + guideToAugmented(simulateVisitor); } class RenderVisitor : public MetavoxelVisitor { @@ -125,9 +110,6 @@ int RenderVisitor::visit(MetavoxelInfo& info) { void MetavoxelSystem::render() { RenderVisitor renderVisitor(getLOD()); guideToAugmented(renderVisitor); - - SpannerRenderVisitor spannerRenderVisitor; - guide(spannerRenderVisitor); } MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) { @@ -239,6 +221,9 @@ void MetavoxelSystemClient::sendDatagram(const QByteArray& data) { Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size()); } +BufferData::~BufferData() { +} + PointBuffer::PointBuffer(const BufferPointVector& points) : _points(points) { } @@ -269,34 +254,76 @@ void PointBuffer::render() { _buffer.release(); } -PointBufferAttribute::PointBufferAttribute() : - InlineAttribute("pointBuffer") { +HeightfieldBuffer::HeightfieldBuffer(const QByteArray& height, const QByteArray& color, const QByteArray& normal) : + _height(height), + _color(color), + _normal(normal), + _heightTexture(QOpenGLTexture::Target2D), + _colorTexture(QOpenGLTexture::Target2D), + _normalTexture(QOpenGLTexture::Target2D) { } -bool PointBufferAttribute::merge(void*& parent, void* children[], bool postRead) const { - PointBufferPointer firstChild = decodeInline(children[0]); +void HeightfieldBuffer::render() { + // initialize textures, etc. on first render + if (!_heightTexture.isCreated()) { + int heightSize = glm::sqrt(_height.size()); + _heightTexture.setSize(heightSize, heightSize); + _heightTexture.setFormat(QOpenGLTexture::LuminanceFormat); + _heightTexture.allocateStorage(); + _heightTexture.setData(QOpenGLTexture::Luminance, QOpenGLTexture::UInt8, _height.data()); + _height.clear(); + + int colorSize = glm::sqrt(_color.size() / 3); + _colorTexture.setSize(colorSize, colorSize); + _colorTexture.setFormat(QOpenGLTexture::RGBFormat); + _colorTexture.allocateStorage(); + _colorTexture.setData(QOpenGLTexture::BGR, QOpenGLTexture::UInt8, _color.data()); + _color.clear(); + + int normalSize = glm::sqrt(_normal.size() / 3); + _normalTexture.setSize(normalSize, normalSize); + _normalTexture.setFormat(QOpenGLTexture::RGBFormat); + _normalTexture.allocateStorage(); + _normalTexture.setData(QOpenGLTexture::BGR, QOpenGLTexture::UInt8, _normal.data()); + _normal.clear(); + } + +} + +BufferDataAttribute::BufferDataAttribute(const QString& name) : + InlineAttribute(name) { +} + +bool BufferDataAttribute::merge(void*& parent, void* children[], bool postRead) const { + BufferDataPointer firstChild = decodeInline(children[0]); for (int i = 1; i < MERGE_COUNT; i++) { - if (firstChild != decodeInline(children[i])) { - *(PointBufferPointer*)&parent = _defaultValue; + if (firstChild != decodeInline(children[i])) { + *(BufferDataPointer*)&parent = _defaultValue; return false; } } - *(PointBufferPointer*)&parent = firstChild; + *(BufferDataPointer*)&parent = firstChild; return true; } -void PointMetavoxelRendererImplementation::init() { - if (!_program.isLinked()) { - _program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert"); - _program.link(); +void DefaultMetavoxelRendererImplementation::init() { + if (!_pointProgram.isLinked()) { + _pointProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert"); + _pointProgram.link(); - _program.bind(); - _pointScaleLocation = _program.uniformLocation("pointScale"); - _program.release(); + _pointProgram.bind(); + _pointScaleLocation = _pointProgram.uniformLocation("pointScale"); + _pointProgram.release(); + + _heightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/metavoxel_heightfield.vert"); + _heightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/metavoxel_heightfield.frag"); + _heightfieldProgram.link(); } } -PointMetavoxelRendererImplementation::PointMetavoxelRendererImplementation() { +DefaultMetavoxelRendererImplementation::DefaultMetavoxelRendererImplementation() { } class PointAugmentVisitor : public MetavoxelVisitor { @@ -344,7 +371,7 @@ int PointAugmentVisitor::visit(MetavoxelInfo& info) { if (info.size >= _pointLeafSize) { BufferPointVector swapPoints; _points.swap(swapPoints); - info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(PointBufferPointer( + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer( new PointBuffer(swapPoints)))); } return STOP_RECURSION; @@ -356,12 +383,30 @@ bool PointAugmentVisitor::postVisit(MetavoxelInfo& info) { } BufferPointVector swapPoints; _points.swap(swapPoints); - info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(PointBufferPointer( + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer( new PointBuffer(swapPoints)))); return true; } -void PointMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous, +class HeightfieldAugmentVisitor : public MetavoxelVisitor { +public: + + HeightfieldAugmentVisitor(const MetavoxelLOD& lod); + + virtual int visit(MetavoxelInfo& info); +}; + +HeightfieldAugmentVisitor::HeightfieldAugmentVisitor(const MetavoxelLOD& lod) : + MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getHeightfieldAttribute() << + AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), QVector() << + Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod) { +} + +int HeightfieldAugmentVisitor::visit(MetavoxelInfo& info) { + return STOP_RECURSION; +} + +void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod) { // copy the previous buffers MetavoxelData expandedPrevious = previous; @@ -377,12 +422,62 @@ void PointMetavoxelRendererImplementation::augment(MetavoxelData& data, const Me PointAugmentVisitor visitor(lod); data.guideToDifferent(expandedPrevious, visitor); + + } -class PointRenderVisitor : public MetavoxelVisitor { +class SpannerSimulateVisitor : public SpannerVisitor { public: - PointRenderVisitor(const MetavoxelLOD& lod); + SpannerSimulateVisitor(float deltaTime, const MetavoxelLOD& lod); + + virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize); + +private: + + float _deltaTime; +}; + +SpannerSimulateVisitor::SpannerSimulateVisitor(float deltaTime, const MetavoxelLOD& lod) : + SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), + QVector(), QVector(), QVector(), lod), + _deltaTime(deltaTime) { +} + +bool SpannerSimulateVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) { + spanner->getRenderer()->simulate(_deltaTime); + return true; +} + +void DefaultMetavoxelRendererImplementation::simulate(MetavoxelData& data, float deltaTime, + MetavoxelInfo& info, const MetavoxelLOD& lod) { + SpannerSimulateVisitor spannerSimulateVisitor(deltaTime, lod); + data.guide(spannerSimulateVisitor); +} + +class SpannerRenderVisitor : public SpannerVisitor { +public: + + SpannerRenderVisitor(const MetavoxelLOD& lod); + + virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize); +}; + +SpannerRenderVisitor::SpannerRenderVisitor(const MetavoxelLOD& lod) : + SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), + QVector(), QVector(), QVector(), + lod, encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())) { +} + +bool SpannerRenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) { + spanner->getRenderer()->render(1.0f, SpannerRenderer::DEFAULT_MODE, clipMinimum, clipSize); + return true; +} + +class BufferRenderVisitor : public MetavoxelVisitor { +public: + + BufferRenderVisitor(const AttributePointer& attribute, const MetavoxelLOD& lod); virtual int visit(MetavoxelInfo& info); @@ -391,21 +486,23 @@ private: int _order; }; -PointRenderVisitor::PointRenderVisitor(const MetavoxelLOD& lod) : - MetavoxelVisitor(QVector() << Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), - QVector(), lod), +BufferRenderVisitor::BufferRenderVisitor(const AttributePointer& attribute, const MetavoxelLOD& lod) : + MetavoxelVisitor(QVector() << attribute, QVector(), lod), _order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())) { } -int PointRenderVisitor::visit(MetavoxelInfo& info) { - PointBufferPointer buffer = info.inputValues.at(0).getInlineValue(); +int BufferRenderVisitor::visit(MetavoxelInfo& info) { + BufferDataPointer buffer = info.inputValues.at(0).getInlineValue(); if (buffer) { buffer->render(); } return info.isLeaf ? STOP_RECURSION : _order; } -void PointMetavoxelRendererImplementation::render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod) { +void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod) { + SpannerRenderVisitor spannerRenderVisitor(lod); + data.guide(spannerRenderVisitor); + int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); const int VIEWPORT_WIDTH_INDEX = 2; @@ -416,8 +513,8 @@ void PointMetavoxelRendererImplementation::render(MetavoxelData& data, Metavoxel float worldDiagonal = glm::distance(Application::getInstance()->getViewFrustum()->getNearBottomLeft(), Application::getInstance()->getViewFrustum()->getNearTopRight()); - _program.bind(); - _program.setUniformValue(_pointScaleLocation, viewportDiagonal * + _pointProgram.bind(); + _pointProgram.setUniformValue(_pointScaleLocation, viewportDiagonal * Application::getInstance()->getViewFrustum()->getNearClip() / worldDiagonal); glEnableClientState(GL_VERTEX_ARRAY); @@ -428,10 +525,8 @@ void PointMetavoxelRendererImplementation::render(MetavoxelData& data, Metavoxel glDisable(GL_BLEND); - PointRenderVisitor visitor(lod); - data.guide(visitor); - - glEnable(GL_BLEND); + BufferRenderVisitor pointRenderVisitor(Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod); + data.guide(pointRenderVisitor); glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); @@ -439,11 +534,18 @@ void PointMetavoxelRendererImplementation::render(MetavoxelData& data, Metavoxel glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); - _program.release(); + _pointProgram.release(); + + BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), + lod); + data.guide(heightfieldRenderVisitor); + + glEnable(GL_BLEND); } - -ProgramObject PointMetavoxelRendererImplementation::_program; -int PointMetavoxelRendererImplementation::_pointScaleLocation; + +ProgramObject DefaultMetavoxelRendererImplementation::_pointProgram; +int DefaultMetavoxelRendererImplementation::_pointScaleLocation; +ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldProgram; static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { GLdouble coefficients[] = { x, y, z, w }; diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 4a5b99aa47..be1a02643f 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -36,6 +37,7 @@ public: virtual MetavoxelLOD getLOD(); const AttributePointer& getPointBufferAttribute() { return _pointBufferAttribute; } + const AttributePointer& getHeightfieldBufferAttribute() { return _heightfieldBufferAttribute; } void simulate(float deltaTime); void render(); @@ -49,6 +51,7 @@ private: void guideToAugmented(MetavoxelVisitor& visitor); AttributePointer _pointBufferAttribute; + AttributePointer _heightfieldBufferAttribute; MetavoxelLOD _lod; QReadWriteLock _lodLock; @@ -92,13 +95,24 @@ private: QReadWriteLock _augmentedDataLock; }; +/// Base class for cached static buffers. +class BufferData : public QSharedData { +public: + + virtual ~BufferData(); + + virtual void render() = 0; +}; + +typedef QExplicitlySharedDataPointer BufferDataPointer; + /// Contains the information necessary to render a group of points. -class PointBuffer : public QSharedData { +class PointBuffer : public BufferData { public: PointBuffer(const BufferPointVector& points); - void render(); + virtual void render(); private: @@ -107,36 +121,55 @@ private: int _pointCount; }; -typedef QExplicitlySharedDataPointer PointBufferPointer; +/// Contains the information necessary to render a heightfield block. +class HeightfieldBuffer : public BufferData { +public: + + HeightfieldBuffer(const QByteArray& height, const QByteArray& color, const QByteArray& normal); + + virtual void render(); -/// A client-side attribute that stores point buffers. -class PointBufferAttribute : public InlineAttribute { +private: + + QByteArray _height; + QByteArray _color; + QByteArray _normal; + QOpenGLTexture _heightTexture; + QOpenGLTexture _colorTexture; + QOpenGLTexture _normalTexture; +}; + +/// A client-side attribute that stores renderable buffers. +class BufferDataAttribute : public InlineAttribute { Q_OBJECT public: - Q_INVOKABLE PointBufferAttribute(); + Q_INVOKABLE BufferDataAttribute(const QString& name = QString()); virtual bool merge(void*& parent, void* children[], bool postRead = false) const; }; /// Renders metavoxels as points. -class PointMetavoxelRendererImplementation : public MetavoxelRendererImplementation { +class DefaultMetavoxelRendererImplementation : public MetavoxelRendererImplementation { Q_OBJECT public: static void init(); - Q_INVOKABLE PointMetavoxelRendererImplementation(); + Q_INVOKABLE DefaultMetavoxelRendererImplementation(); virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod); + virtual void simulate(MetavoxelData& data, float deltaTime, MetavoxelInfo& info, const MetavoxelLOD& lod); virtual void render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod); private: - static ProgramObject _program; - static int _pointScaleLocation; + static ProgramObject _pointProgram; + static int _pointScaleLocation; + + static ProgramObject _heightfieldProgram; }; /// Base class for spanner renderers; provides clipping. diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 7c7ded0fb7..4f4da7adf2 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -21,6 +21,8 @@ REGISTER_META_OBJECT(QRgbAttribute) REGISTER_META_OBJECT(PackedNormalAttribute) REGISTER_META_OBJECT(SpannerQRgbAttribute) REGISTER_META_OBJECT(SpannerPackedNormalAttribute) +REGISTER_META_OBJECT(HeightfieldAttribute) +REGISTER_META_OBJECT(HeightfieldColorAttribute) REGISTER_META_OBJECT(SharedObjectAttribute) REGISTER_META_OBJECT(SharedObjectSetAttribute) REGISTER_META_OBJECT(SpannerSetAttribute) @@ -37,13 +39,15 @@ AttributeRegistry::AttributeRegistry() : _guideAttribute(registerAttribute(new SharedObjectAttribute("guide", &MetavoxelGuide::staticMetaObject, new DefaultMetavoxelGuide()))), _rendererAttribute(registerAttribute(new SharedObjectAttribute("renderer", &MetavoxelRenderer::staticMetaObject, - new PointMetavoxelRenderer()))), + new DefaultMetavoxelRenderer()))), _spannersAttribute(registerAttribute(new SpannerSetAttribute("spanners", &Spanner::staticMetaObject))), _colorAttribute(registerAttribute(new QRgbAttribute("color"))), _normalAttribute(registerAttribute(new PackedNormalAttribute("normal"))), _spannerColorAttribute(registerAttribute(new SpannerQRgbAttribute("spannerColor"))), _spannerNormalAttribute(registerAttribute(new SpannerPackedNormalAttribute("spannerNormal"))), - _spannerMaskAttribute(registerAttribute(new FloatAttribute("spannerMask"))) { + _spannerMaskAttribute(registerAttribute(new FloatAttribute("spannerMask"))), + _heightfieldAttribute(registerAttribute(new HeightfieldAttribute("heightfield"))), + _heightfieldColorAttribute(registerAttribute(new HeightfieldColorAttribute("heightfieldColor"))) { // our baseline LOD threshold is for voxels; spanners are a different story const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 8.0f; @@ -451,6 +455,26 @@ AttributeValue SpannerPackedNormalAttribute::inherit(const AttributeValue& paren return AttributeValue(parentValue.getAttribute()); } +HeightfieldData::HeightfieldData(const QByteArray& contents) : + _contents(contents) { +} + +HeightfieldAttribute::HeightfieldAttribute(const QString& name) : + InlineAttribute(name) { +} + +bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead) const { + return false; +} + +HeightfieldColorAttribute::HeightfieldColorAttribute(const QString& name) : + InlineAttribute(name) { +} + +bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool postRead) const { + return false; +} + SharedObjectAttribute::SharedObjectAttribute(const QString& name, const QMetaObject* metaObject, const SharedObjectPointer& defaultValue) : InlineAttribute(name, defaultValue), diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index d07503335f..262ef89462 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -94,6 +94,12 @@ public: /// Returns a reference to the standard "spannerMask" attribute. const AttributePointer& getSpannerMaskAttribute() const { return _spannerMaskAttribute; } + /// Returns a reference to the standard HeightfieldPointer "heightfield" attribute. + const AttributePointer& getHeightfieldAttribute() const { return _heightfieldAttribute; } + + /// Returns a reference to the standard HeightfieldColorPointer "heightfieldColor" attribute. + const AttributePointer& getHeightfieldColorAttribute() const { return _heightfieldColorAttribute; } + private: static QScriptValue getAttribute(QScriptContext* context, QScriptEngine* engine); @@ -109,6 +115,8 @@ private: AttributePointer _spannerColorAttribute; AttributePointer _spannerNormalAttribute; AttributePointer _spannerMaskAttribute; + AttributePointer _heightfieldAttribute; + AttributePointer _heightfieldColorAttribute; }; /// Converts a value to a void pointer. @@ -408,6 +416,43 @@ public: virtual AttributeValue inherit(const AttributeValue& parentValue) const; }; +/// Contains a block of heightfield data. +class HeightfieldData : public QSharedData { +public: + + HeightfieldData(const QByteArray& contents); + + const QByteArray& getContents() const { return _contents; } + +private: + + QByteArray _contents; +}; + +typedef QExplicitlySharedDataPointer HeightfieldDataPointer; + +/// An attribute that stores heightfield data. +class HeightfieldAttribute : public InlineAttribute { + Q_OBJECT + +public: + + Q_INVOKABLE HeightfieldAttribute(const QString& name = QString()); + + virtual bool merge(void*& parent, void* children[], bool postRead = false) const; +}; + +/// An attribute that stores heightfield colors. +class HeightfieldColorAttribute : public InlineAttribute { + Q_OBJECT + +public: + + Q_INVOKABLE HeightfieldColorAttribute(const QString& name = QString()); + + virtual bool merge(void*& parent, void* children[], bool postRead = false) const; +}; + /// An attribute that takes the form of QObjects of a given meta-type (a subclass of SharedObject). class SharedObjectAttribute : public InlineAttribute { Q_OBJECT diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 3bf43ef8d4..29f18f5cc1 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -26,7 +26,7 @@ REGISTER_META_OBJECT(DefaultMetavoxelGuide) REGISTER_META_OBJECT(ScriptedMetavoxelGuide) REGISTER_META_OBJECT(ThrobbingMetavoxelGuide) REGISTER_META_OBJECT(MetavoxelRenderer) -REGISTER_META_OBJECT(PointMetavoxelRenderer) +REGISTER_META_OBJECT(DefaultMetavoxelRenderer) REGISTER_META_OBJECT(Spanner) REGISTER_META_OBJECT(Sphere) REGISTER_META_OBJECT(StaticModel) @@ -1879,20 +1879,27 @@ void MetavoxelRendererImplementation::init(MetavoxelRenderer* renderer) { void MetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod) { + // nothing by default +} + +void MetavoxelRendererImplementation::simulate(MetavoxelData& data, float deltaTime, + MetavoxelInfo& info, const MetavoxelLOD& lod) { + // nothing by default } void MetavoxelRendererImplementation::render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod) { + // nothing by default } QByteArray MetavoxelRenderer::getImplementationClassName() const { return "MetavoxelRendererImplementation"; } -PointMetavoxelRenderer::PointMetavoxelRenderer() { +DefaultMetavoxelRenderer::DefaultMetavoxelRenderer() { } -QByteArray PointMetavoxelRenderer::getImplementationClassName() const { - return "PointMetavoxelRendererImplementation"; +QByteArray DefaultMetavoxelRenderer::getImplementationClassName() const { + return "DefaultMetavoxelRendererImplementation"; } const float DEFAULT_PLACEMENT_GRANULARITY = 0.01f; diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 2dc778cf71..46376601c1 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -555,6 +555,7 @@ public: virtual void init(MetavoxelRenderer* renderer); virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod); + virtual void simulate(MetavoxelData& data, float deltaTime, MetavoxelInfo& info, const MetavoxelLOD& lod); virtual void render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod); protected: @@ -562,13 +563,13 @@ protected: MetavoxelRenderer* _renderer; }; -/// Renders metavoxels as points. -class PointMetavoxelRenderer : public MetavoxelRenderer { +/// The standard, usual renderer. +class DefaultMetavoxelRenderer : public MetavoxelRenderer { Q_OBJECT public: - Q_INVOKABLE PointMetavoxelRenderer(); + Q_INVOKABLE DefaultMetavoxelRenderer(); virtual QByteArray getImplementationClassName() const; }; From f46c064e888ddf817fcba7e62b210b338fd7c3ad Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 28 Jul 2014 19:58:53 -0700 Subject: [PATCH 047/407] Speed up model reading --- examples/editModels.js | 150 +++++++++++++++++++++++++---------------- 1 file changed, 93 insertions(+), 57 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index c5a8c5c1e8..f4170b5655 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -340,72 +340,108 @@ var modelUploader = (function () { } function readGeometry(fbxBuffer) { - var dv = new DataView(fbxBuffer.buffer), - geometry = {}, - binary, - stringLength, - filename, - author, - i; + var geometry, + view, + index, + EOF; - binary = (dv.string(0, 18) === "Kaydara FBX Binary"); + // Reference: + // http://code.blender.org/index.php/2013/08/fbx-binary-file-format-specification/ - // Simple direct search of FBX file for relevant texture filenames (excl. paths) instead of interpreting FBX format. - // Binary format: - // - 'RelativeFilename' Record type - // - char Subtype - // - Uint8 Length of path string - // - 00 00 00 3 null chars - // - Path and name of texture file - // Text format: - // - 'RelativeFilename' Record type - // - ': " ' Pre-string colon and quote - // - Path and name of texture file - // - '"' End-of-string quote + geometry = {}; geometry.textures = []; - i = 0; - while (i !== -1) { - i = dv.indexOf("RelativeFilename", i); - if (i !== -1) { - if (binary) { - i += 17; - stringLength = dv.getUint8(i); - i += 4; - } else { - i = dv.indexOf("\"", i) + 1; - stringLength = dv.indexOf("\"", i) - i; - } - filename = dv.string(i, stringLength).fileName(); + view = new DataView(fbxBuffer.buffer); + EOF = false; + + function parseBinaryFBX() { + var endOffset, + numProperties, + propertyListLength, + nameLength, + name, + filename, + author; + + endOffset = view.getUint32(index, true); + numProperties = view.getUint32(index + 4, true); + propertyListLength = view.getUint32(index + 8, true); + nameLength = view.getUint8(index + 12); + index += 13; + + if (endOffset === 0) { + return; + } + if (endOffset < index || endOffset > view.byteLength) { + EOF = true; + return; + } + + name = view.string(index, nameLength).toLowerCase(); + index += nameLength; + + if (name === "relativefilename") { + filename = view.string(index + 5, view.getUint32(index + 1, true)).fileName(); geometry.textures.push(filename); - i += stringLength; + + } else if (name === "author") { + author = view.string(index + 5, view.getUint32(index + 1, true)); + geometry.author = author; + + } + + index += (propertyListLength); + + while (index < endOffset && !EOF) { + parseBinaryFBX(); } } - // Simple direct search of FBX file for the first author record. - // Binary format: - // - 'Author' Record type - // - char Subtype - // - Uint8 Length of path string - // - 00 00 00 3 null chars - // - Author name - // Text format: - // - 'Author' Record type - // - ': "' Pre-string colon and quote - // - Author name; may be empty - // - '"' End-of-string quote - i = dv.indexOf("Author", 0); - if (i !== -1) { - if (binary) { - i += 7; - stringLength = dv.getUint8(i); - } else { - i = dv.indexOf("\"", i) + 1; - stringLength = dv.indexOf("\"", i) - i; + function readTextFBX() { + var line, + view, + viewLength, + charCode, + charCodes, + author, + filename; + + view = new Uint8Array(fbxBuffer.buffer); + viewLength = view.byteLength; + charCodes = []; + + for (index = 0; index < viewLength; index += 1) { + charCode = view[index]; + if (charCode === 10) { // Can ignore EOF + line = String.fromCharCode.apply(String, charCodes).trim(); + + if (line.slice(0, 7).toLowerCase() === "author:") { + author = line.slice(line.indexOf("\""), line.lastIndexOf("\"") - line.length); + geometry.author = author; + + } + if (line.slice(0, 17).toLowerCase() === "relativefilename:") { + filename = line.slice(line.indexOf("\""), line.lastIndexOf("\"") - line.length).fileName(); + geometry.textures.push(filename); + } + + charCodes = []; + } else { + charCodes.push(charCode); + } } - if (stringLength > 0) { - author = dv.string(i, stringLength); - geometry.author = author; + } + + if (view.string(0, 18) === "Kaydara FBX Binary") { + + index = 27; + while (index < view.byteLength - 39 && !EOF) { + parseBinaryFBX(); } + + } else { + + readTextFBX(); + } return geometry; From 63d7ff0bdea225e61c67d71b2c35d00b8c2739f8 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 28 Jul 2014 20:00:23 -0700 Subject: [PATCH 048/407] Tidying --- examples/editModels.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index f4170b5655..6bf0d54e1d 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -59,13 +59,13 @@ var mode = 0; if (typeof String.prototype.fileName !== "function") { - String.prototype.fileName = function (str) { + String.prototype.fileName = function () { return this.replace(/^(.*[\/\\])*/, ""); }; } if (typeof String.prototype.path !== "function") { - String.prototype.path = function (str) { + String.prototype.path = function () { return this.replace(/[\\\/][^\\\/]*$/, ""); }; } @@ -185,8 +185,7 @@ var httpMultiPart = (function () { // - name, buffer var buffer, stringBuffer, - string, - length; + string; if (object.name === undefined) { @@ -267,7 +266,6 @@ var httpMultiPart = (function () { return that; }()); - var modelUploader = (function () { var that = {}, urlBase = "http://public.highfidelity.io/meshes/", @@ -283,15 +281,14 @@ var modelUploader = (function () { ANIMATION_URL_FIELD = "animationurl", PITCH_FIELD = "pitch", YAW_FIELD = "yaw", - ROLL_FIELD = "roll", - fbxDataView; + ROLL_FIELD = "roll"; function error(message) { Window.alert(message); print(message); } - function readFile(filename, buffer, length) { + function readFile(filename) { var url = "file:///" + filename, req = new XMLHttpRequest(); @@ -305,7 +302,7 @@ var modelUploader = (function () { return { filename: filename.fileName(), - buffer: req.response, + buffer: req.response }; } @@ -561,7 +558,6 @@ var modelUploader = (function () { } function createHttpMessage() { - var i; print("Preparing to send model"); From ccf37c6c178eb297a6224a78a6f5fd5feb76e09a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 28 Jul 2014 21:53:00 -0700 Subject: [PATCH 049/407] Fix text displayed on Window.form() directory button --- interface/src/scripting/WindowScriptingInterface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 19e2ba8194..c1be4f8a02 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -184,6 +184,7 @@ QScriptValue WindowScriptingInterface::showForm(const QString& title, QScriptVal directory->setProperty("displayAs", displayAs); directory->setProperty("validateAs", validateAs); directory->setProperty("errorMessage", errorMessage); + displayAs.indexIn(path); directory->setText(displayAs.cap(1) != "" ? displayAs.cap(1) : "."); directory->setMinimumWidth(200); From 0bb42ba5f26aee60560470d3d3ed72eda12cd14e Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 28 Jul 2014 21:55:05 -0700 Subject: [PATCH 050/407] Fix call stack overflow when preparing large multipart/form-data --- examples/editModels.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 6bf0d54e1d..ce9b52c3a0 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -248,15 +248,15 @@ var httpMultiPart = (function () { byteLength += buffer.byteLength; parts.push(buffer); - charCodes = []; + str = ""; for (i = 0; i < parts.length; i += 1) { + charCodes = []; view = new Uint8Array(parts[i]); - for (j = 0; j < view.length; j += 1) { + for(j = 0; j < view.length; j += 1) { charCodes.push(view[j]); } + str = str + String.fromCharCode.apply(String, charCodes); } - str = String.fromCharCode.apply(String, charCodes); - return str; } that.response = response; From c7c2f3119253e4cfc928933313c82b059823f05b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 28 Jul 2014 21:59:44 -0700 Subject: [PATCH 051/407] Fix display of scale read from model file --- examples/editModels.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index ce9b52c3a0..b3e90d7995 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -488,8 +488,11 @@ var modelUploader = (function () { } geometry = readGeometry(fbxBuffer); - if (!mapping.hasOwnProperty(SCALE_FIELD)) { - mapping[SCALE_FIELD] = (geometry.author === "www.makehuman.org" ? 150.0 : 15.0); + + if (mapping.hasOwnProperty(SCALE_FIELD)) { + mapping[SCALE_FIELD] = parseFloat(mapping[SCALE_FIELD]); + } else { + mapping[SCALE_FIELD] = (geometry.author === "www.makehuman.org" ? 150.0: 15.0); } } From 00abf43faee07c8118571fe07b53cf892b8700b9 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 28 Jul 2014 22:10:25 -0700 Subject: [PATCH 052/407] Add LOD files to multipart/form-data --- examples/editModels.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/examples/editModels.js b/examples/editModels.js index b3e90d7995..24b0745503 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -561,6 +561,8 @@ var modelUploader = (function () { } function createHttpMessage() { + var lodCount, + lodBuffer; print("Preparing to send model"); @@ -603,7 +605,15 @@ var modelUploader = (function () { } // LOD files - // DJRTODO + lodCount = 0; + for (var n in mapping["lod"]) { + lodBuffer = readFile(modelFile.path() + "\\" + n); + httpMultiPart.add({ + name: "lod" + lodCount, + buffer: lodBuffer + }) + lodCount += 1; + } // Textures // DJRTODO From edf96b749e3465d1d49c4560d450cbeb2743eab9 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 28 Jul 2014 23:01:12 -0700 Subject: [PATCH 053/407] Add texture files to multipart/form-data --- examples/editModels.js | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 24b0745503..01871b8a60 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -281,7 +281,8 @@ var modelUploader = (function () { ANIMATION_URL_FIELD = "animationurl", PITCH_FIELD = "pitch", YAW_FIELD = "yaw", - ROLL_FIELD = "roll"; + ROLL_FIELD = "roll", + geometry; function error(message) { Window.alert(message); @@ -338,6 +339,7 @@ var modelUploader = (function () { function readGeometry(fbxBuffer) { var geometry, + textures, view, index, EOF; @@ -347,6 +349,7 @@ var modelUploader = (function () { geometry = {}; geometry.textures = []; + textures = {}; view = new DataView(fbxBuffer.buffer); EOF = false; @@ -378,7 +381,10 @@ var modelUploader = (function () { if (name === "relativefilename") { filename = view.string(index + 5, view.getUint32(index + 1, true)).fileName(); - geometry.textures.push(filename); + if (!textures.hasOwnProperty(filename)) { + textures[filename] = ""; + geometry.textures.push(filename); + } } else if (name === "author") { author = view.string(index + 5, view.getUint32(index + 1, true)); @@ -418,7 +424,10 @@ var modelUploader = (function () { } if (line.slice(0, 17).toLowerCase() === "relativefilename:") { filename = line.slice(line.indexOf("\""), line.lastIndexOf("\"") - line.length).fileName(); - geometry.textures.push(filename); + if (!textures.hasOwnProperty(filename)) { + textures[filename] = ""; + geometry.textures.push(filename); + } } charCodes = []; @@ -445,8 +454,7 @@ var modelUploader = (function () { } function readModel() { - var geometry, - fbxFilename; + var fbxFilename; print("Reading model file: " + modelFile); @@ -562,7 +570,10 @@ var modelUploader = (function () { function createHttpMessage() { var lodCount, - lodBuffer; + lodBuffer, + textureCount, + textureBuffer, + i; print("Preparing to send model"); @@ -607,7 +618,7 @@ var modelUploader = (function () { // LOD files lodCount = 0; for (var n in mapping["lod"]) { - lodBuffer = readFile(modelFile.path() + "\\" + n); + lodBuffer = readFile(modelFile.path() + "\/" + n); httpMultiPart.add({ name: "lod" + lodCount, buffer: lodBuffer @@ -616,7 +627,15 @@ var modelUploader = (function () { } // Textures - // DJRTODO + textureCount = 0; + for (i = 0; i < geometry.textures.length; i += 1) { + textureBuffer = readFile(modelFile.path() + "\/" + mapping[TEXDIR_FIELD] + "\/" + geometry.textures[i]); + httpMultiPart.add({ + name: "texture" + textureCount, + buffer: textureBuffer + }); + textureCount += 1; + } // Model category httpMultiPart.add({ From 5a5bbfd612ef0721aab2dab50b76f8cb131b1434 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 29 Jul 2014 09:46:54 -0700 Subject: [PATCH 054/407] Tidying --- examples/editModels.js | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 01871b8a60..31a55bf821 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -252,7 +252,7 @@ var httpMultiPart = (function () { for (i = 0; i < parts.length; i += 1) { charCodes = []; view = new Uint8Array(parts[i]); - for(j = 0; j < view.length; j += 1) { + for (j = 0; j < view.length; j += 1) { charCodes.push(view[j]); } str = str + String.fromCharCode.apply(String, charCodes); @@ -458,6 +458,9 @@ var modelUploader = (function () { print("Reading model file: " + modelFile); + fstBuffer = null; + fbxBuffer = null; + svoBuffer = null; mapping = {}; if (modelFile.toLowerCase().slice(-4) === ".svo") { @@ -500,7 +503,7 @@ var modelUploader = (function () { if (mapping.hasOwnProperty(SCALE_FIELD)) { mapping[SCALE_FIELD] = parseFloat(mapping[SCALE_FIELD]); } else { - mapping[SCALE_FIELD] = (geometry.author === "www.makehuman.org" ? 150.0: 15.0); + mapping[SCALE_FIELD] = (geometry.author === "www.makehuman.org" ? 150.0 : 15.0); } } @@ -570,8 +573,8 @@ var modelUploader = (function () { function createHttpMessage() { var lodCount, + lodFile, lodBuffer, - textureCount, textureBuffer, i; @@ -617,24 +620,26 @@ var modelUploader = (function () { // LOD files lodCount = 0; - for (var n in mapping["lod"]) { - lodBuffer = readFile(modelFile.path() + "\/" + n); - httpMultiPart.add({ - name: "lod" + lodCount, - buffer: lodBuffer - }) - lodCount += 1; + for (lodFile in mapping.lod) { + if (mapping.lod.hasOwnProperty(lodFile)) { + lodBuffer = readFile(modelFile.path() + "\/" + lodFile); + httpMultiPart.add({ + name: "lod" + lodCount, + buffer: lodBuffer + }); + lodCount += 1; + } } // Textures - textureCount = 0; for (i = 0; i < geometry.textures.length; i += 1) { - textureBuffer = readFile(modelFile.path() + "\/" + mapping[TEXDIR_FIELD] + "\/" + geometry.textures[i]); + textureBuffer = readFile(modelFile.path() + "\/" + + (mapping[TEXDIR_FIELD] !== "." ? mapping[TEXDIR_FIELD] + "\/" : "") + + geometry.textures[i]); httpMultiPart.add({ - name: "texture" + textureCount, + name: "texture" + i, buffer: textureBuffer }); - textureCount += 1; } // Model category From ef5db5321d7051fdcc4375b5ec1c511c4fe7c65b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 29 Jul 2014 09:46:59 -0700 Subject: [PATCH 055/407] make voxel charges affect agents --- domain-server/resources/web/settings/describe.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/web/settings/describe.json b/domain-server/resources/web/settings/describe.json index 0ab647734b..beb02411c9 100644 --- a/domain-server/resources/web/settings/describe.json +++ b/domain-server/resources/web/settings/describe.json @@ -19,7 +19,7 @@ }, "voxels": { "label": "Voxels", - "assignment-types": [3], + "assignment-types": [2,3], "settings": { "voxel-wallet": { "label": "Destination Wallet ID", From 9a7267a10c33506cd39e6ebe4bb404e23fefb54f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 29 Jul 2014 10:52:14 -0700 Subject: [PATCH 056/407] remove an unecessary reference to loop --- assignment-client/src/audio/AudioMixer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 91ecee76e2..e2d9636118 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -415,7 +415,7 @@ void AudioMixer::run() { // block until we get the settingsRequestComplete signal QEventLoop loop; - loop.connect(&domainHandler, &DomainHandler::settingsRequestComplete, &loop, &QEventLoop::quit); + connect(&domainHandler, &DomainHandler::settingsRequestComplete, &loop, &QEventLoop::quit); domainHandler.requestDomainSettings(); loop.exec(); From 85b8449e83832d4d479da9f814c4a7b10c249b94 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 29 Jul 2014 11:17:27 -0700 Subject: [PATCH 057/407] use two different signals for settings success and failure --- assignment-client/src/audio/AudioMixer.cpp | 3 ++- libraries/networking/src/DomainHandler.cpp | 4 ++-- libraries/networking/src/DomainHandler.h | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index e2d9636118..4c3d951716 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -415,7 +415,8 @@ void AudioMixer::run() { // block until we get the settingsRequestComplete signal QEventLoop loop; - connect(&domainHandler, &DomainHandler::settingsRequestComplete, &loop, &QEventLoop::quit); + connect(&domainHandler, &DomainHandler::settingsReceived, &loop, &QEventLoop::quit); + connect(&domainHandler, &DomainHandler::settingsReceiveFail, &loop, &QEventLoop::quit); domainHandler.requestDomainSettings(); loop.exec(); diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 0f37160512..e316ea2cc5 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -157,7 +157,7 @@ void DomainHandler::settingsRequestFinished() { _settingsObject = QJsonDocument::fromJson(settingsReply->readAll()).object(); qDebug() << "Received domain settings."; - emit settingsRequestComplete(true); + emit settingsReceived(); // reset failed settings requests to 0, we got them _failedSettingsRequests = 0; @@ -170,7 +170,7 @@ void DomainHandler::settingsRequestFinished() { qDebug() << "Failed to retreive domain-server settings" << MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS << "times. Re-setting connection to domain."; clearSettings(); clearConnectionInfo(); - emit settingsRequestComplete(false); + emit settingsReceiveFail(); } else { requestDomainSettings(); } diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 67edd64172..81745713e7 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -69,7 +69,8 @@ signals: void hostnameChanged(const QString& hostname); void connectedToDomain(const QString& hostname); - void settingsRequestComplete(bool wasSuccessful); + void settingsReceived(); + void settingsReceiveFail(); private: void reset(); From 39e6d7d31b99483a01e3d293d215bd3af4254b92 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 29 Jul 2014 11:40:07 -0700 Subject: [PATCH 058/407] octree packet methods can take a cost --- libraries/octree/src/OctreeEditPacketSender.cpp | 9 ++++++--- libraries/octree/src/OctreeEditPacketSender.h | 6 +++--- libraries/voxels/src/VoxelsScriptingInterface.cpp | 1 - 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 2ed8f6c2a0..5f6fb1274b 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -87,7 +87,8 @@ bool OctreeEditPacketSender::serversExist() const { // This method is called when the edit packet layer has determined that it has a fully formed packet destined for // a known nodeID. -void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned char* buffer, ssize_t length) { +void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned char* buffer, + ssize_t length, qint64 satoshiCost) { NodeList* nodeList = NodeList::getInstance(); foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { @@ -157,7 +158,8 @@ void OctreeEditPacketSender::processPreServerExistsPackets() { } } -void OctreeEditPacketSender::queuePendingPacketToNodes(PacketType type, unsigned char* buffer, ssize_t length) { +void OctreeEditPacketSender::queuePendingPacketToNodes(PacketType type, unsigned char* buffer, + ssize_t length, qint64 satoshiCost) { // If we're asked to save messages while waiting for voxel servers to arrive, then do so... if (_maxPendingMessages > 0) { @@ -210,7 +212,8 @@ void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t l // NOTE: codeColorBuffer - is JUST the octcode/color and does not contain the packet header! -void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, unsigned char* codeColorBuffer, ssize_t length) { +void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, unsigned char* codeColorBuffer, + ssize_t length, qint64 satoshiCost) { if (!_shouldSend) { return; // bail early diff --git a/libraries/octree/src/OctreeEditPacketSender.h b/libraries/octree/src/OctreeEditPacketSender.h index cdcfc21d4a..584f74fd39 100644 --- a/libraries/octree/src/OctreeEditPacketSender.h +++ b/libraries/octree/src/OctreeEditPacketSender.h @@ -39,7 +39,7 @@ public: /// Queues a single edit message. Will potentially send a pending multi-command packet. Determines which server /// node or nodes the packet should be sent to. Can be called even before servers are known, in which case up to /// MaxPendingMessages will be buffered and processed when servers are known. - void queueOctreeEditMessage(PacketType type, unsigned char* buffer, ssize_t length); + void queueOctreeEditMessage(PacketType type, unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0); /// Releases all queued messages even if those messages haven't filled an MTU packet. This will move the packed message /// packets onto the send queue. If running in threaded mode, the caller does not need to do any further processing to @@ -100,8 +100,8 @@ public: protected: bool _shouldSend; - void queuePacketToNode(const QUuid& nodeID, unsigned char* buffer, ssize_t length); - void queuePendingPacketToNodes(PacketType type, unsigned char* buffer, ssize_t length); + void queuePacketToNode(const QUuid& nodeID, unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0); + void queuePendingPacketToNodes(PacketType type, unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0); void queuePacketToNodes(unsigned char* buffer, ssize_t length); void initializePacket(EditPacketBuffer& packetBuffer, PacketType type); void releaseQueuedPacket(EditPacketBuffer& packetBuffer); // releases specific queued packet diff --git a/libraries/voxels/src/VoxelsScriptingInterface.cpp b/libraries/voxels/src/VoxelsScriptingInterface.cpp index e877f99760..05be0fe350 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.cpp +++ b/libraries/voxels/src/VoxelsScriptingInterface.cpp @@ -71,7 +71,6 @@ void VoxelsScriptingInterface::setVoxel(float x, float y, float z, float scale, VoxelDetail addVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, scale / (float)TREE_SCALE, red, green, blue}; - // handle the local tree also... if (_tree) { if (_undoStack) { From 287e3d6800c1ac04831213777a1906a414abf3ee Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 29 Jul 2014 13:52:52 -0700 Subject: [PATCH 059/407] Compress model and texture file data in multipart/form-data A compress() method is added to the JavaScript ArrayBuffer object. --- examples/editModels.js | 8 +++++--- .../script-engine/src/ArrayBufferPrototype.cpp | 15 +++++++++++++++ .../script-engine/src/ArrayBufferPrototype.h | 1 + 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 31a55bf821..1a242d16d2 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -184,8 +184,9 @@ var httpMultiPart = (function () { // - name, string // - name, buffer var buffer, + string, stringBuffer, - string; + compressedBuffer; if (object.name === undefined) { @@ -217,9 +218,10 @@ var httpMultiPart = (function () { + "\r\n"; stringBuffer = string.toArrayBuffer(); - buffer = new Uint8Array(stringBuffer.byteLength + object.buffer.buffer.byteLength); + compressedBuffer = object.buffer.buffer.compress(); + buffer = new Uint8Array(stringBuffer.byteLength + compressedBuffer.byteLength); buffer.set(new Uint8Array(stringBuffer)); - buffer.set(new Uint8Array(object.buffer.buffer), stringBuffer.byteLength); + buffer.set(new Uint8Array(compressedBuffer), stringBuffer.byteLength); } else { diff --git a/libraries/script-engine/src/ArrayBufferPrototype.cpp b/libraries/script-engine/src/ArrayBufferPrototype.cpp index 53ebebc740..6f78caad2d 100644 --- a/libraries/script-engine/src/ArrayBufferPrototype.cpp +++ b/libraries/script-engine/src/ArrayBufferPrototype.cpp @@ -14,6 +14,9 @@ #include "ArrayBufferClass.h" #include "ArrayBufferPrototype.h" +static const int QCOMPRESS_HEADER_POSITION = 0; +static const int QCOMPRESS_HEADER_SIZE = 4; + Q_DECLARE_METATYPE(QByteArray*) ArrayBufferPrototype::ArrayBufferPrototype(QObject* parent) : QObject(parent) { @@ -43,6 +46,18 @@ QByteArray ArrayBufferPrototype::slice(qint32 begin) const { return ba->mid(begin, -1); } +QByteArray ArrayBufferPrototype::compress() const { + QByteArray* ba = thisArrayBuffer(); + + QByteArray buffer = qCompress(*ba); + + // Qt's qCompress() default compression level (-1) is the standard zLib compression. + // Here remove Qt's custom header that prevents the data server from uncompressing the files with zLib. + buffer.remove(QCOMPRESS_HEADER_POSITION, QCOMPRESS_HEADER_SIZE); + + return buffer; +} + QByteArray* ArrayBufferPrototype::thisArrayBuffer() const { return qscriptvalue_cast(thisObject().data()); } diff --git a/libraries/script-engine/src/ArrayBufferPrototype.h b/libraries/script-engine/src/ArrayBufferPrototype.h index 09d4596f28..2ad9843571 100644 --- a/libraries/script-engine/src/ArrayBufferPrototype.h +++ b/libraries/script-engine/src/ArrayBufferPrototype.h @@ -23,6 +23,7 @@ public: public slots: QByteArray slice(qint32 begin, qint32 end) const; QByteArray slice(qint32 begin) const; + QByteArray compress() const; private: QByteArray* thisArrayBuffer() const; From d04eb6261e1d07d42f7bbcd5b82441873e9a16d1 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 29 Jul 2014 14:27:51 -0700 Subject: [PATCH 060/407] More work on heightfields. --- interface/src/MetavoxelSystem.cpp | 191 +++++++++++++++++++++++---- interface/src/MetavoxelSystem.h | 26 +++- interface/src/ui/MetavoxelEditor.cpp | 93 ++++++++++++- interface/src/ui/MetavoxelEditor.h | 31 +++++ 4 files changed, 308 insertions(+), 33 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 318bf65614..f43ec1e001 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -254,15 +254,22 @@ void PointBuffer::render() { _buffer.release(); } -HeightfieldBuffer::HeightfieldBuffer(const QByteArray& height, const QByteArray& color, const QByteArray& normal) : +HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale, + const QByteArray& height, const QByteArray& color) : + _translation(translation), + _scale(scale), _height(height), _color(color), - _normal(normal), _heightTexture(QOpenGLTexture::Target2D), - _colorTexture(QOpenGLTexture::Target2D), - _normalTexture(QOpenGLTexture::Target2D) { + _colorTexture(QOpenGLTexture::Target2D) { } +class HeightfieldPoint { +public: + glm::vec2 textureCoord; + glm::vec3 vertex; +}; + void HeightfieldBuffer::render() { // initialize textures, etc. on first render if (!_heightTexture.isCreated()) { @@ -273,21 +280,116 @@ void HeightfieldBuffer::render() { _heightTexture.setData(QOpenGLTexture::Luminance, QOpenGLTexture::UInt8, _height.data()); _height.clear(); - int colorSize = glm::sqrt(_color.size() / 3); - _colorTexture.setSize(colorSize, colorSize); + if (!_color.isEmpty()) { + int colorSize = glm::sqrt(_color.size() / 3); + _colorTexture.setSize(colorSize, colorSize); + } _colorTexture.setFormat(QOpenGLTexture::RGBFormat); _colorTexture.allocateStorage(); - _colorTexture.setData(QOpenGLTexture::BGR, QOpenGLTexture::UInt8, _color.data()); - _color.clear(); + if (!_color.isEmpty()) { + _colorTexture.setData(QOpenGLTexture::BGR, QOpenGLTexture::UInt8, _color.data()); + _color.clear(); + + } else { + const quint8 WHITE_COLOR[] = { 255, 255, 255 }; + _colorTexture.setData(QOpenGLTexture::BGR, QOpenGLTexture::UInt8, const_cast(WHITE_COLOR)); + } + } + // create the buffer objects lazily + int size = _heightTexture.width(); + int sizeWithSkirt = size + 2; + int vertexCount = sizeWithSkirt * sizeWithSkirt; + int rows = sizeWithSkirt - 1; + int indexCount = rows * rows * 4; + BufferPair& bufferPair = _bufferPairs[size]; + if (!bufferPair.first.isCreated()) { + QVector vertices(vertexCount); + HeightfieldPoint* point = vertices.data(); - int normalSize = glm::sqrt(_normal.size() / 3); - _normalTexture.setSize(normalSize, normalSize); - _normalTexture.setFormat(QOpenGLTexture::RGBFormat); - _normalTexture.allocateStorage(); - _normalTexture.setData(QOpenGLTexture::BGR, QOpenGLTexture::UInt8, _normal.data()); - _normal.clear(); + float step = 1.0f / (size - 1); + float z = -step; + for (int i = 0; i < sizeWithSkirt; i++, z += step) { + float x = -step; + const float SKIRT_LENGTH = 1.0f; + float baseY = (i == 0 || i == sizeWithSkirt - 1) ? -SKIRT_LENGTH : 0.0f; + for (int j = 0; j < sizeWithSkirt; j++, point++, x += step) { + point->vertex = glm::vec3(x, (j == 0 || j == sizeWithSkirt - 1) ? -SKIRT_LENGTH : baseY, z); + point->textureCoord = glm::vec2(x, z); + } + } + + bufferPair.first.setUsagePattern(QOpenGLBuffer::StaticDraw); + bufferPair.first.create(); + bufferPair.first.bind(); + bufferPair.first.allocate(vertices.constData(), vertexCount * sizeof(HeightfieldPoint)); + + QVector indices(indexCount); + int* index = indices.data(); + for (int i = 0; i < rows; i++) { + int lineIndex = i * sizeWithSkirt; + int nextLineIndex = (i + 1) * sizeWithSkirt; + for (int j = 0; j < rows; j++) { + *index++ = lineIndex + j; + *index++ = lineIndex + j + 1; + *index++ = nextLineIndex + j; + *index++ = nextLineIndex + j + 1; + } + } + + bufferPair.second = QOpenGLBuffer(QOpenGLBuffer::IndexBuffer); + bufferPair.second.create(); + bufferPair.second.bind(); + bufferPair.second.allocate(indices.constData(), indexCount * sizeof(int)); + + } else { + bufferPair.first.bind(); + bufferPair.second.bind(); } + HeightfieldPoint* point = 0; + glVertexPointer(3, GL_FLOAT, sizeof(HeightfieldPoint), &point->vertex); + glTexCoordPointer(2, GL_FLOAT, sizeof(HeightfieldPoint), &point->textureCoord); + + glPushMatrix(); + glTranslatef(_translation.x, _translation.y, _translation.z); + glScalef(_scale, _scale, _scale); + + _heightTexture.bind(0); + _colorTexture.bind(1); + + glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); + + _colorTexture.release(1); + _heightTexture.release(0); + + glPopMatrix(); + + bufferPair.first.release(); + bufferPair.second.release(); +} + +QHash HeightfieldBuffer::_bufferPairs; + +void HeightfieldPreview::render(const glm::vec3& translation, float scale) const { + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + DefaultMetavoxelRendererImplementation::getHeightfieldProgram().bind(); + + glPushMatrix(); + glTranslatef(translation.x, translation.y, translation.z); + glScalef(scale, scale, scale); + + foreach (const BufferDataPointer& buffer, _buffers) { + buffer->render(); + } + + glPopMatrix(); + + DefaultMetavoxelRendererImplementation::getHeightfieldProgram().release(); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); } BufferDataAttribute::BufferDataAttribute(const QString& name) : @@ -368,11 +470,14 @@ int PointAugmentVisitor::visit(MetavoxelInfo& info) { { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; _points.append(point); } - if (info.size >= _pointLeafSize) { - BufferPointVector swapPoints; - _points.swap(swapPoints); - info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer( - new PointBuffer(swapPoints)))); + if (info.size >= _pointLeafSize) { + PointBuffer* buffer = NULL; + if (!_points.isEmpty()) { + BufferPointVector swapPoints; + _points.swap(swapPoints); + buffer = new PointBuffer(swapPoints); + } + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer))); } return STOP_RECURSION; } @@ -381,10 +486,13 @@ bool PointAugmentVisitor::postVisit(MetavoxelInfo& info) { if (info.size != _pointLeafSize) { return false; } - BufferPointVector swapPoints; - _points.swap(swapPoints); - info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer( - new PointBuffer(swapPoints)))); + PointBuffer* buffer = NULL; + if (!_points.isEmpty()) { + BufferPointVector swapPoints; + _points.swap(swapPoints); + buffer = new PointBuffer(swapPoints); + } + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer))); return true; } @@ -403,7 +511,18 @@ HeightfieldAugmentVisitor::HeightfieldAugmentVisitor(const MetavoxelLOD& lod) : } int HeightfieldAugmentVisitor::visit(MetavoxelInfo& info) { - return STOP_RECURSION; + if (info.isLeaf) { + HeightfieldBuffer* buffer = NULL; + HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue(); + if (height) { + HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue(); + buffer = new HeightfieldBuffer(info.minimum, info.size, height->getContents(), + color ? color->getContents() : QByteArray()); + } + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer))); + return STOP_RECURSION; + } + return DEFAULT_ORDER; } void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous, @@ -419,11 +538,19 @@ void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const data.setRoot(pointBufferAttribute, root); root->incrementReferenceCount(); } + const AttributePointer& heightfieldBufferAttribute = + Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(); + root = expandedPrevious.getRoot(heightfieldBufferAttribute); + if (root) { + data.setRoot(heightfieldBufferAttribute, root); + root->incrementReferenceCount(); + } - PointAugmentVisitor visitor(lod); - data.guideToDifferent(expandedPrevious, visitor); - + PointAugmentVisitor pointAugmentVisitor(lod); + data.guideToDifferent(expandedPrevious, pointAugmentVisitor); + HeightfieldAugmentVisitor heightfieldAugmentVisitor(lod); + data.guideToDifferent(expandedPrevious, heightfieldAugmentVisitor); } class SpannerSimulateVisitor : public SpannerVisitor { @@ -530,16 +657,24 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); - glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); _pointProgram.release(); + _heightfieldProgram.bind(); + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod); data.guide(heightfieldRenderVisitor); + _heightfieldProgram.release(); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glEnable(GL_BLEND); } diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index be1a02643f..1ee037f8c0 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -125,18 +125,34 @@ private: class HeightfieldBuffer : public BufferData { public: - HeightfieldBuffer(const QByteArray& height, const QByteArray& color, const QByteArray& normal); + HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color); virtual void render(); private: + glm::vec3 _translation; + float _scale; QByteArray _height; QByteArray _color; - QByteArray _normal; QOpenGLTexture _heightTexture; QOpenGLTexture _colorTexture; - QOpenGLTexture _normalTexture; + + typedef QPair BufferPair; + static QHash _bufferPairs; +}; + +/// Convenience class for rendering a preview of a heightfield. +class HeightfieldPreview { +public: + + void setBuffers(const QVector& buffers) { _buffers = buffers; } + + void render(const glm::vec3& translation, float scale) const; + +private: + + QVector _buffers; }; /// A client-side attribute that stores renderable buffers. @@ -157,7 +173,9 @@ class DefaultMetavoxelRendererImplementation : public MetavoxelRendererImplement public: static void init(); - + + static ProgramObject& getHeightfieldProgram() { return _heightfieldProgram; } + Q_INVOKABLE DefaultMetavoxelRendererImplementation(); virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod); diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 1f0c2498c5..80088c040a 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -15,11 +15,12 @@ #include #include #include +#include #include #include #include #include -#include +#include #include #include #include @@ -113,6 +114,7 @@ MetavoxelEditor::MetavoxelEditor() : addTool(new RemoveSpannerTool(this)); addTool(new ClearSpannersTool(this)); addTool(new SetSpannerTool(this)); + addTool(new ImportHeightfieldTool(this)); updateAttributes(); @@ -891,3 +893,92 @@ void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedOb QThreadPool::globalInstance()->start(new Voxelizer(size, cellBounds, spannerData->getVoxelizationGranularity(), directionImages)); } + +ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) : + MetavoxelTool(editor, "Import Heightfield", false) { + + QWidget* widget = new QWidget(); + QFormLayout* form = new QFormLayout(); + widget->setLayout(form); + layout()->addWidget(widget); + + form->addRow("Height:", _height = new QPushButton()); + connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile); + form->addRow("Color:", _color = new QPushButton()); + connect(_color, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectColorFile); +} + +bool ImportHeightfieldTool::appliesTo(const AttributePointer& attribute) const { + return attribute->inherits("HeightfieldAttribute"); +} + +void ImportHeightfieldTool::render() { + _preview.render(glm::vec3(), 1.0f); +} + +void ImportHeightfieldTool::selectHeightFile() { + QString filename = QFileDialog::getOpenFileName(this, "Select Height Image", QString(), "Images (*.png *.jpg)"); + if (filename.isNull()) { + return; + } + if (!_heightImage.load(filename)) { + QMessageBox::warning(this, "Invalid Image", "The selected image could not be read."); + return; + } + _heightImage = _heightImage.convertToFormat(QImage::Format_RGB888); + _height->setText(filename); + updatePreview(); +} + +void ImportHeightfieldTool::selectColorFile() { + QString filename = QFileDialog::getOpenFileName(this, "Select Color Image", QString(), "Images (*.png *.jpg)"); + if (filename.isNull()) { + return; + } + if (!_colorImage.load(filename)) { + QMessageBox::warning(this, "Invalid Image", "The selected image could not be read."); + return; + } + _colorImage = _colorImage.convertToFormat(QImage::Format_RGB888); + _color->setText(filename); + updatePreview(); +} + +const int BLOCK_SIZE = 64; + +void ImportHeightfieldTool::updatePreview() { + QVector buffers; + if (_heightImage.width() > 0 && _heightImage.height() > 0) { + float z = 0.0f; + for (int i = 0; i < _heightImage.height(); i += BLOCK_SIZE, z++) { + float x = 0.0f; + for (int j = 0; j < _heightImage.width(); j += BLOCK_SIZE, x++) { + QByteArray height(BLOCK_SIZE * BLOCK_SIZE, 0); + int rows = qMin(BLOCK_SIZE, _heightImage.height() - i); + int columns = qMin(BLOCK_SIZE, _heightImage.width() - j); + const int BYTES_PER_COLOR = 3; + for (int y = 0; y < rows; y++) { + uchar* src = _heightImage.scanLine(i + y); + char* dest = height.data() + y * BLOCK_SIZE; + for (int x = 0; x < columns; x++) { + *dest++ = *src; + src += BYTES_PER_COLOR; + } + } + + QByteArray color; + if (!_colorImage.isNull()) { + color = QByteArray(BLOCK_SIZE * BLOCK_SIZE * BYTES_PER_COLOR, 0); + rows = qMax(0, qMin(BLOCK_SIZE, _colorImage.height() - i)); + columns = qMax(0, qMin(BLOCK_SIZE, _colorImage.width() - j)); + for (int y = 0; y < rows; y++) { + memcpy(color.data() + y * BLOCK_SIZE * BYTES_PER_COLOR, _colorImage.scanLine(i + y), + columns * BYTES_PER_COLOR); + } + } + buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, height, color))); + } + } + } + _preview.setBuffers(buffers); +} diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index 79ffd1e64c..4c97da50bb 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -15,6 +15,7 @@ #include #include +#include "MetavoxelSystem.h" #include "renderer/ProgramObject.h" class QComboBox; @@ -223,4 +224,34 @@ protected: virtual void applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner); }; +/// Allows importing a heightfield. +class ImportHeightfieldTool : public MetavoxelTool { + Q_OBJECT + +public: + + ImportHeightfieldTool(MetavoxelEditor* editor); + + virtual bool appliesTo(const AttributePointer& attribute) const; + + virtual void render(); + +private slots: + + void selectHeightFile(); + void selectColorFile(); + +private: + + void updatePreview(); + + QPushButton* _height; + QPushButton* _color; + + QImage _heightImage; + QImage _colorImage; + + HeightfieldPreview _preview; +}; + #endif // hifi_MetavoxelEditor_h From 68244797622263f48aad566d034cb5ce4550e7b5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 29 Jul 2014 16:06:35 -0700 Subject: [PATCH 061/407] Progress on rendering heightfield buffers. --- .../shaders/metavoxel_heightfield.frag | 11 ++++++++- .../shaders/metavoxel_heightfield.vert | 19 ++++++++++++++- interface/src/MetavoxelSystem.cpp | 23 +++++++++++++++---- interface/src/ui/MetavoxelEditor.cpp | 5 ++-- 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/interface/resources/shaders/metavoxel_heightfield.frag b/interface/resources/shaders/metavoxel_heightfield.frag index de520d57ac..f99a0a6403 100644 --- a/interface/resources/shaders/metavoxel_heightfield.frag +++ b/interface/resources/shaders/metavoxel_heightfield.frag @@ -11,6 +11,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +// the diffuse texture +uniform sampler2D diffuseMap; + +// the interpolated normal +varying vec4 normal; + void main(void) { - gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); + // compute the base color based on OpenGL lighting model + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * max(0.0, dot(normalize(normal), gl_LightSource[0].position))); + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st); } diff --git a/interface/resources/shaders/metavoxel_heightfield.vert b/interface/resources/shaders/metavoxel_heightfield.vert index 6b90bdc44d..a5e7ec66c1 100644 --- a/interface/resources/shaders/metavoxel_heightfield.vert +++ b/interface/resources/shaders/metavoxel_heightfield.vert @@ -11,6 +11,23 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +// the height texture +uniform sampler2D heightMap; + +// the interpolated normal +varying vec4 normal; + void main(void) { - gl_Position = ftransform(); + // transform and store the normal for interpolation + normal = normalize(gl_ModelViewMatrix * vec4(0.0, 1.0, 0.0, 0.0)); + + // pass along the vertex color + gl_FrontColor = gl_Color; + + // pass along the texture coordinates + gl_TexCoord[0] = gl_MultiTexCoord0; + + // add the height to the position + gl_Position = gl_ModelViewProjectionMatrix * (gl_Vertex + + vec4(0.0, texture2D(heightMap, gl_MultiTexCoord0.st).r, 0.0, 0.0)); } diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index f43ec1e001..c090edcbef 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -275,6 +275,9 @@ void HeightfieldBuffer::render() { if (!_heightTexture.isCreated()) { int heightSize = glm::sqrt(_height.size()); _heightTexture.setSize(heightSize, heightSize); + _heightTexture.setAutoMipMapGenerationEnabled(false); + _heightTexture.setMinificationFilter(QOpenGLTexture::Linear); + _heightTexture.setWrapMode(QOpenGLTexture::ClampToEdge); _heightTexture.setFormat(QOpenGLTexture::LuminanceFormat); _heightTexture.allocateStorage(); _heightTexture.setData(QOpenGLTexture::Luminance, QOpenGLTexture::UInt8, _height.data()); @@ -284,15 +287,18 @@ void HeightfieldBuffer::render() { int colorSize = glm::sqrt(_color.size() / 3); _colorTexture.setSize(colorSize, colorSize); } + _colorTexture.setAutoMipMapGenerationEnabled(false); + _colorTexture.setMinificationFilter(QOpenGLTexture::Linear); + _colorTexture.setWrapMode(QOpenGLTexture::ClampToEdge); _colorTexture.setFormat(QOpenGLTexture::RGBFormat); _colorTexture.allocateStorage(); if (!_color.isEmpty()) { - _colorTexture.setData(QOpenGLTexture::BGR, QOpenGLTexture::UInt8, _color.data()); + _colorTexture.setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, _color.data()); _color.clear(); } else { const quint8 WHITE_COLOR[] = { 255, 255, 255 }; - _colorTexture.setData(QOpenGLTexture::BGR, QOpenGLTexture::UInt8, const_cast(WHITE_COLOR)); + _colorTexture.setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, const_cast(WHITE_COLOR)); } } // create the buffer objects lazily @@ -310,7 +316,7 @@ void HeightfieldBuffer::render() { float z = -step; for (int i = 0; i < sizeWithSkirt; i++, z += step) { float x = -step; - const float SKIRT_LENGTH = 1.0f; + const float SKIRT_LENGTH = 0.25f; float baseY = (i == 0 || i == sizeWithSkirt - 1) ? -SKIRT_LENGTH : 0.0f; for (int j = 0; j < sizeWithSkirt; j++, point++, x += step) { point->vertex = glm::vec3(x, (j == 0 || j == sizeWithSkirt - 1) ? -SKIRT_LENGTH : baseY, z); @@ -331,8 +337,8 @@ void HeightfieldBuffer::render() { for (int j = 0; j < rows; j++) { *index++ = lineIndex + j; *index++ = lineIndex + j + 1; - *index++ = nextLineIndex + j; *index++ = nextLineIndex + j + 1; + *index++ = nextLineIndex + j; } } @@ -371,6 +377,8 @@ void HeightfieldBuffer::render() { QHash HeightfieldBuffer::_bufferPairs; void HeightfieldPreview::render(const glm::vec3& translation, float scale) const { + glColor4f(1.0f, 1.0f, 1.0f, 0.75f); + glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -422,6 +430,11 @@ void DefaultMetavoxelRendererImplementation::init() { _heightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/metavoxel_heightfield.frag"); _heightfieldProgram.link(); + + _heightfieldProgram.bind(); + _heightfieldProgram.setUniformValue("heightMap", 0); + _heightfieldProgram.setUniformValue("diffuseMap", 1); + _heightfieldProgram.release(); } } @@ -662,6 +675,8 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox _pointProgram.release(); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + _heightfieldProgram.bind(); glEnableClientState(GL_TEXTURE_COORD_ARRAY); diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 80088c040a..36fbf5d9e7 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -945,14 +945,15 @@ void ImportHeightfieldTool::selectColorFile() { } const int BLOCK_SIZE = 64; +const int BLOCK_ADVANCEMENT = BLOCK_SIZE - 1; void ImportHeightfieldTool::updatePreview() { QVector buffers; if (_heightImage.width() > 0 && _heightImage.height() > 0) { float z = 0.0f; - for (int i = 0; i < _heightImage.height(); i += BLOCK_SIZE, z++) { + for (int i = 0; i < _heightImage.height(); i += BLOCK_ADVANCEMENT, z++) { float x = 0.0f; - for (int j = 0; j < _heightImage.width(); j += BLOCK_SIZE, x++) { + for (int j = 0; j < _heightImage.width(); j += BLOCK_ADVANCEMENT, x++) { QByteArray height(BLOCK_SIZE * BLOCK_SIZE, 0); int rows = qMin(BLOCK_SIZE, _heightImage.height() - i); int columns = qMin(BLOCK_SIZE, _heightImage.width() - j); From 436727dfdb5623b0d82e6f4875e1b6081dee8682 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 29 Jul 2014 16:33:36 -0700 Subject: [PATCH 062/407] Added scale field, fixed height/color extraction. --- interface/src/ui/MetavoxelEditor.cpp | 15 ++++++++++----- interface/src/ui/MetavoxelEditor.h | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 36fbf5d9e7..e1f7b38466 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -906,6 +906,11 @@ ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) : connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile); form->addRow("Color:", _color = new QPushButton()); connect(_color, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectColorFile); + form->addRow("Scale:", _scale = new QDoubleSpinBox()); + _scale->setMinimum(-FLT_MAX); + _scale->setMaximum(FLT_MAX); + _scale->setPrefix("2^"); + _scale->setValue(1.0); } bool ImportHeightfieldTool::appliesTo(const AttributePointer& attribute) const { @@ -913,7 +918,7 @@ bool ImportHeightfieldTool::appliesTo(const AttributePointer& attribute) const { } void ImportHeightfieldTool::render() { - _preview.render(glm::vec3(), 1.0f); + _preview.render(glm::vec3(), pow(2.0, _scale->value())); } void ImportHeightfieldTool::selectHeightFile() { @@ -944,7 +949,7 @@ void ImportHeightfieldTool::selectColorFile() { updatePreview(); } -const int BLOCK_SIZE = 64; +const int BLOCK_SIZE = 32; const int BLOCK_ADVANCEMENT = BLOCK_SIZE - 1; void ImportHeightfieldTool::updatePreview() { @@ -959,7 +964,7 @@ void ImportHeightfieldTool::updatePreview() { int columns = qMin(BLOCK_SIZE, _heightImage.width() - j); const int BYTES_PER_COLOR = 3; for (int y = 0; y < rows; y++) { - uchar* src = _heightImage.scanLine(i + y); + uchar* src = _heightImage.scanLine(i + y) + j * BYTES_PER_COLOR; char* dest = height.data() + y * BLOCK_SIZE; for (int x = 0; x < columns; x++) { *dest++ = *src; @@ -973,8 +978,8 @@ void ImportHeightfieldTool::updatePreview() { rows = qMax(0, qMin(BLOCK_SIZE, _colorImage.height() - i)); columns = qMax(0, qMin(BLOCK_SIZE, _colorImage.width() - j)); for (int y = 0; y < rows; y++) { - memcpy(color.data() + y * BLOCK_SIZE * BYTES_PER_COLOR, _colorImage.scanLine(i + y), - columns * BYTES_PER_COLOR); + memcpy(color.data() + y * BLOCK_SIZE * BYTES_PER_COLOR, + _colorImage.scanLine(i + y) + j * BYTES_PER_COLOR, columns * BYTES_PER_COLOR); } } buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, height, color))); diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index 4c97da50bb..1fbae86e1a 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -247,6 +247,7 @@ private: QPushButton* _height; QPushButton* _color; + QDoubleSpinBox* _scale; QImage _heightImage; QImage _colorImage; From 5fd7a11c6b41020168789b7c34d9b1d6aea658a9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 29 Jul 2014 16:38:07 -0700 Subject: [PATCH 063/407] rename the voxel cost settings --- domain-server/resources/web/settings/describe.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/domain-server/resources/web/settings/describe.json b/domain-server/resources/web/settings/describe.json index beb02411c9..2cb558bf0c 100644 --- a/domain-server/resources/web/settings/describe.json +++ b/domain-server/resources/web/settings/describe.json @@ -27,15 +27,15 @@ "placeholder": "00000000-0000-0000-0000-000000000000", "default": "" }, - "per-voxel-cost": { + "per-voxel-credits": { "label": "Per Voxel Cost", "help": "Credit cost to change each voxel", "placeholder": "0.0", "default": "0.0", "input_addon": "₵" }, - "volume-cost": { - "label": "Volume Cost", + "per-meter-cubed-credits": { + "label": "Per Meter Cubed Cost", "help": "Credit cost to change each cubed meter of voxel space", "placeholder": "0.0", "default": "0.0", From 40e08d50088de709035fed7ee2cd586be4b17795 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 29 Jul 2014 16:39:06 -0700 Subject: [PATCH 064/407] add voxel cost amounts to VoxelEditPacketSender --- .../voxels/src/VoxelEditPacketSender.cpp | 23 +++++++++++++++++++ libraries/voxels/src/VoxelEditPacketSender.h | 16 +++++++++++++ 2 files changed, 39 insertions(+) diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index 1832d5436e..b4de63b302 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -142,3 +142,26 @@ void VoxelEditPacketSender::queueVoxelEditMessages(PacketType type, int numberOf } } } + +void VoxelEditPacketSender::updateVoxelCosts(const QJsonObject& domainSettingsObject) { + + // from the domain-handler, figure out the satoshi cost per voxel and per meter cubed + const QString VOXEL_SETTINGS_KEY = "voxels"; + const QString PER_VOXEL_COST_KEY = "per-voxel-credits"; + const QString PER_METER_CUBED_COST_KEY = "per-meter-cubed-credits"; + + if (!domainSettingsObject.isEmpty()) { + float perVoxelCredits = (float) domainSettingsObject[VOXEL_SETTINGS_KEY].toObject()[PER_VOXEL_COST_KEY].toDouble(); + float perMeterCubedCredits = (float) domainSettingsObject[VOXEL_SETTINGS_KEY].toObject()[PER_METER_CUBED_COST_KEY].toDouble(); + + qDebug() << "PV: " << perVoxelCredits << "PMC: " << perMeterCubedCredits; + } else { + qDebug() << "CALLED WITH EMPTY SETTINGS!"; + _satoshisPerVoxel = 0; + _satoshisPerMeterCubed = 0; + } +} + +qint64 VoxelEditPacketSender::satoshiCostForMessage(PacketType type, int numberOfDetails, VoxelDetail *details) { + return 0; +} diff --git a/libraries/voxels/src/VoxelEditPacketSender.h b/libraries/voxels/src/VoxelEditPacketSender.h index 3ef257de6c..33382d7faf 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.h +++ b/libraries/voxels/src/VoxelEditPacketSender.h @@ -15,6 +15,7 @@ #define hifi_VoxelEditPacketSender_h #include + #include "VoxelDetail.h" /// Utility for processing, packing, queueing and sending of outbound edit voxel messages. @@ -49,5 +50,20 @@ public: // My server type is the voxel server virtual char getMyNodeType() const { return NodeType::VoxelServer; } + + qint64 satoshiCostForMessage(PacketType type, int numberOfDetails, VoxelDetail* details); + + void setSatoshisPerVoxel(qint64 satoshisPerVoxel) { _satoshisPerVoxel = satoshisPerVoxel; } + qint64 getSatoshisPerVoxel() const { return _satoshisPerVoxel; } + + void setSatoshisPerMeterCubed(qint64 satoshisPerMeterCubed) { _satoshisPerMeterCubed = satoshisPerMeterCubed; } + qint64 getSatoshisPerMeterCubed() const { return _satoshisPerMeterCubed; } + +public slots: + void updateVoxelCosts(const QJsonObject& domainSettingsObject); + +private: + qint64 _satoshisPerVoxel; + qint64 _satoshisPerMeterCubed; }; #endif // hifi_VoxelEditPacketSender_h From 34628aef3b231b31659b63b2ae2890f3fd5faf4d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 29 Jul 2014 16:47:54 -0700 Subject: [PATCH 065/407] separate muscle constraints from joint constraints --- interface/src/avatar/SkeletonModel.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 3caaad1391..9a3094df12 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -567,8 +567,8 @@ void SkeletonModel::buildRagdollConstraints() { ++itr; } - float MAX_STRENGTH = 0.3f; - float MIN_STRENGTH = 0.005f; + float MAX_STRENGTH = 0.6f; + float MIN_STRENGTH = 0.05f; // each joint gets a MuscleConstraint to its parent for (int i = 1; i < numPoints; ++i) { const JointState& state = _jointStates.at(i); @@ -577,7 +577,6 @@ void SkeletonModel::buildRagdollConstraints() { continue; } MuscleConstraint* constraint = new MuscleConstraint(&(_ragdollPoints[p]), &(_ragdollPoints[i])); - _ragdollConstraints.push_back(constraint); _muscleConstraints.push_back(constraint); // Short joints are more susceptible to wiggle so we modulate the strength based on the joint's length: @@ -643,6 +642,10 @@ void SkeletonModel::updateVisibleJointStates() { void SkeletonModel::stepRagdollForward(float deltaTime) { Ragdoll::stepRagdollForward(deltaTime); updateMuscles(); + int numConstraints = _muscleConstraints.size(); + for (int i = 0; i < numConstraints; ++i) { + _muscleConstraints[i]->enforce(); + } } float DENSITY_OF_WATER = 1000.0f; // kg/m^3 @@ -742,13 +745,8 @@ void SkeletonModel::updateMuscles() { for (int i = 0; i < numConstraints; ++i) { MuscleConstraint* constraint = _muscleConstraints[i]; int j = constraint->getParentIndex(); - if (j == -1) { - continue; - } int k = constraint->getChildIndex(); - if (k == -1) { - continue; - } + assert(j != -1 && k != -1); constraint->setChildOffset(_jointStates.at(k).getPosition() - _jointStates.at(j).getPosition()); } } From 67b9c185eba71a5072bead7a7b7f62f38aae6330 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 29 Jul 2014 16:48:34 -0700 Subject: [PATCH 066/407] formatting and minor tweaks to constraint strengths --- interface/src/avatar/MuscleConstraint.cpp | 3 +-- interface/src/avatar/MuscleConstraint.h | 2 +- libraries/shared/src/VerletPoint.cpp | 4 +++- libraries/shared/src/VerletPoint.h | 4 ---- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/MuscleConstraint.cpp b/interface/src/avatar/MuscleConstraint.cpp index f4ba7975d0..31da56d3d3 100644 --- a/interface/src/avatar/MuscleConstraint.cpp +++ b/interface/src/avatar/MuscleConstraint.cpp @@ -16,8 +16,7 @@ const float DEFAULT_MUSCLE_STRENGTH = 0.5f * MAX_MUSCLE_STRENGTH; -MuscleConstraint::MuscleConstraint(VerletPoint* parent, VerletPoint* child) - : _rootPoint(parent), _childPoint(child), +MuscleConstraint::MuscleConstraint(VerletPoint* parent, VerletPoint* child) : _rootPoint(parent), _childPoint(child), _parentIndex(-1), _childndex(-1), _strength(DEFAULT_MUSCLE_STRENGTH) { _childOffset = child->_position - parent->_position; } diff --git a/interface/src/avatar/MuscleConstraint.h b/interface/src/avatar/MuscleConstraint.h index 882b351b80..b2387a33f0 100644 --- a/interface/src/avatar/MuscleConstraint.h +++ b/interface/src/avatar/MuscleConstraint.h @@ -17,7 +17,7 @@ // MuscleConstraint is a simple constraint that pushes the child toward an offset relative to the parent. // It does NOT push the parent. -const float MAX_MUSCLE_STRENGTH = 0.5f; +const float MAX_MUSCLE_STRENGTH = 0.75f; class MuscleConstraint : public Constraint { public: diff --git a/libraries/shared/src/VerletPoint.cpp b/libraries/shared/src/VerletPoint.cpp index 641ac39341..654a74d7ac 100644 --- a/libraries/shared/src/VerletPoint.cpp +++ b/libraries/shared/src/VerletPoint.cpp @@ -11,9 +11,11 @@ #include "VerletPoint.h" +const float INTEGRATION_FRICTION_FACTOR = 0.6f; + void VerletPoint::integrateForward() { glm::vec3 oldPosition = _position; - _position += 0.6f * (_position - _lastPosition); + _position += INTEGRATION_FRICTION_FACTOR * (_position - _lastPosition); _lastPosition = oldPosition; } diff --git a/libraries/shared/src/VerletPoint.h b/libraries/shared/src/VerletPoint.h index 076a624776..f59afb16c5 100644 --- a/libraries/shared/src/VerletPoint.h +++ b/libraries/shared/src/VerletPoint.h @@ -23,10 +23,6 @@ public: void accumulateDelta(const glm::vec3& delta); void applyAccumulatedDelta(); - glm::vec3 getAccumulatedDelta() const { - return (_numDeltas > 0) ? _accumulatedDelta / (float)_numDeltas : glm::vec3(0.0f); - } - glm::vec3 _position; glm::vec3 _lastPosition; float _mass; From 9dbe74b02f85bb70f6d747678fda898dbb079677 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 29 Jul 2014 17:22:17 -0700 Subject: [PATCH 067/407] parse voxel costs to the DomainHandler object --- .../resources/web/settings/describe.json | 2 ++ .../src/DomainServerSettingsManager.cpp | 9 +++++++- libraries/networking/src/DomainHandler.cpp | 23 +++++++++++++++++++ libraries/networking/src/DomainHandler.h | 8 +++++++ .../networking/src/UserActivityLogger.cpp | 2 +- .../voxels/src/VoxelEditPacketSender.cpp | 19 --------------- libraries/voxels/src/VoxelEditPacketSender.h | 13 ----------- 7 files changed, 42 insertions(+), 34 deletions(-) diff --git a/domain-server/resources/web/settings/describe.json b/domain-server/resources/web/settings/describe.json index 2cb558bf0c..bf1a9cc23c 100644 --- a/domain-server/resources/web/settings/describe.json +++ b/domain-server/resources/web/settings/describe.json @@ -28,6 +28,7 @@ "default": "" }, "per-voxel-credits": { + "type": "double", "label": "Per Voxel Cost", "help": "Credit cost to change each voxel", "placeholder": "0.0", @@ -35,6 +36,7 @@ "input_addon": "₵" }, "per-meter-cubed-credits": { + "type": "double", "label": "Per Meter Cubed Cost", "help": "Credit cost to change each cubed meter of voxel space", "placeholder": "0.0", diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 4ec88996a6..9c741b2a3b 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -141,6 +141,8 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection return false; } +const QString SETTING_DESCRIPTION_TYPE_KEY = "type"; + void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, QVariantMap& settingsVariant, QJsonObject descriptionObject) { @@ -155,7 +157,12 @@ void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ // this is an empty value, clear it in settings variant so the default is sent settingsVariant.remove(key); } else { - settingsVariant[key] = rootValue.toString(); + if (descriptionObject[key].toObject().contains(SETTING_DESCRIPTION_TYPE_KEY)) { + // for now this means that this is a double, so set it as a double + settingsVariant[key] = rootValue.toString().toDouble(); + } else { + settingsVariant[key] = rootValue.toString(); + } } } else if (rootValue.isBool()) { settingsVariant[key] = rootValue.toBool(); diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index e316ea2cc5..a50f735542 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include #include "Assignment.h" @@ -159,6 +161,8 @@ void DomainHandler::settingsRequestFinished() { qDebug() << "Received domain settings."; emit settingsReceived(); + updateVoxelCosts(); + // reset failed settings requests to 0, we got them _failedSettingsRequests = 0; } else { @@ -177,6 +181,25 @@ void DomainHandler::settingsRequestFinished() { } } +void DomainHandler::updateVoxelCosts() { + + // from the domain-handler, figure out the satoshi cost per voxel and per meter cubed + const QString VOXEL_SETTINGS_KEY = "voxels"; + const QString PER_VOXEL_COST_KEY = "per-voxel-credits"; + const QString PER_METER_CUBED_COST_KEY = "per-meter-cubed-credits"; + + if (!_settingsObject.isEmpty()) { + float perVoxelCredits = (float) _settingsObject[VOXEL_SETTINGS_KEY].toObject()[PER_VOXEL_COST_KEY].toDouble(); + float perMeterCubedCredits = (float) _settingsObject[VOXEL_SETTINGS_KEY].toObject()[PER_METER_CUBED_COST_KEY].toDouble(); + + _satoshisPerVoxel = (qint64) floorf(perVoxelCredits * SATOSHIS_PER_CREDIT); + _satoshisPerMeterCubed = (qint64) floorf(perMeterCubedCredits * SATOSHIS_PER_CREDIT); + } else { + _satoshisPerVoxel = 0; + _satoshisPerMeterCubed = 0; + } +} + void DomainHandler::parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket) { // figure out the port that the DS wants us to use for us to talk to them with DTLS int numBytesPacketHeader = numBytesForPacketHeader(dtlsRequirementPacket); diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 81745713e7..7b7a80b49a 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -62,6 +62,9 @@ public: void parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket); + qint64 getSatoshisPerVoxel() const { return _satoshisPerVoxel; } + qint64 getSatoshisPerMeterCubed() const { return _satoshisPerMeterCubed; } + private slots: void completedHostnameLookup(const QHostInfo& hostInfo); void settingsRequestFinished(); @@ -75,6 +78,8 @@ signals: private: void reset(); + void updateVoxelCosts(); + QUuid _uuid; QString _hostname; HifiSockAddr _sockAddr; @@ -83,6 +88,9 @@ private: QTimer* _handshakeTimer; QJsonObject _settingsObject; int _failedSettingsRequests; + + qint64 _satoshisPerVoxel; + qint64 _satoshisPerMeterCubed; }; #endif // hifi_DomainHandler_h diff --git a/libraries/networking/src/UserActivityLogger.cpp b/libraries/networking/src/UserActivityLogger.cpp index 90b9da07dc..e2d3434867 100644 --- a/libraries/networking/src/UserActivityLogger.cpp +++ b/libraries/networking/src/UserActivityLogger.cpp @@ -70,7 +70,7 @@ void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCall } void UserActivityLogger::requestFinished(const QJsonObject& object) { - qDebug() << object; + // qDebug() << object; } void UserActivityLogger::requestError(QNetworkReply::NetworkError error,const QString& string) { diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index b4de63b302..40a0f853f6 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -143,25 +143,6 @@ void VoxelEditPacketSender::queueVoxelEditMessages(PacketType type, int numberOf } } -void VoxelEditPacketSender::updateVoxelCosts(const QJsonObject& domainSettingsObject) { - - // from the domain-handler, figure out the satoshi cost per voxel and per meter cubed - const QString VOXEL_SETTINGS_KEY = "voxels"; - const QString PER_VOXEL_COST_KEY = "per-voxel-credits"; - const QString PER_METER_CUBED_COST_KEY = "per-meter-cubed-credits"; - - if (!domainSettingsObject.isEmpty()) { - float perVoxelCredits = (float) domainSettingsObject[VOXEL_SETTINGS_KEY].toObject()[PER_VOXEL_COST_KEY].toDouble(); - float perMeterCubedCredits = (float) domainSettingsObject[VOXEL_SETTINGS_KEY].toObject()[PER_METER_CUBED_COST_KEY].toDouble(); - - qDebug() << "PV: " << perVoxelCredits << "PMC: " << perMeterCubedCredits; - } else { - qDebug() << "CALLED WITH EMPTY SETTINGS!"; - _satoshisPerVoxel = 0; - _satoshisPerMeterCubed = 0; - } -} - qint64 VoxelEditPacketSender::satoshiCostForMessage(PacketType type, int numberOfDetails, VoxelDetail *details) { return 0; } diff --git a/libraries/voxels/src/VoxelEditPacketSender.h b/libraries/voxels/src/VoxelEditPacketSender.h index 33382d7faf..4fb8f718cc 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.h +++ b/libraries/voxels/src/VoxelEditPacketSender.h @@ -52,18 +52,5 @@ public: virtual char getMyNodeType() const { return NodeType::VoxelServer; } qint64 satoshiCostForMessage(PacketType type, int numberOfDetails, VoxelDetail* details); - - void setSatoshisPerVoxel(qint64 satoshisPerVoxel) { _satoshisPerVoxel = satoshisPerVoxel; } - qint64 getSatoshisPerVoxel() const { return _satoshisPerVoxel; } - - void setSatoshisPerMeterCubed(qint64 satoshisPerMeterCubed) { _satoshisPerMeterCubed = satoshisPerMeterCubed; } - qint64 getSatoshisPerMeterCubed() const { return _satoshisPerMeterCubed; } - -public slots: - void updateVoxelCosts(const QJsonObject& domainSettingsObject); - -private: - qint64 _satoshisPerVoxel; - qint64 _satoshisPerMeterCubed; }; #endif // hifi_VoxelEditPacketSender_h From f39aed37b674198a024cfeb8d492487c11293103 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 29 Jul 2014 17:26:42 -0700 Subject: [PATCH 068/407] Recode and rescale texture file data before uploading A recodeImage() method is added to the JavaScript ArrayBuffer object. --- examples/editModels.js | 15 ++++++++ .../src/ArrayBufferPrototype.cpp | 34 ++++++++++++++++--- .../script-engine/src/ArrayBufferPrototype.h | 1 + 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 1a242d16d2..589f4e4bfb 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -64,6 +64,12 @@ if (typeof String.prototype.fileName !== "function") { }; } +if (typeof String.prototype.fileType !== "function") { + String.prototype.fileType = function () { + return this.slice(this.lastIndexOf(".") + 1); + }; +} + if (typeof String.prototype.path !== "function") { String.prototype.path = function () { return this.replace(/[\\\/][^\\\/]*$/, ""); @@ -284,6 +290,7 @@ var modelUploader = (function () { PITCH_FIELD = "pitch", YAW_FIELD = "yaw", ROLL_FIELD = "roll", + MAX_TEXTURE_SIZE = 1024, geometry; function error(message) { @@ -578,6 +585,8 @@ var modelUploader = (function () { lodFile, lodBuffer, textureBuffer, + textureSourceFormat, + textureTargetFormat, i; print("Preparing to send model"); @@ -638,6 +647,12 @@ var modelUploader = (function () { textureBuffer = readFile(modelFile.path() + "\/" + (mapping[TEXDIR_FIELD] !== "." ? mapping[TEXDIR_FIELD] + "\/" : "") + geometry.textures[i]); + + textureSourceFormat = geometry.textures[i].fileType().toLowerCase(); + textureTargetFormat = (textureSourceFormat === "jpg" ? "jpg" : "png"); + textureBuffer.buffer = textureBuffer.buffer.recodeImage(textureSourceFormat, textureTargetFormat, MAX_TEXTURE_SIZE); + textureBuffer.filename = textureBuffer.filename.slice(0, -textureSourceFormat.length) + textureTargetFormat; + httpMultiPart.add({ name: "texture" + i, buffer: textureBuffer diff --git a/libraries/script-engine/src/ArrayBufferPrototype.cpp b/libraries/script-engine/src/ArrayBufferPrototype.cpp index 6f78caad2d..9739f67381 100644 --- a/libraries/script-engine/src/ArrayBufferPrototype.cpp +++ b/libraries/script-engine/src/ArrayBufferPrototype.cpp @@ -11,6 +11,9 @@ #include +#include +#include + #include "ArrayBufferClass.h" #include "ArrayBufferPrototype.h" @@ -47,17 +50,40 @@ QByteArray ArrayBufferPrototype::slice(qint32 begin) const { } QByteArray ArrayBufferPrototype::compress() const { + // Compresses the ArrayBuffer data in Zlib format. QByteArray* ba = thisArrayBuffer(); QByteArray buffer = qCompress(*ba); - - // Qt's qCompress() default compression level (-1) is the standard zLib compression. - // Here remove Qt's custom header that prevents the data server from uncompressing the files with zLib. - buffer.remove(QCOMPRESS_HEADER_POSITION, QCOMPRESS_HEADER_SIZE); + buffer.remove(QCOMPRESS_HEADER_POSITION, QCOMPRESS_HEADER_SIZE); // Remove Qt's custom header to make it proper Zlib. return buffer; } +QByteArray ArrayBufferPrototype::recodeImage(const QString& sourceFormat, const QString& targetFormat, qint32 maxSize) const { + // Recodes image data if sourceFormat and targetFormat are different. + // Rescales image data if either dimension is greater than the specified maximum. + QByteArray* ba = thisArrayBuffer(); + + bool mustRecode = sourceFormat.toLower() != targetFormat.toLower(); + + QImage image = QImage::fromData(*ba); + if (image.width() > maxSize || image.height() > maxSize) { + image = image.scaled(maxSize, maxSize, Qt::KeepAspectRatio); + mustRecode = true; + } + + if (mustRecode) { + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + std::string str = targetFormat.toUpper().toStdString(); + const char* format = str.c_str(); + image.save(&buffer, format); + return buffer.data(); + } + + return *ba; +} + QByteArray* ArrayBufferPrototype::thisArrayBuffer() const { return qscriptvalue_cast(thisObject().data()); } diff --git a/libraries/script-engine/src/ArrayBufferPrototype.h b/libraries/script-engine/src/ArrayBufferPrototype.h index 2ad9843571..f9dd667dc4 100644 --- a/libraries/script-engine/src/ArrayBufferPrototype.h +++ b/libraries/script-engine/src/ArrayBufferPrototype.h @@ -24,6 +24,7 @@ public slots: QByteArray slice(qint32 begin, qint32 end) const; QByteArray slice(qint32 begin) const; QByteArray compress() const; + QByteArray recodeImage(const QString& sourceFormat, const QString& targetFormat, qint32 maxSize) const; private: QByteArray* thisArrayBuffer() const; From 6a534a6ff1911df5e3ae495e914c2e4a639d3149 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 29 Jul 2014 17:31:12 -0700 Subject: [PATCH 069/407] send along satoshi costs for voxel additions from VoxelEditPacketSender --- .../octree/src/OctreeEditPacketSender.cpp | 2 +- libraries/octree/src/OctreeEditPacketSender.h | 2 +- .../voxels/src/VoxelEditPacketSender.cpp | 19 ++++++++++++++----- libraries/voxels/src/VoxelEditPacketSender.h | 2 +- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 5f6fb1274b..1d0c40d659 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -177,7 +177,7 @@ void OctreeEditPacketSender::queuePendingPacketToNodes(PacketType type, unsigned } } -void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t length) { +void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t length, qint64 satoshiCost) { if (!_shouldSend) { return; // bail early } diff --git a/libraries/octree/src/OctreeEditPacketSender.h b/libraries/octree/src/OctreeEditPacketSender.h index 584f74fd39..ad2526b866 100644 --- a/libraries/octree/src/OctreeEditPacketSender.h +++ b/libraries/octree/src/OctreeEditPacketSender.h @@ -102,7 +102,7 @@ protected: bool _shouldSend; void queuePacketToNode(const QUuid& nodeID, unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0); void queuePendingPacketToNodes(PacketType type, unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0); - void queuePacketToNodes(unsigned char* buffer, ssize_t length); + void queuePacketToNodes(unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0); void initializePacket(EditPacketBuffer& packetBuffer, PacketType type); void releaseQueuedPacket(EditPacketBuffer& packetBuffer); // releases specific queued packet diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index 40a0f853f6..0913b10272 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -117,9 +117,9 @@ void VoxelEditPacketSender::sendVoxelEditMessage(PacketType type, const VoxelDet // If we don't have voxel jurisdictions, then we will simply queue up these packets and wait till we have // jurisdictions for processing if (!voxelServersExist()) { - queuePendingPacketToNodes(type, bufferOut, sizeOut); + queuePendingPacketToNodes(type, bufferOut, sizeOut, satoshiCostForMessage(detail)); } else { - queuePacketToNodes(bufferOut, sizeOut); + queuePacketToNodes(bufferOut, sizeOut, satoshiCostForMessage(detail)); } // either way, clean up the created buffer @@ -138,11 +138,20 @@ void VoxelEditPacketSender::queueVoxelEditMessages(PacketType type, int numberOf int sizeOut = 0; if (encodeVoxelEditMessageDetails(type, 1, &details[i], &bufferOut[0], _maxPacketSize, sizeOut)) { - queueOctreeEditMessage(type, bufferOut, sizeOut); + queueOctreeEditMessage(type, bufferOut, sizeOut, satoshiCostForMessage(details[i])); } } } -qint64 VoxelEditPacketSender::satoshiCostForMessage(PacketType type, int numberOfDetails, VoxelDetail *details) { - return 0; +qint64 VoxelEditPacketSender::satoshiCostForMessage(const VoxelDetail& details) { + const DomainHandler& domainHandler = NodeList::getInstance()->getDomainHandler(); + + qint64 totalSatoshiCost = domainHandler.getSatoshisPerVoxel(); + + qint64 costPerMeterCubed = domainHandler.getSatoshisPerMeterCubed(); + float totalVolume = details.s * details.s * details.s; + + totalSatoshiCost += floorf(totalVolume * costPerMeterCubed); + + return costPerMeterCubed; } diff --git a/libraries/voxels/src/VoxelEditPacketSender.h b/libraries/voxels/src/VoxelEditPacketSender.h index 4fb8f718cc..e761812629 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.h +++ b/libraries/voxels/src/VoxelEditPacketSender.h @@ -51,6 +51,6 @@ public: // My server type is the voxel server virtual char getMyNodeType() const { return NodeType::VoxelServer; } - qint64 satoshiCostForMessage(PacketType type, int numberOfDetails, VoxelDetail* details); + qint64 satoshiCostForMessage(const VoxelDetail& details); }; #endif // hifi_VoxelEditPacketSender_h From 496f4a184eb7f9d7e286b2e76619f8794b23f5d6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 29 Jul 2014 17:36:52 -0700 Subject: [PATCH 070/407] Translation, etc. --- interface/src/ui/MetavoxelEditor.cpp | 16 +++++++++++----- interface/src/ui/MetavoxelEditor.h | 4 +++- libraries/metavoxels/src/MetavoxelUtil.cpp | 10 +++++++--- libraries/metavoxels/src/MetavoxelUtil.h | 4 ++++ 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index e1f7b38466..70573b02c7 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -31,6 +31,7 @@ #include #include +#include #include "Application.h" #include "MetavoxelEditor.h" @@ -902,15 +903,16 @@ ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) : widget->setLayout(form); layout()->addWidget(widget); - form->addRow("Height:", _height = new QPushButton()); - connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile); - form->addRow("Color:", _color = new QPushButton()); - connect(_color, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectColorFile); + form->addRow("Translation:", _translation = new Vec3Editor(widget)); form->addRow("Scale:", _scale = new QDoubleSpinBox()); _scale->setMinimum(-FLT_MAX); _scale->setMaximum(FLT_MAX); _scale->setPrefix("2^"); _scale->setValue(1.0); + form->addRow("Height:", _height = new QPushButton()); + connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile); + form->addRow("Color:", _color = new QPushButton()); + connect(_color, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectColorFile); } bool ImportHeightfieldTool::appliesTo(const AttributePointer& attribute) const { @@ -918,7 +920,11 @@ bool ImportHeightfieldTool::appliesTo(const AttributePointer& attribute) const { } void ImportHeightfieldTool::render() { - _preview.render(glm::vec3(), pow(2.0, _scale->value())); + float scale = pow(2.0, _scale->value()); + _translation->setSingleStep(scale); + glm::vec3 quantizedTranslation = scale * glm::floor(_translation->getValue() / scale); + _translation->setValue(quantizedTranslation); + _preview.render(quantizedTranslation, scale); } void ImportHeightfieldTool::selectHeightFile() { diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index 1fbae86e1a..bc9dfdf741 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -26,6 +26,7 @@ class QPushButton; class QScrollArea; class MetavoxelTool; +class Vec3Editor; /// Allows editing metavoxels. class MetavoxelEditor : public QWidget { @@ -245,9 +246,10 @@ private: void updatePreview(); + Vec3Editor* _translation; + QDoubleSpinBox* _scale; QPushButton* _height; QPushButton* _color; - QDoubleSpinBox* _scale; QImage _heightImage; QImage _colorImage; diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index d35b9a698a..a96b831dc1 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -401,6 +401,12 @@ BaseVec3Editor::BaseVec3Editor(QWidget* parent) : QWidget(parent) { layout->addWidget(_z = createComponentBox()); } +void BaseVec3Editor::setSingleStep(double singleStep) { + _x->setSingleStep(singleStep); + _y->setSingleStep(singleStep); + _z->setSingleStep(singleStep); +} + QDoubleSpinBox* BaseVec3Editor::createComponentBox() { QDoubleSpinBox* box = new QDoubleSpinBox(); box->setMinimum(-FLT_MAX); @@ -411,9 +417,7 @@ QDoubleSpinBox* BaseVec3Editor::createComponentBox() { } Vec3Editor::Vec3Editor(QWidget* parent) : BaseVec3Editor(parent) { - _x->setSingleStep(0.01); - _y->setSingleStep(0.01); - _z->setSingleStep(0.01); + setSingleStep(0.01); } static void setComponentValue(QDoubleSpinBox* box, double value) { diff --git a/libraries/metavoxels/src/MetavoxelUtil.h b/libraries/metavoxels/src/MetavoxelUtil.h index 83aac1318e..021fbcb20d 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.h +++ b/libraries/metavoxels/src/MetavoxelUtil.h @@ -153,6 +153,8 @@ public: BaseVec3Editor(QWidget* parent); + void setSingleStep(double singleStep); + protected slots: virtual void updateValue() = 0; @@ -175,6 +177,8 @@ public: Vec3Editor(QWidget* parent); + const glm::vec3& getValue() const { return _value; } + signals: void valueChanged(const glm::vec3& vector); From 1ea9b0ccbcf4141fd9ab6988d6a00fb569570fa0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 29 Jul 2014 19:13:43 -0700 Subject: [PATCH 071/407] Working on heightfield encoding. --- interface/src/MetavoxelSystem.cpp | 13 +++-- interface/src/MetavoxelSystem.h | 12 +++- interface/src/ui/MetavoxelEditor.cpp | 28 +++++++++- interface/src/ui/MetavoxelEditor.h | 1 + .../metavoxels/src/AttributeRegistry.cpp | 55 +++++++++++++++++++ libraries/metavoxels/src/AttributeRegistry.h | 11 ++++ 6 files changed, 112 insertions(+), 8 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index c090edcbef..e1479f8f02 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -255,11 +255,12 @@ void PointBuffer::render() { } HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale, - const QByteArray& height, const QByteArray& color) : + const QByteArray& height, const QByteArray& color, bool clearAfterLoading) : _translation(translation), _scale(scale), _height(height), _color(color), + _clearAfterLoading(clearAfterLoading), _heightTexture(QOpenGLTexture::Target2D), _colorTexture(QOpenGLTexture::Target2D) { } @@ -281,8 +282,9 @@ void HeightfieldBuffer::render() { _heightTexture.setFormat(QOpenGLTexture::LuminanceFormat); _heightTexture.allocateStorage(); _heightTexture.setData(QOpenGLTexture::Luminance, QOpenGLTexture::UInt8, _height.data()); - _height.clear(); - + if (_clearAfterLoading) { + _height.clear(); + } if (!_color.isEmpty()) { int colorSize = glm::sqrt(_color.size() / 3); _colorTexture.setSize(colorSize, colorSize); @@ -294,8 +296,9 @@ void HeightfieldBuffer::render() { _colorTexture.allocateStorage(); if (!_color.isEmpty()) { _colorTexture.setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, _color.data()); - _color.clear(); - + if (_clearAfterLoading) { + _color.clear(); + } } else { const quint8 WHITE_COLOR[] = { 255, 255, 255 }; _colorTexture.setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, const_cast(WHITE_COLOR)); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 1ee037f8c0..89ea7dcbda 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -125,7 +125,15 @@ private: class HeightfieldBuffer : public BufferData { public: - HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color); + /// Creates a new heightfield buffer. + /// \param clearAfterLoading if true, clear the data arrays after we load them into textures in order to reclaim the space + HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color, + bool clearAfterLoading = true); + + const glm::vec3& getTranslation() const { return _translation; } + + const QByteArray& getHeight() const { return _height; } + const QByteArray& getColor() const { return _color; } virtual void render(); @@ -135,6 +143,7 @@ private: float _scale; QByteArray _height; QByteArray _color; + bool _clearAfterLoading; QOpenGLTexture _heightTexture; QOpenGLTexture _colorTexture; @@ -147,6 +156,7 @@ class HeightfieldPreview { public: void setBuffers(const QVector& buffers) { _buffers = buffers; } + const QVector& getBuffers() const { return _buffers; } void render(const glm::vec3& translation, float scale) const; diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 70573b02c7..3f3198116f 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -908,11 +908,15 @@ ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) : _scale->setMinimum(-FLT_MAX); _scale->setMaximum(FLT_MAX); _scale->setPrefix("2^"); - _scale->setValue(1.0); + _scale->setValue(3.0); form->addRow("Height:", _height = new QPushButton()); connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile); form->addRow("Color:", _color = new QPushButton()); connect(_color, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectColorFile); + + QPushButton* applyButton = new QPushButton("Apply"); + layout()->addWidget(applyButton); + connect(applyButton, &QAbstractButton::clicked, this, &ImportHeightfieldTool::apply); } bool ImportHeightfieldTool::appliesTo(const AttributePointer& attribute) const { @@ -955,6 +959,26 @@ void ImportHeightfieldTool::selectColorFile() { updatePreview(); } +void ImportHeightfieldTool::apply() { + float scale = pow(2.0, _scale->value()); + foreach (const BufferDataPointer& bufferData, _preview.getBuffers()) { + HeightfieldBuffer* buffer = static_cast(bufferData.data()); + MetavoxelData data; + data.setSize(scale); + HeightfieldDataPointer heightPointer(new HeightfieldData(buffer->getHeight())); + data.setRoot(AttributeRegistry::getInstance()->getHeightfieldAttribute(), new MetavoxelNode(AttributeValue( + AttributeRegistry::getInstance()->getHeightfieldAttribute(), encodeInline(heightPointer)))); + if (!buffer->getColor().isEmpty()) { + HeightfieldDataPointer colorPointer(new HeightfieldData(buffer->getColor())); + data.setRoot(AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), new MetavoxelNode(AttributeValue( + AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), encodeInline(colorPointer)))); + } + MetavoxelEditMessage message = { QVariant::fromValue(SetDataEdit( + _translation->getValue() + buffer->getTranslation() * scale, data)) }; + Application::getInstance()->getMetavoxels()->applyEdit(message, true); + } +} + const int BLOCK_SIZE = 32; const int BLOCK_ADVANCEMENT = BLOCK_SIZE - 1; @@ -988,7 +1012,7 @@ void ImportHeightfieldTool::updatePreview() { _colorImage.scanLine(i + y) + j * BYTES_PER_COLOR, columns * BYTES_PER_COLOR); } } - buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, height, color))); + buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, height, color, false))); } } } diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index bc9dfdf741..2545ff57ba 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -241,6 +241,7 @@ private slots: void selectHeightFile(); void selectColorFile(); + void apply(); private: diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 4f4da7adf2..fefbbc3cd8 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include +#include #include #include #include @@ -459,10 +461,49 @@ HeightfieldData::HeightfieldData(const QByteArray& contents) : _contents(contents) { } +void HeightfieldData::write(Bitstream& out, bool color) { + QMutexLocker locker(&_encodedMutex); + if (_encoded.isEmpty()) { + QImage image; + const int BYTES_PER_PIXEL = 3; + if (color) { + int size = glm::sqrt(_contents.size() / (double)BYTES_PER_PIXEL); + image = QImage((uchar*)_contents.data(), size, size, QImage::Format_RGB888); + } else { + int size = glm::sqrt((double)_contents.size()); + image = QImage(size, size, QImage::Format_RGB888); + uchar* dest = image.bits(); + for (const char* src = _contents.constData(), *end = src + _contents.size(); src != end; src++) { + *dest++ = *src; + *dest++ = *src; + *dest++ = *src; + } + } + QBuffer buffer(&_encoded); + buffer.open(QIODevice::WriteOnly); + image.save(&buffer, "JPG"); + } + +} + HeightfieldAttribute::HeightfieldAttribute(const QString& name) : InlineAttribute(name) { } +void HeightfieldAttribute::read(Bitstream& in, void*& value, bool isLeaf) const { + if (isLeaf) { + } +} + +void HeightfieldAttribute::write(Bitstream& out, void* value, bool isLeaf) const { + if (isLeaf) { + HeightfieldDataPointer data = decodeInline(value); + if (data) { + data->write(out, false); + } + } +} + bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead) const { return false; } @@ -471,6 +512,20 @@ HeightfieldColorAttribute::HeightfieldColorAttribute(const QString& name) : InlineAttribute(name) { } +void HeightfieldColorAttribute::read(Bitstream& in, void*& value, bool isLeaf) const { + if (isLeaf) { + } +} + +void HeightfieldColorAttribute::write(Bitstream& out, void* value, bool isLeaf) const { + if (isLeaf) { + HeightfieldDataPointer data = decodeInline(value); + if (data) { + data->write(out, true); + } + } +} + bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool postRead) const { return false; } diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 262ef89462..3ef37646d6 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -13,6 +13,7 @@ #define hifi_AttributeRegistry_h #include +#include #include #include #include @@ -424,9 +425,13 @@ public: const QByteArray& getContents() const { return _contents; } + void write(Bitstream& out, bool color); + private: QByteArray _contents; + QByteArray _encoded; + QMutex _encodedMutex; }; typedef QExplicitlySharedDataPointer HeightfieldDataPointer; @@ -439,6 +444,9 @@ public: Q_INVOKABLE HeightfieldAttribute(const QString& name = QString()); + virtual void read(Bitstream& in, void*& value, bool isLeaf) const; + virtual void write(Bitstream& out, void* value, bool isLeaf) const; + virtual bool merge(void*& parent, void* children[], bool postRead = false) const; }; @@ -450,6 +458,9 @@ public: Q_INVOKABLE HeightfieldColorAttribute(const QString& name = QString()); + virtual void read(Bitstream& in, void*& value, bool isLeaf) const; + virtual void write(Bitstream& out, void* value, bool isLeaf) const; + virtual bool merge(void*& parent, void* children[], bool postRead = false) const; }; From f944c27cafac1a5b434fa4c07d32defecd7afb73 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Jul 2014 09:24:31 -0700 Subject: [PATCH 072/407] don't calculate satoshi cost if the costs are non-existent --- libraries/voxels/src/VoxelEditPacketSender.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index 0913b10272..87bba950c7 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -149,9 +149,12 @@ qint64 VoxelEditPacketSender::satoshiCostForMessage(const VoxelDetail& details) qint64 totalSatoshiCost = domainHandler.getSatoshisPerVoxel(); qint64 costPerMeterCubed = domainHandler.getSatoshisPerMeterCubed(); - float totalVolume = details.s * details.s * details.s; - totalSatoshiCost += floorf(totalVolume * costPerMeterCubed); - - return costPerMeterCubed; + if (totalSatoshiCost == 0 && costPerMeterCubed == 0) { + float totalVolume = details.s * details.s * details.s; + + return totalSatoshiCost + floorf(totalVolume * costPerMeterCubed); + } else { + return 0; + } } From 2c8808e922ec88ec24aff1da5eda4314184552a9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Jul 2014 09:45:33 -0700 Subject: [PATCH 073/407] repairs to cost calculations for voxels --- libraries/networking/src/DomainHandler.cpp | 3 ++- libraries/voxels/src/VoxelEditPacketSender.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index a50f735542..5f20bebd50 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -171,7 +171,8 @@ void DomainHandler::settingsRequestFinished() { qDebug() << "Error getting domain settings -" << settingsReply->errorString() << "- retrying"; if (++_failedSettingsRequests >= MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS) { - qDebug() << "Failed to retreive domain-server settings" << MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS << "times. Re-setting connection to domain."; + qDebug() << "Failed to retreive domain-server settings" << MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS + << "times. Re-setting connection to domain."; clearSettings(); clearConnectionInfo(); emit settingsReceiveFail(); diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index 87bba950c7..ee189f492d 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -147,14 +147,14 @@ qint64 VoxelEditPacketSender::satoshiCostForMessage(const VoxelDetail& details) const DomainHandler& domainHandler = NodeList::getInstance()->getDomainHandler(); qint64 totalSatoshiCost = domainHandler.getSatoshisPerVoxel(); - qint64 costPerMeterCubed = domainHandler.getSatoshisPerMeterCubed(); if (totalSatoshiCost == 0 && costPerMeterCubed == 0) { - float totalVolume = details.s * details.s * details.s; - - return totalSatoshiCost + floorf(totalVolume * costPerMeterCubed); - } else { return 0; + } else { + float meterScale = details.s * TREE_SCALE; + float totalVolume = meterScale * meterScale * meterScale; + + return totalSatoshiCost + (qint64) floorf(totalVolume * costPerMeterCubed); } } From 66592466adfc6b885aac13bbca4add57f6c383dc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Jul 2014 10:05:21 -0700 Subject: [PATCH 074/407] pipe satoshi cost down to queuePacketToNodes --- libraries/octree/src/EditPacketBuffer.cpp | 30 ++++++++++++++++ libraries/octree/src/EditPacketBuffer.h | 34 +++++++++++++++++++ .../octree/src/OctreeEditPacketSender.cpp | 18 ++++------ libraries/octree/src/OctreeEditPacketSender.h | 13 ++----- 4 files changed, 72 insertions(+), 23 deletions(-) create mode 100644 libraries/octree/src/EditPacketBuffer.cpp create mode 100644 libraries/octree/src/EditPacketBuffer.h diff --git a/libraries/octree/src/EditPacketBuffer.cpp b/libraries/octree/src/EditPacketBuffer.cpp new file mode 100644 index 0000000000..d6e7bf0183 --- /dev/null +++ b/libraries/octree/src/EditPacketBuffer.cpp @@ -0,0 +1,30 @@ +// +// EditPacketBuffer.cpp +// libraries/octree/src +// +// Created by Stephen Birarda on 2014-07-30. +// 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 +// + +#include "EditPacketBuffer.h" + +EditPacketBuffer::EditPacketBuffer() : + _nodeUUID(), + _currentType(PacketTypeUnknown), + _currentSize(0), + _satoshiCost(0) +{ + +} + +EditPacketBuffer::EditPacketBuffer(PacketType type, unsigned char* buffer, ssize_t length, qint64 satoshiCost, QUuid nodeUUID) : + _nodeUUID(nodeUUID), + _currentType(type), + _currentSize(length), + _satoshiCost(satoshiCost) +{ + memcpy(_currentBuffer, buffer, length); +}; \ No newline at end of file diff --git a/libraries/octree/src/EditPacketBuffer.h b/libraries/octree/src/EditPacketBuffer.h new file mode 100644 index 0000000000..9b52cbc5e4 --- /dev/null +++ b/libraries/octree/src/EditPacketBuffer.h @@ -0,0 +1,34 @@ +// +// EditPacketBuffer.h +// libraries/octree/src +// +// Created by Stephen Birarda on 2014-07-30. +// 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 +// + +#ifndef hifi_EditPacketBuffer_h +#define hifi_EditPacketBuffer_h + +#include + +#include +#include + +/// Used for construction of edit packets +class EditPacketBuffer { +public: + EditPacketBuffer(); + EditPacketBuffer(PacketType type, unsigned char* codeColorBuffer, ssize_t length, + qint64 satoshiCost = 0, const QUuid nodeUUID = QUuid()); + + QUuid _nodeUUID; + PacketType _currentType; + unsigned char _currentBuffer[MAX_PACKET_SIZE]; + ssize_t _currentSize; + qint64 _satoshiCost; +}; + +#endif // hifi_EditPacketBuffer_h \ No newline at end of file diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 1d0c40d659..b9891f0628 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -17,14 +17,6 @@ #include #include "OctreeEditPacketSender.h" -EditPacketBuffer::EditPacketBuffer(PacketType type, unsigned char* buffer, ssize_t length, QUuid nodeUUID) : - _nodeUUID(nodeUUID), - _currentType(type), - _currentSize(length) -{ - memcpy(_currentBuffer, buffer, length); -}; - const int OctreeEditPacketSender::DEFAULT_MAX_PENDING_MESSAGES = PacketSender::DEFAULT_PACKETS_PER_SECOND; @@ -136,7 +128,7 @@ void OctreeEditPacketSender::processPreServerExistsPackets() { _pendingPacketsLock.lock(); while (!_preServerSingleMessagePackets.empty()) { EditPacketBuffer* packet = _preServerSingleMessagePackets.front(); - queuePacketToNodes(&packet->_currentBuffer[0], packet->_currentSize); + queuePacketToNodes(&packet->_currentBuffer[0], packet->_currentSize, packet->_satoshiCost); delete packet; _preServerSingleMessagePackets.erase(_preServerSingleMessagePackets.begin()); } @@ -163,7 +155,7 @@ void OctreeEditPacketSender::queuePendingPacketToNodes(PacketType type, unsigned // If we're asked to save messages while waiting for voxel servers to arrive, then do so... if (_maxPendingMessages > 0) { - EditPacketBuffer* packet = new EditPacketBuffer(type, buffer, length); + EditPacketBuffer* packet = new EditPacketBuffer(type, buffer, length, satoshiCost); _pendingPacketsLock.lock(); _preServerSingleMessagePackets.push_back(packet); // if we've saved MORE than our max, then clear out the oldest packet... @@ -204,7 +196,7 @@ void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t l isMyJurisdiction = (map.isMyJurisdiction(octCode, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN); _serverJurisdictions->unlock(); if (isMyJurisdiction) { - queuePacketToNode(nodeUUID, buffer, length); + queuePacketToNode(nodeUUID, buffer, length, satoshiCost); } } } @@ -288,6 +280,7 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, unsigned ch memcpy(&packetBuffer._currentBuffer[packetBuffer._currentSize], codeColorBuffer, length); packetBuffer._currentSize += length; + packetBuffer._satoshiCost += satoshiCost; } } } @@ -309,7 +302,8 @@ void OctreeEditPacketSender::releaseQueuedMessages() { void OctreeEditPacketSender::releaseQueuedPacket(EditPacketBuffer& packetBuffer) { _releaseQueuedPacketMutex.lock(); if (packetBuffer._currentSize > 0 && packetBuffer._currentType != PacketTypeUnknown) { - queuePacketToNode(packetBuffer._nodeUUID, &packetBuffer._currentBuffer[0], packetBuffer._currentSize); + queuePacketToNode(packetBuffer._nodeUUID, &packetBuffer._currentBuffer[0], + packetBuffer._currentSize, packetBuffer._satoshiCost); packetBuffer._currentSize = 0; packetBuffer._currentType = PacketTypeUnknown; } diff --git a/libraries/octree/src/OctreeEditPacketSender.h b/libraries/octree/src/OctreeEditPacketSender.h index ad2526b866..d11aa55963 100644 --- a/libraries/octree/src/OctreeEditPacketSender.h +++ b/libraries/octree/src/OctreeEditPacketSender.h @@ -15,20 +15,11 @@ #include #include #include + +#include "EditPacketBuffer.h" #include "JurisdictionMap.h" #include "SentPacketHistory.h" -/// Used for construction of edit packets -class EditPacketBuffer { -public: - EditPacketBuffer() : _nodeUUID(), _currentType(PacketTypeUnknown), _currentSize(0) { } - EditPacketBuffer(PacketType type, unsigned char* codeColorBuffer, ssize_t length, const QUuid nodeUUID = QUuid()); - QUuid _nodeUUID; - PacketType _currentType; - unsigned char _currentBuffer[MAX_PACKET_SIZE]; - ssize_t _currentSize; -}; - /// Utility for processing, packing, queueing and sending of outbound edit messages. class OctreeEditPacketSender : public PacketSender { Q_OBJECT From 7a128e5f779dbde7f690fb48dd018b39d16bd673 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Jul 2014 10:14:51 -0700 Subject: [PATCH 075/407] add satoshi cost to voxel packet debug --- libraries/octree/src/OctreeEditPacketSender.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index b9891f0628..8c9bee2be0 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -94,7 +94,7 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned c unsigned char* sequenceAt = buffer + numBytesPacketHeader; quint16 sequence = _outgoingSequenceNumbers[nodeUUID]++; memcpy(sequenceAt, &sequence, sizeof(quint16)); - + // send packet QByteArray packet(reinterpret_cast(buffer), length); queuePacketForSending(node, packet); @@ -103,7 +103,7 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned c _sentPacketHistories[nodeUUID].packetSent(sequence, packet); // debugging output... - bool wantDebugging = false; + bool wantDebugging = true; if (wantDebugging) { int numBytesPacketHeader = numBytesForPacketHeader(reinterpret_cast(buffer)); unsigned short int sequence = (*((unsigned short int*)(buffer + numBytesPacketHeader))); @@ -113,6 +113,7 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned c qDebug() << "OctreeEditPacketSender::queuePacketToNode() queued " << buffer[0] << " - command to node bytes=" << length << + " satoshiCost=" << satoshiCost << " sequence=" << sequence << " transitTimeSoFar=" << transitTime << " usecs"; } From 81ba686fdf35fa01ce99509401e03eabb4e1b19c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 30 Jul 2014 11:02:47 -0700 Subject: [PATCH 076/407] more perfstats for ragdoll simulation --- libraries/shared/src/PhysicsSimulation.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index ca9d3d303a..33d88f0726 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -14,6 +14,7 @@ #include "PhysicsSimulation.h" +#include "PerfStat.h" #include "PhysicsEntity.h" #include "Ragdoll.h" #include "SharedUtil.h" @@ -142,10 +143,12 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter computeCollisions(); processCollisions(); - // enforce constraints - error = 0.0f; - for (int i = 0; i < numDolls; ++i) { - error = glm::max(error, _dolls[i]->enforceRagdollConstraints()); + { // enforce constraints + PerformanceTimer perfTimer("4-enforce"); + error = 0.0f; + for (int i = 0; i < numDolls; ++i) { + error = glm::max(error, _dolls[i]->enforceRagdollConstraints()); + } } ++iterations; @@ -166,6 +169,7 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter } void PhysicsSimulation::moveRagdolls(float deltaTime) { + PerformanceTimer perfTimer("1-integrate"); int numDolls = _dolls.size(); for (int i = 0; i < numDolls; ++i) { _dolls.at(i)->stepRagdollForward(deltaTime); @@ -173,6 +177,7 @@ void PhysicsSimulation::moveRagdolls(float deltaTime) { } void PhysicsSimulation::computeCollisions() { + PerformanceTimer perfTimer("2-collide"); _collisionList.clear(); // TODO: keep track of QSet collidedEntities; int numEntities = _entities.size(); @@ -204,6 +209,7 @@ void PhysicsSimulation::computeCollisions() { } void PhysicsSimulation::processCollisions() { + PerformanceTimer perfTimer("3-resolve"); // walk all collisions, accumulate movement on shapes, and build a list of affected shapes QSet shapes; int numCollisions = _collisionList.size(); From dde0cbddcce3c1f4cc44dcb1bab298050f7632af Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 30 Jul 2014 11:09:19 -0700 Subject: [PATCH 077/407] add Shape::_id --- libraries/shared/src/Shape.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/Shape.h b/libraries/shared/src/Shape.h index 09ed30a116..a322e6defa 100644 --- a/libraries/shared/src/Shape.h +++ b/libraries/shared/src/Shape.h @@ -14,6 +14,7 @@ #include #include +#include class PhysicsEntity; @@ -21,6 +22,7 @@ const float MAX_SHAPE_MASS = 1.0e18f; // something less than sqrt(FLT_MAX) class Shape { public: + static quint32 getNextID() { static quint32 nextID = 0; return ++nextID; } enum Type{ UNKNOWN_SHAPE = 0, @@ -31,9 +33,10 @@ public: }; Shape() : _type(UNKNOWN_SHAPE), _owningEntity(NULL), _boundingRadius(0.f), _translation(0.f), _rotation(), _mass(MAX_SHAPE_MASS) { } - virtual ~Shape() {} + virtual ~Shape() { _shapeID = getNextID(); } int getType() const { return _type; } + quint32 getID() const { return _shapeID; } void setEntity(PhysicsEntity* entity) { _owningEntity = entity; } PhysicsEntity* getEntity() const { return _owningEntity; } @@ -80,6 +83,7 @@ protected: void setBoundingRadius(float radius) { _boundingRadius = radius; } int _type; + unsigned int _shapeID; PhysicsEntity* _owningEntity; float _boundingRadius; glm::vec3 _translation; From 917833d92a36437835a97ed7052e7e0f7c207ac6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 30 Jul 2014 11:29:07 -0700 Subject: [PATCH 078/407] namechange for Shape::_id --- libraries/shared/src/Shape.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/Shape.h b/libraries/shared/src/Shape.h index a322e6defa..197bc912aa 100644 --- a/libraries/shared/src/Shape.h +++ b/libraries/shared/src/Shape.h @@ -33,10 +33,10 @@ public: }; Shape() : _type(UNKNOWN_SHAPE), _owningEntity(NULL), _boundingRadius(0.f), _translation(0.f), _rotation(), _mass(MAX_SHAPE_MASS) { } - virtual ~Shape() { _shapeID = getNextID(); } + virtual ~Shape() { _id = getNextID(); } int getType() const { return _type; } - quint32 getID() const { return _shapeID; } + quint32 getID() const { return _id; } void setEntity(PhysicsEntity* entity) { _owningEntity = entity; } PhysicsEntity* getEntity() const { return _owningEntity; } @@ -83,7 +83,7 @@ protected: void setBoundingRadius(float radius) { _boundingRadius = radius; } int _type; - unsigned int _shapeID; + unsigned int _id; PhysicsEntity* _owningEntity; float _boundingRadius; glm::vec3 _translation; From 53db6dec136217d0b58d622761cfa187e2737376 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 30 Jul 2014 11:29:43 -0700 Subject: [PATCH 079/407] fix old copy-n-paste typo --- libraries/shared/src/VerletCapsuleShape.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/VerletCapsuleShape.cpp b/libraries/shared/src/VerletCapsuleShape.cpp index 3ac4899682..6a145b4924 100644 --- a/libraries/shared/src/VerletCapsuleShape.cpp +++ b/libraries/shared/src/VerletCapsuleShape.cpp @@ -91,7 +91,7 @@ float VerletCapsuleShape::computeEffectiveMass(const glm::vec3& penetration, con _startLagrangeCoef = startCoef / maxCoef; _endLagrangeCoef = endCoef / maxCoef; assert(!glm::isnan(_startLagrangeCoef)); - assert(!glm::isnan(_startLagrangeCoef)); + assert(!glm::isnan(_endLagrangeCoef)); } else { // The coefficients are the same --> the collision will move both equally // as if the object were solid. From c0689f37840ff02fb75e737d326ca2ecabd739ed Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 30 Jul 2014 11:30:08 -0700 Subject: [PATCH 080/407] fix old bug: rotation of CapsuleShape not updated when setting endpoints directly --- libraries/shared/src/CapsuleShape.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/CapsuleShape.cpp b/libraries/shared/src/CapsuleShape.cpp index 12ab6ba479..03bc48bd94 100644 --- a/libraries/shared/src/CapsuleShape.cpp +++ b/libraries/shared/src/CapsuleShape.cpp @@ -73,7 +73,7 @@ void CapsuleShape::setEndPoints(const glm::vec3& startPoint, const glm::vec3& en if (height > EPSILON) { _halfHeight = 0.5f * height; axis /= height; - computeNewRotation(axis); + _rotation = computeNewRotation(axis); } updateBoundingRadius(); } From 7b76753daf1c45edebdab9605e3fd1b784041107 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 30 Jul 2014 11:45:53 -0700 Subject: [PATCH 081/407] add PhysicsSimulation::_frame --- libraries/shared/src/PhysicsSimulation.cpp | 3 ++- libraries/shared/src/PhysicsSimulation.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index 33d88f0726..ad52948670 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -26,7 +26,7 @@ int MAX_COLLISIONS_PER_SIMULATION = 256; PhysicsSimulation::PhysicsSimulation() : _collisionList(MAX_COLLISIONS_PER_SIMULATION), - _numIterations(0), _numCollisions(0), _constraintError(0.0f), _stepTime(0) { + _frame(0), _numIterations(0), _numCollisions(0), _constraintError(0.0f), _stepTime(0) { } PhysicsSimulation::~PhysicsSimulation() { @@ -129,6 +129,7 @@ void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { } void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIterations, quint64 maxUsec) { + ++_frame; quint64 now = usecTimestampNow(); quint64 startTime = now; quint64 expiry = startTime + maxUsec; diff --git a/libraries/shared/src/PhysicsSimulation.h b/libraries/shared/src/PhysicsSimulation.h index c611e06870..efd4c543c2 100644 --- a/libraries/shared/src/PhysicsSimulation.h +++ b/libraries/shared/src/PhysicsSimulation.h @@ -12,6 +12,7 @@ #ifndef hifi_PhysicsSimulation #define hifi_PhysicsSimulation +#include #include #include "CollisionInfo.h" @@ -51,6 +52,7 @@ private: QVector _dolls; // some stats + quint32 _frame; int _numIterations; int _numCollisions; float _constraintError; From 176d8d157dacb2c1a8707ad6e5599f8619d49aeb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 30 Jul 2014 13:07:32 -0700 Subject: [PATCH 082/407] remove unused Constraint::_type --- libraries/shared/src/Constraint.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/shared/src/Constraint.h b/libraries/shared/src/Constraint.h index 422675b85d..9bbdc185e1 100644 --- a/libraries/shared/src/Constraint.h +++ b/libraries/shared/src/Constraint.h @@ -20,9 +20,6 @@ public: /// Enforce contraint by moving relevant points. /// \return max distance of point movement virtual float enforce() = 0; - -protected: - int _type; }; #endif // hifi_Constraint_h From f579d2a0e22df758ae8278c03a07843a87c4562b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 30 Jul 2014 13:11:45 -0700 Subject: [PATCH 083/407] add CollisionInfo::getShapePairKey() --- libraries/shared/src/CollisionInfo.cpp | 10 ++++++++++ libraries/shared/src/CollisionInfo.h | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/libraries/shared/src/CollisionInfo.cpp b/libraries/shared/src/CollisionInfo.cpp index e862a22f4a..9dc321fa44 100644 --- a/libraries/shared/src/CollisionInfo.cpp +++ b/libraries/shared/src/CollisionInfo.cpp @@ -26,6 +26,16 @@ CollisionInfo::CollisionInfo() : _addedVelocity(0.f) { } +quint64 CollisionInfo::getShapePairKey() const { + if (_shapeB == NULL || _shapeA == NULL) { + // zero is an invalid key + return 0; + } + quint32 idA = _shapeA->getID(); + quint32 idB = _shapeB->getID(); + return idA < idB ? ((quint64)idA << 32) + (quint64)idB : ((quint64)idB << 32) + (quint64)idA; +} + CollisionList::CollisionList(int maxSize) : _maxSize(maxSize), _size(0) { diff --git a/libraries/shared/src/CollisionInfo.h b/libraries/shared/src/CollisionInfo.h index 1ab06e2ef5..6e70654d15 100644 --- a/libraries/shared/src/CollisionInfo.h +++ b/libraries/shared/src/CollisionInfo.h @@ -15,6 +15,7 @@ #include #include +#include #include class Shape; @@ -47,6 +48,9 @@ public: Shape* getShapeA() const { return const_cast(_shapeA); } Shape* getShapeB() const { return const_cast(_shapeB); } + /// \return unique key for shape pair + quint64 getShapePairKey() const; + const Shape* _shapeA; // pointer to shapeA in this collision const Shape* _shapeB; // pointer to shapeB in this collision From ab1be38fd5eba19ed91f098e17e25b2777764b4e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Jul 2014 14:02:46 -0700 Subject: [PATCH 084/407] reset the cost of the packet back to 0 so it doesn't keep accumulating --- libraries/octree/src/OctreeEditPacketSender.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 8c9bee2be0..634a0bb260 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -324,6 +324,9 @@ void OctreeEditPacketSender::initializePacket(EditPacketBuffer& packetBuffer, Pa packetBuffer._currentSize += sizeof(quint64); // nudge past timestamp packetBuffer._currentType = type; + + // reset cost for packet to 0 + packetBuffer._satoshiCost = 0; } bool OctreeEditPacketSender::process() { From 92b75d29cff1d340366c6aec6c0428b9cbc3ecd7 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 30 Jul 2014 14:18:55 -0700 Subject: [PATCH 085/407] Added referentials base class --- libraries/avatars/src/Referential.cpp | 18 +++++++++++++ libraries/avatars/src/Referential.h | 38 +++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 libraries/avatars/src/Referential.cpp create mode 100644 libraries/avatars/src/Referential.h diff --git a/libraries/avatars/src/Referential.cpp b/libraries/avatars/src/Referential.cpp new file mode 100644 index 0000000000..c929e2701f --- /dev/null +++ b/libraries/avatars/src/Referential.cpp @@ -0,0 +1,18 @@ +// +// Referential.cpp +// +// +// Created by Clement on 7/30/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 +// + +#include "Referential.h" + +Referential::Referential(AvatarData* avatar) : + _isValid(true), + _avatar(avatar) +{ +} diff --git a/libraries/avatars/src/Referential.h b/libraries/avatars/src/Referential.h new file mode 100644 index 0000000000..d125819edc --- /dev/null +++ b/libraries/avatars/src/Referential.h @@ -0,0 +1,38 @@ +// +// Referential.h +// +// +// Created by Clement on 7/30/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 +// + +#ifndef hifi_Referential_h +#define hifi_Referential_h + +#include "AvatarData.h" + +class Referential { +public: + virtual bool isValid() { return _isValid; } + virtual void update() = 0; + +protected: + Referential(AvatarData* avatar); + + bool _isValid; + AvatarData* _avatar; + + glm::vec3 _refPosition; + glm::quat _refRotation; + float _refScale; + + glm::vec3 _translation; + glm::quat _rotation; + float _scale; +}; + + +#endif // hifi_Referential_h \ No newline at end of file From 069f1ed247ec1991bd462004cb2ed6af06e50780 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 30 Jul 2014 14:19:25 -0700 Subject: [PATCH 086/407] Added ModelReferential --- libraries/models/CMakeLists.txt | 1 + libraries/models/src/ModelReferential.cpp | 60 +++++++++++++++++++++++ libraries/models/src/ModelReferential.h | 29 +++++++++++ 3 files changed, 90 insertions(+) create mode 100644 libraries/models/src/ModelReferential.cpp create mode 100644 libraries/models/src/ModelReferential.h diff --git a/libraries/models/CMakeLists.txt b/libraries/models/CMakeLists.txt index 06578371cc..3486d329e3 100644 --- a/libraries/models/CMakeLists.txt +++ b/libraries/models/CMakeLists.txt @@ -29,6 +29,7 @@ link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") +link_hifi_library(avatars ${TARGET_NAME} "${ROOT_DIR}") # for streamable link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") diff --git a/libraries/models/src/ModelReferential.cpp b/libraries/models/src/ModelReferential.cpp new file mode 100644 index 0000000000..e54b49a1e7 --- /dev/null +++ b/libraries/models/src/ModelReferential.cpp @@ -0,0 +1,60 @@ +// +// ModelReferential.cpp +// +// +// Created by Clement on 7/30/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 +// + +#include "ModelTree.h" + +#include "ModelReferential.h" + +ModelReferential::ModelReferential(uint32_t modelID, ModelTree* tree, AvatarData* avatar) : +Referential(avatar), +_modelID(modelID), +_tree(tree) +{ + const ModelItem* item = _tree->findModelByID(_modelID); + if (!_isValid || item == NULL || _avatar == NULL) { + _isValid = false; + return; + } + + _refScale = item->getRadius(); + _refRotation = item->getModelRotation(); + _refPosition = item->getPosition(); + + glm::quat refInvRot = glm::inverse(_refRotation); + _scale = _avatar->getTargetScale() / _refScale; + _rotation = refInvRot * _avatar->getOrientation(); + _translation = refInvRot * (avatar->getPosition() - _refPosition) / _refScale; +} + +void ModelReferential::update() { + const ModelItem* item = _tree->findModelByID(_modelID); + if (!_isValid || item == NULL || _avatar == NULL) { + _isValid = false; + return; + } + + bool somethingChanged = false; + if (item->getRadius() != _refScale) { + _refScale = item->getRadius(); + _avatar->setTargetScale(_refScale * _scale); + somethingChanged = true; + } + if (item->getModelRotation() != _refRotation) { + _refRotation = item->getModelRotation(); + _avatar->setOrientation(_refRotation * _rotation); + somethingChanged = true; + } + if (item->getPosition() != _refPosition || somethingChanged) { + _refPosition = item->getPosition(); + _avatar->setPosition(_refPosition + _refRotation * (_translation * _refScale)); + somethingChanged = true; + } +} diff --git a/libraries/models/src/ModelReferential.h b/libraries/models/src/ModelReferential.h new file mode 100644 index 0000000000..8ae692568a --- /dev/null +++ b/libraries/models/src/ModelReferential.h @@ -0,0 +1,29 @@ +// +// ModelReferential.h +// +// +// Created by Clement on 7/30/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 +// + +#ifndef hifi_ModelReferential_h +#define hifi_ModelReferential_h + +#include + +class ModelTree; + +class ModelReferential : public Referential { +public: + ModelReferential(uint32_t modelID, ModelTree* tree, AvatarData* avatar); + virtual void update(); + +protected: + uint32_t _modelID; + ModelTree* _tree; +}; + +#endif // hifi_ModelReferential_h \ No newline at end of file From 82e442c11551acb0c83ff0ca0f4a787bfd3c9763 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 30 Jul 2014 14:54:38 -0700 Subject: [PATCH 087/407] Working on heightfield transmission, merging. --- interface/src/MetavoxelSystem.cpp | 65 ++++--- interface/src/MetavoxelSystem.h | 11 +- .../metavoxels/src/AttributeRegistry.cpp | 160 +++++++++++++++++- libraries/metavoxels/src/AttributeRegistry.h | 1 + libraries/metavoxels/src/Bitstream.cpp | 10 ++ libraries/metavoxels/src/Bitstream.h | 5 + 6 files changed, 220 insertions(+), 32 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index e1479f8f02..d357ab5ce4 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -29,6 +29,7 @@ REGISTER_META_OBJECT(DefaultMetavoxelRendererImplementation) REGISTER_META_OBJECT(SphereRenderer) REGISTER_META_OBJECT(StaticModelRenderer) +static int texturePointerMetaTypeId = qRegisterMetaType(); static int bufferPointVectorMetaTypeId = qRegisterMetaType(); void MetavoxelSystem::init() { @@ -112,6 +113,11 @@ void MetavoxelSystem::render() { guideToAugmented(renderVisitor); } +void MetavoxelSystem::deleteTextures(const TexturePointer& height, const TexturePointer& color) { + delete height; + delete color; +} + MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) { return new MetavoxelSystemClient(node, _updater); } @@ -261,8 +267,19 @@ HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale, _height(height), _color(color), _clearAfterLoading(clearAfterLoading), - _heightTexture(QOpenGLTexture::Target2D), - _colorTexture(QOpenGLTexture::Target2D) { + _heightTexture(new QOpenGLTexture(QOpenGLTexture::Target2D)), + _colorTexture(new QOpenGLTexture(QOpenGLTexture::Target2D)) { +} + +HeightfieldBuffer::~HeightfieldBuffer() { + // the textures have to be deleted on the main thread (for its opengl context) + if (QThread::currentThread() != Application::getInstance()->thread()) { + QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "deleteTextures", + Q_ARG(const TexturePointer&, _heightTexture), Q_ARG(const TexturePointer&, _colorTexture)); + } else { + delete _heightTexture; + delete _colorTexture; + } } class HeightfieldPoint { @@ -273,39 +290,39 @@ public: void HeightfieldBuffer::render() { // initialize textures, etc. on first render - if (!_heightTexture.isCreated()) { + if (!_heightTexture->isCreated()) { int heightSize = glm::sqrt(_height.size()); - _heightTexture.setSize(heightSize, heightSize); - _heightTexture.setAutoMipMapGenerationEnabled(false); - _heightTexture.setMinificationFilter(QOpenGLTexture::Linear); - _heightTexture.setWrapMode(QOpenGLTexture::ClampToEdge); - _heightTexture.setFormat(QOpenGLTexture::LuminanceFormat); - _heightTexture.allocateStorage(); - _heightTexture.setData(QOpenGLTexture::Luminance, QOpenGLTexture::UInt8, _height.data()); + _heightTexture->setSize(heightSize, heightSize); + _heightTexture->setAutoMipMapGenerationEnabled(false); + _heightTexture->setMinificationFilter(QOpenGLTexture::Linear); + _heightTexture->setWrapMode(QOpenGLTexture::ClampToEdge); + _heightTexture->setFormat(QOpenGLTexture::LuminanceFormat); + _heightTexture->allocateStorage(); + _heightTexture->setData(QOpenGLTexture::Luminance, QOpenGLTexture::UInt8, _height.data()); if (_clearAfterLoading) { _height.clear(); } if (!_color.isEmpty()) { int colorSize = glm::sqrt(_color.size() / 3); - _colorTexture.setSize(colorSize, colorSize); + _colorTexture->setSize(colorSize, colorSize); } - _colorTexture.setAutoMipMapGenerationEnabled(false); - _colorTexture.setMinificationFilter(QOpenGLTexture::Linear); - _colorTexture.setWrapMode(QOpenGLTexture::ClampToEdge); - _colorTexture.setFormat(QOpenGLTexture::RGBFormat); - _colorTexture.allocateStorage(); + _colorTexture->setAutoMipMapGenerationEnabled(false); + _colorTexture->setMinificationFilter(QOpenGLTexture::Linear); + _colorTexture->setWrapMode(QOpenGLTexture::ClampToEdge); + _colorTexture->setFormat(QOpenGLTexture::RGBFormat); + _colorTexture->allocateStorage(); if (!_color.isEmpty()) { - _colorTexture.setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, _color.data()); + _colorTexture->setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, _color.data()); if (_clearAfterLoading) { _color.clear(); } } else { const quint8 WHITE_COLOR[] = { 255, 255, 255 }; - _colorTexture.setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, const_cast(WHITE_COLOR)); + _colorTexture->setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, const_cast(WHITE_COLOR)); } } // create the buffer objects lazily - int size = _heightTexture.width(); + int size = _heightTexture->width(); int sizeWithSkirt = size + 2; int vertexCount = sizeWithSkirt * sizeWithSkirt; int rows = sizeWithSkirt - 1; @@ -363,13 +380,13 @@ void HeightfieldBuffer::render() { glTranslatef(_translation.x, _translation.y, _translation.z); glScalef(_scale, _scale, _scale); - _heightTexture.bind(0); - _colorTexture.bind(1); + _heightTexture->bind(0); + _colorTexture->bind(1); glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); - _colorTexture.release(1); - _heightTexture.release(0); + _colorTexture->release(1); + _heightTexture->release(0); glPopMatrix(); @@ -678,7 +695,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox _pointProgram.release(); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glColor4f(1.0f, 1.0f, 1.0f, 0.0f); _heightfieldProgram.bind(); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 89ea7dcbda..725ef9ca71 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -26,6 +26,8 @@ class Model; +typedef QOpenGLTexture* TexturePointer; + /// Renders a metavoxel tree. class MetavoxelSystem : public MetavoxelClientManager { Q_OBJECT @@ -42,6 +44,8 @@ public: void simulate(float deltaTime); void render(); + Q_INVOKABLE void deleteTextures(const TexturePointer& height, const TexturePointer& color); + protected: virtual MetavoxelClient* createClient(const SharedNodePointer& node); @@ -57,6 +61,8 @@ private: QReadWriteLock _lodLock; }; +Q_DECLARE_METATYPE(TexturePointer) + /// Describes contents of a point in a point buffer. class BufferPoint { public: @@ -129,6 +135,7 @@ public: /// \param clearAfterLoading if true, clear the data arrays after we load them into textures in order to reclaim the space HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color, bool clearAfterLoading = true); + ~HeightfieldBuffer(); const glm::vec3& getTranslation() const { return _translation; } @@ -144,8 +151,8 @@ private: QByteArray _height; QByteArray _color; bool _clearAfterLoading; - QOpenGLTexture _heightTexture; - QOpenGLTexture _colorTexture; + TexturePointer _heightTexture; + TexturePointer _colorTexture; typedef QPair BufferPair; static QHash _bufferPairs; diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index fefbbc3cd8..a255a9f8ef 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -51,9 +51,13 @@ AttributeRegistry::AttributeRegistry() : _heightfieldAttribute(registerAttribute(new HeightfieldAttribute("heightfield"))), _heightfieldColorAttribute(registerAttribute(new HeightfieldColorAttribute("heightfieldColor"))) { - // our baseline LOD threshold is for voxels; spanners are a different story + // our baseline LOD threshold is for voxels; spanners and heightfields are a different story const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 8.0f; _spannersAttribute->setLODThresholdMultiplier(SPANNER_LOD_THRESHOLD_MULTIPLIER); + + const float HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER = 32.0f; + _heightfieldAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER); + _heightfieldColorAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER); } static QScriptValue qDebugFunction(QScriptContext* context, QScriptEngine* engine) { @@ -461,16 +465,35 @@ HeightfieldData::HeightfieldData(const QByteArray& contents) : _contents(contents) { } +const int BYTES_PER_PIXEL = 3; + +HeightfieldData::HeightfieldData(Bitstream& in, int bytes, bool color) : + _encoded(in.readAligned(bytes)) { + + QImage image = QImage::fromData(_encoded).convertToFormat(QImage::Format_RGB888); + if (color) { + _contents.resize(image.width() * image.height() * BYTES_PER_PIXEL); + memcpy(_contents.data(), image.constBits(), _contents.size()); + + } else { + _contents.resize(image.width() * image.height()); + char* dest = _contents.data(); + for (const uchar* src = image.constBits(), *end = src + _contents.size() * BYTES_PER_PIXEL; + src != end; src += BYTES_PER_PIXEL) { + *dest++ = *src; + } + } +} + void HeightfieldData::write(Bitstream& out, bool color) { QMutexLocker locker(&_encodedMutex); if (_encoded.isEmpty()) { - QImage image; - const int BYTES_PER_PIXEL = 3; + QImage image; if (color) { - int size = glm::sqrt(_contents.size() / (double)BYTES_PER_PIXEL); + int size = glm::sqrt(_contents.size() / (float)BYTES_PER_PIXEL); image = QImage((uchar*)_contents.data(), size, size, QImage::Format_RGB888); } else { - int size = glm::sqrt((double)_contents.size()); + int size = glm::sqrt((float)_contents.size()); image = QImage(size, size, QImage::Format_RGB888); uchar* dest = image.bits(); for (const char* src = _contents.constData(), *end = src + _contents.size(); src != end; src++) { @@ -483,7 +506,8 @@ void HeightfieldData::write(Bitstream& out, bool color) { buffer.open(QIODevice::WriteOnly); image.save(&buffer, "JPG"); } - + out << _encoded.size(); + out.writeAligned(_encoded); } HeightfieldAttribute::HeightfieldAttribute(const QString& name) : @@ -492,6 +516,13 @@ HeightfieldAttribute::HeightfieldAttribute(const QString& name) : void HeightfieldAttribute::read(Bitstream& in, void*& value, bool isLeaf) const { if (isLeaf) { + int size; + in >> size; + if (size == 0) { + *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(); + } else { + *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, false)); + } } } @@ -500,11 +531,65 @@ void HeightfieldAttribute::write(Bitstream& out, void* value, bool isLeaf) const HeightfieldDataPointer data = decodeInline(value); if (data) { data->write(out, false); + } else { + out << 0; } } } bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead) const { + int maxSize = 0; + for (int i = 0; i < MERGE_COUNT; i++) { + HeightfieldDataPointer pointer = decodeInline(children[i]); + if (pointer) { + maxSize = qMax(maxSize, pointer->getContents().size()); + } + } + if (maxSize == 0) { + *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(); + return true; + } + int size = glm::sqrt((float)maxSize); + QByteArray contents(size * size, 0); + int halfSize = size / 2; + for (int i = 0; i < MERGE_COUNT; i++) { + HeightfieldDataPointer child = decodeInline(children[i]); + if (!child) { + continue; + } + const QByteArray& childContents = child->getContents(); + int childSize = glm::sqrt((float)childContents.size()); + if (childSize != size) { + continue; // TODO: handle differently-sized children + } + const int INDEX_MASK = 1; + int xIndex = i & INDEX_MASK; + const int Y_SHIFT = 1; + int yIndex = (i >> Y_SHIFT) & INDEX_MASK; + if (yIndex == 0 && decodeInline(children[i | (1 << Y_SHIFT)])) { + continue; // bottom is overriden by top + } + const int HALF_RANGE = 128; + int yOffset = yIndex * HALF_RANGE; + int Z_SHIFT = 2; + int zIndex = (i >> Z_SHIFT) & INDEX_MASK; + char* dest = contents.data() + (zIndex * halfSize * size) + (xIndex * halfSize); + uchar* src0 = (uchar*)childContents.data(); + uchar* src1 = src0 + 1; + uchar* src2 = src0 + childSize; + uchar* src3 = src2 + 1; + for (int z = 0; z < halfSize; z++) { + for (char* end = dest + halfSize; dest != end; ) { + *dest++ = yOffset + (qMax(qMax(*src0++, *src1++), qMax(*src2++, *src3++)) >> 1); + } + dest += halfSize; + src0 += childSize; + src1 += childSize; + src2 += childSize; + src3 += childSize; + } + } + *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(new HeightfieldData(contents)); return false; } @@ -514,6 +599,13 @@ HeightfieldColorAttribute::HeightfieldColorAttribute(const QString& name) : void HeightfieldColorAttribute::read(Bitstream& in, void*& value, bool isLeaf) const { if (isLeaf) { + int size; + in >> size; + if (size == 0) { + *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(); + } else { + *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, true)); + } } } @@ -522,11 +614,67 @@ void HeightfieldColorAttribute::write(Bitstream& out, void* value, bool isLeaf) HeightfieldDataPointer data = decodeInline(value); if (data) { data->write(out, true); + } else { + out << 0; } } } bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool postRead) const { + int maxSize = 0; + for (int i = 0; i < MERGE_COUNT; i++) { + HeightfieldDataPointer pointer = decodeInline(children[i]); + if (pointer) { + maxSize = qMax(maxSize, pointer->getContents().size()); + } + } + if (maxSize == 0) { + *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(); + return true; + } + int size = glm::sqrt(maxSize / (float)BYTES_PER_PIXEL); + QByteArray contents(size * size * BYTES_PER_PIXEL, 0); + int halfSize = size / 2; + for (int i = 0; i < MERGE_COUNT; i++) { + HeightfieldDataPointer child = decodeInline(children[i]); + if (!child) { + continue; + } + const QByteArray& childContents = child->getContents(); + int childSize = glm::sqrt(childContents.size() / (float)BYTES_PER_PIXEL); + if (childSize != size) { + continue; // TODO: handle differently-sized children + } + const int INDEX_MASK = 1; + int xIndex = i & INDEX_MASK; + const int Y_SHIFT = 1; + int yIndex = (i >> Y_SHIFT) & INDEX_MASK; + if (yIndex == 0 && decodeInline(children[i | (1 << Y_SHIFT)])) { + continue; // bottom is overriden by top + } + int Z_SHIFT = 2; + int zIndex = (i >> Z_SHIFT) & INDEX_MASK; + char* dest = contents.data() + ((zIndex * halfSize * size) + (xIndex * halfSize)) * BYTES_PER_PIXEL; + uchar* src0 = (uchar*)childContents.data(); + uchar* src1 = src0 + BYTES_PER_PIXEL; + int childStride = childSize * BYTES_PER_PIXEL; + uchar* src2 = src0 + childStride; + uchar* src3 = src2 + BYTES_PER_PIXEL; + int halfStride = halfSize * BYTES_PER_PIXEL; + for (int z = 0; z < halfSize; z++) { + for (char* end = dest + halfSize * BYTES_PER_PIXEL; dest != end; ) { + *dest++ = ((int)(*src0++) + (int)(*src1++) + (int)(*src2++) + (int)(*src3++)) >> 2; + *dest++ = ((int)(*src0++) + (int)(*src1++) + (int)(*src2++) + (int)(*src3++)) >> 2; + *dest++ = ((int)(*src0++) + (int)(*src1++) + (int)(*src2++) + (int)(*src3++)) >> 2; + } + dest += halfStride; + src0 += childStride; + src1 += childStride; + src2 += childStride; + src3 += childStride; + } + } + *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(new HeightfieldData(contents)); return false; } diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 3ef37646d6..767ebf6527 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -422,6 +422,7 @@ class HeightfieldData : public QSharedData { public: HeightfieldData(const QByteArray& contents); + HeightfieldData(Bitstream& in, int bytes, bool color); const QByteArray& getContents() const { return _contents; } diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index f49ae1c04f..e9ac3d6319 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -639,6 +639,16 @@ void Bitstream::readRawDelta(QScriptValue& value, const QScriptValue& reference) } } +void Bitstream::writeAligned(const QByteArray& data) { + flush(); + _underlying.device()->write(data); +} + +QByteArray Bitstream::readAligned(int bytes) { + reset(); + return _underlying.device()->read(bytes); +} + Bitstream& Bitstream::operator<<(bool value) { if (value) { _byte |= (1 << _position); diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 7602424ded..1fd9205387 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -430,6 +430,11 @@ public: template void writeRawDelta(const QHash& value, const QHash& reference); template void readRawDelta(QHash& value, const QHash& reference); + /// Writes the specified array aligned on byte boundaries to avoid the inefficiency + /// of bit-twiddling (at the cost of up to seven bits of wasted space). + void writeAligned(const QByteArray& data); + QByteArray readAligned(int bytes); + Bitstream& operator<<(bool value); Bitstream& operator>>(bool& value); From a722c4ba0a1e371187cc3b6bbfa7c06f6ab5363d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 30 Jul 2014 15:22:45 -0700 Subject: [PATCH 088/407] Merge fix. --- .../metavoxels/src/AttributeRegistry.cpp | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index a255a9f8ef..499f8146cf 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -574,19 +574,14 @@ bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead) int Z_SHIFT = 2; int zIndex = (i >> Z_SHIFT) & INDEX_MASK; char* dest = contents.data() + (zIndex * halfSize * size) + (xIndex * halfSize); - uchar* src0 = (uchar*)childContents.data(); - uchar* src1 = src0 + 1; - uchar* src2 = src0 + childSize; - uchar* src3 = src2 + 1; + uchar* src = (uchar*)childContents.data(); + int childSizePlusOne = childSize + 1; for (int z = 0; z < halfSize; z++) { - for (char* end = dest + halfSize; dest != end; ) { - *dest++ = yOffset + (qMax(qMax(*src0++, *src1++), qMax(*src2++, *src3++)) >> 1); + for (char* end = dest + halfSize; dest != end; src += 2) { + *dest++ = yOffset + (qMax(qMax(src[0], src[1]), qMax(src[childSize], src[childSizePlusOne])) >> 1); } dest += halfSize; - src0 += childSize; - src1 += childSize; - src2 += childSize; - src3 += childSize; + src += childSize; } } *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(new HeightfieldData(contents)); @@ -655,23 +650,25 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post int Z_SHIFT = 2; int zIndex = (i >> Z_SHIFT) & INDEX_MASK; char* dest = contents.data() + ((zIndex * halfSize * size) + (xIndex * halfSize)) * BYTES_PER_PIXEL; - uchar* src0 = (uchar*)childContents.data(); - uchar* src1 = src0 + BYTES_PER_PIXEL; + uchar* src = (uchar*)childContents.data(); int childStride = childSize * BYTES_PER_PIXEL; - uchar* src2 = src0 + childStride; - uchar* src3 = src2 + BYTES_PER_PIXEL; int halfStride = halfSize * BYTES_PER_PIXEL; + int childStep = 2 * BYTES_PER_PIXEL; + int redOffset3 = childStride + BYTES_PER_PIXEL; + int greenOffset1 = BYTES_PER_PIXEL + 1; + int greenOffset2 = childStride + 1; + int greenOffset3 = childStride + BYTES_PER_PIXEL + 1; + int blueOffset1 = BYTES_PER_PIXEL + 2; + int blueOffset2 = childStride + 2; + int blueOffset3 = childStride + BYTES_PER_PIXEL + 2; for (int z = 0; z < halfSize; z++) { - for (char* end = dest + halfSize * BYTES_PER_PIXEL; dest != end; ) { - *dest++ = ((int)(*src0++) + (int)(*src1++) + (int)(*src2++) + (int)(*src3++)) >> 2; - *dest++ = ((int)(*src0++) + (int)(*src1++) + (int)(*src2++) + (int)(*src3++)) >> 2; - *dest++ = ((int)(*src0++) + (int)(*src1++) + (int)(*src2++) + (int)(*src3++)) >> 2; + for (char* end = dest + halfSize * BYTES_PER_PIXEL; dest != end; src += childStep) { + *dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2; + *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2; + *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2; } dest += halfStride; - src0 += childStride; - src1 += childStride; - src2 += childStride; - src3 += childStride; + src += childStride; } } *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(new HeightfieldData(contents)); From f356f0652b72eb4cb6ef88e44aa1666c3bc9aaca Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 30 Jul 2014 16:36:40 -0700 Subject: [PATCH 089/407] Collapse nodes when they fall out of LOD. --- libraries/metavoxels/src/MetavoxelData.cpp | 176 ++++++++++++--------- libraries/metavoxels/src/MetavoxelData.h | 6 + 2 files changed, 111 insertions(+), 71 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 29f18f5cc1..8860d30c93 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -54,6 +54,18 @@ bool MetavoxelLOD::becameSubdivided(const glm::vec3& minimum, float size, return true; } +bool MetavoxelLOD::becameSubdividedOrCollapsed(const glm::vec3& minimum, float size, + const MetavoxelLOD& reference, float multiplier) const { + if (position == reference.position && threshold == reference.threshold) { + return false; // first off, nothing becomes subdivided or collapsed if it doesn't change + } + if (!(shouldSubdivide(minimum, size, multiplier) || reference.shouldSubdivide(minimum, size, multiplier))) { + return false; // this one or the reference must be subdivided + } + // TODO: find some way of culling subtrees that can't possibly contain subdivided or collapsed nodes + return true; +} + MetavoxelData::MetavoxelData() : _size(1.0f) { } @@ -567,53 +579,67 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, const MetavoxelLOD // shallow copy the reference *this = reference; + QHash remainingRoots = _roots; + glm::vec3 minimum = getMinimum(); + bool changed; in >> changed; - if (!changed) { - return; - } - - bool sizeChanged; - in >> sizeChanged; - if (sizeChanged) { - float size; - in >> size; - while (_size < size) { - expand(); - } - } - - forever { - AttributePointer attribute; - in >> attribute; - if (!attribute) { - break; - } - MetavoxelStreamBase base = { attribute, in, lod, referenceLOD }; - MetavoxelStreamState state = { base, getMinimum(), _size }; - MetavoxelNode* oldRoot = _roots.value(attribute); - if (oldRoot) { - bool changed; - in >> changed; - if (changed) { - oldRoot->incrementReferenceCount(); - attribute->readMetavoxelDelta(*this, *oldRoot, state); - oldRoot->decrementReferenceCount(attribute); - } else { - attribute->readMetavoxelSubdivision(*this, state); + if (changed) { + bool sizeChanged; + in >> sizeChanged; + if (sizeChanged) { + float size; + in >> size; + while (_size < size) { + expand(); } - } else { - attribute->readMetavoxelRoot(*this, state); - } + } + + forever { + AttributePointer attribute; + in >> attribute; + if (!attribute) { + break; + } + MetavoxelStreamBase base = { attribute, in, lod, referenceLOD }; + MetavoxelStreamState state = { base, minimum, _size }; + MetavoxelNode* oldRoot = _roots.value(attribute); + if (oldRoot) { + bool changed; + in >> changed; + if (changed) { + oldRoot->incrementReferenceCount(); + attribute->readMetavoxelDelta(*this, *oldRoot, state); + oldRoot->decrementReferenceCount(attribute); + } else { + attribute->readMetavoxelSubdivision(*this, state); + } + remainingRoots.remove(attribute); + + } else { + attribute->readMetavoxelRoot(*this, state); + } + } + + forever { + AttributePointer attribute; + in >> attribute; + if (!attribute) { + break; + } + _roots.take(attribute)->decrementReferenceCount(attribute); + remainingRoots.remove(attribute); + } } - forever { - AttributePointer attribute; - in >> attribute; - if (!attribute) { - break; + // read subdivisions for the remaining roots if there's any chance of a collapse + if (!(lod.position == referenceLOD.position && lod.threshold <= referenceLOD.threshold)) { + for (QHash::const_iterator it = remainingRoots.constBegin(); + it != remainingRoots.constEnd(); it++) { + MetavoxelStreamBase base = { it.key(), in, lod, referenceLOD }; + MetavoxelStreamState state = { base, minimum, _size }; + it.key()->readMetavoxelSubdivision(*this, state); } - _roots.take(attribute)->decrementReferenceCount(attribute); } } @@ -788,6 +814,10 @@ bool MetavoxelStreamState::becameSubdivided() const { return base.lod.becameSubdivided(minimum, size, base.referenceLOD, base.attribute->getLODThresholdMultiplier()); } +bool MetavoxelStreamState::becameSubdividedOrCollapsed() const { + return base.lod.becameSubdividedOrCollapsed(minimum, size, base.referenceLOD, base.attribute->getLODThresholdMultiplier()); +} + void MetavoxelStreamState::setMinimum(const glm::vec3& lastMinimum, int index) { minimum = getNextMinimum(lastMinimum, size, index); } @@ -923,7 +953,7 @@ void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamSta _children[i] = new MetavoxelNode(state.base.attribute); _children[i]->readDelta(*reference._children[i], nextState); } else { - if (nextState.becameSubdivided()) { + if (nextState.becameSubdividedOrCollapsed()) { _children[i] = reference._children[i]->readSubdivision(nextState); if (_children[i] == reference._children[i]) { _children[i]->incrementReferenceCount(); @@ -972,42 +1002,46 @@ void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamSt } MetavoxelNode* MetavoxelNode::readSubdivision(MetavoxelStreamState& state) { - if (!state.shouldSubdivideReference()) { - bool leaf; - state.base.stream >> leaf; - if (leaf) { - return isLeaf() ? this : new MetavoxelNode(getAttributeValue(state.base.attribute)); - - } else { - MetavoxelNode* newNode = new MetavoxelNode(getAttributeValue(state.base.attribute)); + if (state.shouldSubdivide()) { + if (!state.shouldSubdivideReference()) { + bool leaf; + state.base.stream >> leaf; + if (leaf) { + return isLeaf() ? this : new MetavoxelNode(getAttributeValue(state.base.attribute)); + + } else { + MetavoxelNode* newNode = new MetavoxelNode(getAttributeValue(state.base.attribute)); + MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + newNode->_children[i] = new MetavoxelNode(state.base.attribute); + newNode->_children[i]->read(nextState); + } + return newNode; + } + } else if (!isLeaf()) { + MetavoxelNode* node = this; MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); - newNode->_children[i] = new MetavoxelNode(state.base.attribute); - newNode->_children[i]->read(nextState); - } - return newNode; - } - } else if (!isLeaf()) { - MetavoxelNode* node = this; - MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; - for (int i = 0; i < CHILD_COUNT; i++) { - nextState.setMinimum(state.minimum, i); - if (nextState.becameSubdivided()) { - MetavoxelNode* child = _children[i]->readSubdivision(nextState); - if (child != _children[i]) { - if (node == this) { - node = new MetavoxelNode(state.base.attribute, this); + if (nextState.becameSubdividedOrCollapsed()) { + MetavoxelNode* child = _children[i]->readSubdivision(nextState); + if (child != _children[i]) { + if (node == this) { + node = new MetavoxelNode(state.base.attribute, this); + } + node->_children[i] = child; + _children[i]->decrementReferenceCount(state.base.attribute); } - node->_children[i] = child; - _children[i]->decrementReferenceCount(state.base.attribute); } } + if (node != this) { + node->mergeChildren(state.base.attribute, true); + } + return node; } - if (node != this) { - node->mergeChildren(state.base.attribute, true); - } - return node; + } else if (!isLeaf()) { + return new MetavoxelNode(getAttributeValue(state.base.attribute)); } return this; } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 46376601c1..24eb09763c 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -55,6 +55,11 @@ public: /// Checks whether the node or any of the nodes underneath it have had subdivision enabled as compared to the reference. bool becameSubdivided(const glm::vec3& minimum, float size, const MetavoxelLOD& reference, float multiplier = 1.0f) const; + + /// Checks whether the node or any of the nodes underneath it have had subdivision + /// enabled or disabled as compared to the reference. + bool becameSubdividedOrCollapsed(const glm::vec3& minimum, float size, + const MetavoxelLOD& reference, float multiplier = 1.0f) const; }; DECLARE_STREAMABLE_METATYPE(MetavoxelLOD) @@ -181,6 +186,7 @@ public: bool shouldSubdivide() const; bool shouldSubdivideReference() const; bool becameSubdivided() const; + bool becameSubdividedOrCollapsed() const; void setMinimum(const glm::vec3& lastMinimum, int index); }; From bc77630c5bbe885e155bd7e76328b58063e5a60f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 30 Jul 2014 16:48:11 -0700 Subject: [PATCH 090/407] Extanded FBXService + moved ModelReferential --- .../src/avatar}/ModelReferential.cpp | 35 ++++++++++++++++++- .../src/avatar}/ModelReferential.h | 12 +++++++ interface/src/models/ModelTreeRenderer.cpp | 4 +++ interface/src/models/ModelTreeRenderer.h | 2 +- libraries/models/src/ModelTree.h | 4 +++ 5 files changed, 55 insertions(+), 2 deletions(-) rename {libraries/models/src => interface/src/avatar}/ModelReferential.cpp (66%) rename {libraries/models/src => interface/src/avatar}/ModelReferential.h (68%) diff --git a/libraries/models/src/ModelReferential.cpp b/interface/src/avatar/ModelReferential.cpp similarity index 66% rename from libraries/models/src/ModelReferential.cpp rename to interface/src/avatar/ModelReferential.cpp index e54b49a1e7..c681bb29da 100644 --- a/libraries/models/src/ModelReferential.cpp +++ b/interface/src/avatar/ModelReferential.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "ModelTree.h" #include "ModelReferential.h" @@ -19,7 +21,7 @@ _modelID(modelID), _tree(tree) { const ModelItem* item = _tree->findModelByID(_modelID); - if (!_isValid || item == NULL || _avatar == NULL) { + if (!_isValid || item == NULL) { _isValid = false; return; } @@ -58,3 +60,34 @@ void ModelReferential::update() { somethingChanged = true; } } + +JointReferential::JointReferential(uint32_t jointID, uint32_t modelID, ModelTree* tree, AvatarData* avatar) : + ModelReferential(modelID, tree, avatar), + _jointID(jointID) +{ + const Model* model = getModel(_tree->findModelByID(_modelID)); + + if (!_isValid || model == NULL || model->getJointStateCount() <= jointID) { + _isValid = false; + return; + } +} + +void JointReferential::update() { + const ModelItem* item = _tree->findModelByID(_modelID); + if (!_isValid || item == NULL) { + _isValid = false; + return; + } + + +} + +const Model* JointReferential::getModel(const ModelItem* item) { + ModelItemFBXService* fbxService = _tree->getFBXService(); + if (item != NULL && fbxService != NULL) { + return fbxService->getModelForModelItem(*item); + } + + return NULL; +} diff --git a/libraries/models/src/ModelReferential.h b/interface/src/avatar/ModelReferential.h similarity index 68% rename from libraries/models/src/ModelReferential.h rename to interface/src/avatar/ModelReferential.h index 8ae692568a..8f9333451a 100644 --- a/libraries/models/src/ModelReferential.h +++ b/interface/src/avatar/ModelReferential.h @@ -15,6 +15,7 @@ #include class ModelTree; +class Model; class ModelReferential : public Referential { public: @@ -26,4 +27,15 @@ protected: ModelTree* _tree; }; +class JointReferential : public ModelReferential { +public: + JointReferential(uint32_t jointID, uint32_t modelID, ModelTree* tree, AvatarData* avatar); + virtual void update(); + +protected: + const Model* getModel(const ModelItem* item); + + uint32_t _jointID; +}; + #endif // hifi_ModelReferential_h \ No newline at end of file diff --git a/interface/src/models/ModelTreeRenderer.cpp b/interface/src/models/ModelTreeRenderer.cpp index 78107db699..acbb373ffc 100644 --- a/interface/src/models/ModelTreeRenderer.cpp +++ b/interface/src/models/ModelTreeRenderer.cpp @@ -76,6 +76,10 @@ const FBXGeometry* ModelTreeRenderer::getGeometryForModel(const ModelItem& model return result; } +const Model* ModelTreeRenderer::getModelForModelItem(const ModelItem& modelItem) { + return getModel(modelItem); +} + Model* ModelTreeRenderer::getModel(const ModelItem& modelItem) { Model* model = NULL; diff --git a/interface/src/models/ModelTreeRenderer.h b/interface/src/models/ModelTreeRenderer.h index d69b85efe9..63363e4ce2 100644 --- a/interface/src/models/ModelTreeRenderer.h +++ b/interface/src/models/ModelTreeRenderer.h @@ -51,7 +51,7 @@ public: virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE); virtual const FBXGeometry* getGeometryForModel(const ModelItem& modelItem); - + virtual const Model* getModelForModelItem(const ModelItem& modelItem); /// clears the tree virtual void clear(); diff --git a/libraries/models/src/ModelTree.h b/libraries/models/src/ModelTree.h index a2a3c9cd28..41bcfcdcc3 100644 --- a/libraries/models/src/ModelTree.h +++ b/libraries/models/src/ModelTree.h @@ -15,6 +15,8 @@ #include #include "ModelTreeElement.h" +class Model; + class NewlyCreatedModelHook { public: virtual void modelCreated(const ModelItem& newModel, const SharedNodePointer& senderNode) = 0; @@ -23,6 +25,7 @@ public: class ModelItemFBXService { public: virtual const FBXGeometry* getGeometryForModel(const ModelItem& modelItem) = 0; + virtual const Model* getModelForModelItem(const ModelItem& modelItem) = 0; }; class ModelTree : public Octree { @@ -80,6 +83,7 @@ public: void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode); void handleAddModelResponse(const QByteArray& packet); + ModelItemFBXService* getFBXService() const { return _fbxService; } void setFBXService(ModelItemFBXService* service) { _fbxService = service; } const FBXGeometry* getGeometryForModel(const ModelItem& modelItem) { return _fbxService ? _fbxService->getGeometryForModel(modelItem) : NULL; From 1138a3a275edbcecc3ccdbc33fa315b4c8a95a91 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 30 Jul 2014 16:49:53 -0700 Subject: [PATCH 091/407] Added referentials to AvatarData --- interface/src/avatar/MyAvatar.cpp | 5 +++++ interface/src/avatar/MyAvatar.h | 2 ++ libraries/avatars/src/AvatarData.cpp | 2 ++ libraries/avatars/src/AvatarData.h | 3 +++ libraries/avatars/src/Referential.cpp | 4 ++++ libraries/avatars/src/Referential.h | 7 ++++++- 6 files changed, 22 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4d2d679956..9126f680b8 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -444,6 +444,11 @@ glm::vec3 MyAvatar::getRightPalmPosition() { return rightHandPosition; } +void MyAvatar::changeReferential(Referential *ref) { + delete _referential; + _referential = ref; +} + void MyAvatar::setLocalGravity(glm::vec3 gravity) { _motionBehaviors |= AVATAR_MOTION_OBEY_LOCAL_GRAVITY; // Environmental and Local gravities are incompatible. Since Local is being set here diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 581044c522..4744ca80b8 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -149,6 +149,8 @@ public slots: glm::vec3 getLeftPalmPosition(); glm::vec3 getRightPalmPosition(); + void changeReferential(Referential* ref); + signals: void transformChanged(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index c3ea2f8b50..005a2abb44 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -36,6 +36,7 @@ using namespace std; AvatarData::AvatarData() : _sessionUUID(), _handPosition(0,0,0), + _referential(NULL), _bodyYaw(-90.f), _bodyPitch(0.0f), _bodyRoll(0.0f), @@ -62,6 +63,7 @@ AvatarData::AvatarData() : AvatarData::~AvatarData() { delete _headData; delete _handData; + delete _referential; } glm::vec3 AvatarData::getHandPosition() const { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 008aecc817..aed1047947 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -49,6 +49,7 @@ typedef unsigned long long quint64; #include +#include "Referential.h" #include "HeadData.h" #include "HandData.h" @@ -283,6 +284,8 @@ protected: QUuid _sessionUUID; glm::vec3 _position; glm::vec3 _handPosition; + + Referential* _referential; // Body rotation float _bodyYaw; // degrees diff --git a/libraries/avatars/src/Referential.cpp b/libraries/avatars/src/Referential.cpp index c929e2701f..dd504485f5 100644 --- a/libraries/avatars/src/Referential.cpp +++ b/libraries/avatars/src/Referential.cpp @@ -15,4 +15,8 @@ Referential::Referential(AvatarData* avatar) : _isValid(true), _avatar(avatar) { + if (_avatar == NULL) { + _isValid = false; + return; + } } diff --git a/libraries/avatars/src/Referential.h b/libraries/avatars/src/Referential.h index d125819edc..a1a9fcd0f7 100644 --- a/libraries/avatars/src/Referential.h +++ b/libraries/avatars/src/Referential.h @@ -12,10 +12,15 @@ #ifndef hifi_Referential_h #define hifi_Referential_h -#include "AvatarData.h" +#include +#include + +class AvatarData; class Referential { public: + virtual ~Referential(); + virtual bool isValid() { return _isValid; } virtual void update() = 0; From eba92eb5173584d28ee11baddb6d33bc52075f79 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Jul 2014 17:21:04 -0700 Subject: [PATCH 092/407] have the OctreeEditPacketSender emit a signal when payment is required --- libraries/octree/src/OctreeEditPacketSender.cpp | 11 ++++++++++- libraries/octree/src/OctreeEditPacketSender.h | 14 +++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 634a0bb260..86208c9fd2 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -26,7 +26,10 @@ OctreeEditPacketSender::OctreeEditPacketSender() : _maxPendingMessages(DEFAULT_MAX_PENDING_MESSAGES), _releaseQueuedMessagesPending(false), _serverJurisdictions(NULL), - _maxPacketSize(MAX_PACKET_SIZE) { + _maxPacketSize(MAX_PACKET_SIZE), + _destinationWalletUUID() +{ + } OctreeEditPacketSender::~OctreeEditPacketSender() { @@ -98,6 +101,12 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned c // send packet QByteArray packet(reinterpret_cast(buffer), length); queuePacketForSending(node, packet); + + if (hasDestinationWalletUUID() && satoshiCost > 0) { + // if we have a destination wallet UUID and a cost associated with this packet, signal that it + // needs to be sent + emit octreePaymentRequired(satoshiCost, nodeUUID, _destinationWalletUUID); + } // add packet to history _sentPacketHistories[nodeUUID].packetSent(sequence, packet); diff --git a/libraries/octree/src/OctreeEditPacketSender.h b/libraries/octree/src/OctreeEditPacketSender.h index d11aa55963..7b39a1d785 100644 --- a/libraries/octree/src/OctreeEditPacketSender.h +++ b/libraries/octree/src/OctreeEditPacketSender.h @@ -82,13 +82,19 @@ public: // you must override these... virtual char getMyNodeType() const = 0; virtual void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) { }; + + bool hasDestinationWalletUUID() const { return _destinationWalletUUID.isNull(); } + void setDestinationWalletUUID(const QUuid& destinationWalletUUID) { _destinationWalletUUID = destinationWalletUUID; } + const QUuid& getDestinationWalletUUID() { return _destinationWalletUUID; } + + void processNackPacket(const QByteArray& packet); public slots: void nodeKilled(SharedNodePointer node); -public: - void processNackPacket(const QByteArray& packet); - +signals: + void octreePaymentRequired(qint64 satoshiAmount, const QUuid& nodeUUID, const QUuid& destinationWalletUUID); + protected: bool _shouldSend; void queuePacketToNode(const QUuid& nodeID, unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0); @@ -118,5 +124,7 @@ protected: // TODO: add locks for this and _pendingEditPackets QHash _sentPacketHistories; QHash _outgoingSequenceNumbers; + + QUuid _destinationWalletUUID; }; #endif // hifi_OctreeEditPacketSender_h From 6c15468c87b83c95bfe6c83162ac5a4ca0353cd9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 30 Jul 2014 17:21:31 -0700 Subject: [PATCH 093/407] Fix for sizing. --- libraries/metavoxels/src/MetavoxelData.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 8860d30c93..a0b1f1efb0 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -580,8 +580,7 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, const MetavoxelLOD *this = reference; QHash remainingRoots = _roots; - glm::vec3 minimum = getMinimum(); - + bool changed; in >> changed; if (changed) { @@ -594,7 +593,8 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, const MetavoxelLOD expand(); } } - + + glm::vec3 minimum = getMinimum(); forever { AttributePointer attribute; in >> attribute; @@ -634,6 +634,7 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, const MetavoxelLOD // read subdivisions for the remaining roots if there's any chance of a collapse if (!(lod.position == referenceLOD.position && lod.threshold <= referenceLOD.threshold)) { + glm::vec3 minimum = getMinimum(); for (QHash::const_iterator it = remainingRoots.constBegin(); it != remainingRoots.constEnd(); it++) { MetavoxelStreamBase base = { it.key(), in, lod, referenceLOD }; From 363cef6d8a6890fb29be98657dbf1c7b794e63fb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Jul 2014 17:33:37 -0700 Subject: [PATCH 094/407] move satoshi costs to VoxelEditPacketSender --- interface/src/Application.cpp | 31 +++++++++++++++++++ interface/src/Application.h | 2 ++ libraries/networking/src/DomainHandler.cpp | 23 +------------- libraries/networking/src/DomainHandler.h | 10 +----- .../voxels/src/VoxelEditPacketSender.cpp | 7 ++--- libraries/voxels/src/VoxelEditPacketSender.h | 7 +++++ 6 files changed, 44 insertions(+), 36 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9b54b84351..480f215d40 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3788,6 +3788,37 @@ void Application::uploadAttachment() { uploadModel(ATTACHMENT_MODEL); } +void Application::domainSettingsReceived(const QJsonObject& domainSettingsObject) { + // from the domain-handler, figure out the satoshi cost per voxel and per meter cubed + const QString VOXEL_SETTINGS_KEY = "voxels"; + const QString PER_VOXEL_COST_KEY = "per-voxel-credits"; + const QString PER_METER_CUBED_COST_KEY = "per-meter-cubed-credits"; + const QString VOXEL_WALLET_UUID = "voxel-wallet"; + + const QJsonObject& voxelObject = domainSettingsObject[VOXEL_SETTINGS_KEY].toObject(); + + qint64 satoshisPerVoxel = 0; + qint64 satoshisPerMeterCubed = 0; + QUuid voxelWalletUUID; + + if (domainSettingsObject.isEmpty()) { + float perVoxelCredits = (float) voxelObject[PER_VOXEL_COST_KEY].toDouble(); + float perMeterCubedCredits = (float) voxelObject[PER_METER_CUBED_COST_KEY].toDouble(); + + satoshisPerVoxel = (qint64) floorf(perVoxelCredits * SATOSHIS_PER_CREDIT); + satoshisPerMeterCubed = (qint64) floorf(perMeterCubedCredits * SATOSHIS_PER_CREDIT); + + voxelWalletUUID = QUuid(voxelObject[VOXEL_WALLET_UUID].toString()); + } + + qDebug() << "Voxel costs are" << satoshisPerVoxel << "per voxel and" << satoshisPerMeterCubed << "per meter cubed"; + qDebug() << "Destination wallet UUID for voxel payments is" << voxelWalletUUID; + + _voxelEditSender.setSatoshisPerVoxel(satoshisPerVoxel); + _voxelEditSender.setSatoshisPerMeterCubed(satoshisPerMeterCubed); + _voxelEditSender.setDestinationWalletUUID(voxelWalletUUID); +} + QString Application::getPreviousScriptLocation() { QString suggestedName; if (_previousScriptLocation.isEmpty()) { diff --git a/interface/src/Application.h b/interface/src/Application.h index a356b26725..54fb25839a 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -342,6 +342,8 @@ public slots: void uploadAttachment(); void bumpSettings() { ++_numChangedSettings; } + + void domainSettingsReceived(const QJsonObject& domainSettingsObject); private slots: void timer(); diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 5f20bebd50..1bcf03f477 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -159,9 +159,7 @@ void DomainHandler::settingsRequestFinished() { _settingsObject = QJsonDocument::fromJson(settingsReply->readAll()).object(); qDebug() << "Received domain settings."; - emit settingsReceived(); - - updateVoxelCosts(); + emit settingsReceived(_settingsObject); // reset failed settings requests to 0, we got them _failedSettingsRequests = 0; @@ -182,25 +180,6 @@ void DomainHandler::settingsRequestFinished() { } } -void DomainHandler::updateVoxelCosts() { - - // from the domain-handler, figure out the satoshi cost per voxel and per meter cubed - const QString VOXEL_SETTINGS_KEY = "voxels"; - const QString PER_VOXEL_COST_KEY = "per-voxel-credits"; - const QString PER_METER_CUBED_COST_KEY = "per-meter-cubed-credits"; - - if (!_settingsObject.isEmpty()) { - float perVoxelCredits = (float) _settingsObject[VOXEL_SETTINGS_KEY].toObject()[PER_VOXEL_COST_KEY].toDouble(); - float perMeterCubedCredits = (float) _settingsObject[VOXEL_SETTINGS_KEY].toObject()[PER_METER_CUBED_COST_KEY].toDouble(); - - _satoshisPerVoxel = (qint64) floorf(perVoxelCredits * SATOSHIS_PER_CREDIT); - _satoshisPerMeterCubed = (qint64) floorf(perMeterCubedCredits * SATOSHIS_PER_CREDIT); - } else { - _satoshisPerVoxel = 0; - _satoshisPerMeterCubed = 0; - } -} - void DomainHandler::parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket) { // figure out the port that the DS wants us to use for us to talk to them with DTLS int numBytesPacketHeader = numBytesForPacketHeader(dtlsRequirementPacket); diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 7b7a80b49a..a2b8e2e307 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -62,9 +62,6 @@ public: void parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket); - qint64 getSatoshisPerVoxel() const { return _satoshisPerVoxel; } - qint64 getSatoshisPerMeterCubed() const { return _satoshisPerMeterCubed; } - private slots: void completedHostnameLookup(const QHostInfo& hostInfo); void settingsRequestFinished(); @@ -72,14 +69,12 @@ signals: void hostnameChanged(const QString& hostname); void connectedToDomain(const QString& hostname); - void settingsReceived(); + void settingsReceived(const QJsonObject& domainSettingsObject); void settingsReceiveFail(); private: void reset(); - void updateVoxelCosts(); - QUuid _uuid; QString _hostname; HifiSockAddr _sockAddr; @@ -88,9 +83,6 @@ private: QTimer* _handshakeTimer; QJsonObject _settingsObject; int _failedSettingsRequests; - - qint64 _satoshisPerVoxel; - qint64 _satoshisPerMeterCubed; }; #endif // hifi_DomainHandler_h diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index ee189f492d..3bb76d17fe 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -146,15 +146,12 @@ void VoxelEditPacketSender::queueVoxelEditMessages(PacketType type, int numberOf qint64 VoxelEditPacketSender::satoshiCostForMessage(const VoxelDetail& details) { const DomainHandler& domainHandler = NodeList::getInstance()->getDomainHandler(); - qint64 totalSatoshiCost = domainHandler.getSatoshisPerVoxel(); - qint64 costPerMeterCubed = domainHandler.getSatoshisPerMeterCubed(); - - if (totalSatoshiCost == 0 && costPerMeterCubed == 0) { + if (_satoshisPerVoxel == 0 && _satoshisPerMeterCubed == 0) { return 0; } else { float meterScale = details.s * TREE_SCALE; float totalVolume = meterScale * meterScale * meterScale; - return totalSatoshiCost + (qint64) floorf(totalVolume * costPerMeterCubed); + return _satoshisPerVoxel + (qint64) floorf(totalVolume * _satoshisPerMeterCubed); } } diff --git a/libraries/voxels/src/VoxelEditPacketSender.h b/libraries/voxels/src/VoxelEditPacketSender.h index e761812629..560c585ed5 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.h +++ b/libraries/voxels/src/VoxelEditPacketSender.h @@ -51,6 +51,13 @@ public: // My server type is the voxel server virtual char getMyNodeType() const { return NodeType::VoxelServer; } + void setSatoshisPerVoxel(qint64 satoshisPerVoxel) { _satoshisPerVoxel = satoshisPerVoxel; } + void setSatoshisPerMeterCubed(qint64 satoshisPerMeterCubed) { _satoshisPerMeterCubed = satoshisPerMeterCubed; } + qint64 satoshiCostForMessage(const VoxelDetail& details); + +private: + qint64 _satoshisPerVoxel; + qint64 _satoshisPerMeterCubed; }; #endif // hifi_VoxelEditPacketSender_h From 99daa062c017cdc691feae5310b686dd1e902855 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Jul 2014 17:35:33 -0700 Subject: [PATCH 095/407] trigger domainSettingsReceived slot when connected to domain --- interface/src/Application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 480f215d40..be8e9c240e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -240,6 +240,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(&nodeList->getDomainHandler(), SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&))); connect(&nodeList->getDomainHandler(), SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&))); + connect(&nodeList->getDomainHandler(), &DomainHandler::settingsReceived, &Application::domainSettingsReceived); // update our location every 5 seconds in the data-server, assuming that we are authenticated with one const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000; From 9c1dd7c4a4ce7b96fc6ebf01edf1f6a46a957873 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Jul 2014 17:35:49 -0700 Subject: [PATCH 096/407] fix call to connect in Application --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index be8e9c240e..d30cd63105 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -240,7 +240,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(&nodeList->getDomainHandler(), SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&))); connect(&nodeList->getDomainHandler(), SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&))); - connect(&nodeList->getDomainHandler(), &DomainHandler::settingsReceived, &Application::domainSettingsReceived); + connect(&nodeList->getDomainHandler(), &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived); // update our location every 5 seconds in the data-server, assuming that we are authenticated with one const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000; From db25cd9d2c6139674e9066f81e54725f6223a0d7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Jul 2014 18:07:08 -0700 Subject: [PATCH 097/407] call PaymentManager when an OctreeEditPacketSender needs to pay --- interface/src/Application.cpp | 17 ++++++++++--- interface/src/PaymentManager.cpp | 24 ++++++++++++++++++ interface/src/PaymentManager.h | 25 +++++++++++++++++++ libraries/octree/src/OctreeEditPacketSender.h | 2 +- 4 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 interface/src/PaymentManager.cpp create mode 100644 interface/src/PaymentManager.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d30cd63105..a099231654 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -69,6 +69,7 @@ #include "InterfaceVersion.h" #include "Menu.h" #include "ModelUploader.h" +#include "PaymentManager.h" #include "Util.h" #include "devices/MIDIManager.h" #include "devices/OculusManager.h" @@ -237,10 +238,17 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(audioThread, SIGNAL(started()), &_audio, SLOT(start())); audioThread->start(); + + const DomainHandler& domainHandler = nodeList->getDomainHandler(); - connect(&nodeList->getDomainHandler(), SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&))); - connect(&nodeList->getDomainHandler(), SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&))); - connect(&nodeList->getDomainHandler(), &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived); + connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&))); + connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&))); + connect(&domainHandler, &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived); + + // hookup VoxelEditSender to PaymentManager so we can pay for octree edits + const PaymentManager& paymentManager = PaymentManager::getInstance(); + connect(&_voxelEditSender, &VoxelEditPacketSender::octreePaymentRequired, + &paymentManager, &PaymentManager::sendSignedPayment); // update our location every 5 seconds in the data-server, assuming that we are authenticated with one const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000; @@ -3790,6 +3798,7 @@ void Application::uploadAttachment() { } void Application::domainSettingsReceived(const QJsonObject& domainSettingsObject) { + // from the domain-handler, figure out the satoshi cost per voxel and per meter cubed const QString VOXEL_SETTINGS_KEY = "voxels"; const QString PER_VOXEL_COST_KEY = "per-voxel-credits"; @@ -3802,7 +3811,7 @@ void Application::domainSettingsReceived(const QJsonObject& domainSettingsObject qint64 satoshisPerMeterCubed = 0; QUuid voxelWalletUUID; - if (domainSettingsObject.isEmpty()) { + if (!domainSettingsObject.isEmpty()) { float perVoxelCredits = (float) voxelObject[PER_VOXEL_COST_KEY].toDouble(); float perMeterCubedCredits = (float) voxelObject[PER_METER_CUBED_COST_KEY].toDouble(); diff --git a/interface/src/PaymentManager.cpp b/interface/src/PaymentManager.cpp new file mode 100644 index 0000000000..f4d23fca30 --- /dev/null +++ b/interface/src/PaymentManager.cpp @@ -0,0 +1,24 @@ +// +// PaymentManager.cpp +// interface/src +// +// Created by Stephen Birarda on 2014-07-30. +// 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 +// + +#include +#include + +#include "PaymentManager.h" + +PaymentManager& PaymentManager::getInstance() { + static PaymentManager sharedInstance; + return sharedInstance; +} + +void PaymentManager::sendSignedPayment(qint64 satoshiAmount, const QUuid& nodeUUID, const QUuid& destinationWalletUUID) { + qDebug() << "Paying" << satoshiAmount << "satoshis to" << destinationWalletUUID << "via" << nodeUUID; +} \ No newline at end of file diff --git a/interface/src/PaymentManager.h b/interface/src/PaymentManager.h new file mode 100644 index 0000000000..67419a39a4 --- /dev/null +++ b/interface/src/PaymentManager.h @@ -0,0 +1,25 @@ +// +// PaymentManager.h +// interface/src +// +// Created by Stephen Birarda on 2014-07-30. +// 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 +// + +#ifndef hifi_PaymentManager_h +#define hifi_PaymentManager_h + +#include + +class PaymentManager : public QObject { + Q_OBJECT +public: + static PaymentManager& getInstance(); +public slots: + void sendSignedPayment(qint64 satoshiAmount, const QUuid& nodeUUID, const QUuid& destinationWalletUUID); +}; + +#endif // hifi_PaymentManager_h \ No newline at end of file diff --git a/libraries/octree/src/OctreeEditPacketSender.h b/libraries/octree/src/OctreeEditPacketSender.h index 7b39a1d785..a11c626003 100644 --- a/libraries/octree/src/OctreeEditPacketSender.h +++ b/libraries/octree/src/OctreeEditPacketSender.h @@ -83,7 +83,7 @@ public: virtual char getMyNodeType() const = 0; virtual void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) { }; - bool hasDestinationWalletUUID() const { return _destinationWalletUUID.isNull(); } + bool hasDestinationWalletUUID() const { return !_destinationWalletUUID.isNull(); } void setDestinationWalletUUID(const QUuid& destinationWalletUUID) { _destinationWalletUUID = destinationWalletUUID; } const QUuid& getDestinationWalletUUID() { return _destinationWalletUUID; } From ef58453fda85edb51eeb1db4929dd3f228e5b06f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Jul 2014 18:10:11 -0700 Subject: [PATCH 098/407] turn off verbose octree packet debug --- interface/src/PaymentManager.cpp | 2 ++ libraries/octree/src/OctreeEditPacketSender.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/PaymentManager.cpp b/interface/src/PaymentManager.cpp index f4d23fca30..4baf11386b 100644 --- a/interface/src/PaymentManager.cpp +++ b/interface/src/PaymentManager.cpp @@ -21,4 +21,6 @@ PaymentManager& PaymentManager::getInstance() { void PaymentManager::sendSignedPayment(qint64 satoshiAmount, const QUuid& nodeUUID, const QUuid& destinationWalletUUID) { qDebug() << "Paying" << satoshiAmount << "satoshis to" << destinationWalletUUID << "via" << nodeUUID; + + } \ No newline at end of file diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 86208c9fd2..543f47273c 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -112,7 +112,7 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned c _sentPacketHistories[nodeUUID].packetSent(sequence, packet); // debugging output... - bool wantDebugging = true; + bool wantDebugging = false; if (wantDebugging) { int numBytesPacketHeader = numBytesForPacketHeader(reinterpret_cast(buffer)); unsigned short int sequence = (*((unsigned short int*)(buffer + numBytesPacketHeader))); From c3c2265ddd3e89ae3f66596f82c553b4fc085bd2 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 30 Jul 2014 18:14:11 -0700 Subject: [PATCH 099/407] Hide the unset (black) bits. --- .../resources/shaders/metavoxel_heightfield.vert | 10 +++++----- interface/src/MetavoxelSystem.cpp | 15 +++++++++++++-- libraries/metavoxels/src/AttributeRegistry.cpp | 3 ++- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/interface/resources/shaders/metavoxel_heightfield.vert b/interface/resources/shaders/metavoxel_heightfield.vert index a5e7ec66c1..3cf43e87cd 100644 --- a/interface/resources/shaders/metavoxel_heightfield.vert +++ b/interface/resources/shaders/metavoxel_heightfield.vert @@ -21,13 +21,13 @@ void main(void) { // transform and store the normal for interpolation normal = normalize(gl_ModelViewMatrix * vec4(0.0, 1.0, 0.0, 0.0)); - // pass along the vertex color - gl_FrontColor = gl_Color; - // pass along the texture coordinates gl_TexCoord[0] = gl_MultiTexCoord0; // add the height to the position - gl_Position = gl_ModelViewProjectionMatrix * (gl_Vertex + - vec4(0.0, texture2D(heightMap, gl_MultiTexCoord0.st).r, 0.0, 0.0)); + float height = texture2D(heightMap, gl_MultiTexCoord0.st).r; + gl_Position = gl_ModelViewProjectionMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0)); + + // the zero height should be invisible + gl_FrontColor = vec4(1.0, 1.0, 1.0, step(height, 0.0)); } diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index d357ab5ce4..16ce98c65c 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -397,7 +397,11 @@ void HeightfieldBuffer::render() { QHash HeightfieldBuffer::_bufferPairs; void HeightfieldPreview::render(const glm::vec3& translation, float scale) const { - glColor4f(1.0f, 1.0f, 1.0f, 0.75f); + glDisable(GL_BLEND); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_EQUAL, 0.0f); + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -418,6 +422,9 @@ void HeightfieldPreview::render(const glm::vec3& translation, float scale) const glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); + + glDisable(GL_ALPHA_TEST); + glEnable(GL_BLEND); } BufferDataAttribute::BufferDataAttribute(const QString& name) : @@ -695,7 +702,10 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox _pointProgram.release(); - glColor4f(1.0f, 1.0f, 1.0f, 0.0f); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_EQUAL, 0.0f); + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); _heightfieldProgram.bind(); @@ -710,6 +720,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); + glDisable(GL_ALPHA_TEST); glEnable(GL_BLEND); } diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 499f8146cf..7219e9da41 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -578,7 +578,8 @@ bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead) int childSizePlusOne = childSize + 1; for (int z = 0; z < halfSize; z++) { for (char* end = dest + halfSize; dest != end; src += 2) { - *dest++ = yOffset + (qMax(qMax(src[0], src[1]), qMax(src[childSize], src[childSizePlusOne])) >> 1); + int max = qMax(qMax(src[0], src[1]), qMax(src[childSize], src[childSizePlusOne])); + *dest++ = (max == 0) ? 0 : (yOffset + (max >> 1)); } dest += halfSize; src += childSize; From 631977bac2c72b24662ea204c49e47a73087f5a2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Jul 2014 18:15:20 -0700 Subject: [PATCH 100/407] setup a SignedTransaction from PaymentManager --- interface/src/PaymentManager.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/interface/src/PaymentManager.cpp b/interface/src/PaymentManager.cpp index 4baf11386b..b8af43ec67 100644 --- a/interface/src/PaymentManager.cpp +++ b/interface/src/PaymentManager.cpp @@ -9,9 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include +#include "SignedWalletTransaction.h" + #include "PaymentManager.h" PaymentManager& PaymentManager::getInstance() { @@ -22,5 +25,11 @@ PaymentManager& PaymentManager::getInstance() { void PaymentManager::sendSignedPayment(qint64 satoshiAmount, const QUuid& nodeUUID, const QUuid& destinationWalletUUID) { qDebug() << "Paying" << satoshiAmount << "satoshis to" << destinationWalletUUID << "via" << nodeUUID; + // setup a signed wallet transaction + const qint64 DEFAULT_TRANSACTION_EXPIRY_SECONDS = 60; + qint64 currentTimestamp = QDateTime::currentDateTimeUtc().toTime_t(); + SignedWalletTransaction newTransaction(destinationWalletUUID, satoshiAmount, + currentTimestamp, DEFAULT_TRANSACTION_EXPIRY_SECONDS); + // send the signed transaction to the redeeming node } \ No newline at end of file From 06294b403b0a8efbe04ed9f22081b078b1152757 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 30 Jul 2014 18:31:58 -0700 Subject: [PATCH 101/407] Add pasteModels --- interface/src/Application.cpp | 19 ++++++------------- interface/src/Application.h | 3 +++ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 476cc45242..7a2a359dbb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1602,17 +1602,13 @@ void Application::importVoxels() { } void Application::importModels(const QString& filename) { - _importSucceded = false; + _modelClipboard.eraseAllOctreeElements(); + _modelClipboard.readFromSVOFile(filename.toLocal8Bit().constData()); + _modelClipboard.reaverageOctreeElements(); +} - - _models.getTree()->readFromSVOFile(filename.toLocal8Bit().constData()); - _models.getTree()->reaverageOctreeElements(); - - - // restore the main window's active state - _window->activateWindow(); - - emit importDone(); +void Application::pasteModels(float x, float y, float z) { + _modelClipboard.sendModels(&_modelEditSender, x, y, z); } void Application::cutVoxels(const VoxelDetail& sourceVoxel) { @@ -2124,7 +2120,6 @@ void Application::update(float deltaTime) { { PerformanceTimer perfTimer("models"); _models.update(); // update the models... - _modelClipboardRenderer.update(); } { @@ -2613,7 +2608,6 @@ void Application::updateShadowMap() { _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); _particles.render(OctreeRenderer::SHADOW_RENDER_MODE); _models.render(OctreeRenderer::SHADOW_RENDER_MODE); - _modelClipboardRenderer.render(OctreeRenderer::SHADOW_RENDER_MODE); glDisable(GL_POLYGON_OFFSET_FILL); @@ -2814,7 +2808,6 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... models..."); _models.render(); - _modelClipboardRenderer.render(); } // render the ambient occlusion effect if enabled diff --git a/interface/src/Application.h b/interface/src/Application.h index 1f20d21de6..82427f697a 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -200,6 +200,8 @@ public: bool getImportSucceded() { return _importSucceded; } VoxelSystem* getSharedVoxelSystem() { return &_sharedVoxelSystem; } VoxelTree* getClipboard() { return &_clipboard; } + ModelTree* getModelClipboard() { return &_modelClipboard; } + ModelTreeRenderer* getModelClipboardRenderer() { return &_modelClipboardRenderer; } Environment* getEnvironment() { return &_environment; } bool isMousePressed() const { return _mousePressed; } bool isMouseHidden() const { return _mouseHidden; } @@ -312,6 +314,7 @@ public slots: void nodeKilled(SharedNodePointer node); void packetSent(quint64 length); + void pasteModels(float x, float y, float z); void exportModels(const QString& filename, float x, float y, float z, float scale); void importModels(const QString& filename); From 051bbd5d3403ec8b4a66b51c2336c9c15c8194a5 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 30 Jul 2014 18:34:22 -0700 Subject: [PATCH 102/407] Add LocalModelsOverlay --- .../src/ui/overlays/LocalModelsOverlay.cpp | 45 +++++++++++++++++++ .../src/ui/overlays/LocalModelsOverlay.h | 35 +++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 interface/src/ui/overlays/LocalModelsOverlay.cpp create mode 100644 interface/src/ui/overlays/LocalModelsOverlay.h diff --git a/interface/src/ui/overlays/LocalModelsOverlay.cpp b/interface/src/ui/overlays/LocalModelsOverlay.cpp new file mode 100644 index 0000000000..ed38d41603 --- /dev/null +++ b/interface/src/ui/overlays/LocalModelsOverlay.cpp @@ -0,0 +1,45 @@ +// +// LocalModelsOverlay.cpp +// interface/src/ui/overlays +// +// Created by Ryan Huffman on 07/08/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 +// + +#include "Application.h" + +#include "LocalModelsOverlay.h" + +LocalModelsOverlay::LocalModelsOverlay(ModelTreeRenderer* modelTreeRenderer) : + Volume3DOverlay(), + _modelTreeRenderer(modelTree) { +} + +LocalModelsOverlay::~LocalModelsOverlay() { +} + +void LocalModelsOverlay::update(float deltatime) { + _modelTreeRenderer->update(); +} + +void LocalModelsOverlay::render() { + if (_visible) { + glPushMatrix(); { + glTranslatef(_position.x, _position.y, _position.z); + glScalef(_size, _size, _size); + _modelTreeRenderer->render(); + } glPopMatrix(); + } +} + +void LocalModelsOverlay::setProperties(const QScriptValue &properties) { + Volume3DOverlay::setProperties(properties); + + if (properties.property("scale").isValid()) { + setSize(properties.property("scale").toVariant().toFloat()); + } +} + diff --git a/interface/src/ui/overlays/LocalModelsOverlay.h b/interface/src/ui/overlays/LocalModelsOverlay.h new file mode 100644 index 0000000000..02a990119a --- /dev/null +++ b/interface/src/ui/overlays/LocalModelsOverlay.h @@ -0,0 +1,35 @@ +// +// LocalModelsOverlay.h +// interface/src/ui/overlays +// +// Created by Ryan Huffman on 07/08/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 +// + +#ifndef hifi_LocalModelsOverlay_h +#define hifi_LocalModelsOverlay_h + +// #include "models/ModelTree.h" +#include "models/ModelTreeRenderer.h" + +#include "Volume3DOverlay.h" + +class LocalModelsOverlay : public Volume3DOverlay { + Q_OBJECT +public: + LocalModelsOverlay(ModelTreeRenderer* modelTreeRenderer); + ~LocalModelsOverlay(); + + virtual void update(float deltatime); + virtual void render(); + + virtual void setProperties(const QScriptValue& properties); + +private: + ModelTreeRenderer *_modelTreeRenderer; +}; + +#endif // hifi_LocalModelsOverlay_h From 7bd1628465d3343c3bf1326025b8f7cdee6b8ebb Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 30 Jul 2014 18:36:43 -0700 Subject: [PATCH 103/407] Add SendModelsOperation --- libraries/models/src/ModelTree.cpp | 29 +++++++++++++++++++++++++ libraries/models/src/ModelTree.h | 3 +++ libraries/models/src/ModelTreeElement.h | 6 +++++ 3 files changed, 38 insertions(+) diff --git a/libraries/models/src/ModelTree.cpp b/libraries/models/src/ModelTree.cpp index 1489f4db19..98902ac6c0 100644 --- a/libraries/models/src/ModelTree.cpp +++ b/libraries/models/src/ModelTree.cpp @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ModelEditPacketSender.h" +#include "ModelItem.h" + #include "ModelTree.h" ModelTree::ModelTree(bool shouldReaverage) : Octree(shouldReaverage) { @@ -204,6 +207,32 @@ void ModelTree::deleteModel(const ModelItemID& modelID) { } } +void ModelTree::sendModels(ModelEditPacketSender* packetSender, float x, float y, float z) { + SendModelsOperationArgs args; + args.packetSender = packetSender; + args.root = glm::vec3(x, y, z); + recurseTreeWithOperation(sendModelsOperation, &args); + packetSender->releaseQueuedMessages(); +} + +bool ModelTree::sendModelsOperation(OctreeElement* element, void* extraData) { + SendModelsOperationArgs* args = static_cast(extraData); + ModelTreeElement* modelTreeElement = static_cast(element); + + const QList& modelList = modelTreeElement->getModels(); + + for (int i = 0; i < modelList.size(); i++) { + uint32_t creatorTokenID = ModelItem::getNextCreatorTokenID(); + ModelItemID id(NEW_MODEL, creatorTokenID, false); + ModelItemProperties properties; + properties.copyFromModelItem(modelList.at(i)); + properties.setPosition(properties.getPosition() + args->root); + args->packetSender->queueModelEditMessage(PacketTypeModelAddOrEdit, id, properties); + } + + return true; +} + // scans the tree and handles mapping locally created models to know IDs. // in the event that this tree is also viewing the scene, then we need to also // search the tree to make sure we don't have a duplicate model from the viewing diff --git a/libraries/models/src/ModelTree.h b/libraries/models/src/ModelTree.h index 9ab081f46c..7827d9f9f3 100644 --- a/libraries/models/src/ModelTree.h +++ b/libraries/models/src/ModelTree.h @@ -84,10 +84,13 @@ public: void setFBXService(ModelItemFBXService* service) { _fbxService = service; } const FBXGeometry* getGeometryForModel(const ModelItem& modelItem) { return _fbxService ? _fbxService->getGeometryForModel(modelItem) : NULL; + } + void sendModels(ModelEditPacketSender* packetSender, float x, float y, float z); private: + static bool sendModelsOperation(OctreeElement* element, void* extraData); static bool updateOperation(OctreeElement* element, void* extraData); static bool findAndUpdateOperation(OctreeElement* element, void* extraData); static bool findAndUpdateWithIDandPropertiesOperation(OctreeElement* element, void* extraData); diff --git a/libraries/models/src/ModelTreeElement.h b/libraries/models/src/ModelTreeElement.h index 8d2f5064bd..5f28b2f981 100644 --- a/libraries/models/src/ModelTreeElement.h +++ b/libraries/models/src/ModelTreeElement.h @@ -44,6 +44,12 @@ public: bool isViewing; }; +class SendModelsOperationArgs { +public: + glm::vec3 root; + ModelEditPacketSender* packetSender; +}; + class ModelTreeElement : public OctreeElement { From 521bf6023e40b137c10fb997a2da41155f4bd657 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 30 Jul 2014 18:38:09 -0700 Subject: [PATCH 104/407] Implement pasteModels in Clipboard --- interface/src/scripting/ClipboardScriptingInterface.cpp | 6 +++--- interface/src/scripting/ClipboardScriptingInterface.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp index 39b5db9418..d75e29e423 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.cpp +++ b/interface/src/scripting/ClipboardScriptingInterface.cpp @@ -103,13 +103,13 @@ void ClipboardScriptingInterface::nudgeVoxel(float x, float y, float z, float s, void ClipboardScriptingInterface::exportModels(const QString& filename, float x, float y, float z, float s) { - Application::getInstance()->exportModels(filename, x / TREE_SCALE, y / TREE_SCALE, z / TREE_SCALE, s / TREE_SCALE); + Application::getInstance()->exportModels(filename, x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, s / (float)TREE_SCALE); } void ClipboardScriptingInterface::importModels(const QString& filename) { Application::getInstance()->importModels(filename); } -void ClipboardScriptingInterface::pasteModels() { - // TODO +void ClipboardScriptingInterface::pasteModels(float x, float y, float z, float s) { + Application::getInstance()->pasteModels(x, y, z); } diff --git a/interface/src/scripting/ClipboardScriptingInterface.h b/interface/src/scripting/ClipboardScriptingInterface.h index 2ff287b29f..373a7308ae 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.h +++ b/interface/src/scripting/ClipboardScriptingInterface.h @@ -45,7 +45,7 @@ public slots: void importModels(const QString& filename); void exportModels(const QString& filename, float x, float y, float z, float s); - void pasteModels(); + void pasteModels(float x, float y, float z, float s); }; #endif // hifi_ClipboardScriptingInterface_h From 43f61b4718c9ef47ed94bf1e3613e37b7f31181e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 30 Jul 2014 18:38:42 -0700 Subject: [PATCH 105/407] Add localmodels overlay type --- interface/src/ui/overlays/Overlays.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 581947c074..d73a01103d 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -14,6 +14,7 @@ #include "Cube3DOverlay.h" #include "ImageOverlay.h" #include "Line3DOverlay.h" +#include "LocalModelsOverlay.h" #include "LocalVoxelsOverlay.h" #include "ModelOverlay.h" #include "Overlays.h" @@ -158,6 +159,13 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope thisOverlay->setProperties(properties); created = true; is3D = true; + } else if (type == "localmodels") { + qDebug() << "Making localmodels"; + thisOverlay = new LocalModelsOverlay(Application::getInstance()->getModelClipboardRenderer()); + thisOverlay->init(_parent); + thisOverlay->setProperties(properties); + created = true; + is3D = true; } else if (type == "model") { thisOverlay = new ModelOverlay(); thisOverlay->init(_parent); From 06e6505584429e69b31aed8a972935bd0d7b2803 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 30 Jul 2014 18:39:44 -0700 Subject: [PATCH 106/407] Update and add localModels overlay to editModels.js import/export --- examples/editModels.js | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index aa0505304b..47161d57a8 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -153,7 +153,7 @@ var ExportMenu = function(opts) { width: cancelWidth, height: height, color: { red: 255, green: 255, blue: 255 }, - text: "Cancel" + text: "Close" }); var voxelPreview = Overlays.addOverlay("cube", { @@ -291,6 +291,12 @@ var ModelImporter = function(opts) { var fullWidth = titleWidth + cancelWidth + (2 * margin); // TODO: Show import preview + var localModels = Overlays.addOverlay("localmodels", { + position: { x: 1, y: 1, z: 1 }, + scale: 1, + visible: false + }); + var importScale = 1; var importBoundaries = Overlays.addOverlay("cube", { position: { x: 0, y: 0, z: 0 }, size: 1, @@ -337,6 +343,7 @@ var ModelImporter = function(opts) { this.setImportVisible = function(visible) { Overlays.editOverlay(importBoundaries, { visible: visible }); + Overlays.editOverlay(localModels, { visible: visible }); Overlays.editOverlay(cancelButton, { visible: visible }); Overlays.editOverlay(titleText, { visible: visible }); Overlays.editOverlay(background, { visible: visible }); @@ -346,6 +353,9 @@ var ModelImporter = function(opts) { this.moveImport = function(position) { importPosition = position; // TODO: Show import preview + Overlays.editOverlay(localModels, { + position: { x: importPosition.x, y: importPosition.y, z: importPosition.z } + }); Overlays.editOverlay(importBoundaries, { position: { x: importPosition.x, y: importPosition.y, z: importPosition.z } }); @@ -412,14 +422,15 @@ var ModelImporter = function(opts) { var y = parts[3]; var z = parts[4]; var s = parts[5]; + importScale = s; if (hostname != location.hostname) { if (!Window.confirm(("These models were not originally exported from this domain. Continue?"))) { return; } } else { if (Window.confirm(("Would you like to import back to the source location?"))) { - Window.alert("(TODO) Importing backing to source location"); Clipboard.importModels(filename); + Clipboard.pasteModels(x, y, z, 1); return; } } @@ -427,19 +438,21 @@ var ModelImporter = function(opts) { Clipboard.importModels(filename); self._importing = true; self.setImportVisible(true); + Overlays.editOverlay(importBoundaries, { size: s }); } } } this.paste = function() { if (self._importing) { - self._importing = false; - self.setImportVisible(false); - Clipboard.pasteModels(); + // self._importing = false; + // self.setImportVisible(false); + Clipboard.pasteModels(importPosition.x, importPosition.y, importPosition.z, 1); } } this.cleanup = function() { + Overlays.deleteOverlay(localModels); Overlays.deleteOverlay(importBoundaries); Overlays.deleteOverlay(cancelButton); Overlays.deleteOverlay(titleText); From 01737e18b2e9e06c78dc650d662238923a9208de Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 30 Jul 2014 19:06:10 -0700 Subject: [PATCH 107/407] Update LocalModelOverlay to work prorperly with translations --- interface/src/Application.cpp | 1 + interface/src/Application.h | 1 + .../src/ui/overlays/LocalModelsOverlay.cpp | 19 +++++++------------ .../src/ui/overlays/LocalModelsOverlay.h | 2 -- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7a2a359dbb..e85d44a901 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -179,6 +179,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _lastNackTime(usecTimestampNow()), _lastSendDownstreamAudioStats(usecTimestampNow()) { + // read the ApplicationInfo.ini file for Name/Version/Domain information QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); diff --git a/interface/src/Application.h b/interface/src/Application.h index 82427f697a..756cb7dff7 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -227,6 +227,7 @@ public: float getPacketsPerSecond() const { return _packetsPerSecond; } float getBytesPerSecond() const { return _bytesPerSecond; } const glm::vec3& getViewMatrixTranslation() const { return _viewMatrixTranslation; } + void setViewMatrixTranslation(const glm::vec3& translation) { _viewMatrixTranslation = translation; } /// if you need to access the application settings, use lockSettings()/unlockSettings() QSettings* lockSettings() { _settingsMutex.lock(); return _settings; } diff --git a/interface/src/ui/overlays/LocalModelsOverlay.cpp b/interface/src/ui/overlays/LocalModelsOverlay.cpp index ed38d41603..6bb1d9ce88 100644 --- a/interface/src/ui/overlays/LocalModelsOverlay.cpp +++ b/interface/src/ui/overlays/LocalModelsOverlay.cpp @@ -15,7 +15,7 @@ LocalModelsOverlay::LocalModelsOverlay(ModelTreeRenderer* modelTreeRenderer) : Volume3DOverlay(), - _modelTreeRenderer(modelTree) { + _modelTreeRenderer(modelTreeRenderer) { } LocalModelsOverlay::~LocalModelsOverlay() { @@ -28,18 +28,13 @@ void LocalModelsOverlay::update(float deltatime) { void LocalModelsOverlay::render() { if (_visible) { glPushMatrix(); { - glTranslatef(_position.x, _position.y, _position.z); - glScalef(_size, _size, _size); + Application* app = Application::getInstance(); + glm::vec3 oldTranslation = app->getViewMatrixTranslation(); + app->setViewMatrixTranslation(oldTranslation + _position); + _modelTreeRenderer->render(); + + Application::getInstance()->setViewMatrixTranslation(oldTranslation); } glPopMatrix(); } } - -void LocalModelsOverlay::setProperties(const QScriptValue &properties) { - Volume3DOverlay::setProperties(properties); - - if (properties.property("scale").isValid()) { - setSize(properties.property("scale").toVariant().toFloat()); - } -} - diff --git a/interface/src/ui/overlays/LocalModelsOverlay.h b/interface/src/ui/overlays/LocalModelsOverlay.h index 02a990119a..88bf55aaf0 100644 --- a/interface/src/ui/overlays/LocalModelsOverlay.h +++ b/interface/src/ui/overlays/LocalModelsOverlay.h @@ -25,8 +25,6 @@ public: virtual void update(float deltatime); virtual void render(); - - virtual void setProperties(const QScriptValue& properties); private: ModelTreeRenderer *_modelTreeRenderer; From 6a53765a47241d491b1e3924cd53faf0c4f95eef Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 30 Jul 2014 19:06:23 -0700 Subject: [PATCH 108/407] Rename buttons in editModels.js --- examples/editModels.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 47161d57a8..671c79ad39 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -153,7 +153,7 @@ var ExportMenu = function(opts) { width: cancelWidth, height: height, color: { red: 255, green: 255, blue: 255 }, - text: "Close" + text: "Cancel" }); var voxelPreview = Overlays.addOverlay("cube", { @@ -337,7 +337,7 @@ var ModelImporter = function(opts) { height: height, color: { red: 255, green: 255, blue: 255 }, visible: false, - text: "Cancel" + text: "Close" }); this._importing = false; From 0c589b73c473000dd7f59d2838d93d8ef40c5378 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 30 Jul 2014 22:12:11 -0700 Subject: [PATCH 109/407] Tidy model data handling --- examples/editModels.js | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 589f4e4bfb..f5183b16d6 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -282,6 +282,7 @@ var modelUploader = (function () { fbxBuffer, svoBuffer, mapping, + geometry, NAME_FIELD = "name", SCALE_FIELD = "scale", FILENAME_FIELD = "filename", @@ -290,14 +291,22 @@ var modelUploader = (function () { PITCH_FIELD = "pitch", YAW_FIELD = "yaw", ROLL_FIELD = "roll", - MAX_TEXTURE_SIZE = 1024, - geometry; + MAX_TEXTURE_SIZE = 1024; function error(message) { Window.alert(message); print(message); } + function resetDataObjects() { + fstBuffer = null; + fbxBuffer = null; + svoBuffer = null; + mapping = {}; + geometry = {}; + geometry.textures = []; + } + function readFile(filename) { var url = "file:///" + filename, req = new XMLHttpRequest(); @@ -318,7 +327,6 @@ var modelUploader = (function () { function readMapping(fstBuffer) { var dv = new DataView(fstBuffer.buffer), - mapping = {}, lines, line, values, @@ -342,13 +350,10 @@ var modelUploader = (function () { } } } - - return mapping; } function readGeometry(fbxBuffer) { - var geometry, - textures, + var textures, view, index, EOF; @@ -356,8 +361,6 @@ var modelUploader = (function () { // Reference: // http://code.blender.org/index.php/2013/08/fbx-binary-file-format-specification/ - geometry = {}; - geometry.textures = []; textures = {}; view = new DataView(fbxBuffer.buffer); EOF = false; @@ -458,8 +461,6 @@ var modelUploader = (function () { readTextFBX(); } - - return geometry; } function readModel() { @@ -467,11 +468,6 @@ var modelUploader = (function () { print("Reading model file: " + modelFile); - fstBuffer = null; - fbxBuffer = null; - svoBuffer = null; - mapping = {}; - if (modelFile.toLowerCase().slice(-4) === ".svo") { svoBuffer = readFile(modelFile); if (svoBuffer === null) { @@ -485,7 +481,7 @@ var modelUploader = (function () { if (fstBuffer === null) { return false; } - mapping = readMapping(fstBuffer); + readMapping(fstBuffer); if (mapping.hasOwnProperty(FILENAME_FIELD)) { fbxFilename = modelFile.path() + "\\" + mapping[FILENAME_FIELD]; } else { @@ -507,7 +503,7 @@ var modelUploader = (function () { return false; } - geometry = readGeometry(fbxBuffer); + readGeometry(fbxBuffer); if (mapping.hasOwnProperty(SCALE_FIELD)) { mapping[SCALE_FIELD] = parseFloat(mapping[SCALE_FIELD]); @@ -697,23 +693,29 @@ var modelUploader = (function () { modelFile = file; + resetDataObjects(); + // Read model content ... if (!readModel()) { + resetDataObjects(); return; } // Set model properties ... if (!setProperties()) { + resetDataObjects(); return; } // Put model in HTTP message ... if (!createHttpMessage()) { + resetDataObjects(); return; } // Send model to High Fidelity ... sendToHighFidelity(url, callback); + resetDataObjects(); }; return that; From d54e3741edc4fec430c8ba588de9158d2ae48f71 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 31 Jul 2014 01:09:38 -0700 Subject: [PATCH 110/407] Add ModelTree::findModelsInCube --- libraries/models/src/ModelTree.cpp | 22 +++++++++++++++++++++- libraries/models/src/ModelTree.h | 4 +++- libraries/models/src/ModelTreeElement.cpp | 13 +++++++++++++ libraries/models/src/ModelTreeElement.h | 2 ++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/libraries/models/src/ModelTree.cpp b/libraries/models/src/ModelTree.cpp index 98902ac6c0..df94213213 100644 --- a/libraries/models/src/ModelTree.cpp +++ b/libraries/models/src/ModelTree.cpp @@ -387,6 +387,26 @@ public: QVector _foundModels; }; +void ModelTree::findModelsInCube(const AACube& cube, QVector& foundModels) { + FindModelsInCubeArgs args(cube); + lockForRead(); + recurseTreeWithOperation(findInCubeOperation, &args); + unlock(); + // swap the two lists of model pointers instead of copy + foundModels.swap(args._foundModels); +} + +bool ModelTree::findInCubeOperation(OctreeElement* element, void* extraData) { + FindModelsInCubeArgs* args = static_cast< FindModelsInCubeArgs*>(extraData); + const AACube& elementCube = element->getAACube(); + if (elementCube.touches(args->_cube)) { + ModelTreeElement* modelTreeElement = static_cast(element); + modelTreeElement->getModelsInside(args->_cube, args->_foundModels); + return true; + } + return false; +} + bool ModelTree::findInCubeForUpdateOperation(OctreeElement* element, void* extraData) { FindModelsInCubeArgs* args = static_cast< FindModelsInCubeArgs*>(extraData); const AACube& elementCube = element->getAACube(); @@ -398,7 +418,7 @@ bool ModelTree::findInCubeForUpdateOperation(OctreeElement* element, void* extra return false; } -void ModelTree::findModelsForUpdate(const AACube& cube, QVector foundModels) { +void ModelTree::findModelsForUpdate(const AACube& cube, QVector& foundModels) { FindModelsInCubeArgs args(cube); lockForRead(); recurseTreeWithOperation(findInCubeForUpdateOperation, &args); diff --git a/libraries/models/src/ModelTree.h b/libraries/models/src/ModelTree.h index 7827d9f9f3..3a1159c9cf 100644 --- a/libraries/models/src/ModelTree.h +++ b/libraries/models/src/ModelTree.h @@ -63,12 +63,13 @@ public: /// \param foundModels[out] vector of const ModelItem* /// \remark Side effect: any initial contents in foundModels will be lost void findModels(const glm::vec3& center, float radius, QVector& foundModels); + void findModelsInCube(const AACube& cube, QVector& foundModels); /// finds all models that touch a cube /// \param cube the query cube /// \param foundModels[out] vector of non-const ModelItem* /// \remark Side effect: any initial contents in models will be lost - void findModelsForUpdate(const AACube& cube, QVector foundModels); + void findModelsForUpdate(const AACube& cube, QVector& foundModels); void addNewlyCreatedHook(NewlyCreatedModelHook* hook); void removeNewlyCreatedHook(NewlyCreatedModelHook* hook); @@ -92,6 +93,7 @@ private: static bool sendModelsOperation(OctreeElement* element, void* extraData); static bool updateOperation(OctreeElement* element, void* extraData); + static bool findInCubeOperation(OctreeElement* element, void* extraData); static bool findAndUpdateOperation(OctreeElement* element, void* extraData); static bool findAndUpdateWithIDandPropertiesOperation(OctreeElement* element, void* extraData); static bool findNearPointOperation(OctreeElement* element, void* extraData); diff --git a/libraries/models/src/ModelTreeElement.cpp b/libraries/models/src/ModelTreeElement.cpp index 960d1dd4cb..47ea8babac 100644 --- a/libraries/models/src/ModelTreeElement.cpp +++ b/libraries/models/src/ModelTreeElement.cpp @@ -399,6 +399,19 @@ void ModelTreeElement::getModels(const glm::vec3& searchPosition, float searchRa } } +void ModelTreeElement::getModelsInside(const AACube& box, QVector& foundModels) { + QList::iterator modelItr = _modelItems->begin(); + QList::iterator modelEnd = _modelItems->end(); + AACube modelCube; + while(modelItr != modelEnd) { + ModelItem* model = &(*modelItr); + if (box.contains(model->getPosition())) { + foundModels.push_back(model); + } + ++modelItr; + } +} + void ModelTreeElement::getModelsForUpdate(const AACube& box, QVector& foundModels) { QList::iterator modelItr = _modelItems->begin(); QList::iterator modelEnd = _modelItems->end(); diff --git a/libraries/models/src/ModelTreeElement.h b/libraries/models/src/ModelTreeElement.h index 5f28b2f981..c0e2e36095 100644 --- a/libraries/models/src/ModelTreeElement.h +++ b/libraries/models/src/ModelTreeElement.h @@ -138,6 +138,8 @@ public: /// \param models[out] vector of non-const ModelItem* void getModelsForUpdate(const AACube& box, QVector& foundModels); + void getModelsInside(const AACube& box, QVector& foundModels); + const ModelItem* getModelWithID(uint32_t id) const; bool removeModelWithID(uint32_t id); From 6ecc12cdeacb04eadb52758343f9b69871027529 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 31 Jul 2014 01:11:05 -0700 Subject: [PATCH 111/407] Fix export models not cancelling correctly --- examples/editModels.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/editModels.js b/examples/editModels.js index 671c79ad39..1a5753838d 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -217,7 +217,9 @@ var ExportMenu = function(opts) { var s = self._scale; var filename = "models__" + Window.location.hostname + "__" + x + "_" + y + "_" + z + "_" + s + "__.svo"; filename = Window.save("Select where to save", filename, "*.svo") - Clipboard.exportModels(filename, x, y, z, s); + if (filename) { + Clipboard.exportModels(filename, x, y, z, s); + } self.close(); }; From a39a7e23564fe3b380b9ae493aa1d4b757d09e1c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 31 Jul 2014 01:13:17 -0700 Subject: [PATCH 112/407] Update exportModels implementation --- interface/src/Application.cpp | 22 +++++++++++++++++----- interface/src/Application.h | 2 +- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e85d44a901..e469cc7535 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1506,19 +1506,31 @@ struct SendVoxelsOperationArgs { const unsigned char* newBaseOctCode; }; -void Application::exportModels(const QString& filename, float x, float y, float z, float scale) { - ModelTreeElement* selectedNode = _models.getTree()->getModelAt(x, y, z, scale); - if (selectedNode) { - qDebug() << "Exporting models doing it!" << filename; +bool Application::exportModels(const QString& filename, float x, float y, float z, float scale) { + QVector models; + _models.getTree()->findModelsInCube(AACube(glm::vec3(x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE), scale / (float)TREE_SCALE), models); + if (models.size() > 0) { + glm::vec3 root(x, y, z); ModelTree exportTree; - _models.getTree()->copySubTreeIntoNewTree(selectedNode, &exportTree, true); + + for (int i = 0; i < models.size(); i++) { + ModelItemProperties properties; + ModelItemID id = models.at(i)->getModelItemID(); + id.isKnownID = false; + properties.copyFromModelItem(*models.at(i)); + properties.setPosition(properties.getPosition() - root); + exportTree.addModel(id, properties); + } + exportTree.writeToSVOFile(filename.toLocal8Bit().constData()); } else { qDebug() << "No models were selected"; + return false; } // restore the main window's active state _window->activateWindow(); + return true; } bool Application::sendVoxelsOperation(OctreeElement* element, void* extraData) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 756cb7dff7..44a93f5d7b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -316,7 +316,7 @@ public slots: void packetSent(quint64 length); void pasteModels(float x, float y, float z); - void exportModels(const QString& filename, float x, float y, float z, float scale); + bool exportModels(const QString& filename, float x, float y, float z, float scale); void importModels(const QString& filename); void importVoxels(); // doesn't include source voxel because it goes to clipboard From 68f1ad79d6dd0c9c5a71a6dd775ac195d3ed3de7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 31 Jul 2014 01:14:07 -0700 Subject: [PATCH 113/407] Update clipboard call to exportModels to not scale to tree size --- interface/src/scripting/ClipboardScriptingInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp index d75e29e423..10799c2abb 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.cpp +++ b/interface/src/scripting/ClipboardScriptingInterface.cpp @@ -103,7 +103,7 @@ void ClipboardScriptingInterface::nudgeVoxel(float x, float y, float z, float s, void ClipboardScriptingInterface::exportModels(const QString& filename, float x, float y, float z, float s) { - Application::getInstance()->exportModels(filename, x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, s / (float)TREE_SCALE); + Application::getInstance()->exportModels(filename, x, y, z, s); } void ClipboardScriptingInterface::importModels(const QString& filename) { From 49e35bbc84ea2f66e641712eb7402b3c7c3691c3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 31 Jul 2014 01:14:18 -0700 Subject: [PATCH 114/407] Fix bug with ModelItemProperties When copying from a ModelItem the properties should be considered changed --- libraries/models/src/ModelItem.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/libraries/models/src/ModelItem.cpp b/libraries/models/src/ModelItem.cpp index 750af8f1b6..afa64e3bc6 100644 --- a/libraries/models/src/ModelItem.cpp +++ b/libraries/models/src/ModelItem.cpp @@ -1142,19 +1142,19 @@ void ModelItemProperties::copyFromModelItem(const ModelItem& modelItem) { _id = modelItem.getID(); _idSet = true; - _positionChanged = false; - _colorChanged = false; - _radiusChanged = false; + _positionChanged = true; + _colorChanged = true; + _radiusChanged = true; - _shouldDieChanged = false; - _modelURLChanged = false; - _modelRotationChanged = false; - _animationURLChanged = false; - _animationIsPlayingChanged = false; - _animationFrameIndexChanged = false; - _animationFPSChanged = false; - _glowLevelChanged = false; - _defaultSettings = false; + _shouldDieChanged = true; + _modelURLChanged = true; + _modelRotationChanged = true; + _animationURLChanged = true; + _animationIsPlayingChanged = true; + _animationFrameIndexChanged = true; + _animationFPSChanged = true; + _glowLevelChanged = true; + _defaultSettings = true; } QScriptValue ModelItemPropertiesToScriptValue(QScriptEngine* engine, const ModelItemProperties& properties) { From 350c75961801fe6a0132ed86e064ecc1c7a73f5c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 31 Jul 2014 09:18:57 -0700 Subject: [PATCH 115/407] add a method to SignedWalletTransaction to return binary message --- interface/src/SignedWalletTransaction.cpp | 8 ++++++-- interface/src/SignedWalletTransaction.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/interface/src/SignedWalletTransaction.cpp b/interface/src/SignedWalletTransaction.cpp index d29207e4f5..8a0d4e6fdb 100644 --- a/interface/src/SignedWalletTransaction.cpp +++ b/interface/src/SignedWalletTransaction.cpp @@ -32,7 +32,7 @@ SignedWalletTransaction::SignedWalletTransaction(const QUuid& destinationUUID, q } -QByteArray SignedWalletTransaction::hexMessage() { +QByteArray SignedWalletTransaction::binaryMessage() { // build the message using the components of this transaction // UUID, source UUID, destination UUID, message timestamp, expiry delta, amount @@ -49,7 +49,11 @@ QByteArray SignedWalletTransaction::hexMessage() { messageBinary.append(reinterpret_cast(&_amount), sizeof(_amount)); - return messageBinary.toHex(); + return messageBinary; +} + +QByteArray SignedWalletTransaction::hexMessage() { + return binaryMessage().toHex(); } QByteArray SignedWalletTransaction::messageDigest() { diff --git a/interface/src/SignedWalletTransaction.h b/interface/src/SignedWalletTransaction.h index 3b13f73335..6bc66a535e 100644 --- a/interface/src/SignedWalletTransaction.h +++ b/interface/src/SignedWalletTransaction.h @@ -19,6 +19,7 @@ class SignedWalletTransaction : public WalletTransaction { public: SignedWalletTransaction(const QUuid& destinationUUID, qint64 amount, qint64 messageTimestamp, qint64 expiryDelta); + QByteArray binaryMessage(); QByteArray hexMessage(); QByteArray messageDigest(); QByteArray signedMessageDigest(); From ce4336894a1fed5172dda18071334fa200023b75 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 31 Jul 2014 09:26:18 -0700 Subject: [PATCH 116/407] actually send signed transaction from PaymentManager --- interface/src/PaymentManager.cpp | 15 ++++++++++++++- interface/src/SignedWalletTransaction.h | 2 ++ libraries/networking/src/PacketHeaders.h | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/interface/src/PaymentManager.cpp b/interface/src/PaymentManager.cpp index b8af43ec67..84f5e96fc9 100644 --- a/interface/src/PaymentManager.cpp +++ b/interface/src/PaymentManager.cpp @@ -13,6 +13,9 @@ #include #include +#include +#include + #include "SignedWalletTransaction.h" #include "PaymentManager.h" @@ -23,7 +26,6 @@ PaymentManager& PaymentManager::getInstance() { } void PaymentManager::sendSignedPayment(qint64 satoshiAmount, const QUuid& nodeUUID, const QUuid& destinationWalletUUID) { - qDebug() << "Paying" << satoshiAmount << "satoshis to" << destinationWalletUUID << "via" << nodeUUID; // setup a signed wallet transaction const qint64 DEFAULT_TRANSACTION_EXPIRY_SECONDS = 60; @@ -32,4 +34,15 @@ void PaymentManager::sendSignedPayment(qint64 satoshiAmount, const QUuid& nodeUU currentTimestamp, DEFAULT_TRANSACTION_EXPIRY_SECONDS); // send the signed transaction to the redeeming node + QByteArray transactionByteArray = byteArrayWithPopulatedHeader(PacketTypeSignedTransactionPayment); + + // append the binary message and the signed message digest + transactionByteArray.append(newTransaction.binaryMessage()); + transactionByteArray.append(newTransaction.signedMessageDigest()); + + qDebug() << "Paying" << satoshiAmount << "satoshis to" << destinationWalletUUID << "via" << nodeUUID; + + // use the NodeList to send that to the right node + NodeList* nodeList = NodeList::getInstance(); + nodeList->writeDatagram(transactionByteArray, nodeList->nodeWithUUID(nodeUUID)); } \ No newline at end of file diff --git a/interface/src/SignedWalletTransaction.h b/interface/src/SignedWalletTransaction.h index 6bc66a535e..b3b1620dac 100644 --- a/interface/src/SignedWalletTransaction.h +++ b/interface/src/SignedWalletTransaction.h @@ -14,6 +14,8 @@ #include +const int NUM_BYTES_SIGNED_TRANSACTION_MESSAGE = 72; + class SignedWalletTransaction : public WalletTransaction { Q_OBJECT public: diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 83350a32d1..436c34e6eb 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -70,6 +70,7 @@ enum PacketType { PacketTypeVoxelEditNack, PacketTypeParticleEditNack, PacketTypeModelEditNack, + PacketTypeSignedTransactionPayment }; typedef char PacketVersion; From eadae8ed1ae224439e57586c69b7dcca8bbe8e2d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 31 Jul 2014 10:05:26 -0700 Subject: [PATCH 117/407] allow unauthenticated redemptions of signed transactions from octree server --- assignment-client/src/octree/OctreeServer.cpp | 52 ++++++ assignment-client/src/octree/OctreeServer.h | 3 + interface/src/SignedWalletTransaction.h | 2 - libraries/networking/src/AccountManager.cpp | 155 ++++++++++-------- libraries/networking/src/AccountManager.h | 10 +- 5 files changed, 154 insertions(+), 68 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 551bed795d..42dc9a047d 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -9,11 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include #include #include + +#include #include #include #include @@ -244,6 +247,10 @@ OctreeServer::OctreeServer(const QByteArray& packet) : _averageLoopTime.updateAverage(0); qDebug() << "Octree server starting... [" << this << "]"; + + // make sure the AccountManager has an Auth URL for payment redemptions + + AccountManager::getInstance().setAuthURL(DEFAULT_NODE_AUTH_URL); } OctreeServer::~OctreeServer() { @@ -857,6 +864,8 @@ void OctreeServer::readPendingDatagrams() { } } else if (packetType == PacketTypeJurisdictionRequest) { _jurisdictionSender->queueReceivedPacket(matchingNode, receivedPacket); + } else if (packetType == PacketTypeSignedTransactionPayment) { + handleSignedTransactionPayment(packetType, receivedPacket); } else if (_octreeInboundPacketProcessor && getOctree()->handlesEditPacketType(packetType)) { _octreeInboundPacketProcessor->queueReceivedPacket(matchingNode, receivedPacket); } else { @@ -1204,6 +1213,49 @@ QString OctreeServer::getStatusLink() { return result; } +void OctreeServer::handleSignedTransactionPayment(PacketType packetType, const QByteArray& datagram) { + // for now we're not verifying that this is actual payment for any octree edits + // just use the AccountManager to send it up to the data server and have it redeemed + AccountManager& accountManager = AccountManager::getInstance(); + + const int NUM_BYTES_SIGNED_TRANSACTION_BINARY_MESSAGE = 72; + const int NUM_BYTES_SIGNED_TRANSACTION_BINARY_SIGNATURE = 256; + + int numBytesPacketHeader = numBytesForPacketHeaderGivenPacketType(packetType); + + // pull out the transaction message in binary + QByteArray messageHex = datagram.mid(numBytesPacketHeader, NUM_BYTES_SIGNED_TRANSACTION_BINARY_MESSAGE).toHex(); + // pull out the binary signed message digest + QByteArray signatureHex = datagram.mid(numBytesPacketHeader + NUM_BYTES_SIGNED_TRANSACTION_BINARY_MESSAGE, + NUM_BYTES_SIGNED_TRANSACTION_BINARY_SIGNATURE).toHex(); + + // setup the QJSONObject we are posting + QJsonObject postObject; + + const QString TRANSACTION_OBJECT_MESSAGE_KEY = "message"; + const QString TRANSACTION_OBJECT_SIGNATURE_KEY = "signature"; + const QString POST_OBJECT_TRANSACTION_KEY = "transaction"; + + QJsonObject transactionObject; + transactionObject.insert(TRANSACTION_OBJECT_MESSAGE_KEY, QString(messageHex)); + transactionObject.insert(TRANSACTION_OBJECT_SIGNATURE_KEY, QString(signatureHex)); + + postObject.insert(POST_OBJECT_TRANSACTION_KEY, transactionObject); + + // setup our callback params + JSONCallbackParameters callbackParameters; + callbackParameters.jsonCallbackReceiver = this; + callbackParameters.jsonCallbackMethod = "handleSignedTransactionPaymentResponse"; + + accountManager.unauthenticatedRequest("/api/v1/transactions/redeem", QNetworkAccessManager::PostOperation, + callbackParameters, QJsonDocument(postObject).toJson()); + +} + +void OctreeServer::handleSignedTransactionPaymentResponse(const QJsonObject& jsonObject) { + qDebug() << "STP response:" << jsonObject; +} + void OctreeServer::sendStatsPacket() { // TODO: we have too many stats to fit in a single MTU... so for now, we break it into multiple JSON objects and // send them separately. What we really should do is change the NodeList::sendStatsToDomainServer() to handle the diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 76b39c5771..d00af41d5e 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -137,6 +137,9 @@ protected: QString getConfiguration(); QString getStatusLink(); + void handleSignedTransactionPayment(PacketType packetType, const QByteArray& datagram); + void handleSignedTransactionPaymentResponse(const QJsonObject& jsonObject); + int _argc; const char** _argv; char** _parsedArgV; diff --git a/interface/src/SignedWalletTransaction.h b/interface/src/SignedWalletTransaction.h index b3b1620dac..6bc66a535e 100644 --- a/interface/src/SignedWalletTransaction.h +++ b/interface/src/SignedWalletTransaction.h @@ -14,8 +14,6 @@ #include -const int NUM_BYTES_SIGNED_TRANSACTION_MESSAGE = 72; - class SignedWalletTransaction : public WalletTransaction { Q_OBJECT public: diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 563d735790..68af384007 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -15,15 +15,15 @@ #include #include #include +#include #include -#include #include "NodeList.h" #include "PacketHeaders.h" #include "AccountManager.h" -const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false; +const bool VERBOSE_HTTP_REQUEST_DEBUGGING = true; AccountManager& AccountManager::getInstance() { static AccountManager sharedInstance; @@ -62,6 +62,8 @@ AccountManager::AccountManager() : qRegisterMetaType("QNetworkAccessManager::Operation"); qRegisterMetaType("JSONCallbackParameters"); + + qRegisterMetaType("QHttpMultiPart*"); connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged); } @@ -142,90 +144,113 @@ void AccountManager::authenticatedRequest(const QString& path, QNetworkAccessMan const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) { + QMetaObject::invokeMethod(this, "invokedRequest", Q_ARG(const QString&, path), + Q_ARG(bool, true), Q_ARG(QNetworkAccessManager::Operation, operation), Q_ARG(const JSONCallbackParameters&, callbackParams), Q_ARG(const QByteArray&, dataByteArray), Q_ARG(QHttpMultiPart*, dataMultiPart)); } -void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::Operation operation, +void AccountManager::unauthenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation, + const JSONCallbackParameters& callbackParams, + const QByteArray& dataByteArray, + QHttpMultiPart* dataMultiPart) { + + QMetaObject::invokeMethod(this, "invokedRequest", + Q_ARG(const QString&, path), + Q_ARG(bool, false), + Q_ARG(QNetworkAccessManager::Operation, operation), + Q_ARG(const JSONCallbackParameters&, callbackParams), + Q_ARG(const QByteArray&, dataByteArray), + Q_ARG(QHttpMultiPart*, dataMultiPart)); +} + +void AccountManager::invokedRequest(const QString& path, + bool requiresAuthentication, + QNetworkAccessManager::Operation operation, const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) { NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - if (hasValidAccessToken()) { - QNetworkRequest authenticatedRequest; - - QUrl requestURL = _authURL; - - if (path.startsWith("/")) { - requestURL.setPath(path); + QNetworkRequest networkRequest; + + QUrl requestURL = _authURL; + + if (path.startsWith("/")) { + requestURL.setPath(path); + } else { + requestURL.setPath("/" + path); + } + + if (requiresAuthentication) { + if (hasValidAccessToken()) { + requestURL.setQuery("access_token=" + _accountInfo.getAccessToken().token); } else { - requestURL.setPath("/" + path); + qDebug() << "No valid access token present. Bailing on authenticated invoked request."; + return; } - - requestURL.setQuery("access_token=" + _accountInfo.getAccessToken().token); - - authenticatedRequest.setUrl(requestURL); - - if (VERBOSE_HTTP_REQUEST_DEBUGGING) { - qDebug() << "Making an authenticated request to" << qPrintable(requestURL.toString()); - - if (!dataByteArray.isEmpty()) { - qDebug() << "The POST/PUT body -" << QString(dataByteArray); - } + } + + networkRequest.setUrl(requestURL); + + if (VERBOSE_HTTP_REQUEST_DEBUGGING) { + qDebug() << "Making an authenticated request to" << qPrintable(requestURL.toString()); + + if (!dataByteArray.isEmpty()) { + qDebug() << "The POST/PUT body -" << QString(dataByteArray); } - - QNetworkReply* networkReply = NULL; - - switch (operation) { - case QNetworkAccessManager::GetOperation: - networkReply = networkAccessManager.get(authenticatedRequest); - break; - case QNetworkAccessManager::PostOperation: - case QNetworkAccessManager::PutOperation: - if (dataMultiPart) { - if (operation == QNetworkAccessManager::PostOperation) { - networkReply = networkAccessManager.post(authenticatedRequest, dataMultiPart); - } else { - networkReply = networkAccessManager.put(authenticatedRequest, dataMultiPart); - } - dataMultiPart->setParent(networkReply); + } + + QNetworkReply* networkReply = NULL; + + switch (operation) { + case QNetworkAccessManager::GetOperation: + networkReply = networkAccessManager.get(networkRequest); + break; + case QNetworkAccessManager::PostOperation: + case QNetworkAccessManager::PutOperation: + if (dataMultiPart) { + if (operation == QNetworkAccessManager::PostOperation) { + networkReply = networkAccessManager.post(networkRequest, dataMultiPart); } else { - authenticatedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - if (operation == QNetworkAccessManager::PostOperation) { - networkReply = networkAccessManager.post(authenticatedRequest, dataByteArray); - } else { - networkReply = networkAccessManager.put(authenticatedRequest, dataByteArray); - } + networkReply = networkAccessManager.put(networkRequest, dataMultiPart); } - - break; - case QNetworkAccessManager::DeleteOperation: - networkReply = networkAccessManager.sendCustomRequest(authenticatedRequest, "DELETE"); - break; - default: - // other methods not yet handled - break; - } - - if (networkReply) { - if (!callbackParams.isEmpty()) { - // if we have information for a callback, insert the callbackParams into our local map - _pendingCallbackMap.insert(networkReply, callbackParams); - - if (callbackParams.updateReciever && !callbackParams.updateSlot.isEmpty()) { - callbackParams.updateReciever->connect(networkReply, SIGNAL(uploadProgress(qint64, qint64)), - callbackParams.updateSlot.toStdString().c_str()); + dataMultiPart->setParent(networkReply); + } else { + networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + if (operation == QNetworkAccessManager::PostOperation) { + networkReply = networkAccessManager.post(networkRequest, dataByteArray); + } else { + networkReply = networkAccessManager.put(networkRequest, dataByteArray); } } - - // if we ended up firing of a request, hook up to it now - connect(networkReply, SIGNAL(finished()), SLOT(processReply())); + + break; + case QNetworkAccessManager::DeleteOperation: + networkReply = networkAccessManager.sendCustomRequest(networkRequest, "DELETE"); + break; + default: + // other methods not yet handled + break; + } + + if (networkReply) { + if (!callbackParams.isEmpty()) { + // if we have information for a callback, insert the callbackParams into our local map + _pendingCallbackMap.insert(networkReply, callbackParams); + + if (callbackParams.updateReciever && !callbackParams.updateSlot.isEmpty()) { + callbackParams.updateReciever->connect(networkReply, SIGNAL(uploadProgress(qint64, qint64)), + callbackParams.updateSlot.toStdString().c_str()); + } } + + // if we ended up firing of a request, hook up to it now + connect(networkReply, SIGNAL(finished()), SLOT(processReply())); } } diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index 49a39c1a22..64d62cd1c2 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -47,6 +47,12 @@ public: const JSONCallbackParameters& callbackParams = JSONCallbackParameters(), const QByteArray& dataByteArray = QByteArray(), QHttpMultiPart* dataMultiPart = NULL); + + void unauthenticatedRequest(const QString& path, + QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation, + const JSONCallbackParameters& callbackParams = JSONCallbackParameters(), + const QByteArray& dataByteArray = QByteArray(), + QHttpMultiPart* dataMultiPart = NULL); const QUrl& getAuthURL() const { return _authURL; } void setAuthURL(const QUrl& authURL); @@ -88,7 +94,9 @@ private: void passSuccessToCallback(QNetworkReply* reply); void passErrorToCallback(QNetworkReply* reply); - Q_INVOKABLE void invokedRequest(const QString& path, QNetworkAccessManager::Operation operation, + Q_INVOKABLE void invokedRequest(const QString& path, + bool requiresAuthentication, + QNetworkAccessManager::Operation operation, const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart); From 3e2bb0f1684891f28f4c6d6dff5dc70ec2855a6c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 31 Jul 2014 10:40:45 -0700 Subject: [PATCH 118/407] Add more complete error handling for import/export models --- examples/editModels.js | 25 +++++++++++++------ interface/src/Application.cpp | 9 ++++--- interface/src/Application.h | 2 +- .../scripting/ClipboardScriptingInterface.cpp | 8 +++--- .../scripting/ClipboardScriptingInterface.h | 4 +-- 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 1a5753838d..f3650bada2 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -218,7 +218,10 @@ var ExportMenu = function(opts) { var filename = "models__" + Window.location.hostname + "__" + x + "_" + y + "_" + z + "_" + s + "__.svo"; filename = Window.save("Select where to save", filename, "*.svo") if (filename) { - Clipboard.exportModels(filename, x, y, z, s); + var success = Clipboard.exportModels(filename, x, y, z, s); + if (!succcess) { + WIndow.alert("Export failed: no models found in selected area."); + } } self.close(); }; @@ -431,16 +434,24 @@ var ModelImporter = function(opts) { } } else { if (Window.confirm(("Would you like to import back to the source location?"))) { - Clipboard.importModels(filename); - Clipboard.pasteModels(x, y, z, 1); + var success = Clipboard.importModels(filename); + if (success) { + Clipboard.pasteModels(x, y, z, 1); + } else { + Window.alert("There was an error importing the model file."); + } return; } } } - Clipboard.importModels(filename); - self._importing = true; - self.setImportVisible(true); - Overlays.editOverlay(importBoundaries, { size: s }); + var success = Clipboard.importModels(filename); + if (success) { + self._importing = true; + self.setImportVisible(true); + Overlays.editOverlay(importBoundaries, { size: s }); + } else { + Window.alert("There was an error importing the model file."); + } } } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e469cc7535..540cb47a79 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1614,10 +1614,13 @@ void Application::importVoxels() { emit importDone(); } -void Application::importModels(const QString& filename) { +bool Application::importModels(const QString& filename) { _modelClipboard.eraseAllOctreeElements(); - _modelClipboard.readFromSVOFile(filename.toLocal8Bit().constData()); - _modelClipboard.reaverageOctreeElements(); + bool success = _modelClipboard.readFromSVOFile(filename.toLocal8Bit().constData()); + if (success) { + _modelClipboard.reaverageOctreeElements(); + } + return success; } void Application::pasteModels(float x, float y, float z) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 44a93f5d7b..d15d8ae63f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -317,7 +317,7 @@ public slots: void pasteModels(float x, float y, float z); bool exportModels(const QString& filename, float x, float y, float z, float scale); - void importModels(const QString& filename); + bool importModels(const QString& filename); void importVoxels(); // doesn't include source voxel because it goes to clipboard void cutVoxels(const VoxelDetail& sourceVoxel); diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp index 10799c2abb..aa4a06fa50 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.cpp +++ b/interface/src/scripting/ClipboardScriptingInterface.cpp @@ -102,12 +102,12 @@ void ClipboardScriptingInterface::nudgeVoxel(float x, float y, float z, float s, } -void ClipboardScriptingInterface::exportModels(const QString& filename, float x, float y, float z, float s) { - Application::getInstance()->exportModels(filename, x, y, z, s); +bool ClipboardScriptingInterface::exportModels(const QString& filename, float x, float y, float z, float s) { + return Application::getInstance()->exportModels(filename, x, y, z, s); } -void ClipboardScriptingInterface::importModels(const QString& filename) { - Application::getInstance()->importModels(filename); +bool ClipboardScriptingInterface::importModels(const QString& filename) { + return Application::getInstance()->importModels(filename); } void ClipboardScriptingInterface::pasteModels(float x, float y, float z, float s) { diff --git a/interface/src/scripting/ClipboardScriptingInterface.h b/interface/src/scripting/ClipboardScriptingInterface.h index 373a7308ae..aa5234a115 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.h +++ b/interface/src/scripting/ClipboardScriptingInterface.h @@ -43,8 +43,8 @@ public slots: void nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec); void nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec); - void importModels(const QString& filename); - void exportModels(const QString& filename, float x, float y, float z, float s); + bool importModels(const QString& filename); + bool exportModels(const QString& filename, float x, float y, float z, float s); void pasteModels(float x, float y, float z, float s); }; From 85ed18fd415655cfb8817fa45e1ce71073d47061 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 31 Jul 2014 10:43:44 -0700 Subject: [PATCH 119/407] Cleanup editModels.js --- examples/editModels.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index f3650bada2..fc1c43e934 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -186,7 +186,6 @@ var ExportMenu = function(opts) { if (positionStr == null) { break; } - print("position: " + position); var position = self.parsePosition(positionStr); if (position != null) { self.setPosition(position.x, position.y, position.z); @@ -238,13 +237,7 @@ var ExportMenu = function(opts) { }; - this.mousePressEvent = function(event) { - print("Mouse press"); - var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - }; - this.mouseReleaseEvent = function(event) { - print("Mouse release"); var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); if (clickedOverlay == locationButton) { @@ -281,7 +274,6 @@ var ExportMenu = function(opts) { }; print("CONNECTING!"); - Controller.mousePressEvent.connect(this.mousePressEvent); Controller.mouseReleaseEvent.connect(this.mouseReleaseEvent); }; @@ -313,7 +305,7 @@ var ModelImporter = function(opts) { var pos = { x: windowDimensions.x / 2 - (fullWidth / 2), y: windowDimensions.y - 100 }; - var background= Overlays.addOverlay("text", { + var background = Overlays.addOverlay("text", { x: pos.x, y: pos.y, opacity: 1, @@ -414,7 +406,6 @@ var ModelImporter = function(opts) { // Would prefer to use {4} for the coords, but it would only capture the last digit. var fileRegex = /__(.+)__(\d+(?:\.\d+)?)_(\d+(?:\.\d+)?)_(\d+(?:\.\d+)?)_(\d+(?:\.\d+)?)__/; this.doImport = function() { - print("IMPORTING "); if (!self._importing) { var filename = Window.browse("Select models to import", "", "*.svo") if (filename) { @@ -1609,9 +1600,6 @@ function handeMenuEvent(menuItem){ modelImporter.paste(); } else if (menuItem == "Export Models") { if (!exportMenu) { - // if (modelImporter) { - // modelImporter.close(); - // } exportMenu = new ExportMenu({ onClose: function() { exportMenu = null; From a670889ffb15c82a36a3e299d2f4481768f48d47 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 31 Jul 2014 10:44:36 -0700 Subject: [PATCH 120/407] Remove TODO comment --- examples/editModels.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index fc1c43e934..c0dfad871d 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -287,7 +287,6 @@ var ModelImporter = function(opts) { var cancelWidth = 100; var fullWidth = titleWidth + cancelWidth + (2 * margin); - // TODO: Show import preview var localModels = Overlays.addOverlay("localmodels", { position: { x: 1, y: 1, z: 1 }, scale: 1, @@ -349,7 +348,6 @@ var ModelImporter = function(opts) { var importPosition = { x: 0, y: 0, z: 0 }; this.moveImport = function(position) { importPosition = position; - // TODO: Show import preview Overlays.editOverlay(localModels, { position: { x: importPosition.x, y: importPosition.y, z: importPosition.z } }); From aa1c9d88dd88da6aeeb52878af086ba8d77e3dfa Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 31 Jul 2014 10:48:26 -0700 Subject: [PATCH 121/407] Cleaup several qDebug calls and commented lines --- interface/src/scripting/WindowScriptingInterface.cpp | 3 --- interface/src/ui/overlays/LocalModelsOverlay.h | 1 - interface/src/ui/overlays/Overlays.cpp | 1 - 3 files changed, 5 deletions(-) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index f9b1b47549..ea0eeb0dd9 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -204,15 +204,12 @@ QScriptValue WindowScriptingInterface::showBrowse(const QString& title, const QS } QFileDialog fileDialog(Application::getInstance()->getWindow(), title, path, nameFilter); - // fileDialog.setFileMode(QFileDialog::ExistingFile); fileDialog.setAcceptMode(acceptMode); qDebug() << "Opening!"; QUrl fileUrl(directory); if (acceptMode == QFileDialog::AcceptSave) { fileDialog.setFileMode(QFileDialog::Directory); fileDialog.selectFile(fileUrl.fileName()); - // qDebug() << "Setting filename!"; - // fileDialog.setLabelText(QFileDialog::FileName, fileUrl.fileName()); } if (fileDialog.exec()) { return QScriptValue(fileDialog.selectedFiles().first()); diff --git a/interface/src/ui/overlays/LocalModelsOverlay.h b/interface/src/ui/overlays/LocalModelsOverlay.h index 88bf55aaf0..7c4bffa342 100644 --- a/interface/src/ui/overlays/LocalModelsOverlay.h +++ b/interface/src/ui/overlays/LocalModelsOverlay.h @@ -12,7 +12,6 @@ #ifndef hifi_LocalModelsOverlay_h #define hifi_LocalModelsOverlay_h -// #include "models/ModelTree.h" #include "models/ModelTreeRenderer.h" #include "Volume3DOverlay.h" diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index d73a01103d..8ef800ef7b 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -160,7 +160,6 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope created = true; is3D = true; } else if (type == "localmodels") { - qDebug() << "Making localmodels"; thisOverlay = new LocalModelsOverlay(Application::getInstance()->getModelClipboardRenderer()); thisOverlay->init(_parent); thisOverlay->setProperties(properties); From e1ba076a711cbe3dc1397f99054cdb2596d795fe Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 31 Jul 2014 11:03:12 -0700 Subject: [PATCH 122/407] complete redemption of signed transactions from octree server --- assignment-client/src/octree/OctreeServer.cpp | 4 +++- assignment-client/src/octree/OctreeServer.h | 3 ++- libraries/networking/src/AccountManager.cpp | 5 +++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 42dc9a047d..02fb26c09f 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1253,7 +1253,9 @@ void OctreeServer::handleSignedTransactionPayment(PacketType packetType, const Q } void OctreeServer::handleSignedTransactionPaymentResponse(const QJsonObject& jsonObject) { - qDebug() << "STP response:" << jsonObject; + // pull the ID to debug the transaction + QString transactionIDString = jsonObject["data"].toObject()["transaction"].toObject()["id"].toString(); + qDebug() << "Redeemed transaction with ID" << transactionIDString << "successfully."; } void OctreeServer::sendStatsPacket() { diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index d00af41d5e..c904b3d86c 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -127,6 +127,8 @@ public slots: void nodeAdded(SharedNodePointer node); void nodeKilled(SharedNodePointer node); void sendStatsPacket(); + + void handleSignedTransactionPaymentResponse(const QJsonObject& jsonObject); protected: void parsePayload(); @@ -138,7 +140,6 @@ protected: QString getStatusLink(); void handleSignedTransactionPayment(PacketType packetType, const QByteArray& datagram); - void handleSignedTransactionPaymentResponse(const QJsonObject& jsonObject); int _argc; const char** _argv; diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 68af384007..7fda9d74c9 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -23,7 +23,7 @@ #include "AccountManager.h" -const bool VERBOSE_HTTP_REQUEST_DEBUGGING = true; +const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false; AccountManager& AccountManager::getInstance() { static AccountManager sharedInstance; @@ -198,7 +198,7 @@ void AccountManager::invokedRequest(const QString& path, networkRequest.setUrl(requestURL); if (VERBOSE_HTTP_REQUEST_DEBUGGING) { - qDebug() << "Making an authenticated request to" << qPrintable(requestURL.toString()); + qDebug() << "Making a request to" << qPrintable(requestURL.toString()); if (!dataByteArray.isEmpty()) { qDebug() << "The POST/PUT body -" << QString(dataByteArray); @@ -301,6 +301,7 @@ void AccountManager::passErrorToCallback(QNetworkReply* requestReply) { if (VERBOSE_HTTP_REQUEST_DEBUGGING) { qDebug() << "Received error response from data-server that has no matching callback."; qDebug() << "Error" << requestReply->error() << "-" << requestReply->errorString(); + qDebug() << requestReply->readAll(); } } } From 90ce73823a058ee3ed4d60855d1f335b9c14e95f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 31 Jul 2014 11:03:50 -0700 Subject: [PATCH 123/407] Attempting to fix the Linux build error. --- interface/src/MetavoxelSystem.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 725ef9ca71..2258be6e87 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -12,6 +12,9 @@ #ifndef hifi_MetavoxelSystem_h #define hifi_MetavoxelSystem_h +// include this before QOpenGLTexture, which includes an earlier version of OpenGL +#include "InterfaceConfig.h" + #include #include #include From 3c459d8460854b20b8c11ea6e7e61805c004ab8a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 31 Jul 2014 11:12:41 -0700 Subject: [PATCH 124/407] fix include of tgmath for windows --- libraries/networking/src/DomainHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 1bcf03f477..786726b745 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include #include From ab52f384b7fddc64da65f762ba2f4cf01f3a3aff Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Thu, 31 Jul 2014 11:15:20 -0700 Subject: [PATCH 125/407] Improvements on RPS script --- examples/rockPaperScissorsCells.js | 50 ++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/examples/rockPaperScissorsCells.js b/examples/rockPaperScissorsCells.js index d7101ce4c7..2a9cb00a0b 100644 --- a/examples/rockPaperScissorsCells.js +++ b/examples/rockPaperScissorsCells.js @@ -6,12 +6,14 @@ // // This sample script creates a voxel wall that simulates the Rock Paper Scissors cellular // automata. http://www.gamedev.net/blog/844/entry-2249737-another-cellular-automaton-video/ +// If multiple instances of this script are run, they will combine into a larger wall. +// NOTE: You must run each instance one at a time. If they all start at once there are race conditions. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var NUMBER_OF_CELLS_EACH_DIMENSION = 64; +var NUMBER_OF_CELLS_EACH_DIMENSION = 48; var NUMBER_OF_CELLS_REGION_EACH_DIMESION = 16; var REGIONS_EACH_DIMENSION = NUMBER_OF_CELLS_EACH_DIMENSION / NUMBER_OF_CELLS_REGION_EACH_DIMESION; @@ -38,8 +40,6 @@ cellTypes[0] = { r: 255, g: 0, b: 0 }; cellTypes[1] = { r: 0, g: 255, b: 0 }; cellTypes[2] = { r: 0, g:0, b: 255 }; cellTypes[3] = { r: 0, g: 255, b: 255 }; -//cellTypes[4] = { r: 255, g:0, b: 255 }; -//cellTypes[5] = { r: 255, g:255, b: 255 }; //Check for free region for AC @@ -48,8 +48,19 @@ var regionMarkerY = -1; var regionMarkerI = -1; var regionMarkerJ = -1; -var regionMarkerColor = {r: 255, g: 0, b: 255}; +var regionMarkerColor = {r: 254, g: 0, b: 253}; +function setRegionToColor(startX, startY, width, height, color) { + for (var i = startY; i < startY + height; i++) { + for (var j = startX; j < startX + width; j++) { + + currentCells[i][j] = { changed: true, type: color }; + + // put the same value in the nextCells array for first board draw + nextCells[i][j] = { changed: true, type: color }; + } + } +} function init() { @@ -71,24 +82,30 @@ function init() { } } - Voxels.setVoxel(regionMarkerX, regionMarkerY, position.z, cellScale, regionMarkerColor.r, regionMarkerColor.g, regionMarkerColor.b); + //Didnt find an open spot, end script + if (regionMarkerX == -1) { + Script.stop(); + } + + position.x = cornerPosition.x + regionMarkerJ * NUMBER_OF_CELLS_REGION_EACH_DIMESION; + position.y = cornerPosition.y + regionMarkerI * NUMBER_OF_CELLS_REGION_EACH_DIMESION; + position.z = cornerPosition.z; + + Voxels.setVoxel(regionMarkerX, regionMarkerY, cornerPosition.z, cellScale, regionMarkerColor.r, regionMarkerColor.g, regionMarkerColor.b); - // randomly populate the cell start values - var randomColor = Math.floor(Math.random() * cellTypes.length); for (var i = 0; i < NUMBER_OF_CELLS_REGION_EACH_DIMESION; i++) { // create the array to hold this row currentCells[i] = []; // create the array to hold this row in the nextCells array nextCells[i] = []; - - for (var j = 0; j < NUMBER_OF_CELLS_REGION_EACH_DIMESION; j++) { - currentCells[i][j] = { changed: true, type: randomColor }; - - // put the same value in the nextCells array for first board draw - nextCells[i][j] = currentCells[i][j]; - } } + + var width = NUMBER_OF_CELLS_REGION_EACH_DIMESION / 2; + setRegionToColor(0, 0, width, width, 0); + setRegionToColor(0, width, width, width, 1); + setRegionToColor(width, width, width, width, 2); + setRegionToColor(width, 0, width, width, 3); } function updateCells() { @@ -171,7 +188,8 @@ function updateCells() { for (j = 0; j < NUMBER_OF_CELLS_REGION_EACH_DIMESION; j++) { if (nextCells[i][j].changed == true) { // there has been a change to this cell, change the value in the currentCells array - currentCells[i][j] = nextCells[i][j]; + currentCells[i][j].type = nextCells[i][j].type; + currentCells[i][j].changed = true; } } } @@ -224,8 +242,6 @@ function step(deltaTime) { if (frameIndex <= framesToWait) { return; } - - print("UPDATE"); if (sentFirstBoard) { // we've already sent the first full board, perform a step in time From 054e832cf874b97ceddc3667b6d97d4ab640621b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 31 Jul 2014 11:32:17 -0700 Subject: [PATCH 126/407] Fix misspelled variable names --- examples/editModels.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index c0dfad871d..93954d84f3 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -218,8 +218,8 @@ var ExportMenu = function(opts) { filename = Window.save("Select where to save", filename, "*.svo") if (filename) { var success = Clipboard.exportModels(filename, x, y, z, s); - if (!succcess) { - WIndow.alert("Export failed: no models found in selected area."); + if (!success) { + Window.alert("Export failed: no models found in selected area."); } } self.close(); From 7860aa5b870d89eff4f26e95bd8207340d5ea44f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 31 Jul 2014 11:41:49 -0700 Subject: [PATCH 127/407] add some error messages to PaymentManager --- interface/src/PaymentManager.cpp | 50 +++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/interface/src/PaymentManager.cpp b/interface/src/PaymentManager.cpp index 84f5e96fc9..a0c05f34b3 100644 --- a/interface/src/PaymentManager.cpp +++ b/interface/src/PaymentManager.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -27,22 +28,37 @@ PaymentManager& PaymentManager::getInstance() { void PaymentManager::sendSignedPayment(qint64 satoshiAmount, const QUuid& nodeUUID, const QUuid& destinationWalletUUID) { - // setup a signed wallet transaction - const qint64 DEFAULT_TRANSACTION_EXPIRY_SECONDS = 60; - qint64 currentTimestamp = QDateTime::currentDateTimeUtc().toTime_t(); - SignedWalletTransaction newTransaction(destinationWalletUUID, satoshiAmount, - currentTimestamp, DEFAULT_TRANSACTION_EXPIRY_SECONDS); + QByteArray walletPrivateKeyByteArray = Menu::getInstance()->getWalletPrivateKey(); - // send the signed transaction to the redeeming node - QByteArray transactionByteArray = byteArrayWithPopulatedHeader(PacketTypeSignedTransactionPayment); - - // append the binary message and the signed message digest - transactionByteArray.append(newTransaction.binaryMessage()); - transactionByteArray.append(newTransaction.signedMessageDigest()); - - qDebug() << "Paying" << satoshiAmount << "satoshis to" << destinationWalletUUID << "via" << nodeUUID; - - // use the NodeList to send that to the right node - NodeList* nodeList = NodeList::getInstance(); - nodeList->writeDatagram(transactionByteArray, nodeList->nodeWithUUID(nodeUUID)); + if (!walletPrivateKeyByteArray.isEmpty()) { + // setup a signed wallet transaction + const qint64 DEFAULT_TRANSACTION_EXPIRY_SECONDS = 60; + qint64 currentTimestamp = QDateTime::currentDateTimeUtc().toTime_t(); + SignedWalletTransaction newTransaction(destinationWalletUUID, satoshiAmount, + currentTimestamp, DEFAULT_TRANSACTION_EXPIRY_SECONDS); + + // send the signed transaction to the redeeming node + QByteArray transactionByteArray = byteArrayWithPopulatedHeader(PacketTypeSignedTransactionPayment); + + // append the binary message and the signed message digest + transactionByteArray.append(newTransaction.binaryMessage()); + QByteArray signedMessageDigest = newTransaction.signedMessageDigest(); + + if (!signedMessageDigest.isEmpty()) { + transactionByteArray.append(signedMessageDigest); + + qDebug() << "Paying" << satoshiAmount << "satoshis to" << destinationWalletUUID << "via" << nodeUUID; + + // use the NodeList to send that to the right node + NodeList* nodeList = NodeList::getInstance(); + nodeList->writeDatagram(transactionByteArray, nodeList->nodeWithUUID(nodeUUID)); + } else { + qDebug() << "Payment of" << satoshiAmount << "satoshis to" << destinationWalletUUID << "via" << nodeUUID << + "cannot be sent because there was an error signing the transaction."; + } + + } else { + qDebug() << "Payment of" << satoshiAmount << "satoshis to" << destinationWalletUUID << "via" << nodeUUID << + "cannot be sent because there is no stored wallet private key."; + } } \ No newline at end of file From 490dad6bbd3ffb0d1dcff97efcc841efc63a5680 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 31 Jul 2014 11:52:03 -0700 Subject: [PATCH 128/407] Work on network streaming of referentials --- libraries/avatars/src/AvatarData.cpp | 17 ++++++- libraries/avatars/src/AvatarData.h | 3 +- libraries/avatars/src/Referential.cpp | 64 ++++++++++++++++++++++++++- libraries/avatars/src/Referential.h | 26 +++++++++-- 4 files changed, 104 insertions(+), 6 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 005a2abb44..ef2ad581e0 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -137,11 +137,20 @@ QByteArray AvatarData::toByteArray() { // hand state setSemiNibbleAt(bitItems,HAND_STATE_START_BIT,_handState); // faceshift state - if (_headData->_isFaceshiftConnected) { setAtBit(bitItems, IS_FACESHIFT_CONNECTED); } + if (_headData->_isFaceshiftConnected) { + setAtBit(bitItems, IS_FACESHIFT_CONNECTED); + } if (_isChatCirclingEnabled) { setAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED); } + if (_referential != NULL && _referential->isValid()) { + setAtBit(bitItems, HAS_REFERENTIAL); + } *destinationBuffer++ = bitItems; + + if (_referential != NULL && _referential->isValid()) { + destinationBuffer += _referential->packReferential(destinationBuffer); + } // If it is connected, pack up the data if (_headData->_isFaceshiftConnected) { @@ -384,6 +393,12 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { _headData->_isFaceshiftConnected = oneAtBit(bitItems, IS_FACESHIFT_CONNECTED); _isChatCirclingEnabled = oneAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED); + bool hasReferential = oneAtBit(bitItems, HAS_REFERENTIAL); + if (hasReferential) { + _referential = new Referential(sourceBuffer); + } + + if (_headData->_isFaceshiftConnected) { float leftEyeBlink, rightEyeBlink, averageLoudness, browAudioLift; minPossibleSize += sizeof(leftEyeBlink) + sizeof(rightEyeBlink) + sizeof(averageLoudness) + sizeof(browAudioLift); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index aed1047947..029d48be34 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -81,7 +81,8 @@ const quint32 AVATAR_MOTION_SCRIPTABLE_BITS = const int KEY_STATE_START_BIT = 0; // 1st and 2nd bits const int HAND_STATE_START_BIT = 2; // 3rd and 4th bits const int IS_FACESHIFT_CONNECTED = 4; // 5th bit -const int IS_CHAT_CIRCLING_ENABLED = 5; +const int IS_CHAT_CIRCLING_ENABLED = 5; // 6th bit +const int HAS_REFERENTIAL = 6; static const float MAX_AVATAR_SCALE = 1000.f; static const float MIN_AVATAR_SCALE = .005f; diff --git a/libraries/avatars/src/Referential.cpp b/libraries/avatars/src/Referential.cpp index dd504485f5..f38fb97d99 100644 --- a/libraries/avatars/src/Referential.cpp +++ b/libraries/avatars/src/Referential.cpp @@ -9,9 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "Referential.h" -Referential::Referential(AvatarData* avatar) : +Referential::Referential(Type type, AvatarData* avatar) : + _type(type), + _createdAt(usecTimestampNow()), _isValid(true), _avatar(avatar) { @@ -20,3 +24,61 @@ Referential::Referential(AvatarData* avatar) : return; } } + +Referential::Referential(const unsigned char*& sourceBuffer) : + _isValid(false), + _avatar(NULL) +{ + sourceBuffer += unpack(sourceBuffer); +} + +Referential::~Referential() { +} + +int Referential::packReferential(unsigned char* destinationBuffer) { + const unsigned char* startPosition = destinationBuffer; + destinationBuffer += pack(destinationBuffer); + destinationBuffer += packExtraData(destinationBuffer); + return destinationBuffer - startPosition; +} + +int Referential::unpackReferential(const unsigned char* sourceBuffer) { + const unsigned char* startPosition = sourceBuffer; + sourceBuffer += unpack(sourceBuffer); + sourceBuffer += unpackExtraData(sourceBuffer); + return sourceBuffer - startPosition; +} + +int Referential::unpackExtraData(const unsigned char* sourceBuffer) { + const unsigned char* startPosition = sourceBuffer; + int size = *sourceBuffer++; + _extraDataBuffer.clear(); + _extraDataBuffer.setRawData(reinterpret_cast(sourceBuffer), size); + sourceBuffer += size; + return sourceBuffer - startPosition; +} + +int Referential::pack(unsigned char* destinationBuffer) { + unsigned char* startPosition = destinationBuffer; + *destinationBuffer++ = (unsigned char)_type; + memcpy(destinationBuffer, &_createdAt, sizeof(_createdAt)); + + destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, _translation, 0); + destinationBuffer += packOrientationQuatToBytes(destinationBuffer, _rotation); + destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, _scale, 0); + return destinationBuffer - startPosition; +} + +int Referential::unpack(const unsigned char* sourceBuffer) { + const unsigned char* startPosition = sourceBuffer; + _type = (Type)*sourceBuffer++; + memcpy(&_createdAt, sourceBuffer, sizeof(_createdAt)); + sourceBuffer += sizeof(_createdAt); + + sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, _translation, 0); + sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, _rotation); + sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*)sourceBuffer, &_scale, 0); + return sourceBuffer - startPosition; +} + + diff --git a/libraries/avatars/src/Referential.h b/libraries/avatars/src/Referential.h index a1a9fcd0f7..06ddf457e4 100644 --- a/libraries/avatars/src/Referential.h +++ b/libraries/avatars/src/Referential.h @@ -19,16 +19,36 @@ class AvatarData; class Referential { public: + enum Type { + MODEL, + JOINT, + AVATAR + }; + + Referential(const unsigned char*& sourceBuffer); virtual ~Referential(); - virtual bool isValid() { return _isValid; } - virtual void update() = 0; + Type type() { return _type; } + quint64 createdAt() { return _createdAt; } + bool isValid() { return _isValid; } + + virtual void update() {} + int packReferential(unsigned char* destinationBuffer); + int unpackReferential(const unsigned char* sourceBuffer); protected: - Referential(AvatarData* avatar); + Referential(Type type, AvatarData* avatar); + int pack(unsigned char* destinationBuffer); + int unpack(const unsigned char* sourceBuffer); + int packExtraData(unsigned char* destinationBuffer) { return 0; } + int unpackExtraData(const unsigned char* sourceBuffer); + + Type _type; + quint64 _createdAt; bool _isValid; AvatarData* _avatar; + QByteArray _extraDataBuffer; glm::vec3 _refPosition; glm::quat _refRotation; From 5fd3fd9f8f2b88436ebed51513843003244b4e63 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 31 Jul 2014 11:54:39 -0700 Subject: [PATCH 129/407] Moved MyAvatar update at the end of Application::update() to have latest data for simulation --- interface/src/Application.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9b54b84351..188fc214c9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2072,12 +2072,6 @@ void Application::update(float deltaTime) { _prioVR.update(deltaTime); } - { - PerformanceTimer perfTimer("myAvatar"); - updateMyAvatarLookAtPosition(); - updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes - } - // Dispatch input events _controllerScriptingInterface.updateInputControllers(); @@ -2109,6 +2103,12 @@ void Application::update(float deltaTime) { PerformanceTimer perfTimer("overlays"); _overlays.update(deltaTime); } + + { + PerformanceTimer perfTimer("myAvatar"); + updateMyAvatarLookAtPosition(); + updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes + } { PerformanceTimer perfTimer("emitSimulating"); From c65dc3fb1efd05471830d5babfdea1712f5058bf Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 31 Jul 2014 11:55:28 -0700 Subject: [PATCH 130/407] Various tweaks to ModelReferentials --- interface/src/avatar/ModelReferential.cpp | 61 +++++++++++++++++++---- interface/src/avatar/ModelReferential.h | 6 ++- interface/src/avatar/MyAvatar.cpp | 13 +++++ 3 files changed, 67 insertions(+), 13 deletions(-) diff --git a/interface/src/avatar/ModelReferential.cpp b/interface/src/avatar/ModelReferential.cpp index c681bb29da..bb1d66d730 100644 --- a/interface/src/avatar/ModelReferential.cpp +++ b/interface/src/avatar/ModelReferential.cpp @@ -12,23 +12,25 @@ #include #include "ModelTree.h" +#include "../renderer/Model.h" #include "ModelReferential.h" ModelReferential::ModelReferential(uint32_t modelID, ModelTree* tree, AvatarData* avatar) : -Referential(avatar), +Referential(MODEL, avatar), _modelID(modelID), _tree(tree) { const ModelItem* item = _tree->findModelByID(_modelID); if (!_isValid || item == NULL) { + qDebug() << "Not Validd"; _isValid = false; return; } _refScale = item->getRadius(); _refRotation = item->getModelRotation(); - _refPosition = item->getPosition(); + _refPosition = item->getPosition() * (float)TREE_SCALE; glm::quat refInvRot = glm::inverse(_refRotation); _scale = _avatar->getTargetScale() / _refScale; @@ -39,6 +41,7 @@ _tree(tree) void ModelReferential::update() { const ModelItem* item = _tree->findModelByID(_modelID); if (!_isValid || item == NULL || _avatar == NULL) { + qDebug() << "Not Valid"; _isValid = false; return; } @@ -51,36 +54,71 @@ void ModelReferential::update() { } if (item->getModelRotation() != _refRotation) { _refRotation = item->getModelRotation(); - _avatar->setOrientation(_refRotation * _rotation); + _avatar->setOrientation(_refRotation);// * _rotation); somethingChanged = true; } if (item->getPosition() != _refPosition || somethingChanged) { _refPosition = item->getPosition(); - _avatar->setPosition(_refPosition + _refRotation * (_translation * _refScale)); + _avatar->setPosition(_refPosition * (float)TREE_SCALE);// + _refRotation * (_translation * _refScale)); + //qDebug() << "Ref: " << item->getLastUpdated() << " " << item->getLastEdited(); somethingChanged = true; } } -JointReferential::JointReferential(uint32_t jointID, uint32_t modelID, ModelTree* tree, AvatarData* avatar) : +int ModelReferential::packReferential(unsigned char* destinationBuffer) { + int size = packPosition(destinationBuffer); + memcpy(destinationBuffer, &_modelID, sizeof(_modelID)); + return size + sizeof(_modelID); +} + +JointReferential::JointReferential(uint32_t jointIndex, uint32_t modelID, ModelTree* tree, AvatarData* avatar) : ModelReferential(modelID, tree, avatar), - _jointID(jointID) + _jointIndex(jointIndex) { - const Model* model = getModel(_tree->findModelByID(_modelID)); - - if (!_isValid || model == NULL || model->getJointStateCount() <= jointID) { + _type = JOINT; + const ModelItem* item = _tree->findModelByID(_modelID); + const Model* model = getModel(item); + if (!_isValid || model == NULL || _jointIndex >= model->getJointStateCount()) { + qDebug() << "Not Validd"; _isValid = false; return; } + + _refScale = item->getRadius(); + model->getJointRotationInWorldFrame(_jointIndex, _refRotation); + model->getJointPositionInWorldFrame(_jointIndex, _refPosition); + + glm::quat refInvRot = glm::inverse(_refRotation); + _scale = _avatar->getTargetScale() / _refScale; + _rotation = refInvRot * _avatar->getOrientation(); + _translation = refInvRot * (avatar->getPosition() - _refPosition) / _refScale; } void JointReferential::update() { const ModelItem* item = _tree->findModelByID(_modelID); - if (!_isValid || item == NULL) { + const Model* model = getModel(item); + if (!_isValid || model == NULL || _jointIndex >= model->getJointStateCount()) { + qDebug() << "Not Valid"; _isValid = false; return; } - + bool somethingChanged = false; + if (item->getRadius() != _refScale) { + _refScale = item->getRadius(); + _avatar->setTargetScale(_refScale * _scale); + somethingChanged = true; + } + if (item->getModelRotation() != _refRotation) { + model->getJointRotationInWorldFrame(_jointIndex, _refRotation); + _avatar->setOrientation(_refRotation * _rotation); + somethingChanged = true; + } + if (item->getPosition() != _refPosition || somethingChanged) { + model->getJointPositionInWorldFrame(_jointIndex, _refPosition); + _avatar->setPosition(_refPosition + _refRotation * (_translation * _refScale)); + somethingChanged = true; + } } const Model* JointReferential::getModel(const ModelItem* item) { @@ -88,6 +126,7 @@ const Model* JointReferential::getModel(const ModelItem* item) { if (item != NULL && fbxService != NULL) { return fbxService->getModelForModelItem(*item); } + qDebug() << "No Model"; return NULL; } diff --git a/interface/src/avatar/ModelReferential.h b/interface/src/avatar/ModelReferential.h index 8f9333451a..5b0c92c767 100644 --- a/interface/src/avatar/ModelReferential.h +++ b/interface/src/avatar/ModelReferential.h @@ -19,6 +19,7 @@ class Model; class ModelReferential : public Referential { public: + ModelReferential(Referential* ref); ModelReferential(uint32_t modelID, ModelTree* tree, AvatarData* avatar); virtual void update(); @@ -29,13 +30,14 @@ protected: class JointReferential : public ModelReferential { public: - JointReferential(uint32_t jointID, uint32_t modelID, ModelTree* tree, AvatarData* avatar); + JointReferential(Referential* ref); + JointReferential(uint32_t jointIndex, uint32_t modelID, ModelTree* tree, AvatarData* avatar); virtual void update(); protected: const Model* getModel(const ModelItem* item); - uint32_t _jointID; + uint32_t _jointIndex; }; #endif // hifi_ModelReferential_h \ No newline at end of file diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9126f680b8..92f0a82cd9 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -32,6 +32,7 @@ #include "Audio.h" #include "Environment.h" #include "Menu.h" +#include "ModelReferential.h" #include "MyAvatar.h" #include "Physics.h" #include "devices/Faceshift.h" @@ -126,6 +127,18 @@ void MyAvatar::update(float deltaTime) { } simulate(deltaTime); + + + const ModelItem* item = Application::getInstance()->getModels()->getTree()->findModelByID(278); + if (_referential) { + PerformanceTimer perfTimer("Referential"); + _referential->update(); + } else if (item != NULL) { + const Model* model = Application::getInstance()->getModels()->getModelForModelItem(*item); + if (model != NULL) { + _referential = new ModelReferential(278, Application::getInstance()->getModels()->getTree(), this); + } + } } void MyAvatar::simulate(float deltaTime) { From a0886d430127995329160b6416200f5b4da06a87 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 31 Jul 2014 11:55:52 -0700 Subject: [PATCH 131/407] Use raw OpenGL textures rather than QOpenGLTexture, since that we're having issues with constants in that class. --- interface/src/MetavoxelSystem.cpp | 79 ++++++++++++++++--------------- interface/src/MetavoxelSystem.h | 15 ++---- 2 files changed, 44 insertions(+), 50 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 16ce98c65c..cff5497183 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -29,7 +29,6 @@ REGISTER_META_OBJECT(DefaultMetavoxelRendererImplementation) REGISTER_META_OBJECT(SphereRenderer) REGISTER_META_OBJECT(StaticModelRenderer) -static int texturePointerMetaTypeId = qRegisterMetaType(); static int bufferPointVectorMetaTypeId = qRegisterMetaType(); void MetavoxelSystem::init() { @@ -113,9 +112,9 @@ void MetavoxelSystem::render() { guideToAugmented(renderVisitor); } -void MetavoxelSystem::deleteTextures(const TexturePointer& height, const TexturePointer& color) { - delete height; - delete color; +void MetavoxelSystem::deleteTextures(int heightID, int colorID) { + glDeleteTextures(1, (GLuint*)&heightID); + glDeleteTextures(1, (GLuint*)&colorID); } MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) { @@ -267,18 +266,19 @@ HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale, _height(height), _color(color), _clearAfterLoading(clearAfterLoading), - _heightTexture(new QOpenGLTexture(QOpenGLTexture::Target2D)), - _colorTexture(new QOpenGLTexture(QOpenGLTexture::Target2D)) { + _heightTextureID(0), + _colorTextureID(0), + _heightSize(glm::sqrt(height.size())) { } HeightfieldBuffer::~HeightfieldBuffer() { // the textures have to be deleted on the main thread (for its opengl context) if (QThread::currentThread() != Application::getInstance()->thread()) { QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "deleteTextures", - Q_ARG(const TexturePointer&, _heightTexture), Q_ARG(const TexturePointer&, _colorTexture)); + Q_ARG(int, _heightTextureID), Q_ARG(int, _colorTextureID)); } else { - delete _heightTexture; - delete _colorTexture; + glDeleteTextures(1, &_heightTextureID); + glDeleteTextures(1, &_colorTextureID); } } @@ -290,49 +290,46 @@ public: void HeightfieldBuffer::render() { // initialize textures, etc. on first render - if (!_heightTexture->isCreated()) { - int heightSize = glm::sqrt(_height.size()); - _heightTexture->setSize(heightSize, heightSize); - _heightTexture->setAutoMipMapGenerationEnabled(false); - _heightTexture->setMinificationFilter(QOpenGLTexture::Linear); - _heightTexture->setWrapMode(QOpenGLTexture::ClampToEdge); - _heightTexture->setFormat(QOpenGLTexture::LuminanceFormat); - _heightTexture->allocateStorage(); - _heightTexture->setData(QOpenGLTexture::Luminance, QOpenGLTexture::UInt8, _height.data()); + if (_heightTextureID == 0) { + glGenTextures(1, &_heightTextureID); + glBindTexture(GL_TEXTURE_2D, _heightTextureID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, _heightSize, _heightSize, 0, + GL_LUMINANCE, GL_UNSIGNED_BYTE, _height.constData()); if (_clearAfterLoading) { _height.clear(); } - if (!_color.isEmpty()) { + + glGenTextures(1, &_colorTextureID); + glBindTexture(GL_TEXTURE_2D, _colorTextureID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (_color.isEmpty()) { + const quint8 WHITE_COLOR[] = { 255, 255, 255 }; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, WHITE_COLOR); + + } else { int colorSize = glm::sqrt(_color.size() / 3); - _colorTexture->setSize(colorSize, colorSize); - } - _colorTexture->setAutoMipMapGenerationEnabled(false); - _colorTexture->setMinificationFilter(QOpenGLTexture::Linear); - _colorTexture->setWrapMode(QOpenGLTexture::ClampToEdge); - _colorTexture->setFormat(QOpenGLTexture::RGBFormat); - _colorTexture->allocateStorage(); - if (!_color.isEmpty()) { - _colorTexture->setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, _color.data()); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, colorSize, colorSize, 0, GL_RGB, GL_UNSIGNED_BYTE, _color.constData()); if (_clearAfterLoading) { _color.clear(); } - } else { - const quint8 WHITE_COLOR[] = { 255, 255, 255 }; - _colorTexture->setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, const_cast(WHITE_COLOR)); } } // create the buffer objects lazily - int size = _heightTexture->width(); - int sizeWithSkirt = size + 2; + int sizeWithSkirt = _heightSize + 2; int vertexCount = sizeWithSkirt * sizeWithSkirt; int rows = sizeWithSkirt - 1; int indexCount = rows * rows * 4; - BufferPair& bufferPair = _bufferPairs[size]; + BufferPair& bufferPair = _bufferPairs[_heightSize]; if (!bufferPair.first.isCreated()) { QVector vertices(vertexCount); HeightfieldPoint* point = vertices.data(); - float step = 1.0f / (size - 1); + float step = 1.0f / (_heightSize - 1); float z = -step; for (int i = 0; i < sizeWithSkirt; i++, z += step) { float x = -step; @@ -380,13 +377,17 @@ void HeightfieldBuffer::render() { glTranslatef(_translation.x, _translation.y, _translation.z); glScalef(_scale, _scale, _scale); - _heightTexture->bind(0); - _colorTexture->bind(1); + glBindTexture(GL_TEXTURE_2D, _heightTextureID); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, _colorTextureID); glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); - _colorTexture->release(1); - _heightTexture->release(0); + glBindTexture(GL_TEXTURE_2D, 0); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, 0); glPopMatrix(); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 2258be6e87..bd05fc0f67 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -12,12 +12,8 @@ #ifndef hifi_MetavoxelSystem_h #define hifi_MetavoxelSystem_h -// include this before QOpenGLTexture, which includes an earlier version of OpenGL -#include "InterfaceConfig.h" - #include #include -#include #include #include @@ -29,8 +25,6 @@ class Model; -typedef QOpenGLTexture* TexturePointer; - /// Renders a metavoxel tree. class MetavoxelSystem : public MetavoxelClientManager { Q_OBJECT @@ -47,7 +41,7 @@ public: void simulate(float deltaTime); void render(); - Q_INVOKABLE void deleteTextures(const TexturePointer& height, const TexturePointer& color); + Q_INVOKABLE void deleteTextures(int heightID, int colorID); protected: @@ -64,8 +58,6 @@ private: QReadWriteLock _lodLock; }; -Q_DECLARE_METATYPE(TexturePointer) - /// Describes contents of a point in a point buffer. class BufferPoint { public: @@ -154,8 +146,9 @@ private: QByteArray _height; QByteArray _color; bool _clearAfterLoading; - TexturePointer _heightTexture; - TexturePointer _colorTexture; + GLuint _heightTextureID; + GLuint _colorTextureID; + int _heightSize; typedef QPair BufferPair; static QHash _bufferPairs; From 0b9f246661878b68681b0a3cf622eec0669b0496 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 31 Jul 2014 13:08:27 -0700 Subject: [PATCH 132/407] set the shape ID in the ctor's NOT the dtor --- libraries/shared/src/Shape.h | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/libraries/shared/src/Shape.h b/libraries/shared/src/Shape.h index 197bc912aa..b1efe6d9ce 100644 --- a/libraries/shared/src/Shape.h +++ b/libraries/shared/src/Shape.h @@ -32,8 +32,11 @@ public: LIST_SHAPE }; - Shape() : _type(UNKNOWN_SHAPE), _owningEntity(NULL), _boundingRadius(0.f), _translation(0.f), _rotation(), _mass(MAX_SHAPE_MASS) { } - virtual ~Shape() { _id = getNextID(); } + Shape() : _type(UNKNOWN_SHAPE), _owningEntity(NULL), _boundingRadius(0.f), + _translation(0.f), _rotation(), _mass(MAX_SHAPE_MASS) { + _id = getNextID(); + } + virtual ~Shape() { } int getType() const { return _type; } quint32 getID() const { return _id; } @@ -72,13 +75,19 @@ public: protected: // these ctors are protected (used by derived classes only) - Shape(Type type) : _type(type), _owningEntity(NULL), _boundingRadius(0.f), _translation(0.f), _rotation() {} + Shape(Type type) : _type(type), _owningEntity(NULL), _boundingRadius(0.f), _translation(0.f), _rotation() { + _id = getNextID(); + } Shape(Type type, const glm::vec3& position) - : _type(type), _owningEntity(NULL), _boundingRadius(0.f), _translation(position), _rotation() {} + : _type(type), _owningEntity(NULL), _boundingRadius(0.f), _translation(position), _rotation() { + _id = getNextID(); + } Shape(Type type, const glm::vec3& position, const glm::quat& rotation) - : _type(type), _owningEntity(NULL), _boundingRadius(0.f), _translation(position), _rotation(rotation) {} + : _type(type), _owningEntity(NULL), _boundingRadius(0.f), _translation(position), _rotation(rotation) { + _id = getNextID(); + } void setBoundingRadius(float radius) { _boundingRadius = radius; } From 0f82236f2c981af25f8286f0619f76aa9cf25758 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 31 Jul 2014 13:09:10 -0700 Subject: [PATCH 133/407] minor cleanup --- libraries/shared/src/VerletCapsuleShape.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/libraries/shared/src/VerletCapsuleShape.cpp b/libraries/shared/src/VerletCapsuleShape.cpp index 6a145b4924..ab956264b5 100644 --- a/libraries/shared/src/VerletCapsuleShape.cpp +++ b/libraries/shared/src/VerletCapsuleShape.cpp @@ -90,11 +90,9 @@ float VerletCapsuleShape::computeEffectiveMass(const glm::vec3& penetration, con // one endpoint will move the full amount while the other will move less. _startLagrangeCoef = startCoef / maxCoef; _endLagrangeCoef = endCoef / maxCoef; - assert(!glm::isnan(_startLagrangeCoef)); - assert(!glm::isnan(_endLagrangeCoef)); } else { // The coefficients are the same --> the collision will move both equally - // as if the object were solid. + // as if the contact were at the center of mass. _startLagrangeCoef = 1.0f; _endLagrangeCoef = 1.0f; } @@ -104,8 +102,8 @@ float VerletCapsuleShape::computeEffectiveMass(const glm::vec3& penetration, con void VerletCapsuleShape::accumulateDelta(float relativeMassFactor, const glm::vec3& penetration) { assert(!glm::isnan(relativeMassFactor)); - _startPoint->accumulateDelta(relativeMassFactor * _startLagrangeCoef * penetration); - _endPoint->accumulateDelta(relativeMassFactor * _endLagrangeCoef * penetration); + _startPoint->accumulateDelta((relativeMassFactor * _startLagrangeCoef) * penetration); + _endPoint->accumulateDelta((relativeMassFactor * _endLagrangeCoef) * penetration); } void VerletCapsuleShape::applyAccumulatedDelta() { From fc1d805d54dec0bd16bb6fae49e9725b193ef14b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 31 Jul 2014 13:16:06 -0700 Subject: [PATCH 134/407] add ContactConstraint and use to impede muscles --- libraries/shared/src/ContactConstraint.cpp | 83 ++++++++++++++++ libraries/shared/src/ContactConstraint.h | 44 +++++++++ libraries/shared/src/PhysicsSimulation.cpp | 104 +++++++++++++++++---- libraries/shared/src/PhysicsSimulation.h | 23 +++-- 4 files changed, 225 insertions(+), 29 deletions(-) create mode 100644 libraries/shared/src/ContactConstraint.cpp create mode 100644 libraries/shared/src/ContactConstraint.h diff --git a/libraries/shared/src/ContactConstraint.cpp b/libraries/shared/src/ContactConstraint.cpp new file mode 100644 index 0000000000..65633788be --- /dev/null +++ b/libraries/shared/src/ContactConstraint.cpp @@ -0,0 +1,83 @@ +// +// ContactConstraint.cpp +// libraries/shared/src +// +// Created by Andrew Meadows 2014.07.30 +// 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 +// + +#include "ContactConstraint.h" +#include "Shape.h" +#include "SharedUtil.h" + +ContactConstraint::ContactConstraint() : _lastFrame(0), _shapeA(NULL), _shapeB(NULL), + _offsetA(0.0f), _offsetB(0.0f), _normal(0.0f) { +} + +ContactConstraint::ContactConstraint(const CollisionInfo& collision, quint32 frame) : _lastFrame(frame), + _shapeA(collision.getShapeA()), _shapeB(collision.getShapeB()), _offsetA(0.0f), _offsetB(0.0f), _normal(0.0f) { + + _offsetA = collision._contactPoint - _shapeA->getTranslation(); + _offsetB = collision._contactPoint - collision._penetration - _shapeB->getTranslation(); + float pLength = glm::length(collision._penetration); + if (pLength > EPSILON) { + _normal = collision._penetration / pLength; + } + + if (_shapeA->getID() > _shapeB->getID()) { + // swap so that _shapeA always has lower ID + _shapeA = collision.getShapeB(); + _shapeB = collision.getShapeA(); + + glm::vec3 temp = _offsetA; + _offsetA = _offsetB; + _offsetB = temp; + _normal = - _normal; + } +} + +// virtual +float ContactConstraint::enforce() { + glm::vec3 pointA = _shapeA->getTranslation() + _offsetA; + glm::vec3 pointB = _shapeB->getTranslation() + _offsetB; + glm::vec3 penetration = pointA - pointB; + if (glm::dot(penetration, _normal) > EPSILON) { + // NOTE: Shape::computeEffectiveMass() has side effects: computes and caches partial Lagrangian coefficients + // which are then used in the accumulateDelta() calls below. + float massA = _shapeA->computeEffectiveMass(penetration, pointA); + float massB = _shapeB->computeEffectiveMass(-penetration, pointB); + float totalMass = massA + massB; + if (totalMass < EPSILON) { + massA = massB = 1.0f; + totalMass = 2.0f; + } + // NOTE: Shape::accumulateDelta() uses the coefficients from previous call to Shape::computeEffectiveMass() + // and remember that penetration points from A into B + _shapeA->accumulateDelta(0.99f * massB / totalMass, -penetration); + _shapeB->accumulateDelta(0.99f * massA / totalMass, penetration); + return glm::length(penetration); + } + return 0.0f; +} + +void ContactConstraint::updateContact(const CollisionInfo& collision, quint32 frame) { + _lastFrame = frame; + _offsetA = collision._contactPoint - collision._shapeA->getTranslation(); + _offsetB = collision._contactPoint - collision._penetration - collision._shapeB->getTranslation(); + float pLength = glm::length(collision._penetration); + if (pLength > EPSILON) { + _normal = collision._penetration / pLength; + } else { + _normal = glm::vec3(0.0f); + } + if (collision._shapeA->getID() > collision._shapeB->getID()) { + // our _shapeA always has lower ID + glm::vec3 temp = _offsetA; + _offsetA = _offsetB; + _offsetB = temp; + _normal = - _normal; + } +} diff --git a/libraries/shared/src/ContactConstraint.h b/libraries/shared/src/ContactConstraint.h new file mode 100644 index 0000000000..1c8b7d1b57 --- /dev/null +++ b/libraries/shared/src/ContactConstraint.h @@ -0,0 +1,44 @@ +// +// ContactConstraint.h +// libraries/shared/src +// +// Created by Andrew Meadows 2014.07.30 +// 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 +// + +#ifndef hifi_ContactConstraint_h +#define hifi_ContactConstraint_h + +#include +#include + +#include "CollisionInfo.h" + +class Shape; + +class ContactConstraint { +public: + ContactConstraint(); + ContactConstraint(const CollisionInfo& collision, quint32 frame); + + virtual float enforce(); + + void updateContact(const CollisionInfo& collision, quint32 frame); + quint32 getLastFrame() const { return _lastFrame; } + + Shape* getShapeA() const { return _shapeA; } + Shape* getShapeB() const { return _shapeB; } + +protected: + quint32 _lastFrame; // frame count of last update + Shape* _shapeA; + Shape* _shapeB; + glm::vec3 _offsetA; // contact point relative to A's center + glm::vec3 _offsetB; // contact point relative to B's center + glm::vec3 _normal; // (points from A toward B) +}; + +#endif // hifi_ContactConstraint_h diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index ad52948670..93b5b2eef2 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -25,8 +25,7 @@ int MAX_ENTITIES_PER_SIMULATION = 64; int MAX_COLLISIONS_PER_SIMULATION = 256; -PhysicsSimulation::PhysicsSimulation() : _collisionList(MAX_COLLISIONS_PER_SIMULATION), - _frame(0), _numIterations(0), _numCollisions(0), _constraintError(0.0f), _stepTime(0) { +PhysicsSimulation::PhysicsSimulation() : _frame(0), _collisions(MAX_COLLISIONS_PER_SIMULATION) { } PhysicsSimulation::~PhysicsSimulation() { @@ -88,6 +87,15 @@ void PhysicsSimulation::removeEntity(PhysicsEntity* entity) { break; } } + // remove corresponding contacts + QMap::iterator itr = _contacts.begin(); + while (itr != _contacts.end()) { + if (entity == itr.value().getShapeA()->getEntity() || entity == itr.value().getShapeB()->getEntity()) { + itr = _contacts.erase(itr); + } else { + ++itr; + } + } } bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { @@ -135,14 +143,19 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter quint64 expiry = startTime + maxUsec; moveRagdolls(deltaTime); - + computeCollisions(); + enforceContacts(); int numDolls = _dolls.size(); - _numCollisions = 0; + for (int i = 0; i < numDolls; ++i) { + _dolls[i]->enforceRagdollConstraints(); + } + int iterations = 0; float error = 0.0f; do { computeCollisions(); - processCollisions(); + updateContacts(); + resolveCollisions(); { // enforce constraints PerformanceTimer perfTimer("4-enforce"); @@ -154,19 +167,17 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter ++iterations; now = usecTimestampNow(); - } while (_numCollisions != 0 && (iterations < maxIterations) && (error > minError) && (now < expiry)); + } while (_collisions.size() != 0 && (iterations < maxIterations) && (error > minError) && (now < expiry)); - _numIterations = iterations; - _constraintError = error; - _stepTime = usecTimestampNow()- startTime; #ifdef ANDREW_DEBUG + quint64 stepTime = usecTimestampNow()- startTime; // temporary debug info for watching simulation performance - static int adebug = 0; ++adebug; - if (0 == (adebug % 100)) { - std::cout << "adebug Ni = " << _numIterations << " E = " << error << " t = " << _stepTime << std::endl; // adebug + if (0 == (_frame % 100)) { + std::cout << "Ni = " << iterations << " E = " << error << " t = " << stepTime << std::endl; } #endif // ANDREW_DEBUG + pruneContacts(); } void PhysicsSimulation::moveRagdolls(float deltaTime) { @@ -179,7 +190,7 @@ void PhysicsSimulation::moveRagdolls(float deltaTime) { void PhysicsSimulation::computeCollisions() { PerformanceTimer perfTimer("2-collide"); - _collisionList.clear(); + _collisions.clear(); // TODO: keep track of QSet collidedEntities; int numEntities = _entities.size(); for (int i = 0; i < numEntities; ++i) { @@ -195,7 +206,7 @@ void PhysicsSimulation::computeCollisions() { for (int k = j+1; k < numShapes; ++k) { const Shape* otherShape = shapes.at(k); if (otherShape && entity->collisionsAreEnabled(j, k)) { - ShapeCollider::collideShapes(shape, otherShape, _collisionList); + ShapeCollider::collideShapes(shape, otherShape, _collisions); } } } @@ -203,19 +214,18 @@ void PhysicsSimulation::computeCollisions() { // collide with others for (int j = i+1; j < numEntities; ++j) { const QVector otherShapes = _entities.at(j)->getShapes(); - ShapeCollider::collideShapesWithShapes(shapes, otherShapes, _collisionList); + ShapeCollider::collideShapesWithShapes(shapes, otherShapes, _collisions); } } - _numCollisions = _collisionList.size(); } -void PhysicsSimulation::processCollisions() { +void PhysicsSimulation::resolveCollisions() { PerformanceTimer perfTimer("3-resolve"); // walk all collisions, accumulate movement on shapes, and build a list of affected shapes QSet shapes; - int numCollisions = _collisionList.size(); + int numCollisions = _collisions.size(); for (int i = 0; i < numCollisions; ++i) { - CollisionInfo* collision = _collisionList.getCollision(i); + CollisionInfo* collision = _collisions.getCollision(i); collision->apply(); // there is always a shapeA shapes.insert(collision->getShapeA()); @@ -231,3 +241,59 @@ void PhysicsSimulation::processCollisions() { ++shapeItr; } } + +void PhysicsSimulation::enforceContacts() { + QSet shapes; + int numCollisions = _collisions.size(); + for (int i = 0; i < numCollisions; ++i) { + CollisionInfo* collision = _collisions.getCollision(i); + quint64 key = collision->getShapePairKey(); + if (key == 0) { + continue; + } + QMap::iterator itr = _contacts.find(key); + if (itr != _contacts.end()) { + if (itr.value().enforce() > 0.0f) { + shapes.insert(collision->getShapeA()); + shapes.insert(collision->getShapeB()); + } + } + } + // walk all affected shapes and apply accumulated movement + QSet::const_iterator shapeItr = shapes.constBegin(); + while (shapeItr != shapes.constEnd()) { + (*shapeItr)->applyAccumulatedDelta(); + ++shapeItr; + } +} + +void PhysicsSimulation::updateContacts() { + PerformanceTimer perfTimer("3.5-updateContacts"); + int numCollisions = _collisions.size(); + for (int i = 0; i < numCollisions; ++i) { + CollisionInfo* collision = _collisions.getCollision(i); + quint64 key = collision->getShapePairKey(); + if (key == 0) { + continue; + } + QMap::iterator itr = _contacts.find(key); + if (itr == _contacts.end()) { + _contacts.insert(key, ContactConstraint(*collision, _frame)); + } else { + itr.value().updateContact(*collision, _frame); + } + } +} + +const quint32 MAX_CONTACT_FRAME_LIFETIME = 2; + +void PhysicsSimulation::pruneContacts() { + QMap::iterator itr = _contacts.begin(); + while (itr != _contacts.end()) { + if (_frame - itr.value().getLastFrame() > MAX_CONTACT_FRAME_LIFETIME) { + itr = _contacts.erase(itr); + } else { + ++itr; + } + } +} diff --git a/libraries/shared/src/PhysicsSimulation.h b/libraries/shared/src/PhysicsSimulation.h index efd4c543c2..6e69e72219 100644 --- a/libraries/shared/src/PhysicsSimulation.h +++ b/libraries/shared/src/PhysicsSimulation.h @@ -13,9 +13,11 @@ #define hifi_PhysicsSimulation #include +#include #include #include "CollisionInfo.h" +#include "ContactConstraint.h" class PhysicsEntity; class Ragdoll; @@ -42,21 +44,22 @@ public: /// \return distance of largest movement void stepForward(float deltaTime, float minError, int maxIterations, quint64 maxUsec); +protected: void moveRagdolls(float deltaTime); void computeCollisions(); - void processCollisions(); + void resolveCollisions(); + + void enforceContacts(); + void updateContacts(); + void pruneContacts(); private: - CollisionList _collisionList; - QVector _entities; - QVector _dolls; - - // some stats quint32 _frame; - int _numIterations; - int _numCollisions; - float _constraintError; - quint64 _stepTime; + + QVector _dolls; + QVector _entities; + CollisionList _collisions; + QMap _contacts; }; #endif // hifi_PhysicsSimulation From 9d2744296e1627f3178f9e1ddddfa7b71371e18f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 31 Jul 2014 13:33:46 -0700 Subject: [PATCH 135/407] update physics stats names --- libraries/shared/src/PhysicsSimulation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index 93b5b2eef2..3e3529be10 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -158,7 +158,7 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter resolveCollisions(); { // enforce constraints - PerformanceTimer perfTimer("4-enforce"); + PerformanceTimer perfTimer("5-enforce"); error = 0.0f; for (int i = 0; i < numDolls; ++i) { error = glm::max(error, _dolls[i]->enforceRagdollConstraints()); @@ -220,7 +220,7 @@ void PhysicsSimulation::computeCollisions() { } void PhysicsSimulation::resolveCollisions() { - PerformanceTimer perfTimer("3-resolve"); + PerformanceTimer perfTimer("4-resolve"); // walk all collisions, accumulate movement on shapes, and build a list of affected shapes QSet shapes; int numCollisions = _collisions.size(); @@ -268,7 +268,7 @@ void PhysicsSimulation::enforceContacts() { } void PhysicsSimulation::updateContacts() { - PerformanceTimer perfTimer("3.5-updateContacts"); + PerformanceTimer perfTimer("3-updateContacts"); int numCollisions = _collisions.size(); for (int i = 0; i < numCollisions; ++i) { CollisionInfo* collision = _collisions.getCollision(i); From e6571d334afa4cd7ec149bd01658dd3b131f711f Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 31 Jul 2014 22:37:02 +0200 Subject: [PATCH 136/407] Oculus SDK 0.4 support for Windows (tested with DK2 HMD) --- interface/src/devices/OculusManager.cpp | 52 +++++++++++++++++++++---- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 49164cc8dd..0ffc7f405f 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -44,7 +44,7 @@ ovrFovPort OculusManager::_eyeFov[ovrEye_Count]; ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count]; ovrSizei OculusManager::_renderTargetSize; ovrVector2f OculusManager::_UVScaleOffset[ovrEye_Count][2]; -GLuint OculusManager::_vertices[ovrEye_Count] = { 0, 0 }; +GLuint OculusManager::_vertices[ovrEye_Count] = { 0, 0 }; GLuint OculusManager::_indices[ovrEye_Count] = { 0, 0 }; GLsizei OculusManager::_meshSize[ovrEye_Count] = { 0, 0 }; ovrFrameTiming OculusManager::_hmdFrameTiming; @@ -66,12 +66,13 @@ void OculusManager::connect() { UserActivityLogger::getInstance().connectedDevice("hmd", "oculus"); } _isConnected = true; - - ovrHmd_GetDesc(_ovrHmd, &_ovrHmdDesc); - +#ifdef _WIN32 + _eyeFov[0] = _ovrHmd->DefaultEyeFov[0]; + _eyeFov[1] = _ovrHmd->DefaultEyeFov[1]; +#else _eyeFov[0] = _ovrHmdDesc.DefaultEyeFov[0]; _eyeFov[1] = _ovrHmdDesc.DefaultEyeFov[1]; - +#endif //Get texture size ovrSizei recommendedTex0Size = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, _eyeFov[0], 1.0f); @@ -86,11 +87,21 @@ void OculusManager::connect() { _eyeRenderDesc[0] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Left, _eyeFov[0]); _eyeRenderDesc[1] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Right, _eyeFov[1]); +#ifdef _WIN32 + ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence); +#else ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_LatencyTest); +#endif +#ifdef _WIN32 + ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | + ovrTrackingCap_MagYawCorrection, + ovrTrackingCap_Orientation); +#else ovrHmd_StartSensor(_ovrHmd, ovrSensorCap_Orientation | ovrSensorCap_YawCorrection | ovrSensorCap_Position, ovrSensorCap_Orientation); +#endif if (!_camera) { _camera = new Camera; @@ -183,6 +194,16 @@ void OculusManager::generateDistortionMesh() { DistortionVertex* v = pVBVerts; ovrDistortionVertex* ov = meshData.pVertexData; for (unsigned int vertNum = 0; vertNum < meshData.VertexCount; vertNum++) { +#ifdef _WIN32 + v->pos.x = ov->ScreenPosNDC.x; + v->pos.y = ov->ScreenPosNDC.y; + v->texR.x = ov->TanEyeAnglesR.x; + v->texR.y = ov->TanEyeAnglesR.y; + v->texG.x = ov->TanEyeAnglesG.x; + v->texG.y = ov->TanEyeAnglesG.y; + v->texB.x = ov->TanEyeAnglesB.x; + v->texB.y = ov->TanEyeAnglesB.y; +#else v->pos.x = ov->Pos.x; v->pos.y = ov->Pos.y; v->texR.x = ov->TexR.x; @@ -191,6 +212,7 @@ void OculusManager::generateDistortionMesh() { v->texG.y = ov->TexG.y; v->texB.x = ov->TexB.x; v->texB.y = ov->TexB.y; +#endif v->color.r = v->color.g = v->color.b = (GLubyte)(ov->VignetteFactor * 255.99f); v->color.a = (GLubyte)(ov->TimeWarpFactor * 255.99f); v++; @@ -294,9 +316,11 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p //Render each eye into an fbo for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) { - +#ifdef _WIN32 + ovrEyeType eye = _ovrHmd->EyeRenderOrder[eyeIndex]; +#else ovrEyeType eye = _ovrHmdDesc.EyeRenderOrder[eyeIndex]; - +#endif //Set the camera rotation for this eye eyeRenderPose[eye] = ovrHmd_GetEyePose(_ovrHmd, eye); orientation.x = eyeRenderPose[eye].Orientation.x; @@ -433,10 +457,22 @@ void OculusManager::reset() { //Gets the current predicted angles from the oculus sensors void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { #ifdef HAVE_LIBOVR +#ifdef _WIN32 + ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); +#else ovrSensorState ss = ovrHmd_GetSensorState(_ovrHmd, _hmdFrameTiming.ScanoutMidpointSeconds); - +#endif +#ifdef _WIN32 + if (ts.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { +#else if (ss.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { +#endif + +#ifdef _WIN32 + ovrPosef pose = ts.CameraPose; +#else ovrPosef pose = ss.Predicted.Pose; +#endif Quatf orientation = Quatf(pose.Orientation); orientation.GetEulerAngles(&yaw, &pitch, &roll); } else { From 11b1425196da577227ca8766c5c6d59664f7581b Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 31 Jul 2014 22:51:23 +0200 Subject: [PATCH 137/407] Windows requires ws2_32.lib for LIBOVR 0.4 --- interface/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 7336b55852..d3c204a021 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -258,5 +258,8 @@ else (APPLE) add_definitions(-Dssize_t=long) target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" wsock32.lib opengl32.lib) + if (LIBOVR_FOUND) + target_link_libraries(${TARGET_NAME} ws2_32.lib) + endif() endif() endif (APPLE) From fe3f1dbe837b47fecfca5545cc8832a11fa04e7b Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 31 Jul 2014 22:56:47 +0200 Subject: [PATCH 138/407] forgot to put back one line of code --- interface/src/devices/OculusManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 0ffc7f405f..ab30ee7c8b 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -70,6 +70,7 @@ void OculusManager::connect() { _eyeFov[0] = _ovrHmd->DefaultEyeFov[0]; _eyeFov[1] = _ovrHmd->DefaultEyeFov[1]; #else + ovrHmd_GetDesc(_ovrHmd, &_ovrHmdDesc); _eyeFov[0] = _ovrHmdDesc.DefaultEyeFov[0]; _eyeFov[1] = _ovrHmdDesc.DefaultEyeFov[1]; #endif From adcf45583e38e95a9f28f3d9937b72990257f6fb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 31 Jul 2014 14:06:43 -0700 Subject: [PATCH 139/407] clear domain settings on NodeList reset --- libraries/networking/src/DomainHandler.cpp | 1 + libraries/networking/src/NodeList.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 786726b745..74bb411845 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -130,6 +130,7 @@ void DomainHandler::setIsConnected(bool isConnected) { } void DomainHandler::requestDomainSettings() const { + qDebug() << _settingsObject; if (_settingsObject.isEmpty()) { // setup the URL required to grab settings JSON QUrl settingsJSONURL; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index b872ec12cf..8db8232516 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -179,6 +179,7 @@ void NodeList::reset() { // clear the domain connection information _domainHandler.clearConnectionInfo(); + _domainHandler.clearSettings(); // if we setup the DTLS socket, also disconnect from the DTLS socket readyRead() so it can handle handshaking if (_dtlsSocket) { From 8986e62b8a1dce2687855f47c829796562bfc8cd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 31 Jul 2014 14:08:25 -0700 Subject: [PATCH 140/407] add distinction between hard reset and soft reset for DomainHandler --- libraries/networking/src/DomainHandler.cpp | 10 +++++++--- libraries/networking/src/DomainHandler.h | 4 +++- libraries/networking/src/NodeList.cpp | 3 +-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 74bb411845..afe380528f 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -49,9 +49,13 @@ void DomainHandler::clearSettings() { _failedSettingsRequests = 0; } -void DomainHandler::reset() { +void DomainHandler::softReset() { clearConnectionInfo(); clearSettings(); +} + +void DomainHandler::hardReset() { + softReset(); _hostname = QString(); _sockAddr.setAddress(QHostAddress::Null); } @@ -59,7 +63,7 @@ void DomainHandler::reset() { void DomainHandler::setSockAddr(const HifiSockAddr& sockAddr, const QString& hostname) { if (_sockAddr != sockAddr) { // we should reset on a sockAddr change - reset(); + hardReset(); // change the sockAddr _sockAddr = sockAddr; } @@ -72,7 +76,7 @@ void DomainHandler::setHostname(const QString& hostname) { if (hostname != _hostname) { // re-set the domain info so that auth information is reloaded - reset(); + hardReset(); int colonIndex = hostname.indexOf(':'); diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index a2b8e2e307..28433c5455 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -62,6 +62,8 @@ public: void parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket); + void softReset(); + private slots: void completedHostnameLookup(const QHostInfo& hostInfo); void settingsRequestFinished(); @@ -73,7 +75,7 @@ signals: void settingsReceiveFail(); private: - void reset(); + void hardReset(); QUuid _uuid; QString _hostname; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 8db8232516..992a168244 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -178,8 +178,7 @@ void NodeList::reset() { setSessionUUID(QUuid()); // clear the domain connection information - _domainHandler.clearConnectionInfo(); - _domainHandler.clearSettings(); + _domainHandler.softReset(); // if we setup the DTLS socket, also disconnect from the DTLS socket readyRead() so it can handle handshaking if (_dtlsSocket) { From 6024b90932ac0bc24bf75345c48924d645016f4d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 31 Jul 2014 14:08:52 -0700 Subject: [PATCH 141/407] remove extra debug line --- libraries/networking/src/DomainHandler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index afe380528f..fcd284fd4a 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -134,7 +134,6 @@ void DomainHandler::setIsConnected(bool isConnected) { } void DomainHandler::requestDomainSettings() const { - qDebug() << _settingsObject; if (_settingsObject.isEmpty()) { // setup the URL required to grab settings JSON QUrl settingsJSONURL; From 2f0f5d2c28d470693171a333dc651631fa5f5371 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 31 Jul 2014 14:11:36 -0700 Subject: [PATCH 142/407] remove unused variable in VoxelEditPacketSender --- libraries/voxels/src/VoxelEditPacketSender.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index 3bb76d17fe..50d6617278 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -143,9 +143,7 @@ void VoxelEditPacketSender::queueVoxelEditMessages(PacketType type, int numberOf } } -qint64 VoxelEditPacketSender::satoshiCostForMessage(const VoxelDetail& details) { - const DomainHandler& domainHandler = NodeList::getInstance()->getDomainHandler(); - +qint64 VoxelEditPacketSender::satoshiCostForMessage(const VoxelDetail& details) { if (_satoshisPerVoxel == 0 && _satoshisPerMeterCubed == 0) { return 0; } else { From f0e7bf0462228dcc24605ab3723e1235edec4092 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 31 Jul 2014 15:13:33 -0700 Subject: [PATCH 143/407] allow assignments to pull script without session cookie --- domain-server/src/DomainServer.cpp | 65 +++++++++++++++--------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 2ea66c2ee3..e05025284b 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -952,6 +952,39 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url return true; } + // check if this is a request for a scripted assignment (with a temp unique UUID) + const QString ASSIGNMENT_REGEX_STRING = QString("\\%1\\/(%2)\\/?$").arg(URI_ASSIGNMENT).arg(UUID_REGEX_STRING); + QRegExp assignmentRegex(ASSIGNMENT_REGEX_STRING); + + if (connection->requestOperation() == QNetworkAccessManager::GetOperation + && assignmentRegex.indexIn(url.path()) != -1) { + QUuid matchingUUID = QUuid(assignmentRegex.cap(1)); + + SharedAssignmentPointer matchingAssignment = _allAssignments.value(matchingUUID); + if (!matchingAssignment) { + // check if we have a pending assignment that matches this temp UUID, and it is a scripted assignment + PendingAssignedNodeData* pendingData = _pendingAssignedNodes.value(matchingUUID); + if (pendingData) { + matchingAssignment = _allAssignments.value(pendingData->getAssignmentUUID()); + + if (matchingAssignment && matchingAssignment->getType() == Assignment::AgentType) { + // we have a matching assignment and it is for the right type, have the HTTP manager handle it + // via correct URL for the script so the client can download + + QUrl scriptURL = url; + scriptURL.setPath(URI_ASSIGNMENT + "/" + + uuidStringWithoutCurlyBraces(pendingData->getAssignmentUUID())); + + // have the HTTPManager serve the appropriate script file + return _httpManager.handleHTTPRequest(connection, scriptURL); + } + } + } + + // request not handled + return false; + } + if (connection->requestOperation() == QNetworkAccessManager::GetOperation) { if (url.path() == "/assignments.json") { // user is asking for json list of assignments @@ -1068,38 +1101,6 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url return false; } - - // check if this is a request for a scripted assignment (with a temp unique UUID) - const QString ASSIGNMENT_REGEX_STRING = QString("\\%1\\/(%2)\\/?$").arg(URI_ASSIGNMENT).arg(UUID_REGEX_STRING); - QRegExp assignmentRegex(ASSIGNMENT_REGEX_STRING); - - if (assignmentRegex.indexIn(url.path()) != -1) { - QUuid matchingUUID = QUuid(assignmentRegex.cap(1)); - - SharedAssignmentPointer matchingAssignment = _allAssignments.value(matchingUUID); - if (!matchingAssignment) { - // check if we have a pending assignment that matches this temp UUID, and it is a scripted assignment - PendingAssignedNodeData* pendingData = _pendingAssignedNodes.value(matchingUUID); - if (pendingData) { - matchingAssignment = _allAssignments.value(pendingData->getAssignmentUUID()); - - if (matchingAssignment && matchingAssignment->getType() == Assignment::AgentType) { - // we have a matching assignment and it is for the right type, have the HTTP manager handle it - // via correct URL for the script so the client can download - - QUrl scriptURL = url; - scriptURL.setPath(URI_ASSIGNMENT + "/" - + uuidStringWithoutCurlyBraces(pendingData->getAssignmentUUID())); - - // have the HTTPManager serve the appropriate script file - return _httpManager.handleHTTPRequest(connection, scriptURL); - } - } - } - - // request not handled - return false; - } } } else if (connection->requestOperation() == QNetworkAccessManager::PostOperation) { if (url.path() == URI_ASSIGNMENT) { From e846fd24f7f1cad2d9b80a9d9be2e11463ba6ff8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 31 Jul 2014 15:23:15 -0700 Subject: [PATCH 144/407] fix an order mistake in DS handling HTTP requests --- domain-server/src/DomainServer.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index e05025284b..2ecae73d0a 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -945,13 +945,6 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url return true; } - // all requests below require a cookie to prove authentication so check that first - if (!isAuthenticatedRequest(connection, url)) { - // this is not an authenticated request - // return true from the handler since it was handled with a 401 or re-direct to auth - return true; - } - // check if this is a request for a scripted assignment (with a temp unique UUID) const QString ASSIGNMENT_REGEX_STRING = QString("\\%1\\/(%2)\\/?$").arg(URI_ASSIGNMENT).arg(UUID_REGEX_STRING); QRegExp assignmentRegex(ASSIGNMENT_REGEX_STRING); @@ -985,6 +978,13 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url return false; } + // all requests below require a cookie to prove authentication so check that first + if (!isAuthenticatedRequest(connection, url)) { + // this is not an authenticated request + // return true from the handler since it was handled with a 401 or re-direct to auth + return true; + } + if (connection->requestOperation() == QNetworkAccessManager::GetOperation) { if (url.path() == "/assignments.json") { // user is asking for json list of assignments From 573ce7261b6a6291c03b6c0c23041a8762513224 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 31 Jul 2014 19:24:46 -0700 Subject: [PATCH 145/407] Add proper sending of ArrayBuffers via JavaScript XMLHttpRequest --- examples/editModels.js | 22 ++++++++----------- .../script-engine/src/XMLHttpRequestClass.cpp | 10 +++++---- .../script-engine/src/XMLHttpRequestClass.h | 2 +- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index f5183b16d6..b6d783700d 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -245,27 +245,23 @@ var httpMultiPart = (function () { function response() { var buffer, - view, - charCodes, + index, str, - i, - j; + i; str = crlf + boundaryString + "--\r\n"; buffer = str.toArrayBuffer(); byteLength += buffer.byteLength; parts.push(buffer); - str = ""; + buffer = new Uint8Array(byteLength); + index = 0; for (i = 0; i < parts.length; i += 1) { - charCodes = []; - view = new Uint8Array(parts[i]); - for (j = 0; j < view.length; j += 1) { - charCodes.push(view[j]); - } - str = str + String.fromCharCode.apply(String, charCodes); + buffer.set(new Uint8Array(parts[i]), index); + index += parts[i].byteLength; } - return str; + + return buffer; } that.response = response; @@ -685,7 +681,7 @@ var modelUploader = (function () { } }; - req.send(httpMultiPart.response()); + req.send(httpMultiPart.response().buffer); } that.upload = function (file, callback) { diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index 563e268222..9d8988c43d 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -20,6 +20,8 @@ #include "XMLHttpRequestClass.h" #include "ScriptEngine.h" +Q_DECLARE_METATYPE(QByteArray*) + XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) : _engine(engine), _async(true), @@ -212,10 +214,10 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a } void XMLHttpRequestClass::send() { - send(QString()); + send(QScriptValue::NullValue); } -void XMLHttpRequestClass::send(const QVariant& data) { +void XMLHttpRequestClass::send(const QScriptValue& data) { if (_readyState == OPENED && !_reply) { if (!data.isNull()) { if (_url.isLocalFile()) { @@ -223,8 +225,8 @@ void XMLHttpRequestClass::send(const QVariant& data) { return; } else { _sendData = new QBuffer(this); - if (_responseType == "arraybuffer") { - QByteArray ba = qvariant_cast(data); + if (data.isObject()) { + QByteArray ba = qscriptvalue_cast(data); _sendData->setData(ba); } else { _sendData->setData(data.toString().toUtf8()); diff --git a/libraries/script-engine/src/XMLHttpRequestClass.h b/libraries/script-engine/src/XMLHttpRequestClass.h index e482e57077..55bf646476 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.h +++ b/libraries/script-engine/src/XMLHttpRequestClass.h @@ -84,7 +84,7 @@ public slots: void open(const QString& method, const QString& url, bool async = true, const QString& username = "", const QString& password = ""); void send(); - void send(const QVariant& data); + void send(const QScriptValue& data); QScriptValue getAllResponseHeaders() const; QScriptValue getResponseHeader(const QString& name) const; From f3b4f708a56bd95501adc947df3f0c6b9db5a965 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 31 Jul 2014 21:50:07 -0700 Subject: [PATCH 146/407] Add Script.load() JavaScript method --- interface/src/Application.cpp | 2 ++ libraries/script-engine/src/ScriptEngine.cpp | 13 +++++++++---- libraries/script-engine/src/ScriptEngine.h | 2 ++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 51f6076e7a..c3f191d9b4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3674,6 +3674,8 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript connect(scriptEngine, SIGNAL(finished(const QString&)), this, SLOT(scriptFinished(const QString&))); + connect(scriptEngine, SIGNAL(loadScript(const QString&)), this, SLOT(loadScript(const QString&))); + scriptEngine->registerGlobalObject("Overlays", &_overlays); QScriptValue windowValue = scriptEngine->registerGlobalObject("Window", WindowScriptingInterface::getInstance()); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index df66fa44d5..49cab1a1fb 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -156,7 +156,7 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL, } else { NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); - qDebug() << "Downloading included script at" << url; + qDebug() << "Downloading script at" << url; QEventLoop loop; QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); loop.exec(); @@ -681,12 +681,12 @@ void ScriptEngine::include(const QString& includeFile) { #endif QFile scriptFile(fileName); if (scriptFile.open(QFile::ReadOnly | QFile::Text)) { - qDebug() << "Loading file:" << fileName; + qDebug() << "Including file:" << fileName; QTextStream in(&scriptFile); includeContents = in.readAll(); } else { - qDebug() << "ERROR Loading file:" << fileName; - emit errorMessage("ERROR Loading file:" + fileName); + qDebug() << "ERROR Including file:" << fileName; + emit errorMessage("ERROR Including file:" + fileName); } } @@ -699,6 +699,11 @@ void ScriptEngine::include(const QString& includeFile) { } } +void ScriptEngine::load(const QString& loadFile) { + QUrl url = resolveInclude(loadFile); + emit loadScript(url.toString()); +} + void ScriptEngine::nodeKilled(SharedNodePointer node) { _outgoingScriptAudioSequenceNumbers.remove(node->getUUID()); } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index fe39f286be..17cda5e183 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -102,6 +102,7 @@ public slots: void clearInterval(QObject* timer) { stopTimer(reinterpret_cast(timer)); } void clearTimeout(QObject* timer) { stopTimer(reinterpret_cast(timer)); } void include(const QString& includeFile); + void load(const QString& loadfile); void print(const QString& message); void nodeKilled(SharedNodePointer node); @@ -115,6 +116,7 @@ signals: void errorMessage(const QString& message); void runningStateChanged(); void evaluationFinished(QScriptValue result, bool isException); + void loadScript(const QString& scriptName); protected: QString _scriptContents; From 779298b7dc63830d9d7f87fa77c1299823dbd31d Mon Sep 17 00:00:00 2001 From: Zu Date: Fri, 1 Aug 2014 14:11:50 +0800 Subject: [PATCH 147/407] improve: reduce animation jerks in avatar head rotation --- interface/src/devices/CaraFaceTracker.cpp | 53 +++++++++++------------ interface/src/devices/CaraFaceTracker.h | 9 ++-- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/interface/src/devices/CaraFaceTracker.cpp b/interface/src/devices/CaraFaceTracker.cpp index 9c67163dca..8160200641 100644 --- a/interface/src/devices/CaraFaceTracker.cpp +++ b/interface/src/devices/CaraFaceTracker.cpp @@ -37,6 +37,7 @@ static QString sampleJson = "[{\"id\":1, \ static const glm::vec3 DEFAULT_HEAD_ORIGIN(0.0f, 0.0f, 0.0f); static const float TRANSLATION_SCALE = 1.0f; static const int NUM_BLENDSHAPE_COEFF = 30; +static const int NUM_SMOOTHING_SAMPLES = 3; struct CaraPerson { struct CaraPose { @@ -217,9 +218,9 @@ private: CaraFaceTracker::CaraFaceTracker() : _lastReceiveTimestamp(0), - _previousPitch(0.0f), - _previousYaw(0.0f), - _previousRoll(0.0f), + _pitchAverage(NUM_SMOOTHING_SAMPLES), + _yawAverage(NUM_SMOOTHING_SAMPLES), + _rollAverage(NUM_SMOOTHING_SAMPLES), _eyeGazeLeftPitch(0.0f), _eyeGazeLeftYaw(0.0f), _eyeGazeRightPitch(0.0f), @@ -252,9 +253,9 @@ CaraFaceTracker::CaraFaceTracker() : CaraFaceTracker::CaraFaceTracker(const QHostAddress& host, quint16 port) : _lastReceiveTimestamp(0), - _previousPitch(0.0f), - _previousYaw(0.0f), - _previousRoll(0.0f), + _pitchAverage(NUM_SMOOTHING_SAMPLES), + _yawAverage(NUM_SMOOTHING_SAMPLES), + _rollAverage(NUM_SMOOTHING_SAMPLES), _eyeGazeLeftPitch(0.0f), _eyeGazeLeftYaw(0.0f), _eyeGazeRightPitch(0.0f), @@ -371,8 +372,9 @@ void CaraFaceTracker::decodePacket(const QByteArray& buffer) { CaraPerson person = CaraPacketDecoder::extractOne(buffer, &jsonError); if(jsonError.error == QJsonParseError::NoError) { + //do some noise filtering to the head poses - //reduce the noise first by truncating to 1 dp + //reduce the noise first by truncating to 1 dp person.pose.roll = glm::floor(person.pose.roll * 10) / 10; person.pose.pitch = glm::floor(person.pose.pitch * 10) / 10; person.pose.yaw = glm::floor(person.pose.yaw * 10) / 10; @@ -386,43 +388,40 @@ void CaraFaceTracker::decodePacket(const QByteArray& buffer) { float theta = 2 * acos(r.w); if (theta > EPSILON) { float rMag = glm::length(glm::vec3(r.x, r.y, r.z)); - const float AVERAGE_CARA_FRAME_TIME = 0.033f; + const float AVERAGE_CARA_FRAME_TIME = 0.04f; const float ANGULAR_VELOCITY_MIN = 1.2f; const float YAW_STANDARD_DEV_DEG = 2.5f; _headAngularVelocity = theta / AVERAGE_CARA_FRAME_TIME * glm::vec3(r.x, r.y, r.z) / rMag; - //use the angular velocity for roll and pitch, if it's below the threshold don't move - if(glm::abs(_headAngularVelocity.x) < ANGULAR_VELOCITY_MIN) { - person.pose.pitch = _previousPitch; - } + _pitchAverage.updateAverage(person.pose.pitch); + _rollAverage.updateAverage(person.pose.roll); - if(glm::abs(_headAngularVelocity.z) < ANGULAR_VELOCITY_MIN) { - person.pose.roll = _previousRoll; - } + //could use the angular velocity to detemine whether to update pitch and roll to further remove the noise. + //use the angular velocity for roll and pitch, update if > THRESHOLD + //if(glm::abs(_headAngularVelocity.x) > ANGULAR_VELOCITY_MIN) { + // _pitchAverage.updateAverage(person.pose.pitch); + //} + + //if(glm::abs(_headAngularVelocity.z) > ANGULAR_VELOCITY_MIN) { + // _rollAverage.updateAverage(person.pose.roll);; + //} //for yaw, the jitter is great, you can't use angular velocity because it swings too much //use the previous and current yaw, calculate the //abs difference and move it the difference is above the standard deviation which is around 2.5 - // (this will introduce some jerks but will not encounter lag) - - // < the standard deviation 2.5 deg, no move - if(glm::abs(person.pose.yaw - _previousYaw) < YAW_STANDARD_DEV_DEG) { + // > the standard deviation 2.5 deg, update the yaw smoothing average + if(glm::abs(person.pose.yaw - _yawAverage.getAverage()) > YAW_STANDARD_DEV_DEG) { //qDebug() << "Yaw Diff: " << glm::abs(person.pose.yaw - _previousYaw); - person.pose.yaw = _previousYaw; + _yawAverage.updateAverage(person.pose.yaw); } - //update the previous angles - _previousPitch = person.pose.pitch; - _previousYaw = person.pose.yaw; - _previousRoll = person.pose.roll; - //set the new rotation - newRotation = glm::quat(glm::vec3(DEGTORAD(person.pose.pitch), DEGTORAD(person.pose.yaw), DEGTORAD(-person.pose.roll))); + newRotation = glm::quat(glm::vec3(DEGTORAD(_pitchAverage.getAverage()), DEGTORAD(_yawAverage.getAverage()), DEGTORAD(-_rollAverage.getAverage()))); } else { //no change in position - newRotation = glm::quat(glm::vec3(DEGTORAD(_previousPitch), DEGTORAD(_previousYaw), DEGTORAD(-_previousRoll))); + newRotation = glm::quat(glm::vec3(DEGTORAD(_pitchAverage.getAverage()), DEGTORAD(_yawAverage.getAverage()), DEGTORAD(-_rollAverage.getAverage()))); _headAngularVelocity = glm::vec3(0,0,0); } diff --git a/interface/src/devices/CaraFaceTracker.h b/interface/src/devices/CaraFaceTracker.h index f51fed0f1b..41dd205d22 100644 --- a/interface/src/devices/CaraFaceTracker.h +++ b/interface/src/devices/CaraFaceTracker.h @@ -14,6 +14,7 @@ #include +#include #include "FaceTracker.h" /*! @@ -90,10 +91,10 @@ private: //head tracking glm::vec3 _headAngularVelocity; - //pose history - float _previousPitch; - float _previousYaw; - float _previousRoll; + //pose average + SimpleMovingAverage _pitchAverage; + SimpleMovingAverage _yawAverage; + SimpleMovingAverage _rollAverage; // eye gaze degrees float _eyeGazeLeftPitch; From 4aa5fb27954e0101fc1800fd9d200ec6b9915e9f Mon Sep 17 00:00:00 2001 From: Zu Date: Fri, 1 Aug 2014 16:12:17 +0800 Subject: [PATCH 148/407] fix: comments, extra white spaces --- interface/src/devices/CaraFaceTracker.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/interface/src/devices/CaraFaceTracker.cpp b/interface/src/devices/CaraFaceTracker.cpp index 8160200641..c7ae322ae8 100644 --- a/interface/src/devices/CaraFaceTracker.cpp +++ b/interface/src/devices/CaraFaceTracker.cpp @@ -374,7 +374,7 @@ void CaraFaceTracker::decodePacket(const QByteArray& buffer) { if(jsonError.error == QJsonParseError::NoError) { //do some noise filtering to the head poses - //reduce the noise first by truncating to 1 dp + //reduce the noise first by truncating to 1 dp person.pose.roll = glm::floor(person.pose.roll * 10) / 10; person.pose.pitch = glm::floor(person.pose.pitch * 10) / 10; person.pose.yaw = glm::floor(person.pose.yaw * 10) / 10; @@ -393,7 +393,6 @@ void CaraFaceTracker::decodePacket(const QByteArray& buffer) { const float YAW_STANDARD_DEV_DEG = 2.5f; _headAngularVelocity = theta / AVERAGE_CARA_FRAME_TIME * glm::vec3(r.x, r.y, r.z) / rMag; - _pitchAverage.updateAverage(person.pose.pitch); _rollAverage.updateAverage(person.pose.roll); @@ -413,14 +412,14 @@ void CaraFaceTracker::decodePacket(const QByteArray& buffer) { // > the standard deviation 2.5 deg, update the yaw smoothing average if(glm::abs(person.pose.yaw - _yawAverage.getAverage()) > YAW_STANDARD_DEV_DEG) { //qDebug() << "Yaw Diff: " << glm::abs(person.pose.yaw - _previousYaw); - _yawAverage.updateAverage(person.pose.yaw); + _yawAverage.updateAverage(person.pose.yaw); } //set the new rotation newRotation = glm::quat(glm::vec3(DEGTORAD(_pitchAverage.getAverage()), DEGTORAD(_yawAverage.getAverage()), DEGTORAD(-_rollAverage.getAverage()))); } else { - //no change in position + //no change in position, use previous averages newRotation = glm::quat(glm::vec3(DEGTORAD(_pitchAverage.getAverage()), DEGTORAD(_yawAverage.getAverage()), DEGTORAD(-_rollAverage.getAverage()))); _headAngularVelocity = glm::vec3(0,0,0); } @@ -455,4 +454,3 @@ void CaraFaceTracker::decodePacket(const QByteArray& buffer) { float CaraFaceTracker::getBlendshapeCoefficient(int index) const { return (index >= 0 && index < (int)_blendshapeCoefficients.size()) ? _blendshapeCoefficients[index] : 0.0f; } - From 7e51ebea49403093c35a3d1f1dc236340c343d17 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 09:42:31 -0700 Subject: [PATCH 149/407] added some additional audio stats --- interface/src/Audio.cpp | 44 +++++++++++++++++++++++++++++++++++++---- interface/src/Audio.h | 3 +++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 4ed1f7aeb3..20ef8163c6 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -49,6 +49,7 @@ static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_ static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300; static const int FRAMES_AVAILABLE_STATS_WINDOW_SECONDS = 10; +static const int APPROXIMATELY_30_SECONDS_OF_AUDIO_PACKETS = (int)(30.0f * 1000.0f / AUDIO_CALLBACK_MSECS); // Mute icon configration static const int MUTE_ICON_SIZE = 24; @@ -112,7 +113,10 @@ Audio::Audio(QObject* parent) : _outgoingAvatarAudioSequenceNumber(0), _audioInputMsecsReadStats(MSECS_PER_SECOND / (float)AUDIO_CALLBACK_MSECS * CALLBACK_ACCELERATOR_RATIO, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS), _inputRingBufferMsecsAvailableStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS), - _audioOutputMsecsUnplayedStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS) + _audioOutputMsecsUnplayedStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS), + _lastSentAudioPacket(0), + _packetSentTimeGaps(1, APPROXIMATELY_30_SECONDS_OF_AUDIO_PACKETS) + { // clear the array of locally injected samples memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); @@ -699,6 +703,17 @@ void Audio::handleAudioInput() { // memcpy our orientation memcpy(currentPacketPtr, &headOrientation, sizeof(headOrientation)); currentPacketPtr += sizeof(headOrientation); + + // first time this is 0 + if (_lastSentAudioPacket == 0) { + _lastSentAudioPacket = usecTimestampNow(); + } else { + quint64 now = usecTimestampNow(); + quint64 gap = now - _lastSentAudioPacket; + _packetSentTimeGaps.update(gap); + + _lastSentAudioPacket = now; + } nodeList->writeDatagram(audioDataPacket, numAudioBytes + leadingBytes, audioMixer); _outgoingAvatarAudioSequenceNumber++; @@ -1307,10 +1322,10 @@ void Audio::renderStats(const float* color, int width, int height) { return; } - const int linesWhenCentered = _statsShowInjectedStreams ? 30 : 23; + const int linesWhenCentered = _statsShowInjectedStreams ? 34 : 27; const int CENTERED_BACKGROUND_HEIGHT = STATS_HEIGHT_PER_LINE * linesWhenCentered; - int lines = _statsShowInjectedStreams ? _audioMixerInjectedStreamAudioStatsMap.size() * 7 + 23 : 23; + int lines = _statsShowInjectedStreams ? _audioMixerInjectedStreamAudioStatsMap.size() * 7 + 27 : 27; int statsHeight = STATS_HEIGHT_PER_LINE * lines; @@ -1384,7 +1399,28 @@ void Audio::renderStats(const float* color, int width, int height) { verticalOffset += STATS_HEIGHT_PER_LINE; // blank line - char upstreamMicLabelString[] = "Upstream mic audio stats:"; + char clientUpstreamMicLabelString[] = "Upstream Mic Audio Packets Sent Gaps (by client):"; + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, clientUpstreamMicLabelString, color); + + char stringBuffer[512]; + sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s", + formatUsecTime(_packetSentTimeGaps.getMin()).toLatin1().data(), + formatUsecTime(_packetSentTimeGaps.getMax()).toLatin1().data(), + formatUsecTime(_packetSentTimeGaps.getAverage()).toLatin1().data()); + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); + + sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s", + formatUsecTime(_packetSentTimeGaps.getWindowMin()).toLatin1().data(), + formatUsecTime(_packetSentTimeGaps.getWindowMax()).toLatin1().data(), + formatUsecTime(_packetSentTimeGaps.getWindowAverage()).toLatin1().data()); + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); + + verticalOffset += STATS_HEIGHT_PER_LINE; // blank line + + char upstreamMicLabelString[] = "Upstream mic audio stats (received and reported by audio-mixer):"; verticalOffset += STATS_HEIGHT_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamMicLabelString, color); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 3006446db1..9dad3b82d7 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -279,6 +279,9 @@ private: MovingMinMaxAvg _inputRingBufferMsecsAvailableStats; MovingMinMaxAvg _audioOutputMsecsUnplayedStats; + + quint64 _lastSentAudioPacket; + MovingMinMaxAvg _packetSentTimeGaps; }; From fa5a2b9a4d90a0357a716600c6d329c00729a012 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 10:04:35 -0700 Subject: [PATCH 150/407] reset sent time gap stats on reset --- interface/src/Audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 20ef8163c6..db55cc3e94 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -132,7 +132,6 @@ void Audio::init(QGLWidget *parent) { void Audio::reset() { _receivedAudioStream.reset(); - resetStats(); } @@ -146,6 +145,7 @@ void Audio::resetStats() { _inputRingBufferMsecsAvailableStats.reset(); _audioOutputMsecsUnplayedStats.reset(); + _packetSentTimeGaps.reset(); } void Audio::audioMixerKilled() { From e1f905cb3667fafaa9e9935a7a6db333fb38639b Mon Sep 17 00:00:00 2001 From: wangyix Date: Fri, 1 Aug 2014 10:23:03 -0700 Subject: [PATCH 151/407] fixed >100% loss rate bug in SequenceNumberStats --- interface/src/Audio.cpp | 4 +- interface/src/ui/OctreeStatsDialog.cpp | 14 ++--- libraries/audio/src/InboundAudioStream.cpp | 2 +- libraries/audio/src/InboundAudioStream.h | 2 +- .../networking/src/SequenceNumberStats.cpp | 55 +++++++++-------- .../networking/src/SequenceNumberStats.h | 61 ++++++++++--------- 6 files changed, 73 insertions(+), 65 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 4ed1f7aeb3..4fcab5b949 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1424,9 +1424,9 @@ void Audio::renderAudioStreamStats(const AudioStreamStats& streamStats, int hori sprintf(stringBuffer, " Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)", streamStats._packetStreamStats.getLostRate() * 100.0f, - streamStats._packetStreamStats._numLost, + streamStats._packetStreamStats._lost, streamStats._packetStreamWindowStats.getLostRate() * 100.0f, - streamStats._packetStreamWindowStats._numLost); + streamStats._packetStreamWindowStats._lost); verticalOffset += STATS_HEIGHT_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); diff --git a/interface/src/ui/OctreeStatsDialog.cpp b/interface/src/ui/OctreeStatsDialog.cpp index afa799815f..7abc42d0e3 100644 --- a/interface/src/ui/OctreeStatsDialog.cpp +++ b/interface/src/ui/OctreeStatsDialog.cpp @@ -366,13 +366,13 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser QString incomingBytesString = locale.toString((uint)stats.getIncomingBytes()); QString incomingWastedBytesString = locale.toString((uint)stats.getIncomingWastedBytes()); const SequenceNumberStats& seqStats = stats.getIncomingOctreeSequenceNumberStats(); - QString incomingOutOfOrderString = locale.toString((uint)seqStats.getNumOutOfOrder()); - QString incomingLateString = locale.toString((uint)seqStats.getNumLate()); - QString incomingUnreasonableString = locale.toString((uint)seqStats.getNumUnreasonable()); - QString incomingEarlyString = locale.toString((uint)seqStats.getNumEarly()); - QString incomingLikelyLostString = locale.toString((uint)seqStats.getNumLost()); - QString incomingRecovered = locale.toString((uint)seqStats.getNumRecovered()); - QString incomingDuplicateString = locale.toString((uint)seqStats.getNumDuplicate()); + QString incomingOutOfOrderString = locale.toString((uint)seqStats.getOutOfOrder()); + QString incomingLateString = locale.toString((uint)seqStats.getLate()); + QString incomingUnreasonableString = locale.toString((uint)seqStats.getUnreasonable()); + QString incomingEarlyString = locale.toString((uint)seqStats.getEarly()); + QString incomingLikelyLostString = locale.toString((uint)seqStats.getLost()); + QString incomingRecovered = locale.toString((uint)seqStats.getRecovered()); + QString incomingDuplicateString = locale.toString((uint)seqStats.getDuplicate()); int clockSkewInMS = node->getClockSkewUsec() / (int)USECS_PER_MSEC; QString incomingFlightTimeString = locale.toString((int)stats.getIncomingFlightTimeAverage()); diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 6ade4b17e9..36145a35f6 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -212,7 +212,7 @@ SequenceNumberStats::ArrivalInfo InboundAudioStream::frameReceivedUpdateNetworkS // discard the first few packets we receive since they usually have gaps that aren't represensative of normal jitter const int NUM_INITIAL_PACKETS_DISCARD = 3; quint64 now = usecTimestampNow(); - if (_incomingSequenceNumberStats.getNumReceived() > NUM_INITIAL_PACKETS_DISCARD) { + if (_incomingSequenceNumberStats.getReceived() > NUM_INITIAL_PACKETS_DISCARD) { quint64 gap = now - _lastFrameReceivedTime; _interframeTimeGapStatsForStatsPacket.update(gap); diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index 06bd329fee..1a196a1c61 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -108,7 +108,7 @@ public: int getSilentFramesDropped() const { return _silentFramesDropped; } int getOverflowCount() const { return _ringBuffer.getOverflowCount(); } - int getPacketReceived() const { return _incomingSequenceNumberStats.getNumReceived(); } + int getPacketsReceived() const { return _incomingSequenceNumberStats.getReceived(); } private: void starved(); diff --git a/libraries/networking/src/SequenceNumberStats.cpp b/libraries/networking/src/SequenceNumberStats.cpp index 66d57500a5..00a3e66877 100644 --- a/libraries/networking/src/SequenceNumberStats.cpp +++ b/libraries/networking/src/SequenceNumberStats.cpp @@ -14,7 +14,8 @@ #include SequenceNumberStats::SequenceNumberStats(int statsHistoryLength) - : _lastReceived(std::numeric_limits::max()), + : _received(0), + _lastReceivedSequence(0), _missingSet(), _stats(), _lastSenderUUID(), @@ -23,8 +24,10 @@ SequenceNumberStats::SequenceNumberStats(int statsHistoryLength) } void SequenceNumberStats::reset() { + _received = 0; _missingSet.clear(); _stats = PacketStreamStats(); + _lastSenderUUID = QUuid(); _statsHistory.clear(); } @@ -36,7 +39,7 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui // if the sender node has changed, reset all stats if (senderUUID != _lastSenderUUID) { - if (_stats._numReceived > 0) { + if (_received > 0) { qDebug() << "sequence number stats was reset due to new sender node"; qDebug() << "previous:" << _lastSenderUUID << "current:" << senderUUID; reset(); @@ -45,13 +48,14 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui } // determine our expected sequence number... handle rollover appropriately - quint16 expected = _stats._numReceived > 0 ? _lastReceived + (quint16)1 : incoming; + quint16 expected = _received > 0 ? _lastReceivedSequence + (quint16)1 : incoming; - _stats._numReceived++; + _received++; if (incoming == expected) { // on time arrivalInfo._status = OnTime; - _lastReceived = incoming; + _lastReceivedSequence = incoming; + _stats._expectedReceived++; } else { // out of order if (wantExtraDebugging) { @@ -76,8 +80,8 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui // ignore packet if gap is unreasonable qDebug() << "ignoring unreasonable sequence number:" << incoming - << "previous:" << _lastReceived; - _stats._numUnreasonable++; + << "previous:" << _lastReceivedSequence; + _stats._unreasonable++; return arrivalInfo; } @@ -94,10 +98,11 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui qDebug() << "this packet is earlier than expected..."; qDebug() << ">>>>>>>> missing gap=" << (incomingInt - expectedInt); } - - _stats._numEarly++; - _stats._numLost += (incomingInt - expectedInt); - _lastReceived = incoming; + int skipped = incomingInt - expectedInt; + _stats._early++; + _stats._lost += skipped; + _stats._expectedReceived += (skipped + 1); + _lastReceivedSequence = incoming; // add all sequence numbers that were skipped to the missing sequence numbers list for (int missingInt = expectedInt; missingInt < incomingInt; missingInt++) { @@ -114,7 +119,7 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui qDebug() << "this packet is later than expected..."; } - _stats._numLate++; + _stats._late++; // do not update _lastReceived; it shouldn't become smaller @@ -125,15 +130,15 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui if (wantExtraDebugging) { qDebug() << "found it in _missingSet"; } - _stats._numLost--; - _stats._numRecovered++; + _stats._lost--; + _stats._recovered++; } else { arrivalInfo._status = Duplicate; if (wantExtraDebugging) { qDebug() << "sequence:" << incoming << "was NOT found in _missingSet and is probably a duplicate"; } - _stats._numDuplicate++; + _stats._duplicate++; } } } @@ -148,7 +153,7 @@ void SequenceNumberStats::pruneMissingSet(const bool wantExtraDebugging) { // some older sequence numbers may be from before a rollover point; this must be handled. // some sequence numbers in this list may be larger than _incomingLastSequence, indicating that they were received // before the most recent rollover. - int cutoff = (int)_lastReceived - MAX_REASONABLE_SEQUENCE_GAP; + int cutoff = (int)_lastReceivedSequence - MAX_REASONABLE_SEQUENCE_GAP; if (cutoff >= 0) { quint16 nonRolloverCutoff = (quint16)cutoff; QSet::iterator i = _missingSet.begin(); @@ -159,7 +164,7 @@ void SequenceNumberStats::pruneMissingSet(const bool wantExtraDebugging) { qDebug() << "old age cutoff:" << nonRolloverCutoff; } - if (missing > _lastReceived || missing < nonRolloverCutoff) { + if (missing > _lastReceivedSequence || missing < nonRolloverCutoff) { i = _missingSet.erase(i); if (wantExtraDebugging) { qDebug() << "pruning really old missing sequence:" << missing; @@ -178,7 +183,7 @@ void SequenceNumberStats::pruneMissingSet(const bool wantExtraDebugging) { qDebug() << "old age cutoff:" << rolloverCutoff; } - if (missing > _lastReceived && missing < rolloverCutoff) { + if (missing > _lastReceivedSequence && missing < rolloverCutoff) { i = _missingSet.erase(i); if (wantExtraDebugging) { qDebug() << "pruning really old missing sequence:" << missing; @@ -202,13 +207,13 @@ PacketStreamStats SequenceNumberStats::getStatsForHistoryWindow() const { // calculate difference between newest stats and oldest stats to get window stats PacketStreamStats windowStats; - windowStats._numReceived = newestStats->_numReceived - oldestStats->_numReceived; - windowStats._numUnreasonable = newestStats->_numUnreasonable - oldestStats->_numUnreasonable; - windowStats._numEarly = newestStats->_numEarly - oldestStats->_numEarly; - windowStats._numLate = newestStats->_numLate - oldestStats->_numLate; - windowStats._numLost = newestStats->_numLost - oldestStats->_numLost; - windowStats._numRecovered = newestStats->_numRecovered - oldestStats->_numRecovered; - windowStats._numDuplicate = newestStats->_numDuplicate - oldestStats->_numDuplicate; + windowStats._expectedReceived = newestStats->_expectedReceived - oldestStats->_expectedReceived; + windowStats._unreasonable = newestStats->_unreasonable - oldestStats->_unreasonable; + windowStats._early = newestStats->_early - oldestStats->_early; + windowStats._late = newestStats->_late - oldestStats->_late; + windowStats._lost = newestStats->_lost - oldestStats->_lost; + windowStats._recovered = newestStats->_recovered - oldestStats->_recovered; + windowStats._duplicate = newestStats->_duplicate - oldestStats->_duplicate; return windowStats; } diff --git a/libraries/networking/src/SequenceNumberStats.h b/libraries/networking/src/SequenceNumberStats.h index f4e85b6fb3..d611a494ad 100644 --- a/libraries/networking/src/SequenceNumberStats.h +++ b/libraries/networking/src/SequenceNumberStats.h @@ -21,29 +21,27 @@ const int MAX_REASONABLE_SEQUENCE_GAP = 1000; class PacketStreamStats { public: PacketStreamStats() - : _numReceived(0), - _numUnreasonable(0), - _numEarly(0), - _numLate(0), - _numLost(0), - _numRecovered(0), - _numDuplicate(0) + : _expectedReceived(0), + _unreasonable(0), + _early(0), + _late(0), + _lost(0), + _recovered(0), + _duplicate(0) {} - float getUnreasonableRate() const { return (float)_numUnreasonable / _numReceived; } - float getNumEaryRate() const { return (float)_numEarly / _numReceived; } - float getLateRate() const { return (float)_numLate / _numReceived; } - float getLostRate() const { return (float)_numLost / _numReceived; } - float getRecoveredRate() const { return (float)_numRecovered / _numReceived; } - float getDuplicateRate() const { return (float)_numDuplicate / _numReceived; } + float getUnreasonableRate() const { return (float)_unreasonable / _expectedReceived; } + float getEaryRate() const { return (float)_early / _expectedReceived; } + float getLateRate() const { return (float)_late / _expectedReceived; } + float getLostRate() const { return (float)_lost / _expectedReceived; } - quint32 _numReceived; - quint32 _numUnreasonable; - quint32 _numEarly; - quint32 _numLate; - quint32 _numLost; - quint32 _numRecovered; - quint32 _numDuplicate; + quint32 _expectedReceived; + quint32 _unreasonable; + quint32 _early; + quint32 _late; + quint32 _lost; + quint32 _recovered; + quint32 _duplicate; }; class SequenceNumberStats { @@ -70,20 +68,25 @@ public: void pruneMissingSet(const bool wantExtraDebugging = false); void pushStatsToHistory() { _statsHistory.insert(_stats); } - quint32 getNumReceived() const { return _stats._numReceived; } - quint32 getNumUnreasonable() const { return _stats._numUnreasonable; } - quint32 getNumOutOfOrder() const { return _stats._numEarly + _stats._numLate; } - quint32 getNumEarly() const { return _stats._numEarly; } - quint32 getNumLate() const { return _stats._numLate; } - quint32 getNumLost() const { return _stats._numLost; } - quint32 getNumRecovered() const { return _stats._numRecovered; } - quint32 getNumDuplicate() const { return _stats._numDuplicate; } + quint32 getReceived() const { return _received; } + + quint32 getExpectedReceived() const { return _stats._expectedReceived; } + quint32 getUnreasonable() const { return _stats._unreasonable; } + quint32 getOutOfOrder() const { return _stats._early + _stats._late; } + quint32 getEarly() const { return _stats._early; } + quint32 getLate() const { return _stats._late; } + quint32 getLost() const { return _stats._lost; } + quint32 getRecovered() const { return _stats._recovered; } + quint32 getDuplicate() const { return _stats._duplicate; } + const PacketStreamStats& getStats() const { return _stats; } PacketStreamStats getStatsForHistoryWindow() const; const QSet& getMissingSet() const { return _missingSet; } private: - quint16 _lastReceived; + int _received; + + quint16 _lastReceivedSequence; QSet _missingSet; PacketStreamStats _stats; From cdcc6ece04ef0fe9e5e3576abc27729280ebe2ef Mon Sep 17 00:00:00 2001 From: wangyix Date: Fri, 1 Aug 2014 10:34:19 -0700 Subject: [PATCH 152/407] fixed compile errors caused by SequenceNumberStats changes --- interface/src/Audio.cpp | 2 +- .../src/SequenceNumberStatsTests.cpp | 96 +++++++++---------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 4fcab5b949..1391045568 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -709,7 +709,7 @@ void Audio::handleAudioInput() { delete[] inputAudioSamples; } - if (_receivedAudioStream.getPacketReceived() > 0) { + if (_receivedAudioStream.getPacketsReceived() > 0) { pushAudioToOutput(); } } diff --git a/tests/networking/src/SequenceNumberStatsTests.cpp b/tests/networking/src/SequenceNumberStatsTests.cpp index de487267e0..c4205f5fb5 100644 --- a/tests/networking/src/SequenceNumberStatsTests.cpp +++ b/tests/networking/src/SequenceNumberStatsTests.cpp @@ -38,12 +38,12 @@ void SequenceNumberStatsTests::rolloverTest() { stats.sequenceNumberReceived(seq); seq = seq + (quint16)1; - assert(stats.getNumDuplicate() == 0); - assert(stats.getNumEarly() == 0); - assert(stats.getNumLate() == 0); - assert(stats.getNumLost() == 0); - assert(stats.getNumReceived() == i + 1); - assert(stats.getNumRecovered() == 0); + assert(stats.getDuplicate() == 0); + assert(stats.getEarly() == 0); + assert(stats.getLate() == 0); + assert(stats.getLost() == 0); + assert(stats.getReceived() == i + 1); + assert(stats.getRecovered() == 0); } stats.reset(); } @@ -69,12 +69,12 @@ void SequenceNumberStatsTests::earlyLateTest() { seq = seq + (quint16)1; numSent++; - assert(stats.getNumDuplicate() == 0); - assert(stats.getNumEarly() == numEarly); - assert(stats.getNumLate() == numLate); - assert(stats.getNumLost() == numLost); - assert(stats.getNumReceived() == numSent); - assert(stats.getNumRecovered() == numRecovered); + assert(stats.getDuplicate() == 0); + assert(stats.getEarly() == numEarly); + assert(stats.getLate() == numLate); + assert(stats.getLost() == numLost); + assert(stats.getReceived() == numSent); + assert(stats.getRecovered() == numRecovered); } // skip 10 @@ -89,12 +89,12 @@ void SequenceNumberStatsTests::earlyLateTest() { seq = seq + (quint16)1; numSent++; - assert(stats.getNumDuplicate() == 0); - assert(stats.getNumEarly() == numEarly); - assert(stats.getNumLate() == numLate); - assert(stats.getNumLost() == numLost); - assert(stats.getNumReceived() == numSent); - assert(stats.getNumRecovered() == numRecovered); + assert(stats.getDuplicate() == 0); + assert(stats.getEarly() == numEarly); + assert(stats.getLate() == numLate); + assert(stats.getLost() == numLost); + assert(stats.getReceived() == numSent); + assert(stats.getRecovered() == numRecovered); } // send ones we skipped @@ -106,12 +106,12 @@ void SequenceNumberStatsTests::earlyLateTest() { numLost--; numRecovered++; - assert(stats.getNumDuplicate() == 0); - assert(stats.getNumEarly() == numEarly); - assert(stats.getNumLate() == numLate); - assert(stats.getNumLost() == numLost); - assert(stats.getNumReceived() == numSent); - assert(stats.getNumRecovered() == numRecovered); + assert(stats.getDuplicate() == 0); + assert(stats.getEarly() == numEarly); + assert(stats.getLate() == numLate); + assert(stats.getLost() == numLost); + assert(stats.getReceived() == numSent); + assert(stats.getRecovered() == numRecovered); } } stats.reset(); @@ -145,12 +145,12 @@ void SequenceNumberStatsTests::duplicateTest() { seq = seq + (quint16)1; numSent++; - assert(stats.getNumDuplicate() == numDuplicate); - assert(stats.getNumEarly() == numEarly); - assert(stats.getNumLate() == numLate); - assert(stats.getNumLost() == numLost); - assert(stats.getNumReceived() == numSent); - assert(stats.getNumRecovered() == 0); + assert(stats.getDuplicate() == numDuplicate); + assert(stats.getEarly() == numEarly); + assert(stats.getLate() == numLate); + assert(stats.getLost() == numLost); + assert(stats.getReceived() == numSent); + assert(stats.getRecovered() == 0); } // skip 10 @@ -167,12 +167,12 @@ void SequenceNumberStatsTests::duplicateTest() { seq = seq + (quint16)1; numSent++; - assert(stats.getNumDuplicate() == numDuplicate); - assert(stats.getNumEarly() == numEarly); - assert(stats.getNumLate() == numLate); - assert(stats.getNumLost() == numLost); - assert(stats.getNumReceived() == numSent); - assert(stats.getNumRecovered() == 0); + assert(stats.getDuplicate() == numDuplicate); + assert(stats.getEarly() == numEarly); + assert(stats.getLate() == numLate); + assert(stats.getLost() == numLost); + assert(stats.getReceived() == numSent); + assert(stats.getRecovered() == 0); } // send 5 duplicates from before skip @@ -183,12 +183,12 @@ void SequenceNumberStatsTests::duplicateTest() { numDuplicate++; numLate++; - assert(stats.getNumDuplicate() == numDuplicate); - assert(stats.getNumEarly() == numEarly); - assert(stats.getNumLate() == numLate); - assert(stats.getNumLost() == numLost); - assert(stats.getNumReceived() == numSent); - assert(stats.getNumRecovered() == 0); + assert(stats.getDuplicate() == numDuplicate); + assert(stats.getEarly() == numEarly); + assert(stats.getLate() == numLate); + assert(stats.getLost() == numLost); + assert(stats.getReceived() == numSent); + assert(stats.getRecovered() == 0); } // send 5 duplicates from after skip @@ -199,12 +199,12 @@ void SequenceNumberStatsTests::duplicateTest() { numDuplicate++; numLate++; - assert(stats.getNumDuplicate() == numDuplicate); - assert(stats.getNumEarly() == numEarly); - assert(stats.getNumLate() == numLate); - assert(stats.getNumLost() == numLost); - assert(stats.getNumReceived() == numSent); - assert(stats.getNumRecovered() == 0); + assert(stats.getDuplicate() == numDuplicate); + assert(stats.getEarly() == numEarly); + assert(stats.getLate() == numLate); + assert(stats.getLost() == numLost); + assert(stats.getReceived() == numSent); + assert(stats.getRecovered() == 0); } } stats.reset(); From 789eeed760eae8c5d4768f0d9378891cc47351c2 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 Aug 2014 11:11:41 -0700 Subject: [PATCH 153/407] limit action of ContactConstraint to penetration --- libraries/shared/src/ContactConstraint.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/ContactConstraint.cpp b/libraries/shared/src/ContactConstraint.cpp index 65633788be..d1d12fa771 100644 --- a/libraries/shared/src/ContactConstraint.cpp +++ b/libraries/shared/src/ContactConstraint.cpp @@ -44,7 +44,9 @@ float ContactConstraint::enforce() { glm::vec3 pointA = _shapeA->getTranslation() + _offsetA; glm::vec3 pointB = _shapeB->getTranslation() + _offsetB; glm::vec3 penetration = pointA - pointB; - if (glm::dot(penetration, _normal) > EPSILON) { + float pDotN = glm::dot(penetration, _normal); + if (pDotN > EPSILON) { + penetration = (0.99f * pDotN) * _normal; // NOTE: Shape::computeEffectiveMass() has side effects: computes and caches partial Lagrangian coefficients // which are then used in the accumulateDelta() calls below. float massA = _shapeA->computeEffectiveMass(penetration, pointA); @@ -56,9 +58,9 @@ float ContactConstraint::enforce() { } // NOTE: Shape::accumulateDelta() uses the coefficients from previous call to Shape::computeEffectiveMass() // and remember that penetration points from A into B - _shapeA->accumulateDelta(0.99f * massB / totalMass, -penetration); - _shapeB->accumulateDelta(0.99f * massA / totalMass, penetration); - return glm::length(penetration); + _shapeA->accumulateDelta(massB / totalMass, -penetration); + _shapeB->accumulateDelta(massA / totalMass, penetration); + return pDotN; } return 0.0f; } From eba07b03e29a4d2901ccdecb0044a2334359412d Mon Sep 17 00:00:00 2001 From: wangyix Date: Fri, 1 Aug 2014 12:00:41 -0700 Subject: [PATCH 154/407] recursive SequenceNumberStats; untested --- .../networking/src/SequenceNumberStats.cpp | 103 +++++++++++++++++- .../networking/src/SequenceNumberStats.h | 21 +++- 2 files changed, 120 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/SequenceNumberStats.cpp b/libraries/networking/src/SequenceNumberStats.cpp index 00a3e66877..a700e01f07 100644 --- a/libraries/networking/src/SequenceNumberStats.cpp +++ b/libraries/networking/src/SequenceNumberStats.cpp @@ -13,22 +13,67 @@ #include -SequenceNumberStats::SequenceNumberStats(int statsHistoryLength) +SequenceNumberStats::SequenceNumberStats(int statsHistoryLength, int maxRecursion) : _received(0), _lastReceivedSequence(0), _missingSet(), _stats(), _lastSenderUUID(), - _statsHistory(statsHistoryLength) + _statsHistory(statsHistoryLength), + + _unreasonableTracker(NULL), + _maxRecursion(maxRecursion) { } +SequenceNumberStats::SequenceNumberStats(const SequenceNumberStats& other) + : _received(other._received), + _lastReceivedSequence(other._lastReceivedSequence), + _missingSet(other._missingSet), + _stats(other._stats), + _lastSenderUUID(other._lastSenderUUID), + _statsHistory(other._statsHistory), + _unreasonableTracker(NULL), + _maxRecursion(other._maxRecursion) +{ + if (other._unreasonableTracker) { + _unreasonableTracker = new SequenceNumberStats(*other._unreasonableTracker); + } +} + +SequenceNumberStats& SequenceNumberStats::operator=(const SequenceNumberStats& rhs) { + _received = rhs._received; + _lastReceivedSequence = rhs._lastReceivedSequence; + _missingSet = rhs._missingSet; + _stats = rhs._stats; + _lastSenderUUID = rhs._lastSenderUUID; + _statsHistory = rhs._statsHistory; + _maxRecursion = rhs._maxRecursion; + + if (rhs._unreasonableTracker) { + _unreasonableTracker = new SequenceNumberStats(*rhs._unreasonableTracker); + } else { + _unreasonableTracker = NULL; + } + return *this; +} + +SequenceNumberStats::~SequenceNumberStats() { + if (_unreasonableTracker) { + delete _unreasonableTracker; + } +} + void SequenceNumberStats::reset() { _received = 0; _missingSet.clear(); _stats = PacketStreamStats(); _lastSenderUUID = QUuid(); _statsHistory.clear(); + + if (_unreasonableTracker) { + delete _unreasonableTracker; + } } static const int UINT16_RANGE = std::numeric_limits::max() + 1; @@ -78,10 +123,64 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui } else if (absGap > MAX_REASONABLE_SEQUENCE_GAP) { arrivalInfo._status = Unreasonable; + /* // ignore packet if gap is unreasonable qDebug() << "ignoring unreasonable sequence number:" << incoming << "previous:" << _lastReceivedSequence; _stats._unreasonable++; + */ + + // do not create a child tracker for unreasonable seq nums if this instance is the last one in the chain. + // otherwise, create one if we don't have one. + + if (!_unreasonableTracker && _maxRecursion > 0) { + _unreasonableTracker = new SequenceNumberStats(0, _maxRecursion - 1); + } + + + if (_unreasonableTracker) { + + // track this unreasonable seq number with our _unreasonableTracker. + ArrivalInfo unreasonableTrackerArrivalInfo = _unreasonableTracker->sequenceNumberReceived(incoming); + + + const int UNREASONABLE_TRACKER_RECEIVED_THRESHOLD = 10; + const float UNRUNREASONABLE_TRACKER_UNREASONABLE_RATE_THRESHOLD = 0.1f; + const float UNREASONABLE_TRACKER_OUT_OF_ORDER_RATE_THRESHOLD = 0.1f; + + // when our _unreasonableTracker has received enough seq nums and doesn't have an _unreasonableTracker of its own, + // we'll either inherit its state only if we think its stream is plausible. it will then be deleted. + // (if it has an _unreasonableTracker of its own, its _unreasonableTracker may be detecting a plausible stream + // while its parent does not, so we should let it accrue seq nums and decide plausibility first) + + if (!_unreasonableTracker->hasUnreasonableTracker() && + _unreasonableTracker->_received >= UNREASONABLE_TRACKER_RECEIVED_THRESHOLD) { + + if (_unreasonableTracker->getUnreasonableRate() < UNRUNREASONABLE_TRACKER_UNREASONABLE_RATE_THRESHOLD && + _unreasonableTracker->getStats().getOutOfOrderRate() < UNREASONABLE_TRACKER_OUT_OF_ORDER_RATE_THRESHOLD) { + + // the _unreasonableTracker has detected a plausible stream of seq numbers; + // copy its state to this tracker. + + _received = _unreasonableTracker->_received; + _lastReceivedSequence = _unreasonableTracker->_lastReceivedSequence; + _missingSet = _unreasonableTracker->_missingSet; + _stats = _unreasonableTracker->_stats; + + // don't copy _lastSenderUUID; _unreasonableTracker always has null UUID for that member. + // ours should be up-to-date. + + // don't copy _statsHistory; _unreasonableTracker keeps a history of length 0. + // simply clear ours. + _statsHistory.clear(); + + arrivalInfo = unreasonableTrackerArrivalInfo; + + } + // remove our _unreasonableTracker + delete _unreasonableTracker; + } + } return arrivalInfo; } diff --git a/libraries/networking/src/SequenceNumberStats.h b/libraries/networking/src/SequenceNumberStats.h index d611a494ad..1f740d7af8 100644 --- a/libraries/networking/src/SequenceNumberStats.h +++ b/libraries/networking/src/SequenceNumberStats.h @@ -18,6 +18,10 @@ const int MAX_REASONABLE_SEQUENCE_GAP = 1000; + +const int DEFAULT_MAX_RECURSION = 5; + + class PacketStreamStats { public: PacketStreamStats() @@ -30,7 +34,7 @@ public: _duplicate(0) {} - float getUnreasonableRate() const { return (float)_unreasonable / _expectedReceived; } + float getOutOfOrderRate() const { return (float)(_early + _late) / _expectedReceived; } float getEaryRate() const { return (float)_early / _expectedReceived; } float getLateRate() const { return (float)_late / _expectedReceived; } float getLostRate() const { return (float)_lost / _expectedReceived; } @@ -61,14 +65,19 @@ public: }; - SequenceNumberStats(int statsHistoryLength = 0); + SequenceNumberStats(int statsHistoryLength = 0, int maxRecursion = DEFAULT_MAX_RECURSION); + SequenceNumberStats(const SequenceNumberStats& other); + SequenceNumberStats& operator=(const SequenceNumberStats& rhs); + ~SequenceNumberStats(); +public: void reset(); ArrivalInfo sequenceNumberReceived(quint16 incoming, QUuid senderUUID = QUuid(), const bool wantExtraDebugging = false); void pruneMissingSet(const bool wantExtraDebugging = false); void pushStatsToHistory() { _statsHistory.insert(_stats); } quint32 getReceived() const { return _received; } + float getUnreasonableRate() const { return _stats._unreasonable / _received; } quint32 getExpectedReceived() const { return _stats._expectedReceived; } quint32 getUnreasonable() const { return _stats._unreasonable; } @@ -94,6 +103,14 @@ private: QUuid _lastSenderUUID; RingBufferHistory _statsHistory; + + + // to deal with the incoming seq nums going out of sync with this tracker, we'll create another instance + // of this class when we encounter an unreasonable + SequenceNumberStats* _unreasonableTracker; + int _maxRecursion; + + bool hasUnreasonableTracker() const { return _unreasonableTracker != NULL; } }; #endif // hifi_SequenceNumberStats_h From 68074cb22a3a0492cb31e3329a88e490944808fa Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 12:59:10 -0700 Subject: [PATCH 155/407] added a simple udp send/receive jitter test tool --- tests/jitter/CMakeLists.txt | 33 +++++++++ tests/jitter/src/main.cpp | 139 ++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 tests/jitter/CMakeLists.txt create mode 100644 tests/jitter/src/main.cpp diff --git a/tests/jitter/CMakeLists.txt b/tests/jitter/CMakeLists.txt new file mode 100644 index 0000000000..8000e4af50 --- /dev/null +++ b/tests/jitter/CMakeLists.txt @@ -0,0 +1,33 @@ +set(TARGET_NAME jitter-tests) + +set(ROOT_DIR ../..) +set(MACRO_DIR ${ROOT_DIR}/cmake/macros) + +# setup for find modules +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") + +#find_package(Qt5Network REQUIRED) +#find_package(Qt5Script REQUIRED) +#find_package(Qt5Widgets REQUIRED) + +include(${MACRO_DIR}/SetupHifiProject.cmake) +setup_hifi_project(${TARGET_NAME} TRUE) + +#include(${MACRO_DIR}/AutoMTC.cmake) +#auto_mtc(${TARGET_NAME} ${ROOT_DIR}) + +#qt5_use_modules(${TARGET_NAME} Network Script Widgets) + +#include glm - because it's a dependency of shared utils... +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) + +# link in the shared libraries +include(${MACRO_DIR}/LinkHifiLibrary.cmake) +link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR}) + +IF (WIN32) + target_link_libraries(${TARGET_NAME} Winmm Ws2_32) +ENDIF(WIN32) + diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp new file mode 100644 index 0000000000..05a05e53d2 --- /dev/null +++ b/tests/jitter/src/main.cpp @@ -0,0 +1,139 @@ +// +// main.cpp +// JitterTester +// +// Created by Philip on 8/1/14. +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + +#include +#include +#include +#include +#include +#include + +#include // for usecTimeStampNow() +#include // for MovingMinMaxAvg + +void runSend(const char* addressOption, int port, int gap, int size); +void runReceive(const char* addressOption, int port, int gap, int size); + + +int main(int argc, const char * argv[]) { + if (argc != 6) { + printf("usage: jitter-tests <--send|--receive>
\n"); + exit(1); + } + const char* typeOption = argv[1]; + const char* addressOption = argv[2]; + const char* portOption = argv[3]; + const char* gapOption = argv[4]; + const char* sizeOption = argv[5]; + int port = atoi(portOption); + int gap = atoi(gapOption); + int size = atoi(sizeOption); + + std::cout << "type:" << typeOption << "\n"; + std::cout << "address:" << addressOption << "\n"; + std::cout << "port:" << port << "\n"; + std::cout << "gap:" << gap << "\n"; + std::cout << "size:" << size << "\n"; + + if (strcmp(typeOption, "--send") == 0) { + runSend(addressOption, port, gap, size); + } else if (strcmp(typeOption, "--receive") == 0) { + runReceive(addressOption, port, gap, size); + } + exit(1); +} + +void runSend(const char* addressOption, int port, int gap, int size) { + std::cout << "runSend...\n"; + + int sockfd; + struct sockaddr_in servaddr; + + char* outputBuffer = new char[size]; + memset(outputBuffer, 0, size); + + sockfd=socket(AF_INET,SOCK_DGRAM,0); + + bzero(&servaddr,sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr=inet_addr(addressOption); + servaddr.sin_port=htons(port); + + const int SAMPLES_FOR_30_SECONDS = 30 * 1000 / gap; + MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats + + quint64 last = usecTimestampNow(); + + while (true) { + + quint64 now = usecTimestampNow(); + quint64 actualGap = now - last; + + + if (actualGap >= gap) { + sendto(sockfd, outputBuffer, size, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); + + timeGaps.update(actualGap); + std::cout << "packet sent gap:" << actualGap << " " + << "min:" << timeGaps.getMin() << " " + << "max:" << timeGaps.getMax() << " " + << "avg:" << timeGaps.getAverage() << " " + << "min last 30:" << timeGaps.getWindowMin() << " " + << "max last 30:" << timeGaps.getWindowMax() << " " + << "avg last 30:" << timeGaps.getWindowAverage() << " " + << "\n"; + last = now; + } + } +} + +void runReceive(const char* addressOption, int port, int gap, int size) { + std::cout << "runReceive...\n"; + + + int sockfd,n; + struct sockaddr_in myaddr; + + char* inputBuffer = new char[size]; + memset(inputBuffer, 0, size); + + sockfd=socket(AF_INET, SOCK_DGRAM, 0); + + bzero(&myaddr,sizeof(myaddr)); + myaddr.sin_family = AF_INET; + myaddr.sin_addr.s_addr=htonl(INADDR_ANY); + myaddr.sin_port=htons(port); + + const int SAMPLES_FOR_30_SECONDS = 30 * 1000 / gap; + MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats + + if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { + std::cout << "bind failed\n"; + return; + } + + quint64 last = usecTimestampNow(); + + while (true) { + n = recvfrom(sockfd, inputBuffer, size, 0, NULL, NULL); // we don't care about where it came from + + quint64 now = usecTimestampNow(); + int actualGap = now - last; + timeGaps.update(actualGap); + std::cout << "packet received gap:" << actualGap << " " + << "min:" << timeGaps.getMin() << " " + << "max:" << timeGaps.getMax() << " " + << "avg:" << timeGaps.getAverage() << " " + << "min last 30:" << timeGaps.getWindowMin() << " " + << "max last 30:" << timeGaps.getWindowMax() << " " + << "avg last 30:" << timeGaps.getWindowAverage() << " " + << "\n"; + last = now; + } +} + From 355cf074433c7fbd406091780f8e149b57e4af68 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 1 Aug 2014 13:03:10 -0700 Subject: [PATCH 156/407] Fix style issue --- libraries/models/src/ModelTree.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/models/src/ModelTree.cpp b/libraries/models/src/ModelTree.cpp index df94213213..53ee60d696 100644 --- a/libraries/models/src/ModelTree.cpp +++ b/libraries/models/src/ModelTree.cpp @@ -397,7 +397,7 @@ void ModelTree::findModelsInCube(const AACube& cube, QVector& foundM } bool ModelTree::findInCubeOperation(OctreeElement* element, void* extraData) { - FindModelsInCubeArgs* args = static_cast< FindModelsInCubeArgs*>(extraData); + FindModelsInCubeArgs* args = static_cast(extraData); const AACube& elementCube = element->getAACube(); if (elementCube.touches(args->_cube)) { ModelTreeElement* modelTreeElement = static_cast(element); @@ -408,7 +408,7 @@ bool ModelTree::findInCubeOperation(OctreeElement* element, void* extraData) { } bool ModelTree::findInCubeForUpdateOperation(OctreeElement* element, void* extraData) { - FindModelsInCubeArgs* args = static_cast< FindModelsInCubeArgs*>(extraData); + FindModelsInCubeArgs* args = static_cast(extraData); const AACube& elementCube = element->getAACube(); if (elementCube.touches(args->_cube)) { ModelTreeElement* modelTreeElement = static_cast(element); From b98ee351a5817a0ac064be36b2a0031fc5c960bc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 1 Aug 2014 13:04:03 -0700 Subject: [PATCH 157/407] Remove unused ModelTree::getModelAt --- libraries/models/src/ModelTree.cpp | 4 ---- libraries/models/src/ModelTree.h | 2 -- 2 files changed, 6 deletions(-) diff --git a/libraries/models/src/ModelTree.cpp b/libraries/models/src/ModelTree.cpp index 53ee60d696..b9b4faed07 100644 --- a/libraries/models/src/ModelTree.cpp +++ b/libraries/models/src/ModelTree.cpp @@ -112,10 +112,6 @@ bool FindAndUpdateModelOperator::PostRecursion(OctreeElement* element) { } -ModelTreeElement* ModelTree::getModelAt(float x, float y, float z, float s) const { - return static_cast(getOctreeElementAt(x, y, z, s)); -} - // TODO: improve this to not use multiple recursions void ModelTree::storeModel(const ModelItem& model, const SharedNodePointer& senderNode) { // First, look for the existing model in the tree.. diff --git a/libraries/models/src/ModelTree.h b/libraries/models/src/ModelTree.h index 3a1159c9cf..e61cc6057e 100644 --- a/libraries/models/src/ModelTree.h +++ b/libraries/models/src/ModelTree.h @@ -36,8 +36,6 @@ public: /// Type safe version of getRoot() ModelTreeElement* getRoot() { return static_cast(_rootElement); } - ModelTreeElement* getModelAt(float x, float y, float z, float s) const; - // These methods will allow the OctreeServer to send your tree inbound edit packets of your // own definition. Implement these to allow your octree based server to support editing virtual bool getWantSVOfileVersions() const { return true; } From 8359ebb82f028d4eb9a2643630f5f8166d001622 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 13:12:37 -0700 Subject: [PATCH 158/407] use c std version of usecTimestampNow() --- tests/jitter/src/main.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index 05a05e53d2..f3d2960d2d 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -12,13 +12,19 @@ #include #include #include +#include -#include // for usecTimeStampNow() +//#include // for usecTimestampNow() #include // for MovingMinMaxAvg void runSend(const char* addressOption, int port, int gap, int size); void runReceive(const char* addressOption, int port, int gap, int size); +quint64 usecTimestampNow() { + struct timeval tv; + gettimeofday(&tv,NULL); + return tv.tv_sec*(uint64_t)1000000+tv.tv_usec; +} int main(int argc, const char * argv[]) { if (argc != 6) { From 8c14f948f2ea3f917293699cf3d17afcd2f10465 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 13:15:57 -0700 Subject: [PATCH 159/407] handle first packet stats better --- tests/jitter/src/main.cpp | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index f3d2960d2d..a44bb3bef1 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -123,23 +123,28 @@ void runReceive(const char* addressOption, int port, int gap, int size) { return; } - quint64 last = usecTimestampNow(); + quint64 last = 0; // first case while (true) { n = recvfrom(sockfd, inputBuffer, size, 0, NULL, NULL); // we don't care about where it came from - - quint64 now = usecTimestampNow(); - int actualGap = now - last; - timeGaps.update(actualGap); - std::cout << "packet received gap:" << actualGap << " " - << "min:" << timeGaps.getMin() << " " - << "max:" << timeGaps.getMax() << " " - << "avg:" << timeGaps.getAverage() << " " - << "min last 30:" << timeGaps.getWindowMin() << " " - << "max last 30:" << timeGaps.getWindowMax() << " " - << "avg last 30:" << timeGaps.getWindowAverage() << " " - << "\n"; - last = now; + + if (last == 0) { + last = usecTimestampNow(); + std::cout << "first packet received\n"; + } else { + quint64 now = usecTimestampNow(); + int actualGap = now - last; + timeGaps.update(actualGap); + std::cout << "packet received gap:" << actualGap << " " + << "min:" << timeGaps.getMin() << " " + << "max:" << timeGaps.getMax() << " " + << "avg:" << timeGaps.getAverage() << " " + << "min last 30:" << timeGaps.getWindowMin() << " " + << "max last 30:" << timeGaps.getWindowMax() << " " + << "avg last 30:" << timeGaps.getWindowAverage() << " " + << "\n"; + last = now; + } } } From ddfdfc92424d9e3b052f85f004d0816225bc0591 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 13:21:46 -0700 Subject: [PATCH 160/407] windows build --- tests/jitter/src/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index a44bb3bef1..e29a26a51b 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -7,7 +7,11 @@ // #include +#ifdef _WINDOWS +#include +#else #include +#endif #include #include #include From ad4dd9404d88a6a257f929dcc3d9125cf2337232 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 13:26:56 -0700 Subject: [PATCH 161/407] windows build --- tests/jitter/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index e29a26a51b..cb7455cebe 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -12,7 +12,7 @@ #else #include #endif -#include +//#include #include #include #include From e0946838f394a656457b54943e8cfd2e2cfbdad2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 13:34:01 -0700 Subject: [PATCH 162/407] windows build --- tests/jitter/src/main.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index cb7455cebe..1f42b9e517 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -12,13 +12,10 @@ #else #include #endif -//#include #include -#include #include #include -//#include // for usecTimestampNow() #include // for MovingMinMaxAvg void runSend(const char* addressOption, int port, int gap, int size); From 48b73e3f0e771b8638daff8e2741b3a1e3ac6a2a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 13:42:37 -0700 Subject: [PATCH 163/407] windows build --- tests/jitter/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index 1f42b9e517..8c42e8e157 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -11,9 +11,9 @@ #include #else #include +#include #endif #include -#include #include #include // for MovingMinMaxAvg From d01d605b4029fdf70529d07d952386e84b3a032b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 1 Aug 2014 13:52:00 -0700 Subject: [PATCH 164/407] Add ModelItemProperties::copyFromNewModelItem --- interface/src/Application.cpp | 2 +- libraries/models/src/ModelItem.cpp | 32 ++++++++++++++++++++++++++++++ libraries/models/src/ModelItem.h | 1 + libraries/models/src/ModelTree.cpp | 2 +- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 540cb47a79..490e5441d2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1517,7 +1517,7 @@ bool Application::exportModels(const QString& filename, float x, float y, float ModelItemProperties properties; ModelItemID id = models.at(i)->getModelItemID(); id.isKnownID = false; - properties.copyFromModelItem(*models.at(i)); + properties.copyFromNewModelItem(*models.at(i)); properties.setPosition(properties.getPosition() - root); exportTree.addModel(id, properties); } diff --git a/libraries/models/src/ModelItem.cpp b/libraries/models/src/ModelItem.cpp index afa64e3bc6..2a3a88fb65 100644 --- a/libraries/models/src/ModelItem.cpp +++ b/libraries/models/src/ModelItem.cpp @@ -1142,6 +1142,38 @@ void ModelItemProperties::copyFromModelItem(const ModelItem& modelItem) { _id = modelItem.getID(); _idSet = true; + _positionChanged = false; + _colorChanged = false; + _radiusChanged = false; + + _shouldDieChanged = false; + _modelURLChanged = false; + _modelRotationChanged = false; + _animationURLChanged = false; + _animationIsPlayingChanged = false; + _animationFrameIndexChanged = false; + _animationFPSChanged = false; + _glowLevelChanged = false; + _defaultSettings = false; +} + +void ModelItemProperties::copyFromNewModelItem(const ModelItem& modelItem) { + _position = modelItem.getPosition() * (float) TREE_SCALE; + _color = modelItem.getXColor(); + _radius = modelItem.getRadius() * (float) TREE_SCALE; + _shouldDie = modelItem.getShouldDie(); + _modelURL = modelItem.getModelURL(); + _modelRotation = modelItem.getModelRotation(); + _animationURL = modelItem.getAnimationURL(); + _animationIsPlaying = modelItem.getAnimationIsPlaying(); + _animationFrameIndex = modelItem.getAnimationFrameIndex(); + _animationFPS = modelItem.getAnimationFPS(); + _glowLevel = modelItem.getGlowLevel(); + _sittingPoints = modelItem.getSittingPoints(); + + _id = modelItem.getID(); + _idSet = true; + _positionChanged = true; _colorChanged = true; _radiusChanged = true; diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 43aaca48a0..3e3c46a12d 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -74,6 +74,7 @@ public: void copyToModelItem(ModelItem& modelItem) const; void copyFromModelItem(const ModelItem& modelItem); + void copyFromNewModelItem(const ModelItem& modelItem); const glm::vec3& getPosition() const { return _position; } xColor getColor() const { return _color; } diff --git a/libraries/models/src/ModelTree.cpp b/libraries/models/src/ModelTree.cpp index b9b4faed07..206e67078c 100644 --- a/libraries/models/src/ModelTree.cpp +++ b/libraries/models/src/ModelTree.cpp @@ -221,7 +221,7 @@ bool ModelTree::sendModelsOperation(OctreeElement* element, void* extraData) { uint32_t creatorTokenID = ModelItem::getNextCreatorTokenID(); ModelItemID id(NEW_MODEL, creatorTokenID, false); ModelItemProperties properties; - properties.copyFromModelItem(modelList.at(i)); + properties.copyFromNewModelItem(modelList.at(i)); properties.setPosition(properties.getPosition() + args->root); args->packetSender->queueModelEditMessage(PacketTypeModelAddOrEdit, id, properties); } From c11b739ad6e3ca0bd48fc4465d7f2bd2820e9c9a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 1 Aug 2014 13:53:46 -0700 Subject: [PATCH 165/407] Frustum class/box intersection testing. --- libraries/metavoxels/src/MetavoxelUtil.cpp | 128 +++++++++++++++++++++ libraries/metavoxels/src/MetavoxelUtil.h | 37 ++++++ 2 files changed, 165 insertions(+) diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index a96b831dc1..2cfa3a5bc3 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -315,6 +315,134 @@ QDebug& operator<<(QDebug& dbg, const Box& box) { return dbg.nospace() << "{type='Box', minimum=" << box.minimum << ", maximum=" << box.maximum << "}"; } +AxisExtents::AxisExtents(const glm::vec3& first0, const glm::vec3& first1, const glm::vec3& first2, const glm::vec3& second) : + axis(glm::cross(first2 - first1, first0 - first1)), + minimum(glm::dot(first1, axis)), + maximum(glm::dot(second, axis)) { +} + +AxisExtents::AxisExtents(const glm::vec3& axis, float minimum, float maximum) : + axis(axis), + minimum(minimum), + maximum(maximum) { +} + +Frustum::Frustum(const glm::vec3& farTopLeft, const glm::vec3& farTopRight, const glm::vec3& farBottomLeft, + const glm::vec3& farBottomRight, const glm::vec3& nearTopLeft, const glm::vec3& nearTopRight, + const glm::vec3& nearBottomLeft, const glm::vec3& nearBottomRight) : + _bounds(glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX), glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX)) { + + _vertices[0] = farBottomLeft; + _vertices[1] = farBottomRight; + _vertices[2] = farTopLeft; + _vertices[3] = farTopRight; + _vertices[4] = nearBottomLeft; + _vertices[5] = nearBottomRight; + _vertices[6] = nearTopLeft; + _vertices[7] = nearTopRight; + + for (int i = 0; i < VERTEX_COUNT; i++) { + _bounds.minimum = glm::min(_bounds.minimum, _vertices[i]); + _bounds.maximum = glm::max(_bounds.maximum, _vertices[i]); + } + + // compute the extents for each side + _sideExtents[0] = AxisExtents(nearBottomLeft, nearTopLeft, nearTopRight, farBottomLeft); + _sideExtents[1] = AxisExtents(nearBottomLeft, farBottomLeft, farTopLeft, farBottomRight); + _sideExtents[2] = AxisExtents(nearBottomRight, nearTopRight, farTopRight, farBottomLeft); + _sideExtents[3] = AxisExtents(nearBottomLeft, nearBottomRight, farBottomRight, farTopLeft); + _sideExtents[4] = AxisExtents(nearTopLeft, farTopLeft, farTopRight, farBottomRight); + + // the other set of extents are derived from the cross products of the frustum and box edges + glm::vec3 edges[] = { nearBottomRight - nearBottomLeft, nearTopLeft - nearBottomLeft, farBottomLeft - nearBottomLeft, + farBottomRight - nearBottomRight, farTopLeft - nearTopLeft, farTopRight - nearTopRight }; + const int AXIS_COUNT = 3; + for (uint i = 0, extentIndex = 0; i < sizeof(edges) / sizeof(edges[0]); i++) { + for (int j = 0; j < AXIS_COUNT; j++) { + glm::vec3 axis; + axis[j] = 1.0f; + glm::vec3 crossProduct = glm::cross(edges[i], axis); + float minimum = FLT_MAX, maximum = -FLT_MAX; + for (int k = 0; k < VERTEX_COUNT; k++) { + float projection = glm::dot(crossProduct, _vertices[k]); + minimum = glm::min(minimum, projection); + maximum = glm::max(maximum, projection); + } + _crossProductExtents[extentIndex++] = AxisExtents(crossProduct, minimum, maximum); + } + } +} + +Frustum::IntersectionType Frustum::getIntersectionType(const Box& box) const { + // first check the bounds (equivalent to checking frustum vertices against box extents) + if (!_bounds.intersects(box)) { + return NO_INTERSECTION; + } + + // check box vertices against side extents + bool allInside = true; + for (int i = 0; i < SIDE_EXTENT_COUNT; i++) { + const AxisExtents& extents = _sideExtents[i]; + float firstProjection = glm::dot(box.getVertex(0), extents.axis); + if (firstProjection < extents.minimum) { + allInside = false; + for (int j = 1; j < Box::VERTEX_COUNT; j++) { + if (glm::dot(box.getVertex(j), extents.axis) >= extents.minimum) { + goto sideContinue; + } + } + return NO_INTERSECTION; + + } else if (firstProjection > extents.maximum) { + allInside = false; + for (int j = 1; j < Box::VERTEX_COUNT; j++) { + if (glm::dot(box.getVertex(j), extents.axis) <= extents.maximum) { + goto sideContinue; + } + } + return NO_INTERSECTION; + + } else if (allInside) { + for (int j = 1; j < Box::VERTEX_COUNT; j++) { + float projection = glm::dot(box.getVertex(j), extents.axis); + if (projection < extents.minimum || projection > extents.maximum) { + allInside = false; + goto sideContinue; + } + } + } + sideContinue: ; + } + if (allInside) { + return CONTAINS_INTERSECTION; + } + + // check box vertices against cross product extents + for (int i = 0; i < CROSS_PRODUCT_EXTENT_COUNT; i++) { + const AxisExtents& extents = _crossProductExtents[i]; + float firstProjection = glm::dot(box.getVertex(0), extents.axis); + if (firstProjection < extents.minimum) { + for (int j = 1; j < Box::VERTEX_COUNT; j++) { + if (glm::dot(box.getVertex(j), extents.axis) >= extents.minimum) { + goto crossProductContinue; + } + } + return NO_INTERSECTION; + + } else if (firstProjection > extents.maximum) { + for (int j = 1; j < Box::VERTEX_COUNT; j++) { + if (glm::dot(box.getVertex(j), extents.axis) <= extents.maximum) { + goto crossProductContinue; + } + } + return NO_INTERSECTION; + } + crossProductContinue: ; + } + + return PARTIAL_INTERSECTION; +} + QMetaObjectEditor::QMetaObjectEditor(QWidget* parent) : QWidget(parent) { QVBoxLayout* layout = new QVBoxLayout(); layout->setContentsMargins(QMargins()); diff --git a/libraries/metavoxels/src/MetavoxelUtil.h b/libraries/metavoxels/src/MetavoxelUtil.h index 021fbcb20d..6a7b15150e 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.h +++ b/libraries/metavoxels/src/MetavoxelUtil.h @@ -65,6 +65,43 @@ Box operator*(const glm::mat4& matrix, const Box& box); QDebug& operator<<(QDebug& out, const Box& box); +/// Represents the extents along an axis. +class AxisExtents { +public: + glm::vec3 axis; + float minimum; + float maximum; + + /// Creates a set of extents given three points on the first plane and one on the second. + AxisExtents(const glm::vec3& first0, const glm::vec3& first1, const glm::vec3& first2, const glm::vec3& second); + + AxisExtents(const glm::vec3& axis = glm::vec3(), float minimum = 0.0f, float maximum = 0.0f); +}; + +/// A simple pyramidal frustum for intersection testing. +class Frustum { +public: + + Frustum(const glm::vec3& farTopLeft, const glm::vec3& farTopRight, const glm::vec3& farBottomLeft, + const glm::vec3& farBottomRight, const glm::vec3& nearTopLeft, const glm::vec3& nearTopRight, + const glm::vec3& nearBottomLeft, const glm::vec3& nearBottomRight); + + enum IntersectionType { NO_INTERSECTION, PARTIAL_INTERSECTION, CONTAINS_INTERSECTION }; + + IntersectionType getIntersectionType(const Box& box) const; + +private: + + static const int VERTEX_COUNT = 8; + static const int SIDE_EXTENT_COUNT = 5; + static const int CROSS_PRODUCT_EXTENT_COUNT = 18; + + glm::vec3 _vertices[VERTEX_COUNT]; + Box _bounds; + AxisExtents _sideExtents[SIDE_EXTENT_COUNT]; + AxisExtents _crossProductExtents[CROSS_PRODUCT_EXTENT_COUNT]; +}; + /// Editor for meta-object values. class QMetaObjectEditor : public QWidget { Q_OBJECT From 8db66e4322bf8c08d3be7d95ffa36114b90dcf27 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 13:58:38 -0700 Subject: [PATCH 166/407] use our ported version of usecTimestampNow cause windows sucks --- tests/jitter/src/main.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index 8c42e8e157..224f3c90cb 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -14,19 +14,13 @@ #include #endif #include -#include #include // for MovingMinMaxAvg +#include // for usecTimestampNow void runSend(const char* addressOption, int port, int gap, int size); void runReceive(const char* addressOption, int port, int gap, int size); -quint64 usecTimestampNow() { - struct timeval tv; - gettimeofday(&tv,NULL); - return tv.tv_sec*(uint64_t)1000000+tv.tv_usec; -} - int main(int argc, const char * argv[]) { if (argc != 6) { printf("usage: jitter-tests <--send|--receive>
\n"); From 36f635ed8d91456fceecbcc2bef40bf15571acc6 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 14:07:14 -0700 Subject: [PATCH 167/407] change stats to display difference between gap and expected gap --- tests/jitter/src/main.cpp | 40 +++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index 224f3c90cb..eebf88c5d0 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -66,27 +66,29 @@ void runSend(const char* addressOption, int port, int gap, int size) { servaddr.sin_port=htons(port); const int SAMPLES_FOR_30_SECONDS = 30 * 1000 / gap; - MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats + MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats quint64 last = usecTimestampNow(); while (true) { quint64 now = usecTimestampNow(); - quint64 actualGap = now - last; + int actualGap = now - last; if (actualGap >= gap) { sendto(sockfd, outputBuffer, size, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); - timeGaps.update(actualGap); - std::cout << "packet sent gap:" << actualGap << " " - << "min:" << timeGaps.getMin() << " " - << "max:" << timeGaps.getMax() << " " - << "avg:" << timeGaps.getAverage() << " " - << "min last 30:" << timeGaps.getWindowMin() << " " - << "max last 30:" << timeGaps.getWindowMax() << " " - << "avg last 30:" << timeGaps.getWindowAverage() << " " + int gapDifferece = actualGap - gap; + timeGaps.update(gapDifferece); + std::cout << "packet sent gap: " << actualGap << " " + << "gapDifference: " << gapDifferece << " " + << "min: " << timeGaps.getMin() << " " + << "max: " << timeGaps.getMax() << " " + << "avg: " << timeGaps.getAverage() << " " + << "min last 30: " << timeGaps.getWindowMin() << " " + << "max last 30: " << timeGaps.getWindowMax() << " " + << "avg last 30: " << timeGaps.getWindowAverage() << " " << "\n"; last = now; } @@ -111,7 +113,7 @@ void runReceive(const char* addressOption, int port, int gap, int size) { myaddr.sin_port=htons(port); const int SAMPLES_FOR_30_SECONDS = 30 * 1000 / gap; - MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats + MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { std::cout << "bind failed\n"; @@ -129,14 +131,16 @@ void runReceive(const char* addressOption, int port, int gap, int size) { } else { quint64 now = usecTimestampNow(); int actualGap = now - last; - timeGaps.update(actualGap); + int gapDifferece = actualGap - gap; + timeGaps.update(gapDifferece); std::cout << "packet received gap:" << actualGap << " " - << "min:" << timeGaps.getMin() << " " - << "max:" << timeGaps.getMax() << " " - << "avg:" << timeGaps.getAverage() << " " - << "min last 30:" << timeGaps.getWindowMin() << " " - << "max last 30:" << timeGaps.getWindowMax() << " " - << "avg last 30:" << timeGaps.getWindowAverage() << " " + << "gapDifference: " << gapDifferece << " " + << "min: " << timeGaps.getMin() << " " + << "max: " << timeGaps.getMax() << " " + << "avg: " << timeGaps.getAverage() << " " + << "min last 30: " << timeGaps.getWindowMin() << " " + << "max last 30: " << timeGaps.getWindowMax() << " " + << "avg last 30: " << timeGaps.getWindowAverage() << " " << "\n"; last = now; } From ca4bca704210c4649f3310a647d3d4575687e5be Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 14:11:24 -0700 Subject: [PATCH 168/407] more windows headaches memset instead of bzero --- tests/jitter/src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index eebf88c5d0..23199f03b3 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -60,7 +60,7 @@ void runSend(const char* addressOption, int port, int gap, int size) { sockfd=socket(AF_INET,SOCK_DGRAM,0); - bzero(&servaddr,sizeof(servaddr)); + memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr=inet_addr(addressOption); servaddr.sin_port=htons(port); @@ -107,7 +107,7 @@ void runReceive(const char* addressOption, int port, int gap, int size) { sockfd=socket(AF_INET, SOCK_DGRAM, 0); - bzero(&myaddr,sizeof(myaddr)); + memset(&myaddr, 0, sizeof(myaddr)); myaddr.sin_family = AF_INET; myaddr.sin_addr.s_addr=htonl(INADDR_ANY); myaddr.sin_port=htons(port); From 374e89817bf86b66df0371065e89cf6ecd4ad5cf Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 Aug 2014 14:46:28 -0700 Subject: [PATCH 169/407] minor optimization of MuscleConstraint::enforce() --- interface/src/avatar/MuscleConstraint.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MuscleConstraint.cpp b/interface/src/avatar/MuscleConstraint.cpp index 31da56d3d3..76f30fdbc4 100644 --- a/interface/src/avatar/MuscleConstraint.cpp +++ b/interface/src/avatar/MuscleConstraint.cpp @@ -22,7 +22,7 @@ MuscleConstraint::MuscleConstraint(VerletPoint* parent, VerletPoint* child) : _r } float MuscleConstraint::enforce() { - _childPoint->_position = (1.0f - _strength) * _childPoint->_position + _strength * (_rootPoint->_position + _childOffset); + _childPoint->_position += _strength * (_rootPoint->_position + _childOffset - _childPoint->_position); return 0.0f; } From 60899d2a0039717e7264be471201e47ab6807344 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 14:55:14 -0700 Subject: [PATCH 170/407] oops --- tests/jitter/src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index 23199f03b3..f93e91e5cf 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -65,7 +65,7 @@ void runSend(const char* addressOption, int port, int gap, int size) { servaddr.sin_addr.s_addr=inet_addr(addressOption); servaddr.sin_port=htons(port); - const int SAMPLES_FOR_30_SECONDS = 30 * 1000 / gap; + const int SAMPLES_FOR_30_SECONDS = 30 * 1000000 / gap; MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats quint64 last = usecTimestampNow(); @@ -112,7 +112,7 @@ void runReceive(const char* addressOption, int port, int gap, int size) { myaddr.sin_addr.s_addr=htonl(INADDR_ANY); myaddr.sin_port=htons(port); - const int SAMPLES_FOR_30_SECONDS = 30 * 1000 / gap; + const int SAMPLES_FOR_30_SECONDS = 30 * 1000000 / gap; MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { From 1ec6ee05f39d93b5efa6ae7f9d3a1b47ce838811 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 Aug 2014 15:08:21 -0700 Subject: [PATCH 171/407] Rename ContactConstraint to ContactPoint --- .../{ContactConstraint.cpp => ContactPoint.cpp} | 12 ++++++------ .../src/{ContactConstraint.h => ContactPoint.h} | 14 +++++++------- libraries/shared/src/PhysicsSimulation.cpp | 10 +++++----- libraries/shared/src/PhysicsSimulation.h | 4 ++-- 4 files changed, 20 insertions(+), 20 deletions(-) rename libraries/shared/src/{ContactConstraint.cpp => ContactPoint.cpp} (88%) rename libraries/shared/src/{ContactConstraint.h => ContactPoint.h} (78%) diff --git a/libraries/shared/src/ContactConstraint.cpp b/libraries/shared/src/ContactPoint.cpp similarity index 88% rename from libraries/shared/src/ContactConstraint.cpp rename to libraries/shared/src/ContactPoint.cpp index d1d12fa771..1f6dbcdb11 100644 --- a/libraries/shared/src/ContactConstraint.cpp +++ b/libraries/shared/src/ContactPoint.cpp @@ -1,5 +1,5 @@ // -// ContactConstraint.cpp +// ContactPoint.cpp // libraries/shared/src // // Created by Andrew Meadows 2014.07.30 @@ -9,15 +9,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "ContactConstraint.h" +#include "ContactPoint.h" #include "Shape.h" #include "SharedUtil.h" -ContactConstraint::ContactConstraint() : _lastFrame(0), _shapeA(NULL), _shapeB(NULL), +ContactPoint::ContactPoint() : _lastFrame(0), _shapeA(NULL), _shapeB(NULL), _offsetA(0.0f), _offsetB(0.0f), _normal(0.0f) { } -ContactConstraint::ContactConstraint(const CollisionInfo& collision, quint32 frame) : _lastFrame(frame), +ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : _lastFrame(frame), _shapeA(collision.getShapeA()), _shapeB(collision.getShapeB()), _offsetA(0.0f), _offsetB(0.0f), _normal(0.0f) { _offsetA = collision._contactPoint - _shapeA->getTranslation(); @@ -40,7 +40,7 @@ ContactConstraint::ContactConstraint(const CollisionInfo& collision, quint32 fra } // virtual -float ContactConstraint::enforce() { +float ContactPoint::enforce() { glm::vec3 pointA = _shapeA->getTranslation() + _offsetA; glm::vec3 pointB = _shapeB->getTranslation() + _offsetB; glm::vec3 penetration = pointA - pointB; @@ -65,7 +65,7 @@ float ContactConstraint::enforce() { return 0.0f; } -void ContactConstraint::updateContact(const CollisionInfo& collision, quint32 frame) { +void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) { _lastFrame = frame; _offsetA = collision._contactPoint - collision._shapeA->getTranslation(); _offsetB = collision._contactPoint - collision._penetration - collision._shapeB->getTranslation(); diff --git a/libraries/shared/src/ContactConstraint.h b/libraries/shared/src/ContactPoint.h similarity index 78% rename from libraries/shared/src/ContactConstraint.h rename to libraries/shared/src/ContactPoint.h index 1c8b7d1b57..84e15a85ee 100644 --- a/libraries/shared/src/ContactConstraint.h +++ b/libraries/shared/src/ContactPoint.h @@ -1,5 +1,5 @@ // -// ContactConstraint.h +// ContactPoint.h // libraries/shared/src // // Created by Andrew Meadows 2014.07.30 @@ -9,8 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_ContactConstraint_h -#define hifi_ContactConstraint_h +#ifndef hifi_ContactPoint_h +#define hifi_ContactPoint_h #include #include @@ -19,10 +19,10 @@ class Shape; -class ContactConstraint { +class ContactPoint { public: - ContactConstraint(); - ContactConstraint(const CollisionInfo& collision, quint32 frame); + ContactPoint(); + ContactPoint(const CollisionInfo& collision, quint32 frame); virtual float enforce(); @@ -41,4 +41,4 @@ protected: glm::vec3 _normal; // (points from A toward B) }; -#endif // hifi_ContactConstraint_h +#endif // hifi_ContactPoint_h diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index 3e3529be10..8bcbb7255a 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -88,7 +88,7 @@ void PhysicsSimulation::removeEntity(PhysicsEntity* entity) { } } // remove corresponding contacts - QMap::iterator itr = _contacts.begin(); + QMap::iterator itr = _contacts.begin(); while (itr != _contacts.end()) { if (entity == itr.value().getShapeA()->getEntity() || entity == itr.value().getShapeB()->getEntity()) { itr = _contacts.erase(itr); @@ -251,7 +251,7 @@ void PhysicsSimulation::enforceContacts() { if (key == 0) { continue; } - QMap::iterator itr = _contacts.find(key); + QMap::iterator itr = _contacts.find(key); if (itr != _contacts.end()) { if (itr.value().enforce() > 0.0f) { shapes.insert(collision->getShapeA()); @@ -276,9 +276,9 @@ void PhysicsSimulation::updateContacts() { if (key == 0) { continue; } - QMap::iterator itr = _contacts.find(key); + QMap::iterator itr = _contacts.find(key); if (itr == _contacts.end()) { - _contacts.insert(key, ContactConstraint(*collision, _frame)); + _contacts.insert(key, ContactPoint(*collision, _frame)); } else { itr.value().updateContact(*collision, _frame); } @@ -288,7 +288,7 @@ void PhysicsSimulation::updateContacts() { const quint32 MAX_CONTACT_FRAME_LIFETIME = 2; void PhysicsSimulation::pruneContacts() { - QMap::iterator itr = _contacts.begin(); + QMap::iterator itr = _contacts.begin(); while (itr != _contacts.end()) { if (_frame - itr.value().getLastFrame() > MAX_CONTACT_FRAME_LIFETIME) { itr = _contacts.erase(itr); diff --git a/libraries/shared/src/PhysicsSimulation.h b/libraries/shared/src/PhysicsSimulation.h index 6e69e72219..8cbc39b9d3 100644 --- a/libraries/shared/src/PhysicsSimulation.h +++ b/libraries/shared/src/PhysicsSimulation.h @@ -17,7 +17,7 @@ #include #include "CollisionInfo.h" -#include "ContactConstraint.h" +#include "ContactPoint.h" class PhysicsEntity; class Ragdoll; @@ -59,7 +59,7 @@ private: QVector _dolls; QVector _entities; CollisionList _collisions; - QMap _contacts; + QMap _contacts; }; #endif // hifi_PhysicsSimulation From 34ca5ded72c98f4c572f40ed99178300e2bf5c74 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 15:09:11 -0700 Subject: [PATCH 172/407] add reporting interval --- tests/jitter/src/main.cpp | 66 ++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index f93e91e5cf..ef63e3b2e1 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -18,12 +18,14 @@ #include // for MovingMinMaxAvg #include // for usecTimestampNow -void runSend(const char* addressOption, int port, int gap, int size); -void runReceive(const char* addressOption, int port, int gap, int size); +const quint64 MSEC_TO_USEC = 1000; + +void runSend(const char* addressOption, int port, int gap, int size, int report); +void runReceive(const char* addressOption, int port, int gap, int size, int report); int main(int argc, const char * argv[]) { - if (argc != 6) { - printf("usage: jitter-tests <--send|--receive>
\n"); + if (argc != 7) { + printf("usage: jitter-tests <--send|--receive>
\n"); exit(1); } const char* typeOption = argv[1]; @@ -31,9 +33,11 @@ int main(int argc, const char * argv[]) { const char* portOption = argv[3]; const char* gapOption = argv[4]; const char* sizeOption = argv[5]; + const char* reportOption = argv[6]; int port = atoi(portOption); int gap = atoi(gapOption); int size = atoi(sizeOption); + int report = atoi(reportOption); std::cout << "type:" << typeOption << "\n"; std::cout << "address:" << addressOption << "\n"; @@ -42,14 +46,14 @@ int main(int argc, const char * argv[]) { std::cout << "size:" << size << "\n"; if (strcmp(typeOption, "--send") == 0) { - runSend(addressOption, port, gap, size); + runSend(addressOption, port, gap, size, report); } else if (strcmp(typeOption, "--receive") == 0) { - runReceive(addressOption, port, gap, size); + runReceive(addressOption, port, gap, size, report); } exit(1); } -void runSend(const char* addressOption, int port, int gap, int size) { +void runSend(const char* addressOption, int port, int gap, int size, int report) { std::cout << "runSend...\n"; int sockfd; @@ -69,6 +73,7 @@ void runSend(const char* addressOption, int port, int gap, int size) { MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats quint64 last = usecTimestampNow(); + quint64 lastReport = 0; while (true) { @@ -81,21 +86,25 @@ void runSend(const char* addressOption, int port, int gap, int size) { int gapDifferece = actualGap - gap; timeGaps.update(gapDifferece); - std::cout << "packet sent gap: " << actualGap << " " - << "gapDifference: " << gapDifferece << " " - << "min: " << timeGaps.getMin() << " " - << "max: " << timeGaps.getMax() << " " - << "avg: " << timeGaps.getAverage() << " " - << "min last 30: " << timeGaps.getWindowMin() << " " - << "max last 30: " << timeGaps.getWindowMax() << " " - << "avg last 30: " << timeGaps.getWindowAverage() << " " - << "\n"; last = now; + + if (now - lastReport >= (report * MSEC_TO_USEC)) { + std::cout << "packet sent gap: " << actualGap << " " + << "gapDifference: " << gapDifferece << " " + << "min: " << timeGaps.getMin() << " " + << "max: " << timeGaps.getMax() << " " + << "avg: " << timeGaps.getAverage() << " " + << "min last 30: " << timeGaps.getWindowMin() << " " + << "max last 30: " << timeGaps.getWindowMax() << " " + << "avg last 30: " << timeGaps.getWindowAverage() << " " + << "\n"; + lastReport = now; + } } } } -void runReceive(const char* addressOption, int port, int gap, int size) { +void runReceive(const char* addressOption, int port, int gap, int size, int report) { std::cout << "runReceive...\n"; @@ -121,6 +130,7 @@ void runReceive(const char* addressOption, int port, int gap, int size) { } quint64 last = 0; // first case + quint64 lastReport = 0; while (true) { n = recvfrom(sockfd, inputBuffer, size, 0, NULL, NULL); // we don't care about where it came from @@ -133,16 +143,20 @@ void runReceive(const char* addressOption, int port, int gap, int size) { int actualGap = now - last; int gapDifferece = actualGap - gap; timeGaps.update(gapDifferece); - std::cout << "packet received gap:" << actualGap << " " - << "gapDifference: " << gapDifferece << " " - << "min: " << timeGaps.getMin() << " " - << "max: " << timeGaps.getMax() << " " - << "avg: " << timeGaps.getAverage() << " " - << "min last 30: " << timeGaps.getWindowMin() << " " - << "max last 30: " << timeGaps.getWindowMax() << " " - << "avg last 30: " << timeGaps.getWindowAverage() << " " - << "\n"; last = now; + + if (now - lastReport >= (report * MSEC_TO_USEC)) { + std::cout << "packet received gap:" << actualGap << " " + << "gapDifference: " << gapDifferece << " " + << "min: " << timeGaps.getMin() << " " + << "max: " << timeGaps.getMax() << " " + << "avg: " << timeGaps.getAverage() << " " + << "min last 30: " << timeGaps.getWindowMin() << " " + << "max last 30: " << timeGaps.getWindowMax() << " " + << "avg last 30: " << timeGaps.getWindowAverage() << " " + << "\n"; + lastReport = now; + } } } } From ce46e8b812e750baf090464f1aa576f80fe5af34 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 15:14:43 -0700 Subject: [PATCH 173/407] tweak format of report --- tests/jitter/src/main.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index ef63e3b2e1..bd6923330c 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -89,8 +89,7 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) last = now; if (now - lastReport >= (report * MSEC_TO_USEC)) { - std::cout << "packet sent gap: " << actualGap << " " - << "gapDifference: " << gapDifferece << " " + std::cout << "SEND gap Difference From Expected " << "min: " << timeGaps.getMin() << " " << "max: " << timeGaps.getMax() << " " << "avg: " << timeGaps.getAverage() << " " @@ -146,8 +145,7 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo last = now; if (now - lastReport >= (report * MSEC_TO_USEC)) { - std::cout << "packet received gap:" << actualGap << " " - << "gapDifference: " << gapDifferece << " " + std::cout << "RECEIVE gap Difference From Expected " << "min: " << timeGaps.getMin() << " " << "max: " << timeGaps.getMax() << " " << "avg: " << timeGaps.getAverage() << " " From cb02ac16b6cf278929bf0aa4407e5f5f67cf1331 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 15:23:52 -0700 Subject: [PATCH 174/407] tweak format of report --- tests/jitter/src/main.cpp | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index bd6923330c..292b01e4a5 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -70,6 +70,9 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) servaddr.sin_port=htons(port); const int SAMPLES_FOR_30_SECONDS = 30 * 1000000 / gap; + + std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n"; + MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats quint64 last = usecTimestampNow(); @@ -90,12 +93,12 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) if (now - lastReport >= (report * MSEC_TO_USEC)) { std::cout << "SEND gap Difference From Expected " - << "min: " << timeGaps.getMin() << " " - << "max: " << timeGaps.getMax() << " " - << "avg: " << timeGaps.getAverage() << " " - << "min last 30: " << timeGaps.getWindowMin() << " " - << "max last 30: " << timeGaps.getWindowMax() << " " - << "avg last 30: " << timeGaps.getWindowAverage() << " " + << "min: " << timeGaps.getMin() << " usecs " + << "max: " << timeGaps.getMax() << " usecs " + << "avg: " << timeGaps.getAverage() << " usecs " + << "min last 30: " << timeGaps.getWindowMin() << " usecs " + << "max last 30: " << timeGaps.getWindowMax() << " usecs " + << "avg last 30: " << timeGaps.getWindowAverage() << " usecs " << "\n"; lastReport = now; } @@ -121,6 +124,9 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo myaddr.sin_port=htons(port); const int SAMPLES_FOR_30_SECONDS = 30 * 1000000 / gap; + + std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n"; + MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { @@ -146,12 +152,12 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo if (now - lastReport >= (report * MSEC_TO_USEC)) { std::cout << "RECEIVE gap Difference From Expected " - << "min: " << timeGaps.getMin() << " " - << "max: " << timeGaps.getMax() << " " - << "avg: " << timeGaps.getAverage() << " " - << "min last 30: " << timeGaps.getWindowMin() << " " - << "max last 30: " << timeGaps.getWindowMax() << " " - << "avg last 30: " << timeGaps.getWindowAverage() << " " + << "min: " << timeGaps.getMin() << " usecs " + << "max: " << timeGaps.getMax() << " usecs " + << "avg: " << timeGaps.getAverage() << " usecs " + << "min last 30: " << timeGaps.getWindowMin() << " usecs " + << "max last 30: " << timeGaps.getWindowMax() << " usecs " + << "avg last 30: " << timeGaps.getWindowAverage() << " usecs " << "\n"; lastReport = now; } From 66d45d354419acd16f1dd45e5a358552191a01e1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 1 Aug 2014 15:25:03 -0700 Subject: [PATCH 175/407] tweak format of report --- tests/jitter/src/main.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index 292b01e4a5..aefed73ccf 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -93,11 +93,11 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) if (now - lastReport >= (report * MSEC_TO_USEC)) { std::cout << "SEND gap Difference From Expected " - << "min: " << timeGaps.getMin() << " usecs " - << "max: " << timeGaps.getMax() << " usecs " - << "avg: " << timeGaps.getAverage() << " usecs " - << "min last 30: " << timeGaps.getWindowMin() << " usecs " - << "max last 30: " << timeGaps.getWindowMax() << " usecs " + << "min: " << timeGaps.getMin() << " usecs, " + << "max: " << timeGaps.getMax() << " usecs, " + << "avg: " << timeGaps.getAverage() << " usecs, " + << "min last 30: " << timeGaps.getWindowMin() << " usecs, " + << "max last 30: " << timeGaps.getWindowMax() << " usecs, " << "avg last 30: " << timeGaps.getWindowAverage() << " usecs " << "\n"; lastReport = now; @@ -152,11 +152,11 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo if (now - lastReport >= (report * MSEC_TO_USEC)) { std::cout << "RECEIVE gap Difference From Expected " - << "min: " << timeGaps.getMin() << " usecs " - << "max: " << timeGaps.getMax() << " usecs " - << "avg: " << timeGaps.getAverage() << " usecs " - << "min last 30: " << timeGaps.getWindowMin() << " usecs " - << "max last 30: " << timeGaps.getWindowMax() << " usecs " + << "min: " << timeGaps.getMin() << " usecs, " + << "max: " << timeGaps.getMax() << " usecs, " + << "avg: " << timeGaps.getAverage() << " usecs, " + << "min last 30: " << timeGaps.getWindowMin() << " usecs, " + << "max last 30: " << timeGaps.getWindowMax() << " usecs, " << "avg last 30: " << timeGaps.getWindowAverage() << " usecs " << "\n"; lastReport = now; From f9ec7b6c18e9444c5d304d91d7e4282ca62dd0a5 Mon Sep 17 00:00:00 2001 From: wangyix Date: Fri, 1 Aug 2014 16:13:52 -0700 Subject: [PATCH 176/407] redesiged SequenceNumberStats child instance handling --- .../networking/src/SequenceNumberStats.cpp | 128 ++++++++++-------- .../networking/src/SequenceNumberStats.h | 11 +- .../src/SequenceNumberStatsTests.cpp | 38 +++++- .../networking/src/SequenceNumberStatsTests.h | 1 + 4 files changed, 112 insertions(+), 66 deletions(-) diff --git a/libraries/networking/src/SequenceNumberStats.cpp b/libraries/networking/src/SequenceNumberStats.cpp index a700e01f07..7e9022934b 100644 --- a/libraries/networking/src/SequenceNumberStats.cpp +++ b/libraries/networking/src/SequenceNumberStats.cpp @@ -13,16 +13,16 @@ #include -SequenceNumberStats::SequenceNumberStats(int statsHistoryLength, int maxRecursion) +SequenceNumberStats::SequenceNumberStats(int statsHistoryLength, bool canDetectOutOfSync) : _received(0), _lastReceivedSequence(0), _missingSet(), _stats(), _lastSenderUUID(), _statsHistory(statsHistoryLength), - - _unreasonableTracker(NULL), - _maxRecursion(maxRecursion) + _canHaveChild(canDetectOutOfSync), + _childInstance(NULL), + _consecutiveReasonable(0) { } @@ -33,11 +33,12 @@ SequenceNumberStats::SequenceNumberStats(const SequenceNumberStats& other) _stats(other._stats), _lastSenderUUID(other._lastSenderUUID), _statsHistory(other._statsHistory), - _unreasonableTracker(NULL), - _maxRecursion(other._maxRecursion) + _childInstance(NULL), + _canHaveChild(other._canHaveChild), + _consecutiveReasonable(other._consecutiveReasonable) { - if (other._unreasonableTracker) { - _unreasonableTracker = new SequenceNumberStats(*other._unreasonableTracker); + if (other._childInstance) { + _childInstance = new SequenceNumberStats(*other._childInstance); } } @@ -48,19 +49,20 @@ SequenceNumberStats& SequenceNumberStats::operator=(const SequenceNumberStats& r _stats = rhs._stats; _lastSenderUUID = rhs._lastSenderUUID; _statsHistory = rhs._statsHistory; - _maxRecursion = rhs._maxRecursion; + _canHaveChild = rhs._canHaveChild; + _consecutiveReasonable = rhs._consecutiveReasonable; - if (rhs._unreasonableTracker) { - _unreasonableTracker = new SequenceNumberStats(*rhs._unreasonableTracker); + if (rhs._childInstance) { + _childInstance = new SequenceNumberStats(*rhs._childInstance); } else { - _unreasonableTracker = NULL; + _childInstance = NULL; } return *this; } SequenceNumberStats::~SequenceNumberStats() { - if (_unreasonableTracker) { - delete _unreasonableTracker; + if (_childInstance) { + delete _childInstance; } } @@ -71,8 +73,9 @@ void SequenceNumberStats::reset() { _lastSenderUUID = QUuid(); _statsHistory.clear(); - if (_unreasonableTracker) { - delete _unreasonableTracker; + if (_childInstance) { + delete _childInstance; + _childInstance = NULL; } } @@ -123,68 +126,78 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui } else if (absGap > MAX_REASONABLE_SEQUENCE_GAP) { arrivalInfo._status = Unreasonable; - /* - // ignore packet if gap is unreasonable - qDebug() << "ignoring unreasonable sequence number:" << incoming - << "previous:" << _lastReceivedSequence; + qDebug() << "unreasonable sequence number:" << incoming << "previous:" << _lastReceivedSequence; + _stats._unreasonable++; - */ + _consecutiveReasonable = 0; - // do not create a child tracker for unreasonable seq nums if this instance is the last one in the chain. - // otherwise, create one if we don't have one. + + // if _canHaveChild, create a child instance of SequenceNumberStats to track this unreasonable seq num and ones in the future. + // if the child instance detects a valid stream of seq nums up to some length, the seq nums sender probably + // fell out of sync with us. - if (!_unreasonableTracker && _maxRecursion > 0) { - _unreasonableTracker = new SequenceNumberStats(0, _maxRecursion - 1); - } + if (_canHaveChild) { + + if (!_childInstance) { + _childInstance = new SequenceNumberStats(0, false); + } - if (_unreasonableTracker) { + ArrivalInfo unreasonableTrackerArrivalInfo = _childInstance->sequenceNumberReceived(incoming); - // track this unreasonable seq number with our _unreasonableTracker. - ArrivalInfo unreasonableTrackerArrivalInfo = _unreasonableTracker->sequenceNumberReceived(incoming); - - const int UNREASONABLE_TRACKER_RECEIVED_THRESHOLD = 10; - const float UNRUNREASONABLE_TRACKER_UNREASONABLE_RATE_THRESHOLD = 0.1f; - const float UNREASONABLE_TRACKER_OUT_OF_ORDER_RATE_THRESHOLD = 0.1f; - - // when our _unreasonableTracker has received enough seq nums and doesn't have an _unreasonableTracker of its own, - // we'll either inherit its state only if we think its stream is plausible. it will then be deleted. - // (if it has an _unreasonableTracker of its own, its _unreasonableTracker may be detecting a plausible stream - // while its parent does not, so we should let it accrue seq nums and decide plausibility first) + // the child instance will be used to detect some threshold number seq nums in a row that are perfectly + // in order. - if (!_unreasonableTracker->hasUnreasonableTracker() && - _unreasonableTracker->_received >= UNREASONABLE_TRACKER_RECEIVED_THRESHOLD) { + const int UNREASONABLE_TRACKER_RECEIVED_THRESHOLD = 8; - if (_unreasonableTracker->getUnreasonableRate() < UNRUNREASONABLE_TRACKER_UNREASONABLE_RATE_THRESHOLD && - _unreasonableTracker->getStats().getOutOfOrderRate() < UNREASONABLE_TRACKER_OUT_OF_ORDER_RATE_THRESHOLD) { + if (unreasonableTrackerArrivalInfo._status != OnTime) { + _childInstance->reset(); - // the _unreasonableTracker has detected a plausible stream of seq numbers; - // copy its state to this tracker. + } else if (_childInstance->getReceived() >= UNREASONABLE_TRACKER_RECEIVED_THRESHOLD) { - _received = _unreasonableTracker->_received; - _lastReceivedSequence = _unreasonableTracker->_lastReceivedSequence; - _missingSet = _unreasonableTracker->_missingSet; - _stats = _unreasonableTracker->_stats; + // the child instance has detected a threshold number of consecutive seq nums. + // copy its state to this instance. - // don't copy _lastSenderUUID; _unreasonableTracker always has null UUID for that member. - // ours should be up-to-date. + _received = _childInstance->_received; + _lastReceivedSequence = _childInstance->_lastReceivedSequence; + _missingSet = _childInstance->_missingSet; + _stats = _childInstance->_stats; - // don't copy _statsHistory; _unreasonableTracker keeps a history of length 0. - // simply clear ours. - _statsHistory.clear(); + // don't copy _lastSenderUUID; _unreasonableTracker always has null UUID for that member. + // ours should be up-to-date. - arrivalInfo = unreasonableTrackerArrivalInfo; + // don't copy _statsHistory; _unreasonableTracker keeps a history of length 0. + // simply clear ours. + _statsHistory.clear(); - } - // remove our _unreasonableTracker - delete _unreasonableTracker; + arrivalInfo = unreasonableTrackerArrivalInfo; + + // delete child instance; + delete _childInstance; + _childInstance = NULL; } } return arrivalInfo; } + _consecutiveReasonable++; + + // if we got a reasonable seq num but have a child instance tracking unreasonable seq nums, + // reset it. if many consecutive reasonable seq nums have occurred (implying the unreasonable seq num + // that caused the creation of the child instance was just a fluke), delete our child instance. + if (_childInstance) { + const int CONSECUTIVE_REASONABLE_CHILD_DELETE_THRESHOLD = 4; + if (_consecutiveReasonable >= CONSECUTIVE_REASONABLE_CHILD_DELETE_THRESHOLD) { + _childInstance->reset(); + } else { + delete _childInstance; + _childInstance = NULL; + } + } + + // now that rollover has been corrected for (if it occurred), incomingInt and expectedInt can be // compared to each other directly, though one of them might be negative @@ -241,6 +254,7 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui } } } + return arrivalInfo; } diff --git a/libraries/networking/src/SequenceNumberStats.h b/libraries/networking/src/SequenceNumberStats.h index 1f740d7af8..71092d7409 100644 --- a/libraries/networking/src/SequenceNumberStats.h +++ b/libraries/networking/src/SequenceNumberStats.h @@ -19,9 +19,6 @@ const int MAX_REASONABLE_SEQUENCE_GAP = 1000; -const int DEFAULT_MAX_RECURSION = 5; - - class PacketStreamStats { public: PacketStreamStats() @@ -65,7 +62,7 @@ public: }; - SequenceNumberStats(int statsHistoryLength = 0, int maxRecursion = DEFAULT_MAX_RECURSION); + SequenceNumberStats(int statsHistoryLength = 0, bool canDetectOutOfSync = true); SequenceNumberStats(const SequenceNumberStats& other); SequenceNumberStats& operator=(const SequenceNumberStats& rhs); ~SequenceNumberStats(); @@ -107,10 +104,10 @@ private: // to deal with the incoming seq nums going out of sync with this tracker, we'll create another instance // of this class when we encounter an unreasonable - SequenceNumberStats* _unreasonableTracker; - int _maxRecursion; + bool _canHaveChild; + SequenceNumberStats* _childInstance; - bool hasUnreasonableTracker() const { return _unreasonableTracker != NULL; } + int _consecutiveReasonable; }; #endif // hifi_SequenceNumberStats_h diff --git a/tests/networking/src/SequenceNumberStatsTests.cpp b/tests/networking/src/SequenceNumberStatsTests.cpp index c4205f5fb5..38aa901a6b 100644 --- a/tests/networking/src/SequenceNumberStatsTests.cpp +++ b/tests/networking/src/SequenceNumberStatsTests.cpp @@ -16,11 +16,12 @@ void SequenceNumberStatsTests::runAllTests() { - + /* rolloverTest(); earlyLateTest(); duplicateTest(); - pruneTest(); + pruneTest();*/ + recursiveTest(); } const quint32 UINT16_RANGE = std::numeric_limits::max() + 1; @@ -278,3 +279,36 @@ void SequenceNumberStatsTests::pruneTest() { numLost = 0; } } + +void SequenceNumberStatsTests::recursiveTest() { + + SequenceNumberStats stats(0); + + quint16 sequence; + + sequence = 89; + stats.sequenceNumberReceived(sequence); + + assert(stats.getUnreasonable() == 0); + + sequence = 2990; + for (int i = 0; i < 10; i++) { + stats.sequenceNumberReceived(sequence); + sequence += (quint16)1; + } + + assert(stats.getUnreasonable() == 0); + + + sequence = 0; + for (int R = 0; R < 7; R++) { + stats.sequenceNumberReceived(sequence); + sequence += (quint16)2000; + } + + for (int i = 0; i < 10; i++) { + stats.sequenceNumberReceived(sequence); + sequence += (quint16)1; + } + assert(stats.getUnreasonable() == 0); +} diff --git a/tests/networking/src/SequenceNumberStatsTests.h b/tests/networking/src/SequenceNumberStatsTests.h index 53a0b66480..80053fd822 100644 --- a/tests/networking/src/SequenceNumberStatsTests.h +++ b/tests/networking/src/SequenceNumberStatsTests.h @@ -23,6 +23,7 @@ namespace SequenceNumberStatsTests { void earlyLateTest(); void duplicateTest(); void pruneTest(); + void recursiveTest(); }; #endif // hifi_SequenceNumberStatsTests_h From fc670d9edb19662a91f4fd9e9cd49fb4dbcc5556 Mon Sep 17 00:00:00 2001 From: wangyix Date: Fri, 1 Aug 2014 16:44:01 -0700 Subject: [PATCH 177/407] minor threshold change --- libraries/networking/src/SequenceNumberStats.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/SequenceNumberStats.cpp b/libraries/networking/src/SequenceNumberStats.cpp index 7e9022934b..4d6e0bb688 100644 --- a/libraries/networking/src/SequenceNumberStats.cpp +++ b/libraries/networking/src/SequenceNumberStats.cpp @@ -186,9 +186,9 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui // if we got a reasonable seq num but have a child instance tracking unreasonable seq nums, // reset it. if many consecutive reasonable seq nums have occurred (implying the unreasonable seq num - // that caused the creation of the child instance was just a fluke), delete our child instance. + // that caused the creation of the child instance was probably a fluke), delete our child instance. if (_childInstance) { - const int CONSECUTIVE_REASONABLE_CHILD_DELETE_THRESHOLD = 4; + const int CONSECUTIVE_REASONABLE_CHILD_DELETE_THRESHOLD = 8; if (_consecutiveReasonable >= CONSECUTIVE_REASONABLE_CHILD_DELETE_THRESHOLD) { _childInstance->reset(); } else { From 1d74ae8197e4ba5d2451a4640b5d22f9a8eeabb9 Mon Sep 17 00:00:00 2001 From: wangyix Date: Fri, 1 Aug 2014 16:49:21 -0700 Subject: [PATCH 178/407] code cleanup --- libraries/networking/src/SequenceNumberStats.cpp | 2 -- libraries/networking/src/SequenceNumberStats.h | 1 - tests/networking/src/SequenceNumberStatsTests.cpp | 3 +-- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/libraries/networking/src/SequenceNumberStats.cpp b/libraries/networking/src/SequenceNumberStats.cpp index 4d6e0bb688..12901e11cd 100644 --- a/libraries/networking/src/SequenceNumberStats.cpp +++ b/libraries/networking/src/SequenceNumberStats.cpp @@ -142,10 +142,8 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui _childInstance = new SequenceNumberStats(0, false); } - ArrivalInfo unreasonableTrackerArrivalInfo = _childInstance->sequenceNumberReceived(incoming); - // the child instance will be used to detect some threshold number seq nums in a row that are perfectly // in order. diff --git a/libraries/networking/src/SequenceNumberStats.h b/libraries/networking/src/SequenceNumberStats.h index 71092d7409..fb3ff68f70 100644 --- a/libraries/networking/src/SequenceNumberStats.h +++ b/libraries/networking/src/SequenceNumberStats.h @@ -67,7 +67,6 @@ public: SequenceNumberStats& operator=(const SequenceNumberStats& rhs); ~SequenceNumberStats(); -public: void reset(); ArrivalInfo sequenceNumberReceived(quint16 incoming, QUuid senderUUID = QUuid(), const bool wantExtraDebugging = false); void pruneMissingSet(const bool wantExtraDebugging = false); diff --git a/tests/networking/src/SequenceNumberStatsTests.cpp b/tests/networking/src/SequenceNumberStatsTests.cpp index 38aa901a6b..1df48b781b 100644 --- a/tests/networking/src/SequenceNumberStatsTests.cpp +++ b/tests/networking/src/SequenceNumberStatsTests.cpp @@ -16,11 +16,10 @@ void SequenceNumberStatsTests::runAllTests() { - /* rolloverTest(); earlyLateTest(); duplicateTest(); - pruneTest();*/ + pruneTest(); recursiveTest(); } From 99df05f770f73b7b5fc9ed6ed52b800a1fdedd81 Mon Sep 17 00:00:00 2001 From: wangyix Date: Fri, 1 Aug 2014 16:54:29 -0700 Subject: [PATCH 179/407] forgot member in reset() --- libraries/networking/src/SequenceNumberStats.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/SequenceNumberStats.cpp b/libraries/networking/src/SequenceNumberStats.cpp index 12901e11cd..28ea06787a 100644 --- a/libraries/networking/src/SequenceNumberStats.cpp +++ b/libraries/networking/src/SequenceNumberStats.cpp @@ -77,6 +77,7 @@ void SequenceNumberStats::reset() { delete _childInstance; _childInstance = NULL; } + _consecutiveReasonable = 0; } static const int UINT16_RANGE = std::numeric_limits::max() + 1; From bd1fbaaf762a25635674d23ff73f24a965efc220 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Sat, 2 Aug 2014 16:02:08 -0700 Subject: [PATCH 180/407] Made static mutex into member variable --- libraries/voxels/src/VoxelsScriptingInterface.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/voxels/src/VoxelsScriptingInterface.cpp b/libraries/voxels/src/VoxelsScriptingInterface.cpp index 093d736720..1b2df471f4 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.cpp +++ b/libraries/voxels/src/VoxelsScriptingInterface.cpp @@ -81,8 +81,7 @@ void VoxelsScriptingInterface::setVoxel(float x, float y, float z, float scale, DeleteVoxelCommand* deleteCommand = new DeleteVoxelCommand(_tree, addVoxelDetail, getVoxelPacketSender()); - static QMutex mutex; - mutex.lock(); + _undoStackMutex.lock(); _undoStack->beginMacro(addCommand->text()); // As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves. @@ -91,7 +90,7 @@ void VoxelsScriptingInterface::setVoxel(float x, float y, float z, float scale, _undoStack->endMacro(); //Unlock the mutex - mutex.unlock(); + _undoStackMutex.unlock(); } else { // queue the destructive add queueVoxelAdd(PacketTypeVoxelSetDestructive, addVoxelDetail); @@ -121,11 +120,10 @@ void VoxelsScriptingInterface::eraseVoxel(float x, float y, float z, float scale deleteVoxelDetail, getVoxelPacketSender()); - static QMutex mutex; - mutex.lock(); + _undoStackMutex.lock(); // As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves. _undoStack->push(command); - mutex.unlock(); + _undoStackMutex.unlock(); } else { getVoxelPacketSender()->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &deleteVoxelDetail); _tree->deleteVoxelAt(deleteVoxelDetail.x, deleteVoxelDetail.y, deleteVoxelDetail.z, deleteVoxelDetail.s); From 5829e3ad1ede5aa80abee796509928d4991c6bb1 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Sat, 2 Aug 2014 16:03:13 -0700 Subject: [PATCH 181/407] Forgot to save header --- libraries/voxels/src/VoxelsScriptingInterface.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/voxels/src/VoxelsScriptingInterface.h b/libraries/voxels/src/VoxelsScriptingInterface.h index 787c37fb20..2e1fc2a8d5 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.h +++ b/libraries/voxels/src/VoxelsScriptingInterface.h @@ -102,6 +102,7 @@ private: void queueVoxelAdd(PacketType addPacketType, VoxelDetail& addVoxelDetails); VoxelTree* _tree; QUndoStack* _undoStack; + QMutex _undoStackMutex; }; #endif // hifi_VoxelsScriptingInterface_h From bd409f2de48d833f8f9ab8f61615acddc8baca70 Mon Sep 17 00:00:00 2001 From: Bennett Goble Date: Sun, 3 Aug 2014 14:01:37 -0400 Subject: [PATCH 182/407] importVoxels() JS override: specify file and location --- interface/interface_en.ts | 12 +- interface/src/Application.cpp | 21 +-- interface/src/Application.h | 5 +- .../scripting/ClipboardScriptingInterface.cpp | 31 ++++ .../scripting/ClipboardScriptingInterface.h | 3 + ...ImportDialog.cpp => VoxelImportDialog.cpp} | 133 +++++++++++++----- .../{ImportDialog.h => VoxelImportDialog.h} | 36 +++-- interface/src/voxels/VoxelImporter.cpp | 115 +++++---------- interface/src/voxels/VoxelImporter.h | 23 +-- 9 files changed, 217 insertions(+), 162 deletions(-) rename interface/src/ui/{ImportDialog.cpp => VoxelImportDialog.cpp} (77%) rename interface/src/ui/{ImportDialog.h => VoxelImportDialog.h} (74%) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 6c4426b2c6..b85628b104 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -245,28 +245,28 @@ QObject - - + + Import Voxels - + Loading ... - + Place voxels - + <b>Import</b> %1 as voxels - + Cancel diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 51f6076e7a..3caf9b2f5f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -137,7 +137,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _frameCount(0), _fps(60.0f), _justStarted(true), - _voxelImporter(NULL), + _voxelImportDialog(NULL), + _voxelImporter(), _importSucceded(false), _sharedVoxelSystem(TREE_SCALE, DEFAULT_MAX_VOXELS_PER_SYSTEM, &_clipboard), _wantToKillLocalVoxels(false), @@ -428,7 +429,7 @@ Application::~Application() { delete idleTimer; _sharedVoxelSystem.changeTree(new VoxelTree); - delete _voxelImporter; + delete _voxelImportDialog; // let the avatar mixer know we're out MyAvatar::sendKillAvatar(); @@ -463,8 +464,8 @@ void Application::saveSettings() { Menu::getInstance()->saveSettings(); _rearMirrorTools->saveSettings(_settings); - if (_voxelImporter) { - _voxelImporter->saveSettings(_settings); + if (_voxelImportDialog) { + _voxelImportDialog->saveSettings(_settings); } _settings->sync(); _numChangedSettings = 0; @@ -1568,17 +1569,17 @@ void Application::exportVoxels(const VoxelDetail& sourceVoxel) { void Application::importVoxels() { _importSucceded = false; - if (!_voxelImporter) { - _voxelImporter = new VoxelImporter(_window); - _voxelImporter->loadSettings(_settings); + if (!_voxelImportDialog) { + _voxelImportDialog = new VoxelImportDialog(_window); + _voxelImportDialog->loadSettings(_settings); } - if (!_voxelImporter->exec()) { + if (!_voxelImportDialog->exec()) { qDebug() << "Import succeeded." << endl; _importSucceded = true; } else { qDebug() << "Import failed." << endl; - if (_sharedVoxelSystem.getTree() == _voxelImporter->getVoxelTree()) { + if (_sharedVoxelSystem.getTree() == _voxelImporter.getVoxelTree()) { _sharedVoxelSystem.killLocalVoxels(); _sharedVoxelSystem.changeTree(&_clipboard); } @@ -1680,7 +1681,7 @@ void Application::init() { // Cleanup of the original shared tree _sharedVoxelSystem.init(); - _voxelImporter = new VoxelImporter(_window); + _voxelImportDialog = new VoxelImportDialog(_window); _environment.init(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 54fb25839a..8c0a999370 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -86,6 +86,7 @@ #include "ui/overlays/Overlays.h" #include "ui/ApplicationOverlay.h" #include "ui/RunningScriptsWidget.h" +#include "ui/VoxelImportDialog.h" #include "voxels/VoxelFade.h" #include "voxels/VoxelHideShowThread.h" #include "voxels/VoxelImporter.h" @@ -192,6 +193,7 @@ public: Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; } + VoxelImporter* getVoxelImporter() { return &_voxelImporter; } VoxelSystem* getVoxels() { return &_voxels; } VoxelTree* getVoxelTree() { return _voxels.getTree(); } const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; } @@ -453,7 +455,8 @@ private: VoxelSystem _voxels; VoxelTree _clipboard; // if I copy/paste - VoxelImporter* _voxelImporter; + VoxelImportDialog* _voxelImportDialog; + VoxelImporter _voxelImporter; bool _importSucceded; VoxelSystem _sharedVoxelSystem; ViewFrustum _sharedVoxelSystemViewFrustum; diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp index e8fb545343..0e63a386ed 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.cpp +++ b/interface/src/scripting/ClipboardScriptingInterface.cpp @@ -87,6 +87,37 @@ bool ClipboardScriptingInterface::importVoxels() { return Application::getInstance()->getImportSucceded(); } +bool ClipboardScriptingInterface::importVoxels(const QString& filename) { + qDebug() << "Importing ... "; + + VoxelImporter* importer = Application::getInstance()->getVoxelImporter(); + + if (!importer->validImportFile(filename)) { + return false; + } + + QEventLoop loop; + connect(importer, SIGNAL(importDone()), &loop, SLOT(quit())); + importer->import(filename); + loop.exec(); + + return true; +} + +bool ClipboardScriptingInterface::importVoxels(const QString& filename, float x, float y, float z, float s) { + bool success = importVoxels(filename); + + if (success) { + pasteVoxel(x, y, z, s); + } + + return success; +} + +bool ClipboardScriptingInterface::importVoxels(const QString& filename, const VoxelDetail& destinationVoxel) { + return importVoxels(filename, destinationVoxel.x, destinationVoxel.y, destinationVoxel.z, destinationVoxel.s); +} + void ClipboardScriptingInterface::nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec) { nudgeVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s, nudgeVec); } diff --git a/interface/src/scripting/ClipboardScriptingInterface.h b/interface/src/scripting/ClipboardScriptingInterface.h index f0258b0cc7..b7b1d85625 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.h +++ b/interface/src/scripting/ClipboardScriptingInterface.h @@ -39,6 +39,9 @@ public slots: void exportVoxel(float x, float y, float z, float s); bool importVoxels(); + bool importVoxels(const QString& filename); + bool importVoxels(const QString& filename, float x, float y, float z, float s); + bool importVoxels(const QString& filename, const VoxelDetail& destinationVoxel); void nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec); void nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec); diff --git a/interface/src/ui/ImportDialog.cpp b/interface/src/ui/VoxelImportDialog.cpp similarity index 77% rename from interface/src/ui/ImportDialog.cpp rename to interface/src/ui/VoxelImportDialog.cpp index 67b89773fb..2d1b71ba7f 100644 --- a/interface/src/ui/ImportDialog.cpp +++ b/interface/src/ui/VoxelImportDialog.cpp @@ -1,5 +1,5 @@ // -// ImportDialog.cpp +// VoxelImportDialog.cpp // interface/src/ui // // Created by Clement Brisset on 8/12/13. @@ -20,7 +20,11 @@ #include "Application.h" -#include "ImportDialog.h" +#include "VoxelImportDialog.h" +#include "voxels/VoxelImporter.h" + +const QString SETTINGS_GROUP_NAME = "VoxelImport"; +const QString IMPORT_DIALOG_SETTINGS_KEY = "VoxelImportDialogSettings"; const QString WINDOW_NAME = QObject::tr("Import Voxels"); const QString IMPORT_BUTTON_NAME = QObject::tr("Import Voxels"); @@ -97,12 +101,14 @@ QString HiFiIconProvider::type(const QFileInfo &info) const { return QFileIconProvider::type(info); } -ImportDialog::ImportDialog(QWidget* parent) : +VoxelImportDialog::VoxelImportDialog(QWidget* parent) : QFileDialog(parent, WINDOW_NAME, DOWNLOAD_LOCATION, NULL), - _progressBar(this), - _importButton(IMPORT_BUTTON_NAME, this), _cancelButton(CANCEL_BUTTON_NAME, this), - _mode(importMode) { + _importButton(IMPORT_BUTTON_NAME, this), + _importer(Application::getInstance()->getVoxelImporter()), + _mode(importMode), + _progressBar(this), + _didImport(false) { setOption(QFileDialog::DontUseNativeDialog, true); setFileMode(QFileDialog::ExistingFile); @@ -113,41 +119,54 @@ ImportDialog::ImportDialog(QWidget* parent) : _progressBar.setRange(0, 100); - connect(&_importButton, SIGNAL(pressed()), SLOT(accept())); - connect(&_cancelButton, SIGNAL(pressed()), SIGNAL(canceled())); + connect(&_importButton, SIGNAL(pressed()), this, SLOT(accept())); + connect(&_cancelButton, SIGNAL(pressed()), this, SLOT(cancel())); connect(this, SIGNAL(currentChanged(QString)), SLOT(saveCurrentFile(QString))); } -void ImportDialog::reset() { - setMode(importMode); - _progressBar.setValue(0); +void VoxelImportDialog::cancel() { + switch (getMode()) { + case importMode: + _importer->cancel(); + close(); + break; + default: + _importer->reset(); + setMode(importMode); + break; + } + emit canceled(); } -void ImportDialog::setMode(dialogMode mode) { +void VoxelImportDialog::saveSettings(QSettings* settings) { + settings->beginGroup(SETTINGS_GROUP_NAME); + settings->setValue(IMPORT_DIALOG_SETTINGS_KEY, saveState()); + settings->endGroup(); +} + +void VoxelImportDialog::loadSettings(QSettings* settings) { + settings->beginGroup(SETTINGS_GROUP_NAME); + restoreState(settings->value(IMPORT_DIALOG_SETTINGS_KEY).toByteArray()); + settings->endGroup(); +} + +bool VoxelImportDialog::prompt() { + reset(); + exec(); + return _didImport; +} + +void VoxelImportDialog::reset() { + setMode(importMode); + _didImport = false; +} + +void VoxelImportDialog::setMode(dialogMode mode) { + dialogMode previousMode = _mode; _mode = mode; switch (_mode) { - case loadingMode: - _importButton.setEnabled(false); - _importButton.setText(LOADING_BUTTON_NAME); - findChild("sidebar")->setEnabled(false); - findChild("treeView")->setEnabled(false); - findChild("backButton")->setEnabled(false); - findChild("forwardButton")->setEnabled(false); - findChild("toParentButton")->setEnabled(false); - break; - case placeMode: - _progressBar.setValue(100); - _importButton.setEnabled(true); - _importButton.setText(PLACE_BUTTON_NAME); - findChild("sidebar")->setEnabled(false); - findChild("treeView")->setEnabled(false); - findChild("backButton")->setEnabled(false); - findChild("forwardButton")->setEnabled(false); - findChild("toParentButton")->setEnabled(false); - break; case importMode: - default: _progressBar.setValue(0); _importButton.setEnabled(true); _importButton.setText(IMPORT_BUTTON_NAME); @@ -157,22 +176,60 @@ void ImportDialog::setMode(dialogMode mode) { findChild("forwardButton")->setEnabled(true); findChild("toParentButton")->setEnabled(true); break; + case loadingMode: + // Connect to VoxelImporter signals + connect(_importer, SIGNAL(importProgress(int)), this, SLOT(updateProgressBar(int))); + connect(_importer, SIGNAL(importDone()), this, SLOT(afterImport())); + + _importButton.setEnabled(false); + _importButton.setText(LOADING_BUTTON_NAME); + findChild("sidebar")->setEnabled(false); + findChild("treeView")->setEnabled(false); + findChild("backButton")->setEnabled(false); + findChild("forwardButton")->setEnabled(false); + findChild("toParentButton")->setEnabled(false); + break; + case finishedMode: + if (previousMode == loadingMode) { + // Disconnect from VoxelImporter signals + disconnect(_importer, SIGNAL(importProgress(int)), this, SLOT(setProgressBarValue(int))); + disconnect(_importer, SIGNAL(importDone()), this, SLOT(afterImport())); + } + setMode(importMode); + break; } } -void ImportDialog::setProgressBarValue(int value) { +void VoxelImportDialog::setProgressBarValue(int value) { _progressBar.setValue(value); } -void ImportDialog::accept() { - emit accepted(); +void VoxelImportDialog::accept() { + if (getMode() == importMode) { + QString filename = getCurrentFile(); + + // If file is invalid we ignore the call + if (!_importer->validImportFile(filename)) { + return; + } + // Let's prepare the dialog window for import + setMode(loadingMode); + + _importer->import(filename); + } } -void ImportDialog::saveCurrentFile(QString filename) { +void VoxelImportDialog::afterImport() { + setMode(finishedMode); + _didImport = true; + close(); +} + +void VoxelImportDialog::saveCurrentFile(QString filename) { _currentFile = QFileInfo(filename).isFile() ? filename : ""; } -void ImportDialog::setLayout() { +void VoxelImportDialog::setLayout() { QGridLayout* gridLayout = (QGridLayout*) layout(); gridLayout->addWidget(&_progressBar, 2, 0, 2, 1); gridLayout->addWidget(&_cancelButton, 2, 1, 2, 1); @@ -258,7 +315,7 @@ void ImportDialog::setLayout() { } -void ImportDialog::setImportTypes() { +void VoxelImportDialog::setImportTypes() { QFile config(Application::resourcesPath() + "config/config.json"); config.open(QFile::ReadOnly | QFile::Text); QJsonDocument document = QJsonDocument::fromJson(config.readAll()); diff --git a/interface/src/ui/ImportDialog.h b/interface/src/ui/VoxelImportDialog.h similarity index 74% rename from interface/src/ui/ImportDialog.h rename to interface/src/ui/VoxelImportDialog.h index 88cfda7a7c..54faf7449a 100644 --- a/interface/src/ui/ImportDialog.h +++ b/interface/src/ui/VoxelImportDialog.h @@ -1,5 +1,5 @@ // -// ImportDialog.h +// VoxelImportDialog.h // interface/src/ui // // Created by Clement Brisset on 8/12/13. @@ -9,8 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_ImportDialog_h -#define hifi_ImportDialog_h +#ifndef hifi_VoxelImportDialog_h +#define hifi_VoxelImportDialog_h #include "InterfaceConfig.h" @@ -23,6 +23,8 @@ #include +#include "voxels/VoxelImporter.h" + class HiFiIconProvider : public QFileIconProvider { public: HiFiIconProvider(const QHash map) { iconsMap = map; }; @@ -35,39 +37,45 @@ public: enum dialogMode { importMode, loadingMode, - placeMode + finishedMode }; -class ImportDialog : public QFileDialog { +class VoxelImportDialog : public QFileDialog { Q_OBJECT public: - ImportDialog(QWidget* parent = NULL); - void reset(); + VoxelImportDialog(QWidget* parent = NULL); QString getCurrentFile() const { return _currentFile; } dialogMode getMode() const { return _mode; } + void setMode(dialogMode mode); + void reset(); + bool prompt(); + void loadSettings(QSettings* settings); + void saveSettings(QSettings* settings); signals: void canceled(); - -public slots: - void setProgressBarValue(int value); private slots: + void setProgressBarValue(int value); void accept(); + void cancel(); void saveCurrentFile(QString filename); + void afterImport(); private: - QString _currentFile; - QProgressBar _progressBar; - QPushButton _importButton; QPushButton _cancelButton; + QString _currentFile; + QPushButton _importButton; + VoxelImporter* _importer; dialogMode _mode; + QProgressBar _progressBar; + bool _didImport; void setLayout(); void setImportTypes(); }; -#endif // hifi_ImportDialog_h +#endif // hifi_VoxelImportDialog_h diff --git a/interface/src/voxels/VoxelImporter.cpp b/interface/src/voxels/VoxelImporter.cpp index f7d5562c06..b713813fb0 100644 --- a/interface/src/voxels/VoxelImporter.cpp +++ b/interface/src/voxels/VoxelImporter.cpp @@ -20,8 +20,7 @@ #include "voxels/VoxelImporter.h" -const QString SETTINGS_GROUP_NAME = "VoxelImport"; -const QString IMPORT_DIALOG_SETTINGS_KEY = "ImportDialogSettings"; +const QStringList SUPPORTED_EXTENSIONS = QStringList() << "png" << "svo" << "schematic"; class ImportTask : public QObject, public QRunnable { public: @@ -32,104 +31,46 @@ private: QString _filename; }; -VoxelImporter::VoxelImporter(QWidget* parent) : - QObject(parent), +VoxelImporter::VoxelImporter() : _voxelTree(true), - _importDialog(parent), - _task(NULL), - _didImport(false) + _task(NULL) { LocalVoxelsList::getInstance()->addPersistantTree(IMPORT_TREE_NAME, &_voxelTree); - connect(&_voxelTree, SIGNAL(importProgress(int)), &_importDialog, SLOT(setProgressBarValue(int))); - connect(&_importDialog, SIGNAL(canceled()), this, SLOT(cancel())); - connect(&_importDialog, SIGNAL(accepted()), this, SLOT(import())); -} - -void VoxelImporter::saveSettings(QSettings* settings) { - settings->beginGroup(SETTINGS_GROUP_NAME); - settings->setValue(IMPORT_DIALOG_SETTINGS_KEY, _importDialog.saveState()); - settings->endGroup(); -} - -void VoxelImporter::loadSettings(QSettings* settings) { - settings->beginGroup(SETTINGS_GROUP_NAME); - _importDialog.restoreState(settings->value(IMPORT_DIALOG_SETTINGS_KEY).toByteArray()); - settings->endGroup(); + connect(&_voxelTree, SIGNAL(importProgress(int)), this, SIGNAL(importProgress(int))); } VoxelImporter::~VoxelImporter() { cleanupTask(); } +void VoxelImporter::cancel() { + if (_task) { + disconnect(_task, 0, 0, 0); + } + reset(); +} + void VoxelImporter::reset() { _voxelTree.eraseAllOctreeElements(); - _importDialog.reset(); - cleanupTask(); } -int VoxelImporter::exec() { - reset(); - _importDialog.exec(); - - if (!_didImport) { - // if the import is rejected, we make sure to cleanup before leaving +void VoxelImporter::import(const QString& filename) { + // If present, abort existing import + if (_task) { cleanupTask(); - return 1; - } else { - _didImport = false; - return 0; } -} -void VoxelImporter::import() { - switch (_importDialog.getMode()) { - case loadingMode: - _importDialog.setMode(placeMode); - return; - case placeMode: - // Means the user chose to import - _didImport = true; - _importDialog.close(); - return; - case importMode: - default: - QString filename = _importDialog.getCurrentFile(); - // if it's not a file, we ignore the call - if (!QFileInfo(filename).isFile()) { - return; - } - - // Let's prepare the dialog window for import - _importDialog.setMode(loadingMode); - - // If not already done, we switch to the local tree - if (Application::getInstance()->getSharedVoxelSystem()->getTree() != &_voxelTree) { - Application::getInstance()->getSharedVoxelSystem()->changeTree(&_voxelTree); - } - - // Creation and launch of the import task on the thread pool - _task = new ImportTask(filename); - connect(_task, SIGNAL(destroyed()), SLOT(import())); - QThreadPool::globalInstance()->start(_task); - break; + // If not already done, we switch to the local tree + if (Application::getInstance()->getSharedVoxelSystem()->getTree() != &_voxelTree) { + Application::getInstance()->getSharedVoxelSystem()->changeTree(&_voxelTree); } -} -void VoxelImporter::cancel() { - switch (_importDialog.getMode()) { - case loadingMode: - disconnect(_task, 0, 0, 0); - cleanupTask(); - case placeMode: - _importDialog.setMode(importMode); - break; - case importMode: - default: - _importDialog.close(); - break; - } + // Creation and launch of the import task on the thread pool + _task = new ImportTask(filename); + connect(_task, SIGNAL(destroyed()), SLOT(finishImport())); + QThreadPool::globalInstance()->start(_task); } void VoxelImporter::cleanupTask() { @@ -140,6 +81,16 @@ void VoxelImporter::cleanupTask() { } } +void VoxelImporter::finishImport() { + cleanupTask(); + emit importDone(); +} + +bool VoxelImporter::validImportFile(const QString& filename) { + QFileInfo fileInfo = QFileInfo(filename); + return fileInfo.isFile() && SUPPORTED_EXTENSIONS.indexOf(fileInfo.suffix().toLower()) != -1; +} + ImportTask::ImportTask(const QString &filename) : _filename(filename) { @@ -151,7 +102,7 @@ void ImportTask::run() { // We start by cleaning up the shared voxel system just in case voxelSystem->killLocalVoxels(); - // Then we call the righ method for the job + // Then we call the right method for the job if (_filename.endsWith(".png", Qt::CaseInsensitive)) { voxelSystem->getTree()->readFromSquareARGB32Pixels(_filename.toLocal8Bit().data()); } else if (_filename.endsWith(".svo", Qt::CaseInsensitive)) { @@ -163,6 +114,6 @@ void ImportTask::run() { qDebug() << "[ERROR] Invalid file extension." << endl; } - // Here we reaverage the tree so that he is ready for preview + // Here we reaverage the tree so that it is ready for preview voxelSystem->getTree()->reaverageOctreeElements(); } diff --git a/interface/src/voxels/VoxelImporter.h b/interface/src/voxels/VoxelImporter.h index 7da89c5a11..21ebbeea2e 100644 --- a/interface/src/voxels/VoxelImporter.h +++ b/interface/src/voxels/VoxelImporter.h @@ -14,8 +14,8 @@ #include #include +#include -#include "ui/ImportDialog.h" #include "voxels/VoxelSystem.h" class ImportTask; @@ -23,28 +23,29 @@ class ImportTask; class VoxelImporter : public QObject { Q_OBJECT public: - VoxelImporter(QWidget* parent = NULL); + VoxelImporter(); ~VoxelImporter(); void reset(); - void loadSettings(QSettings* settings); - void saveSettings(QSettings* settings); - + void cancel(); VoxelTree* getVoxelTree() { return &_voxelTree; } + bool validImportFile(const QString& filename); public slots: - int exec(); - void import(); - void cancel(); + void import(const QString& filename); + +signals: + void importDone(); + void importProgress(int); private: VoxelTree _voxelTree; - ImportDialog _importDialog; - ImportTask* _task; - bool _didImport; void cleanupTask(); + +private slots: + void finishImport(); }; #endif // hifi_VoxelImporter_h From 925270e7279895b4209f07e5d7a7b1e2e12f4d9a Mon Sep 17 00:00:00 2001 From: Bennett Goble Date: Sun, 3 Aug 2014 14:06:51 -0400 Subject: [PATCH 183/407] clipboardExample.js - Replace voxel feature --- examples/clipboardExample.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/clipboardExample.js b/examples/clipboardExample.js index e6db44054f..0b6371e2b7 100644 --- a/examples/clipboardExample.js +++ b/examples/clipboardExample.js @@ -24,6 +24,7 @@ function setupMenus() { Menu.removeMenuItem("Edit", "Paste"); Menu.removeMenuItem("Edit", "Delete"); Menu.removeMenuItem("Edit", "Nudge"); + Menu.removeMenuItem("Edit", "Replace from File"); Menu.removeMenuItem("File", "Export Voxels"); Menu.removeMenuItem("File", "Import Voxels"); @@ -32,6 +33,7 @@ function setupMenus() { Menu.addMenuItem({ menuName: "Edit", menuItemName: "Copy", shortcutKey: "CTRL+C", afterItem: "Cut" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste", shortcutKey: "CTRL+V", afterItem: "Copy" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Nudge", shortcutKey: "CTRL+N", afterItem: "Paste" }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Replace from File", shortcutKey: "CTRL+R", afterItem: "Nudge" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", shortcutKeyEvent: { text: "backspace" }, afterItem: "Nudge" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Export Voxels", shortcutKey: "CTRL+E", afterItem: "Voxels" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Import Voxels", shortcutKey: "CTRL+I", afterItem: "Export Voxels" }); @@ -60,7 +62,6 @@ function menuItemEvent(menuItem) { print("deleting..."); Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); } - if (menuItem == "Export Voxels") { print("export"); Clipboard.exportVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); @@ -73,6 +74,12 @@ function menuItemEvent(menuItem) { print("nudge"); Clipboard.nudgeVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s, { x: -1, y: 0, z: 0 }); } + if (menuItem == "Replace from File") { + var filename = Window.browse("Select file to load replacement", "", "Voxel Files (*.png *.svo *.schematic)"); + if (filename) { + Clipboard.importVoxel(filename, selectedVoxel); + } + } } var selectCube = Overlays.addOverlay("cube", { From 38741aed7358b2b592e18bdb50ff364ba40e6692 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 4 Aug 2014 10:27:19 -0700 Subject: [PATCH 184/407] Fixed wrong header guard --- interface/src/devices/CaraFaceTracker.h | 6 +++--- interface/src/devices/DdeFaceTracker.cpp | 12 ++++++++++++ interface/src/devices/DdeFaceTracker.h | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 interface/src/devices/DdeFaceTracker.cpp create mode 100644 interface/src/devices/DdeFaceTracker.h diff --git a/interface/src/devices/CaraFaceTracker.h b/interface/src/devices/CaraFaceTracker.h index f51fed0f1b..8fdba1f606 100644 --- a/interface/src/devices/CaraFaceTracker.h +++ b/interface/src/devices/CaraFaceTracker.h @@ -9,8 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hi_fi_CaraFaceTracker_h -#define hi_fi_CaraFaceTracker_h +#ifndef hifi_CaraFaceTracker_h +#define hifi_CaraFaceTracker_h #include @@ -120,4 +120,4 @@ private: int _jawOpenIndex; }; -#endif //endif hi_fi_CaraFaceTracker_h \ No newline at end of file +#endif //endif hifi_CaraFaceTracker_h \ No newline at end of file diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp new file mode 100644 index 0000000000..de1576da4b --- /dev/null +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -0,0 +1,12 @@ +// +// DdeFaceTracker.cpp +// +// +// Created by Clement on 8/2/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 +// + +#include "DdeFaceTracker.h" diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h new file mode 100644 index 0000000000..a57711a10d --- /dev/null +++ b/interface/src/devices/DdeFaceTracker.h @@ -0,0 +1,15 @@ +// +// DdeFaceTracker.h +// +// +// Created by Clement on 8/2/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 +// + +#ifndef hifi_DdeFaceTracker_h +#define hifi_DdeFaceTracker_h + +#endif // hifi_DdeFaceTracker_h \ No newline at end of file From bbb52fc4aae9b31bc8bbb844d5a6f9e8288a9414 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 4 Aug 2014 10:28:29 -0700 Subject: [PATCH 185/407] Added dde face tracker class --- interface/src/devices/DdeFaceTracker.cpp | 169 +++++++++++++++++++++++ interface/src/devices/DdeFaceTracker.h | 41 ++++++ 2 files changed, 210 insertions(+) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index de1576da4b..7be5e90a31 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -9,4 +9,173 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + +#include +#include +#include +#include + #include "DdeFaceTracker.h" + +static const QHostAddress DDE_FEATURE_POINT_SERVER_ADDR("127.0.0.1"); +static const quint16 DDE_FEATURE_POINT_SERVER_PORT = 5555; + +static const int NUM_EXPRESSION = 46; +static const int MIN_PACKET_SIZE = (8 + NUM_EXPRESSION) * sizeof(float) + sizeof(int); +static const int MAX_NAME_SIZE = 31; + +struct Packet{ + //roughly in mm + float focal_length[1]; + float translation[3]; + + //quaternion + float rotation[4]; + + //blendshape coefficients ranging between -0.2 and 1.5 + float expressions[NUM_EXPRESSION]; + + //avatar id selected on the UI + int avatar_id; + + //client name, arbitrary length + char name[MAX_NAME_SIZE + 1]; +}; + +DdeFaceTracker::DdeFaceTracker() : +_lastReceiveTimestamp(0), +_reset(false) +{ + connect(&_udpSocket, SIGNAL(readyRead()), SLOT(readPendingDatagrams())); + connect(&_udpSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketErrorOccurred(QAbstractSocket::SocketError))); + connect(&_udpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), SLOT(socketStateChanged(QAbstractSocket::SocketState))); + + bindTo(DDE_FEATURE_POINT_SERVER_PORT); +} + +DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) : +_lastReceiveTimestamp(0), +_reset(false) +{ + connect(&_udpSocket, SIGNAL(readyRead()), SLOT(readPendingDatagrams())); + connect(&_udpSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketErrorOccurred(QAbstractSocket::SocketError))); + connect(&_udpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), SIGNAL(socketStateChanged(QAbstractSocket::SocketState))); + + bindTo(host, port); +} + +DdeFaceTracker::~DdeFaceTracker() { + if(_udpSocket.isOpen()) + _udpSocket.close(); +} + +void DdeFaceTracker::init() { + +} + +void DdeFaceTracker::reset() { + _reset = true; +} + +void DdeFaceTracker::update() { + +} + +void DdeFaceTracker::bindTo(quint16 port) { + bindTo(QHostAddress::Any, port); +} + +void DdeFaceTracker::bindTo(const QHostAddress& host, quint16 port) { + if(_udpSocket.isOpen()) { + _udpSocket.close(); + } + _udpSocket.bind(host, port); +} + +bool DdeFaceTracker::isActive() const { + static const int ACTIVE_TIMEOUT_USECS = 3000000; //3 secs + return (usecTimestampNow() - _lastReceiveTimestamp < ACTIVE_TIMEOUT_USECS); +} + +//private slots and methods +void DdeFaceTracker::socketErrorOccurred(QAbstractSocket::SocketError socketError) { + qDebug() << "[Error] DDE Face Tracker Socket Error: " << _udpSocket.errorString(); +} + +void DdeFaceTracker::socketStateChanged(QAbstractSocket::SocketState socketState) { + QString state; + switch(socketState) { + case QAbstractSocket::BoundState: + state = "Bounded"; + break; + case QAbstractSocket::ClosingState: + state = "Closing"; + break; + case QAbstractSocket::ConnectedState: + state = "Connected"; + break; + case QAbstractSocket::ConnectingState: + state = "Connecting"; + break; + case QAbstractSocket::HostLookupState: + state = "Host Lookup"; + break; + case QAbstractSocket::ListeningState: + state = "Listening"; + break; + case QAbstractSocket::UnconnectedState: + state = "Unconnected"; + break; + } + qDebug() << "[Info] DDE Face Tracker Socket: " << socketState; +} + +void DdeFaceTracker::readPendingDatagrams() { + QByteArray buffer; + while (_udpSocket.hasPendingDatagrams()) { + buffer.resize(_udpSocket.pendingDatagramSize()); + _udpSocket.readDatagram(buffer.data(), buffer.size()); + } + decodePacket(buffer); +} + +void DdeFaceTracker::decodePacket(const QByteArray& buffer) { + if(buffer.size() > MIN_PACKET_SIZE) { + Packet packet; + int bytesToCopy = glm::min((int)sizeof(packet), buffer.size()); + memset(&packet.name, '\n', MAX_NAME_SIZE + 1); + memcpy(&packet, buffer.data(), bytesToCopy); + + glm::vec3 translation; + memcpy(&translation, packet.translation, sizeof(packet.translation)); + glm::quat rotation; + memcpy(&rotation, &packet.rotation, sizeof(packet.rotation)); + if (_reset) { + memcpy(&_referenceTranslation, &translation, sizeof(glm::vec3)); + memcpy(&_referenceRotation, &rotation, sizeof(glm::quat)); + _reset = false; + } + + // Compute relative translation + float DAMPING_FACTOR = 40; + translation -= _referenceTranslation; + translation /= DAMPING_FACTOR; + translation.x *= -1; + + // Compute relative rotation + rotation = glm::inverse(_referenceRotation) * rotation; + + // copy values + _headTranslation = translation; + _headRotation = rotation; + + // Set blendshapes + + + + } else { + qDebug() << "[Error] DDE Face Tracker Decode Error"; + } + _lastReceiveTimestamp = usecTimestampNow(); +} diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index a57711a10d..310ce60212 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -12,4 +12,45 @@ #ifndef hifi_DdeFaceTracker_h #define hifi_DdeFaceTracker_h +#include + +#include "FaceTracker.h" + +class DdeFaceTracker : public FaceTracker { + Q_OBJECT + +public: + DdeFaceTracker(); + DdeFaceTracker(const QHostAddress& host, quint16 port); + ~DdeFaceTracker(); + + //initialization + void init(); + void reset(); + void update(); + + //sockets + void bindTo(quint16 port); + void bindTo(const QHostAddress& host, quint16 port); + bool isActive() const; + +private slots: + + //sockets + void socketErrorOccurred(QAbstractSocket::SocketError socketError); + void readPendingDatagrams(); + void socketStateChanged(QAbstractSocket::SocketState socketState); + +private: + void decodePacket(const QByteArray& buffer); + + // sockets + QUdpSocket _udpSocket; + quint64 _lastReceiveTimestamp; + + bool _reset; + glm::vec3 _referenceTranslation; + glm::quat _referenceRotation; +}; + #endif // hifi_DdeFaceTracker_h \ No newline at end of file From 8d1438a44c1700e39326e58f701cb37a095ef148 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 4 Aug 2014 10:28:52 -0700 Subject: [PATCH 186/407] Plugged in dde face tracker --- interface/src/Application.cpp | 22 ++++++++++++++++------ interface/src/Application.h | 4 ++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 28640dc092..05a4a08c48 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1502,10 +1502,11 @@ glm::vec3 Application::getMouseVoxelWorldCoordinates(const VoxelDetail& mouseVox } FaceTracker* Application::getActiveFaceTracker() { - return _cara.isActive() ? static_cast(&_cara) : - (_faceshift.isActive() ? static_cast(&_faceshift) : - (_faceplus.isActive() ? static_cast(&_faceplus) : - (_visage.isActive() ? static_cast(&_visage) : NULL))); + return (_dde.isActive() ? static_cast(&_dde) : + (_cara.isActive() ? static_cast(&_cara) : + (_faceshift.isActive() ? static_cast(&_faceshift) : + (_faceplus.isActive() ? static_cast(&_faceplus) : + (_visage.isActive() ? static_cast(&_visage) : NULL))))); } struct SendVoxelsOperationArgs { @@ -1937,13 +1938,21 @@ void Application::updateVisage() { _visage.update(); } +void Application::updateDDE() { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateDDE()"); + + // Update Cara + _dde.update(); +} + void Application::updateCara() { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateCara()"); - + // Update Cara _cara.update(); - + // Copy angular velocity if measured by cara, to the head if (_cara.isActive()) { _myAvatar->getHead()->setAngularVelocity(_cara.getHeadAngularVelocity()); @@ -3265,6 +3274,7 @@ void Application::resetSensors() { _faceplus.reset(); _faceshift.reset(); _visage.reset(); + _dde.reset(); OculusManager::reset(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 43a6083457..c898d10cbd 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -64,6 +64,7 @@ #include "devices/SixenseManager.h" #include "devices/Visage.h" #include "devices/CaraFaceTracker.h" +#include "devices/DdeFaceTracker.h" #include "models/ModelTreeRenderer.h" #include "particles/ParticleTreeRenderer.h" #include "renderer/AmbientOcclusionEffect.h" @@ -214,6 +215,7 @@ public: Faceplus* getFaceplus() { return &_faceplus; } Faceshift* getFaceshift() { return &_faceshift; } Visage* getVisage() { return &_visage; } + DdeFaceTracker* getDDE() { return &_dde; } CaraFaceTracker* getCara() { return &_cara; } FaceTracker* getActiveFaceTracker(); SixenseManager* getSixenseManager() { return &_sixenseManager; } @@ -393,6 +395,7 @@ private: void updateFaceplus(); void updateFaceshift(); void updateVisage(); + void updateDDE(); void updateCara(); void updateMyAvatarLookAtPosition(); void updateThreads(float deltaTime); @@ -493,6 +496,7 @@ private: Faceshift _faceshift; Visage _visage; CaraFaceTracker _cara; + DdeFaceTracker _dde; SixenseManager _sixenseManager; PrioVR _prioVR; From cac3983778060f45aadcc6b1d7697a2d63b0213d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 4 Aug 2014 11:03:58 -0700 Subject: [PATCH 187/407] Added a few blendshapes --- interface/src/devices/DdeFaceTracker.cpp | 44 ++++++++++++++++++++++-- interface/src/devices/DdeFaceTracker.h | 33 ++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 7be5e90a31..23dad928d3 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -45,8 +45,22 @@ struct Packet{ DdeFaceTracker::DdeFaceTracker() : _lastReceiveTimestamp(0), -_reset(false) +_reset(false), +_leftBlinkIndex(0), // see http://support.faceshift.com/support/articles/35129-export-of-blendshapes +_rightBlinkIndex(1), +_leftEyeOpenIndex(8), +_rightEyeOpenIndex(9), +_browDownLeftIndex(14), +_browDownRightIndex(15), +_browUpCenterIndex(16), +_browUpLeftIndex(17), +_browUpRightIndex(18), +_mouthSmileLeftIndex(28), +_mouthSmileRightIndex(29), +_jawOpenIndex(21) { + _blendshapeCoefficients.resize(NUM_EXPRESSION); + connect(&_udpSocket, SIGNAL(readyRead()), SLOT(readPendingDatagrams())); connect(&_udpSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketErrorOccurred(QAbstractSocket::SocketError))); connect(&_udpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), SLOT(socketStateChanged(QAbstractSocket::SocketState))); @@ -56,8 +70,22 @@ _reset(false) DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) : _lastReceiveTimestamp(0), -_reset(false) +_reset(false), +_leftBlinkIndex(0), // see http://support.faceshift.com/support/articles/35129-export-of-blendshapes +_rightBlinkIndex(1), +_leftEyeOpenIndex(8), +_rightEyeOpenIndex(9), +_browDownLeftIndex(14), +_browDownRightIndex(15), +_browUpCenterIndex(16), +_browUpLeftIndex(17), +_browUpRightIndex(18), +_mouthSmileLeftIndex(28), +_mouthSmileRightIndex(29), +_jawOpenIndex(21) { + _blendshapeCoefficients.resize(NUM_EXPRESSION); + connect(&_udpSocket, SIGNAL(readyRead()), SLOT(readPendingDatagrams())); connect(&_udpSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketErrorOccurred(QAbstractSocket::SocketError))); connect(&_udpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), SIGNAL(socketStateChanged(QAbstractSocket::SocketState))); @@ -140,6 +168,10 @@ void DdeFaceTracker::readPendingDatagrams() { decodePacket(buffer); } +float DdeFaceTracker::getBlendshapeCoefficient(int index) const { + return (index >= 0 && index < (int)_blendshapeCoefficients.size()) ? _blendshapeCoefficients[index] : 0.0f; +} + void DdeFaceTracker::decodePacket(const QByteArray& buffer) { if(buffer.size() > MIN_PACKET_SIZE) { Packet packet; @@ -171,8 +203,16 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { _headRotation = rotation; // Set blendshapes + _blendshapeCoefficients[_leftBlinkIndex] = packet.expressions[1]; + _blendshapeCoefficients[_rightBlinkIndex] = packet.expressions[0]; + _blendshapeCoefficients[_browDownLeftIndex] = packet.expressions[14]; + _blendshapeCoefficients[_browDownRightIndex] = packet.expressions[15]; + _blendshapeCoefficients[_browUpCenterIndex] = (packet.expressions[14] + packet.expressions[14]) / 2.0f; + _blendshapeCoefficients[_browUpLeftIndex] = packet.expressions[14]; + _blendshapeCoefficients[_browUpRightIndex] = packet.expressions[15]; + _blendshapeCoefficients[_jawOpenIndex] = packet.expressions[21]; } else { qDebug() << "[Error] DDE Face Tracker Decode Error"; diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 310ce60212..96707ac94c 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -34,6 +34,21 @@ public: void bindTo(const QHostAddress& host, quint16 port); bool isActive() const; + float getLeftBlink() const { return getBlendshapeCoefficient(_leftBlinkIndex); } + float getRightBlink() const { return getBlendshapeCoefficient(_rightBlinkIndex); } + float getLeftEyeOpen() const { return getBlendshapeCoefficient(_leftEyeOpenIndex); } + float getRightEyeOpen() const { return getBlendshapeCoefficient(_rightEyeOpenIndex); } + + float getBrowDownLeft() const { return getBlendshapeCoefficient(_browDownLeftIndex); } + float getBrowDownRight() const { return getBlendshapeCoefficient(_browDownRightIndex); } + float getBrowUpCenter() const { return getBlendshapeCoefficient(_browUpCenterIndex); } + float getBrowUpLeft() const { return getBlendshapeCoefficient(_browUpLeftIndex); } + float getBrowUpRight() const { return getBlendshapeCoefficient(_browUpRightIndex); } + + float getMouthSize() const { return getBlendshapeCoefficient(_jawOpenIndex); } + float getMouthSmileLeft() const { return getBlendshapeCoefficient(_mouthSmileLeftIndex); } + float getMouthSmileRight() const { return getBlendshapeCoefficient(_mouthSmileRightIndex); } + private slots: //sockets @@ -42,6 +57,7 @@ private slots: void socketStateChanged(QAbstractSocket::SocketState socketState); private: + float getBlendshapeCoefficient(int index) const; void decodePacket(const QByteArray& buffer); // sockets @@ -51,6 +67,23 @@ private: bool _reset; glm::vec3 _referenceTranslation; glm::quat _referenceRotation; + + int _leftBlinkIndex; + int _rightBlinkIndex; + int _leftEyeOpenIndex; + int _rightEyeOpenIndex; + + // Brows + int _browDownLeftIndex; + int _browDownRightIndex; + int _browUpCenterIndex; + int _browUpLeftIndex; + int _browUpRightIndex; + + int _mouthSmileLeftIndex; + int _mouthSmileRightIndex; + + int _jawOpenIndex; }; #endif // hifi_DdeFaceTracker_h \ No newline at end of file From c80cd0d71d964864d30aad97aec2a27d06ef56d6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 4 Aug 2014 11:04:14 -0700 Subject: [PATCH 188/407] connected blendshapes --- interface/src/avatar/Head.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index d3d1e74fc8..995f3f2390 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -68,6 +68,9 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { if ((_isFaceshiftConnected = faceTracker)) { _blendshapeCoefficients = faceTracker->getBlendshapeCoefficients(); _isFaceshiftConnected = true; + } else if (Application::getInstance()->getDDE()->isActive()) { + faceTracker = Application::getInstance()->getDDE(); + _blendshapeCoefficients = faceTracker->getBlendshapeCoefficients(); } } From d394c203b6c71577bf71c750b799204daa82aa20 Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 4 Aug 2014 11:09:20 -0700 Subject: [PATCH 189/407] improved re-sync handling of SequenceNumberStats removed "duplicate" category since it's not 100% accurate --- examples/bot_procedural.js. | 674 ------------------ interface/src/ui/OctreeStatsDialog.cpp | 4 +- .../networking/src/SequenceNumberStats.cpp | 189 ++--- .../networking/src/SequenceNumberStats.h | 34 +- .../src/SequenceNumberStatsTests.cpp | 33 +- .../networking/src/SequenceNumberStatsTests.h | 2 +- 6 files changed, 94 insertions(+), 842 deletions(-) delete mode 100644 examples/bot_procedural.js. diff --git a/examples/bot_procedural.js. b/examples/bot_procedural.js. deleted file mode 100644 index 265b887e0a..0000000000 --- a/examples/bot_procedural.js. +++ /dev/null @@ -1,674 +0,0 @@ -// -// bot_procedural.js -// hifi -// -// Created by Ben Arnold on 7/29/2013 -// -// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. -// -// This is an example script that demonstrates an NPC avatar. -// -// - -//For procedural walk animation -Script.include("http://s3-us-west-1.amazonaws.com/highfidelity-public/scripts/proceduralAnimationAPI.js"); - -var procAnimAPI = new ProcAnimAPI(); - -function getRandomFloat(min, max) { - return Math.random() * (max - min) + min; -} - -function getRandomInt (min, max) { - return Math.floor(Math.random() * (max - min + 1)) + min; -} - -function printVector(string, vector) { - print(string + " " + vector.x + ", " + vector.y + ", " + vector.z); -} - -var CHANCE_OF_MOVING = 0.005; -var CHANCE_OF_SOUND = 0.005; -var CHANCE_OF_HEAD_TURNING = 0.01; -var CHANCE_OF_BIG_MOVE = 1.0; - -var isMoving = false; -var isTurningHead = false; -var isPlayingAudio = false; - -var X_MIN = 0.50; -var X_MAX = 15.60; -var Z_MIN = 0.50; -var Z_MAX = 15.10; -var Y_FEET = 0.0; -var AVATAR_PELVIS_HEIGHT = 0.84; -var Y_PELVIS = Y_FEET + AVATAR_PELVIS_HEIGHT; -var MAX_PELVIS_DELTA = 2.5; - -var MOVE_RANGE_SMALL = 3.0; -var MOVE_RANGE_BIG = 10.0; -var TURN_RANGE = 70.0; -var STOP_TOLERANCE = 0.05; -var MOVE_RATE = 0.05; -var TURN_RATE = 0.2; -var HEAD_TURN_RATE = 0.05; -var PITCH_RANGE = 15.0; -var YAW_RANGE = 35.0; - -var firstPosition = { x: getRandomFloat(X_MIN, X_MAX), y: Y_PELVIS, z: getRandomFloat(Z_MIN, Z_MAX) }; -var targetPosition = { x: 0, y: 0, z: 0 }; -var targetOrientation = { x: 0, y: 0, z: 0, w: 0 }; -var currentOrientation = { x: 0, y: 0, z: 0, w: 0 }; -var targetHeadPitch = 0.0; -var targetHeadYaw = 0.0; - -var basePelvisHeight = 0.0; -var pelvisOscillatorPosition = 0.0; -var pelvisOscillatorVelocity = 0.0; - -function clamp(val, min, max){ - return Math.max(min, Math.min(max, val)) -} - -//Array of all valid bot numbers -var validBotNumbers = []; - -// right now we only use bot 63, since many other bots have messed up skeletons and LOD issues -var botNumber = 63;//getRandomInt(0, 99); - -var newFaceFilePrefix = "ron"; - -var newBodyFilePrefix = "bot" + botNumber; - -// set the face model fst using the bot number -// there is no need to change the body model - we're using the default -Avatar.faceModelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/" + newFaceFilePrefix + ".fst"; -Avatar.skeletonModelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/" + newBodyFilePrefix + "_a.fst"; -Avatar.billboardURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/billboards/bot" + botNumber + ".png"; - -Agent.isAvatar = true; -Agent.isListeningToAudioStream = true; - -// change the avatar's position to the random one -Avatar.position = firstPosition; -basePelvisHeight = firstPosition.y; -printVector("New dancer, position = ", Avatar.position); - -function loadSounds() { - var sound_filenames = ["AB1.raw", "Anchorman2.raw", "B1.raw", "B1.raw", "Bale1.raw", "Bandcamp.raw", - "Big1.raw", "Big2.raw", "Brian1.raw", "Buster1.raw", "CES1.raw", "CES2.raw", "CES3.raw", "CES4.raw", - "Carrie1.raw", "Carrie3.raw", "Charlotte1.raw", "EN1.raw", "EN2.raw", "EN3.raw", "Eugene1.raw", "Francesco1.raw", - "Italian1.raw", "Japanese1.raw", "Leigh1.raw", "Lucille1.raw", "Lucille2.raw", "MeanGirls.raw", "Murray2.raw", - "Nigel1.raw", "PennyLane.raw", "Pitt1.raw", "Ricardo.raw", "SN.raw", "Sake1.raw", "Samantha1.raw", "Samantha2.raw", - "Spicoli1.raw", "Supernatural.raw", "Swearengen1.raw", "TheDude.raw", "Tony.raw", "Triumph1.raw", "Uma1.raw", - "Walken1.raw", "Walken2.raw", "Z1.raw", "Z2.raw" - ]; - - var footstep_filenames = ["FootstepW2Left-12db.wav", "FootstepW2Right-12db.wav", "FootstepW3Left-12db.wav", "FootstepW3Right-12db.wav", - "FootstepW5Left-12db.wav", "FootstepW5Right-12db.wav"]; - - var SOUND_BASE_URL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Cocktail+Party+Snippets/Raws/"; - - var FOOTSTEP_BASE_URL = "http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Footsteps/"; - - for (var i = 0; i < sound_filenames.length; i++) { - sounds.push(new Sound(SOUND_BASE_URL + sound_filenames[i])); - } - - for (var i = 0; i < footstep_filenames.length; i++) { - footstepSounds.push(new Sound(FOOTSTEP_BASE_URL + footstep_filenames[i])); - } -} - -var sounds = []; -var footstepSounds = []; -loadSounds(); - - -function playRandomSound() { - if (!Agent.isPlayingAvatarSound) { - var whichSound = Math.floor((Math.random() * sounds.length)); - Agent.playAvatarSound(sounds[whichSound]); - } -} - -function playRandomFootstepSound() { - - var whichSound = Math.floor((Math.random() * footstepSounds.length)); - var options = new AudioInjectionOptions(); - options.position = Avatar.position; - options.volume = 1.0; - Audio.playSound(footstepSounds[whichSound], options); - -} - -// ************************************ Facial Animation ********************************** -var allBlendShapes = []; -var targetBlendCoefficient = []; -var currentBlendCoefficient = []; - -//Blendshape constructor -function addBlendshapeToPose(pose, shapeIndex, val) { - var index = pose.blendShapes.length; - pose.blendShapes[index] = {shapeIndex: shapeIndex, val: val }; -} -//The mood of the avatar, determines face. 0 = happy, 1 = angry, 2 = sad. - -//Randomly pick avatar mood. 80% happy, 10% mad 10% sad -var randMood = Math.floor(Math.random() * 11); -var avatarMood; -if (randMood == 0) { - avatarMood = 1; -} else if (randMood == 2) { - avatarMood = 2; -} else { - avatarMood = 0; -} - -var currentExpression = -1; -//Face pose constructor -var happyPoses = []; - -happyPoses[0] = {blendShapes: []}; -addBlendshapeToPose(happyPoses[0], 28, 0.7); //MouthSmile_L -addBlendshapeToPose(happyPoses[0], 29, 0.7); //MouthSmile_R - -happyPoses[1] = {blendShapes: []}; -addBlendshapeToPose(happyPoses[1], 28, 1.0); //MouthSmile_L -addBlendshapeToPose(happyPoses[1], 29, 1.0); //MouthSmile_R -addBlendshapeToPose(happyPoses[1], 21, 0.2); //JawOpen - -happyPoses[2] = {blendShapes: []}; -addBlendshapeToPose(happyPoses[2], 28, 1.0); //MouthSmile_L -addBlendshapeToPose(happyPoses[2], 29, 1.0); //MouthSmile_R -addBlendshapeToPose(happyPoses[2], 21, 0.5); //JawOpen -addBlendshapeToPose(happyPoses[2], 46, 1.0); //CheekSquint_L -addBlendshapeToPose(happyPoses[2], 47, 1.0); //CheekSquint_R -addBlendshapeToPose(happyPoses[2], 17, 1.0); //BrowsU_L -addBlendshapeToPose(happyPoses[2], 18, 1.0); //BrowsU_R - -var angryPoses = []; - -angryPoses[0] = {blendShapes: []}; -addBlendshapeToPose(angryPoses[0], 26, 0.6); //MouthFrown_L -addBlendshapeToPose(angryPoses[0], 27, 0.6); //MouthFrown_R -addBlendshapeToPose(angryPoses[0], 14, 0.6); //BrowsD_L -addBlendshapeToPose(angryPoses[0], 15, 0.6); //BrowsD_R - -angryPoses[1] = {blendShapes: []}; -addBlendshapeToPose(angryPoses[1], 26, 0.9); //MouthFrown_L -addBlendshapeToPose(angryPoses[1], 27, 0.9); //MouthFrown_R -addBlendshapeToPose(angryPoses[1], 14, 0.9); //BrowsD_L -addBlendshapeToPose(angryPoses[1], 15, 0.9); //BrowsD_R - -angryPoses[2] = {blendShapes: []}; -addBlendshapeToPose(angryPoses[2], 26, 1.0); //MouthFrown_L -addBlendshapeToPose(angryPoses[2], 27, 1.0); //MouthFrown_R -addBlendshapeToPose(angryPoses[2], 14, 1.0); //BrowsD_L -addBlendshapeToPose(angryPoses[2], 15, 1.0); //BrowsD_R -addBlendshapeToPose(angryPoses[2], 21, 0.5); //JawOpen -addBlendshapeToPose(angryPoses[2], 46, 1.0); //CheekSquint_L -addBlendshapeToPose(angryPoses[2], 47, 1.0); //CheekSquint_R - -var sadPoses = []; - -sadPoses[0] = {blendShapes: []}; -addBlendshapeToPose(sadPoses[0], 26, 0.6); //MouthFrown_L -addBlendshapeToPose(sadPoses[0], 27, 0.6); //MouthFrown_R -addBlendshapeToPose(sadPoses[0], 16, 0.2); //BrowsU_C -addBlendshapeToPose(sadPoses[0], 2, 0.6); //EyeSquint_L -addBlendshapeToPose(sadPoses[0], 3, 0.6); //EyeSquint_R - -sadPoses[1] = {blendShapes: []}; -addBlendshapeToPose(sadPoses[1], 26, 0.9); //MouthFrown_L -addBlendshapeToPose(sadPoses[1], 27, 0.9); //MouthFrown_R -addBlendshapeToPose(sadPoses[1], 16, 0.6); //BrowsU_C -addBlendshapeToPose(sadPoses[1], 2, 0.9); //EyeSquint_L -addBlendshapeToPose(sadPoses[1], 3, 0.9); //EyeSquint_R - -sadPoses[2] = {blendShapes: []}; -addBlendshapeToPose(sadPoses[2], 26, 1.0); //MouthFrown_L -addBlendshapeToPose(sadPoses[2], 27, 1.0); //MouthFrown_R -addBlendshapeToPose(sadPoses[2], 16, 0.1); //BrowsU_C -addBlendshapeToPose(sadPoses[2], 2, 1.0); //EyeSquint_L -addBlendshapeToPose(sadPoses[2], 3, 1.0); //EyeSquint_R -addBlendshapeToPose(sadPoses[2], 21, 0.3); //JawOpen - -var facePoses = []; -facePoses[0] = happyPoses; -facePoses[1] = angryPoses; -facePoses[2] = sadPoses; - - -function addBlendShape(s) { - allBlendShapes[allBlendShapes.length] = s; -} - -//It is imperative that the following blendshapes are all present and are in the correct order -addBlendShape("EyeBlink_L"); //0 -addBlendShape("EyeBlink_R"); //1 -addBlendShape("EyeSquint_L"); //2 -addBlendShape("EyeSquint_R"); //3 -addBlendShape("EyeDown_L"); //4 -addBlendShape("EyeDown_R"); //5 -addBlendShape("EyeIn_L"); //6 -addBlendShape("EyeIn_R"); //7 -addBlendShape("EyeOpen_L"); //8 -addBlendShape("EyeOpen_R"); //9 -addBlendShape("EyeOut_L"); //10 -addBlendShape("EyeOut_R"); //11 -addBlendShape("EyeUp_L"); //12 -addBlendShape("EyeUp_R"); //13 -addBlendShape("BrowsD_L"); //14 -addBlendShape("BrowsD_R"); //15 -addBlendShape("BrowsU_C"); //16 -addBlendShape("BrowsU_L"); //17 -addBlendShape("BrowsU_R"); //18 -addBlendShape("JawFwd"); //19 -addBlendShape("JawLeft"); //20 -addBlendShape("JawOpen"); //21 -addBlendShape("JawChew"); //22 -addBlendShape("JawRight"); //23 -addBlendShape("MouthLeft"); //24 -addBlendShape("MouthRight"); //25 -addBlendShape("MouthFrown_L"); //26 -addBlendShape("MouthFrown_R"); //27 -addBlendShape("MouthSmile_L"); //28 -addBlendShape("MouthSmile_R"); //29 -addBlendShape("MouthDimple_L"); //30 -addBlendShape("MouthDimple_R"); //31 -addBlendShape("LipsStretch_L"); //32 -addBlendShape("LipsStretch_R"); //33 -addBlendShape("LipsUpperClose"); //34 -addBlendShape("LipsLowerClose"); //35 -addBlendShape("LipsUpperUp"); //36 -addBlendShape("LipsLowerDown"); //37 -addBlendShape("LipsUpperOpen"); //38 -addBlendShape("LipsLowerOpen"); //39 -addBlendShape("LipsFunnel"); //40 -addBlendShape("LipsPucker"); //41 -addBlendShape("ChinLowerRaise"); //42 -addBlendShape("ChinUpperRaise"); //43 -addBlendShape("Sneer"); //44 -addBlendShape("Puff"); //45 -addBlendShape("CheekSquint_L"); //46 -addBlendShape("CheekSquint_R"); //47 - -for (var i = 0; i < allBlendShapes.length; i++) { - targetBlendCoefficient[i] = 0; - currentBlendCoefficient[i] = 0; -} - -function setRandomExpression() { - - //Clear all expression data for current expression - if (currentExpression != -1) { - var expression = facePoses[avatarMood][currentExpression]; - for (var i = 0; i < expression.blendShapes.length; i++) { - targetBlendCoefficient[expression.blendShapes[i].shapeIndex] = 0.0; - } - } - //Get a new current expression - currentExpression = Math.floor(Math.random() * facePoses[avatarMood].length); - var expression = facePoses[avatarMood][currentExpression]; - for (var i = 0; i < expression.blendShapes.length; i++) { - targetBlendCoefficient[expression.blendShapes[i].shapeIndex] = expression.blendShapes[i].val; - } -} - -var expressionChangeSpeed = 0.1; -function updateBlendShapes(deltaTime) { - - for (var i = 0; i < allBlendShapes.length; i++) { - currentBlendCoefficient[i] += (targetBlendCoefficient[i] - currentBlendCoefficient[i]) * expressionChangeSpeed; - Avatar.setBlendshape(allBlendShapes[i], currentBlendCoefficient[i]); - } -} - -var BLINK_SPEED = 0.15; -var CHANCE_TO_BLINK = 0.0025; -var MAX_BLINK = 0.85; -var blink = 0.0; -var isBlinking = false; -function updateBlinking(deltaTime) { - if (isBlinking == false) { - if (Math.random() < CHANCE_TO_BLINK) { - isBlinking = true; - } else { - blink -= BLINK_SPEED; - if (blink < 0.0) blink = 0.0; - } - } else { - blink += BLINK_SPEED; - if (blink > MAX_BLINK) { - blink = MAX_BLINK; - isBlinking = false; - } - } - - currentBlendCoefficient[0] = blink; - currentBlendCoefficient[1] = blink; - targetBlendCoefficient[0] = blink; - targetBlendCoefficient[1] = blink; -} - -// ************************************************************************************* - -//Procedural walk animation using two keyframes -//We use a separate array for front and back joints -//Pitch, yaw, and roll for the joints -var rightAngles = []; -var leftAngles = []; -//for non mirrored joints such as the spine -var middleAngles = []; - -//Actual joint mappings -var SHOULDER_JOINT_NUMBER = 15; -var ELBOW_JOINT_NUMBER = 16; -var JOINT_R_HIP = 1; -var JOINT_R_KNEE = 2; -var JOINT_L_HIP = 6; -var JOINT_L_KNEE = 7; -var JOINT_R_ARM = 15; -var JOINT_R_FOREARM = 16; -var JOINT_L_ARM = 39; -var JOINT_L_FOREARM = 40; -var JOINT_SPINE = 11; -var JOINT_R_FOOT = 3; -var JOINT_L_FOOT = 8; -var JOINT_R_TOE = 4; -var JOINT_L_TOE = 9; - -// ******************************* Animation Is Defined Below ************************************* - -var NUM_FRAMES = 2; -for (var i = 0; i < NUM_FRAMES; i++) { - rightAngles[i] = []; - leftAngles[i] = []; - middleAngles[i] = []; -} -//Joint order for actual joint mappings, should be interleaved R,L,R,L,...S,S,S for R = right, L = left, S = single -var JOINT_ORDER = []; -//*** right / left joints *** -var HIP = 0; -JOINT_ORDER.push(JOINT_R_HIP); -JOINT_ORDER.push(JOINT_L_HIP); -var KNEE = 1; -JOINT_ORDER.push(JOINT_R_KNEE); -JOINT_ORDER.push(JOINT_L_KNEE); -var ARM = 2; -JOINT_ORDER.push(JOINT_R_ARM); -JOINT_ORDER.push(JOINT_L_ARM); -var FOREARM = 3; -JOINT_ORDER.push(JOINT_R_FOREARM); -JOINT_ORDER.push(JOINT_L_FOREARM); -var FOOT = 4; -JOINT_ORDER.push(JOINT_R_FOOT); -JOINT_ORDER.push(JOINT_L_FOOT); -var TOE = 5; -JOINT_ORDER.push(JOINT_R_TOE); -JOINT_ORDER.push(JOINT_L_TOE); -//*** middle joints *** -var SPINE = 0; -JOINT_ORDER.push(JOINT_SPINE); - -//We have to store the angles so we can invert yaw and roll when making the animation -//symmetrical - -//Front refers to leg, not arm. -//Legs Extending -rightAngles[0][HIP] = [30.0, 0.0, 8.0]; -rightAngles[0][KNEE] = [-15.0, 0.0, 0.0]; -rightAngles[0][ARM] = [85.0, -25.0, 0.0]; -rightAngles[0][FOREARM] = [0.0, 0.0, -15.0]; -rightAngles[0][FOOT] = [0.0, 0.0, 0.0]; -rightAngles[0][TOE] = [0.0, 0.0, 0.0]; - -leftAngles[0][HIP] = [-15, 0.0, 8.0]; -leftAngles[0][KNEE] = [-26, 0.0, 0.0]; -leftAngles[0][ARM] = [85.0, 20.0, 0.0]; -leftAngles[0][FOREARM] = [10.0, 0.0, -25.0]; -leftAngles[0][FOOT] = [-13.0, 0.0, 0.0]; -leftAngles[0][TOE] = [34.0, 0.0, 0.0]; - -middleAngles[0][SPINE] = [0.0, -15.0, 5.0]; - -//Legs Passing -rightAngles[1][HIP] = [6.0, 0.0, 8.0]; -rightAngles[1][KNEE] = [-12.0, 0.0, 0.0]; -rightAngles[1][ARM] = [85.0, 0.0, 0.0]; -rightAngles[1][FOREARM] = [0.0, 0.0, -15.0]; -rightAngles[1][FOOT] = [6.0, -8.0, 0.0]; -rightAngles[1][TOE] = [0.0, 0.0, 0.0]; - -leftAngles[1][HIP] = [10.0, 0.0, 8.0]; -leftAngles[1][KNEE] = [-60.0, 0.0, 0.0]; -leftAngles[1][ARM] = [85.0, 0.0, 0.0]; -leftAngles[1][FOREARM] = [0.0, 0.0, -15.0]; -leftAngles[1][FOOT] = [0.0, 0.0, 0.0]; -leftAngles[1][TOE] = [0.0, 0.0, 0.0]; - -middleAngles[1][SPINE] = [0.0, 0.0, 0.0]; - -//Actual keyframes for the animation -var walkKeyFrames = procAnimAPI.generateKeyframes(rightAngles, leftAngles, middleAngles, NUM_FRAMES); - -// ******************************* Animation Is Defined Above ************************************* - -// ********************************** Standing Key Frame ****************************************** -//We don't have to do any mirroring or anything, since this is just a single pose. -var rightQuats = []; -var leftQuats = []; -var middleQuats = []; - -rightQuats[HIP] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 7.0); -rightQuats[KNEE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0); -rightQuats[ARM] = Quat.fromPitchYawRollDegrees(85.0, 0.0, 0.0); -rightQuats[FOREARM] = Quat.fromPitchYawRollDegrees(0.0, 0.0, -10.0); -rightQuats[FOOT] = Quat.fromPitchYawRollDegrees(0.0, -8.0, 0.0); -rightQuats[TOE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0); - -leftQuats[HIP] = Quat.fromPitchYawRollDegrees(0, 0.0, -7.0); -leftQuats[KNEE] = Quat.fromPitchYawRollDegrees(0, 0.0, 0.0); -leftQuats[ARM] = Quat.fromPitchYawRollDegrees(85.0, 0.0, 0.0); -leftQuats[FOREARM] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 10.0); -leftQuats[FOOT] = Quat.fromPitchYawRollDegrees(0.0, 8.0, 0.0); -leftQuats[TOE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0); - -middleQuats[SPINE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0); - -var standingKeyFrame = new procAnimAPI.KeyFrame(rightQuats, leftQuats, middleQuats); - -// ************************************************************************************************ - - -var currentFrame = 0; - -var walkTime = 0.0; - -var walkWheelRadius = 0.5; -var walkWheelRate = 2.0 * 3.141592 * walkWheelRadius / 8.0; - -var avatarAcceleration = 0.75; -var avatarVelocity = 0.0; -var avatarMaxVelocity = 1.4; - -function handleAnimation(deltaTime) { - - updateBlinking(deltaTime); - updateBlendShapes(deltaTime); - - if (Math.random() < 0.01) { - setRandomExpression(); - } - - if (avatarVelocity == 0.0) { - walkTime = 0.0; - currentFrame = 0; - } else { - walkTime += avatarVelocity * deltaTime; - if (walkTime > walkWheelRate) { - walkTime = 0.0; - currentFrame++; - if (currentFrame % 2 == 1) { - playRandomFootstepSound(); - } - if (currentFrame > 3) { - currentFrame = 0; - } - } - } - - var frame = walkKeyFrames[currentFrame]; - - var walkInterp = walkTime / walkWheelRate; - var animInterp = avatarVelocity / (avatarMaxVelocity / 1.3); - if (animInterp > 1.0) animInterp = 1.0; - - for (var i = 0; i < JOINT_ORDER.length; i++) { - var walkJoint = procAnimAPI.deCasteljau(frame.rotations[i], frame.nextFrame.rotations[i], frame.controlPoints[i][0], frame.controlPoints[i][1], walkInterp); - var standJoint = standingKeyFrame.rotations[i]; - var finalJoint = Quat.mix(standJoint, walkJoint, animInterp); - Avatar.setJointData(JOINT_ORDER[i], finalJoint); - } -} - -function jumpWithLoudness(deltaTime) { - // potentially change pelvis height depending on trailing average loudness - - pelvisOscillatorVelocity += deltaTime * Agent.lastReceivedAudioLoudness * 700.0 ; - - pelvisOscillatorVelocity -= pelvisOscillatorPosition * 0.75; - pelvisOscillatorVelocity *= 0.97; - pelvisOscillatorPosition += deltaTime * pelvisOscillatorVelocity; - Avatar.headPitch = pelvisOscillatorPosition * 60.0; - - var pelvisPosition = Avatar.position; - pelvisPosition.y = (Y_PELVIS - 0.35) + pelvisOscillatorPosition; - - if (pelvisPosition.y < Y_PELVIS) { - pelvisPosition.y = Y_PELVIS; - } else if (pelvisPosition.y > Y_PELVIS + 1.0) { - pelvisPosition.y = Y_PELVIS + 1.0; - } - - Avatar.position = pelvisPosition; -} - -var forcedMove = false; - -var wasMovingLastFrame = false; - -function handleHeadTurn() { - if (!isTurningHead && (Math.random() < CHANCE_OF_HEAD_TURNING)) { - targetHeadPitch = getRandomFloat(-PITCH_RANGE, PITCH_RANGE); - targetHeadYaw = getRandomFloat(-YAW_RANGE, YAW_RANGE); - isTurningHead = true; - } else { - Avatar.headPitch = Avatar.headPitch + (targetHeadPitch - Avatar.headPitch) * HEAD_TURN_RATE; - Avatar.headYaw = Avatar.headYaw + (targetHeadYaw - Avatar.headYaw) * HEAD_TURN_RATE; - if (Math.abs(Avatar.headPitch - targetHeadPitch) < STOP_TOLERANCE && - Math.abs(Avatar.headYaw - targetHeadYaw) < STOP_TOLERANCE) { - isTurningHead = false; - } - } -} - -function stopWalking() { - avatarVelocity = 0.0; - isMoving = false; -} - -var MAX_ATTEMPTS = 40; -function handleWalking(deltaTime) { - - if (forcedMove || (!isMoving && Math.random() < CHANCE_OF_MOVING)) { - // Set new target location - - var moveRange; - if (Math.random() < CHANCE_OF_BIG_MOVE) { - moveRange = MOVE_RANGE_BIG; - } else { - moveRange = MOVE_RANGE_SMALL; - } - - //Keep trying new orientations if the desired target location is out of bounds - var attempts = 0; - do { - targetOrientation = Quat.multiply(Avatar.orientation, Quat.angleAxis(getRandomFloat(-TURN_RANGE, TURN_RANGE), { x:0, y:1, z:0 })); - var front = Quat.getFront(targetOrientation); - - targetPosition = Vec3.sum(Avatar.position, Vec3.multiply(front, getRandomFloat(0.0, moveRange))); - } - while ((targetPosition.x < X_MIN || targetPosition.x > X_MAX || targetPosition.z < Z_MIN || targetPosition.z > Z_MAX) - && attempts < MAX_ATTEMPTS); - - targetPosition.x = clamp(targetPosition.x, X_MIN, X_MAX); - targetPosition.z = clamp(targetPosition.z, Z_MIN, Z_MAX); - targetPosition.y = Y_PELVIS; - - wasMovingLastFrame = true; - isMoving = true; - forcedMove = false; - } else if (isMoving) { - - var targetVector = Vec3.subtract(targetPosition, Avatar.position); - var distance = Vec3.length(targetVector); - if (distance <= avatarVelocity * deltaTime) { - Avatar.position = targetPosition; - stopWalking(); - } else { - var direction = Vec3.normalize(targetVector); - //Figure out if we should be slowing down - var t = avatarVelocity / avatarAcceleration; - var d = (avatarVelocity / 2.0) * t; - if (distance < d) { - avatarVelocity -= avatarAcceleration * deltaTime; - if (avatarVelocity <= 0) { - stopWalking(); - } - } else { - avatarVelocity += avatarAcceleration * deltaTime; - if (avatarVelocity > avatarMaxVelocity) avatarVelocity = avatarMaxVelocity; - } - Avatar.position = Vec3.sum(Avatar.position, Vec3.multiply(direction, avatarVelocity * deltaTime)); - Avatar.orientation = Quat.mix(Avatar.orientation, targetOrientation, TURN_RATE); - - wasMovingLastFrame = true; - - } - } -} - -function handleTalking() { - if (Math.random() < CHANCE_OF_SOUND) { - playRandomSound(); - } -} - -function changePelvisHeight(newHeight) { - var newPosition = Avatar.position; - newPosition.y = newHeight; - Avatar.position = newPosition; -} - -function updateBehavior(deltaTime) { - - if (AvatarList.containsAvatarWithDisplayName("mrdj")) { - if (wasMovingLastFrame) { - isMoving = false; - } - - // we have a DJ, shouldn't we be dancing? - jumpWithLoudness(deltaTime); - } else { - - // no DJ, let's just chill on the dancefloor - randomly walking and talking - handleHeadTurn(); - handleAnimation(deltaTime); - handleWalking(deltaTime); - handleTalking(); - } -} - -Script.update.connect(updateBehavior); \ No newline at end of file diff --git a/interface/src/ui/OctreeStatsDialog.cpp b/interface/src/ui/OctreeStatsDialog.cpp index 7abc42d0e3..e548d5c276 100644 --- a/interface/src/ui/OctreeStatsDialog.cpp +++ b/interface/src/ui/OctreeStatsDialog.cpp @@ -372,7 +372,6 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser QString incomingEarlyString = locale.toString((uint)seqStats.getEarly()); QString incomingLikelyLostString = locale.toString((uint)seqStats.getLost()); QString incomingRecovered = locale.toString((uint)seqStats.getRecovered()); - QString incomingDuplicateString = locale.toString((uint)seqStats.getDuplicate()); int clockSkewInMS = node->getClockSkewUsec() / (int)USECS_PER_MSEC; QString incomingFlightTimeString = locale.toString((int)stats.getIncomingFlightTimeAverage()); @@ -386,8 +385,7 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser serverDetails << "
" << " Out of Order: " << qPrintable(incomingOutOfOrderString) << "/ Early: " << qPrintable(incomingEarlyString) << "/ Late: " << qPrintable(incomingLateString) << - "/ Unreasonable: " << qPrintable(incomingUnreasonableString) << - "/ Duplicate: " << qPrintable(incomingDuplicateString); + "/ Unreasonable: " << qPrintable(incomingUnreasonableString); serverDetails << "
" << " Average Flight Time: " << qPrintable(incomingFlightTimeString) << " msecs"; diff --git a/libraries/networking/src/SequenceNumberStats.cpp b/libraries/networking/src/SequenceNumberStats.cpp index 28ea06787a..6a7f5e1964 100644 --- a/libraries/networking/src/SequenceNumberStats.cpp +++ b/libraries/networking/src/SequenceNumberStats.cpp @@ -14,70 +14,23 @@ #include SequenceNumberStats::SequenceNumberStats(int statsHistoryLength, bool canDetectOutOfSync) - : _received(0), - _lastReceivedSequence(0), + : _lastReceivedSequence(0), _missingSet(), _stats(), _lastSenderUUID(), _statsHistory(statsHistoryLength), - _canHaveChild(canDetectOutOfSync), - _childInstance(NULL), - _consecutiveReasonable(0) + _lastUnreasonableSequence(0), + _consecutiveUnreasonableOnTime(0) { } -SequenceNumberStats::SequenceNumberStats(const SequenceNumberStats& other) - : _received(other._received), - _lastReceivedSequence(other._lastReceivedSequence), - _missingSet(other._missingSet), - _stats(other._stats), - _lastSenderUUID(other._lastSenderUUID), - _statsHistory(other._statsHistory), - _childInstance(NULL), - _canHaveChild(other._canHaveChild), - _consecutiveReasonable(other._consecutiveReasonable) -{ - if (other._childInstance) { - _childInstance = new SequenceNumberStats(*other._childInstance); - } -} - -SequenceNumberStats& SequenceNumberStats::operator=(const SequenceNumberStats& rhs) { - _received = rhs._received; - _lastReceivedSequence = rhs._lastReceivedSequence; - _missingSet = rhs._missingSet; - _stats = rhs._stats; - _lastSenderUUID = rhs._lastSenderUUID; - _statsHistory = rhs._statsHistory; - _canHaveChild = rhs._canHaveChild; - _consecutiveReasonable = rhs._consecutiveReasonable; - - if (rhs._childInstance) { - _childInstance = new SequenceNumberStats(*rhs._childInstance); - } else { - _childInstance = NULL; - } - return *this; -} - -SequenceNumberStats::~SequenceNumberStats() { - if (_childInstance) { - delete _childInstance; - } -} - void SequenceNumberStats::reset() { - _received = 0; _missingSet.clear(); _stats = PacketStreamStats(); _lastSenderUUID = QUuid(); _statsHistory.clear(); - - if (_childInstance) { - delete _childInstance; - _childInstance = NULL; - } - _consecutiveReasonable = 0; + _lastUnreasonableSequence = 0; + _consecutiveUnreasonableOnTime = 0; } static const int UINT16_RANGE = std::numeric_limits::max() + 1; @@ -88,7 +41,7 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui // if the sender node has changed, reset all stats if (senderUUID != _lastSenderUUID) { - if (_received > 0) { + if (_stats._received > 0) { qDebug() << "sequence number stats was reset due to new sender node"; qDebug() << "previous:" << _lastSenderUUID << "current:" << senderUUID; reset(); @@ -97,9 +50,9 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui } // determine our expected sequence number... handle rollover appropriately - quint16 expected = _received > 0 ? _lastReceivedSequence + (quint16)1 : incoming; + quint16 expected = _stats._received > 0 ? _lastReceivedSequence + (quint16)1 : incoming; - _received++; + _stats._received++; if (incoming == expected) { // on time arrivalInfo._status = OnTime; @@ -130,72 +83,11 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui qDebug() << "unreasonable sequence number:" << incoming << "previous:" << _lastReceivedSequence; _stats._unreasonable++; - _consecutiveReasonable = 0; - - // if _canHaveChild, create a child instance of SequenceNumberStats to track this unreasonable seq num and ones in the future. - // if the child instance detects a valid stream of seq nums up to some length, the seq nums sender probably - // fell out of sync with us. - - if (_canHaveChild) { - - if (!_childInstance) { - _childInstance = new SequenceNumberStats(0, false); - } - - ArrivalInfo unreasonableTrackerArrivalInfo = _childInstance->sequenceNumberReceived(incoming); - - // the child instance will be used to detect some threshold number seq nums in a row that are perfectly - // in order. - - const int UNREASONABLE_TRACKER_RECEIVED_THRESHOLD = 8; - - if (unreasonableTrackerArrivalInfo._status != OnTime) { - _childInstance->reset(); - - } else if (_childInstance->getReceived() >= UNREASONABLE_TRACKER_RECEIVED_THRESHOLD) { - - // the child instance has detected a threshold number of consecutive seq nums. - // copy its state to this instance. - - _received = _childInstance->_received; - _lastReceivedSequence = _childInstance->_lastReceivedSequence; - _missingSet = _childInstance->_missingSet; - _stats = _childInstance->_stats; - - // don't copy _lastSenderUUID; _unreasonableTracker always has null UUID for that member. - // ours should be up-to-date. - - // don't copy _statsHistory; _unreasonableTracker keeps a history of length 0. - // simply clear ours. - _statsHistory.clear(); - - arrivalInfo = unreasonableTrackerArrivalInfo; - - // delete child instance; - delete _childInstance; - _childInstance = NULL; - } - } - + receivedUnreasonable(incoming); return arrivalInfo; } - _consecutiveReasonable++; - - // if we got a reasonable seq num but have a child instance tracking unreasonable seq nums, - // reset it. if many consecutive reasonable seq nums have occurred (implying the unreasonable seq num - // that caused the creation of the child instance was probably a fluke), delete our child instance. - if (_childInstance) { - const int CONSECUTIVE_REASONABLE_CHILD_DELETE_THRESHOLD = 8; - if (_consecutiveReasonable >= CONSECUTIVE_REASONABLE_CHILD_DELETE_THRESHOLD) { - _childInstance->reset(); - } else { - delete _childInstance; - _childInstance = NULL; - } - } - // now that rollover has been corrected for (if it occurred), incomingInt and expectedInt can be // compared to each other directly, though one of them might be negative @@ -219,7 +111,7 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui for (int missingInt = expectedInt; missingInt < incomingInt; missingInt++) { _missingSet.insert((quint16)(missingInt < 0 ? missingInt + UINT16_RANGE : missingInt)); } - + // prune missing sequence list if it gets too big; sequence numbers that are older than MAX_REASONABLE_SEQUENCE_GAP // will be removed. if (_missingSet.size() > MAX_REASONABLE_SEQUENCE_GAP) { @@ -236,7 +128,7 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui // remove this from missing sequence number if it's in there if (_missingSet.remove(incoming)) { - arrivalInfo._status = Late; + arrivalInfo._status = Recovered; if (wantExtraDebugging) { qDebug() << "found it in _missingSet"; @@ -244,19 +136,62 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui _stats._lost--; _stats._recovered++; } else { - arrivalInfo._status = Duplicate; + // this late seq num is not in our missing set. it is possibly a duplicate, or possibly a late + // packet that should have arrived before our first received packet. we'll count these + // as unreasonable. - if (wantExtraDebugging) { - qDebug() << "sequence:" << incoming << "was NOT found in _missingSet and is probably a duplicate"; - } - _stats._duplicate++; + arrivalInfo._status = Unreasonable; + + qDebug() << "unreasonable sequence number:" << incoming << "(possible duplicate)"; + + _stats._unreasonable++; + + receivedUnreasonable(incoming); + return arrivalInfo; } } } + // if we've made it here, we received a reasonable seq number. + _consecutiveUnreasonableOnTime = 0; + return arrivalInfo; } +void SequenceNumberStats::receivedUnreasonable(quint16 incoming) { + + const int CONSECUTIVE_UNREASONABLE_ON_TIME_THRESHOLD = 8; + + quint16 expected = _consecutiveUnreasonableOnTime > 0 ? _lastUnreasonableSequence + (quint16)1 : incoming; + if (incoming == expected) { + _consecutiveUnreasonableOnTime++; + _lastUnreasonableSequence = incoming; + + if (_consecutiveUnreasonableOnTime >= CONSECUTIVE_UNREASONABLE_ON_TIME_THRESHOLD) { + // we've received many unreasonable seq numbers in a row, all in order. we're probably out of sync with + // the seq num sender. update our state to get back in sync with the sender. + + _lastReceivedSequence = incoming; + _missingSet.clear(); + + _stats._received = CONSECUTIVE_UNREASONABLE_ON_TIME_THRESHOLD; + _stats._unreasonable = 0; + _stats._early = 0; + _stats._late = 0; + _stats._lost = 0; + _stats._recovered = 0; + _stats._expectedReceived = CONSECUTIVE_UNREASONABLE_ON_TIME_THRESHOLD; + + _statsHistory.clear(); + _consecutiveUnreasonableOnTime = 0; + + qDebug() << "re-synced with sequence number sender"; + } + } else { + _consecutiveUnreasonableOnTime = 0; + } +} + void SequenceNumberStats::pruneMissingSet(const bool wantExtraDebugging) { if (wantExtraDebugging) { qDebug() << "pruning _missingSet! size:" << _missingSet.size(); @@ -311,7 +246,7 @@ PacketStreamStats SequenceNumberStats::getStatsForHistoryWindow() const { const PacketStreamStats* newestStats = _statsHistory.getNewestEntry(); const PacketStreamStats* oldestStats = _statsHistory.get(_statsHistory.getNumEntries() - 1); - + // this catches cases where history is length 1 or 0 (both are NULL in case of 0) if (newestStats == oldestStats) { return PacketStreamStats(); @@ -319,13 +254,13 @@ PacketStreamStats SequenceNumberStats::getStatsForHistoryWindow() const { // calculate difference between newest stats and oldest stats to get window stats PacketStreamStats windowStats; - windowStats._expectedReceived = newestStats->_expectedReceived - oldestStats->_expectedReceived; + windowStats._received = newestStats->_received - oldestStats->_received; windowStats._unreasonable = newestStats->_unreasonable - oldestStats->_unreasonable; windowStats._early = newestStats->_early - oldestStats->_early; windowStats._late = newestStats->_late - oldestStats->_late; windowStats._lost = newestStats->_lost - oldestStats->_lost; windowStats._recovered = newestStats->_recovered - oldestStats->_recovered; - windowStats._duplicate = newestStats->_duplicate - oldestStats->_duplicate; + windowStats._expectedReceived = newestStats->_expectedReceived - oldestStats->_expectedReceived; return windowStats; } diff --git a/libraries/networking/src/SequenceNumberStats.h b/libraries/networking/src/SequenceNumberStats.h index fb3ff68f70..5e02dbc850 100644 --- a/libraries/networking/src/SequenceNumberStats.h +++ b/libraries/networking/src/SequenceNumberStats.h @@ -22,27 +22,24 @@ const int MAX_REASONABLE_SEQUENCE_GAP = 1000; class PacketStreamStats { public: PacketStreamStats() - : _expectedReceived(0), + : _received(0), _unreasonable(0), _early(0), _late(0), _lost(0), _recovered(0), - _duplicate(0) + _expectedReceived(0) {} - float getOutOfOrderRate() const { return (float)(_early + _late) / _expectedReceived; } - float getEaryRate() const { return (float)_early / _expectedReceived; } - float getLateRate() const { return (float)_late / _expectedReceived; } float getLostRate() const { return (float)_lost / _expectedReceived; } - quint32 _expectedReceived; + quint32 _received; quint32 _unreasonable; quint32 _early; quint32 _late; quint32 _lost; quint32 _recovered; - quint32 _duplicate; + quint32 _expectedReceived; }; class SequenceNumberStats { @@ -51,8 +48,7 @@ public: OnTime, Unreasonable, Early, - Late, // recovered - Duplicate + Recovered, }; class ArrivalInfo { @@ -63,18 +59,13 @@ public: SequenceNumberStats(int statsHistoryLength = 0, bool canDetectOutOfSync = true); - SequenceNumberStats(const SequenceNumberStats& other); - SequenceNumberStats& operator=(const SequenceNumberStats& rhs); - ~SequenceNumberStats(); void reset(); ArrivalInfo sequenceNumberReceived(quint16 incoming, QUuid senderUUID = QUuid(), const bool wantExtraDebugging = false); void pruneMissingSet(const bool wantExtraDebugging = false); void pushStatsToHistory() { _statsHistory.insert(_stats); } - quint32 getReceived() const { return _received; } - float getUnreasonableRate() const { return _stats._unreasonable / _received; } - + quint32 getReceived() const { return _stats._received; } quint32 getExpectedReceived() const { return _stats._expectedReceived; } quint32 getUnreasonable() const { return _stats._unreasonable; } quint32 getOutOfOrder() const { return _stats._early + _stats._late; } @@ -82,15 +73,15 @@ public: quint32 getLate() const { return _stats._late; } quint32 getLost() const { return _stats._lost; } quint32 getRecovered() const { return _stats._recovered; } - quint32 getDuplicate() const { return _stats._duplicate; } const PacketStreamStats& getStats() const { return _stats; } PacketStreamStats getStatsForHistoryWindow() const; const QSet& getMissingSet() const { return _missingSet; } private: - int _received; + void receivedUnreasonable(quint16 incoming); +private: quint16 _lastReceivedSequence; QSet _missingSet; @@ -100,13 +91,8 @@ private: RingBufferHistory _statsHistory; - - // to deal with the incoming seq nums going out of sync with this tracker, we'll create another instance - // of this class when we encounter an unreasonable - bool _canHaveChild; - SequenceNumberStats* _childInstance; - - int _consecutiveReasonable; + quint16 _lastUnreasonableSequence; + int _consecutiveUnreasonableOnTime; }; #endif // hifi_SequenceNumberStats_h diff --git a/tests/networking/src/SequenceNumberStatsTests.cpp b/tests/networking/src/SequenceNumberStatsTests.cpp index 1df48b781b..901a018235 100644 --- a/tests/networking/src/SequenceNumberStatsTests.cpp +++ b/tests/networking/src/SequenceNumberStatsTests.cpp @@ -20,7 +20,7 @@ void SequenceNumberStatsTests::runAllTests() { earlyLateTest(); duplicateTest(); pruneTest(); - recursiveTest(); + resyncTest(); } const quint32 UINT16_RANGE = std::numeric_limits::max() + 1; @@ -38,7 +38,6 @@ void SequenceNumberStatsTests::rolloverTest() { stats.sequenceNumberReceived(seq); seq = seq + (quint16)1; - assert(stats.getDuplicate() == 0); assert(stats.getEarly() == 0); assert(stats.getLate() == 0); assert(stats.getLost() == 0); @@ -69,7 +68,6 @@ void SequenceNumberStatsTests::earlyLateTest() { seq = seq + (quint16)1; numSent++; - assert(stats.getDuplicate() == 0); assert(stats.getEarly() == numEarly); assert(stats.getLate() == numLate); assert(stats.getLost() == numLost); @@ -89,7 +87,6 @@ void SequenceNumberStatsTests::earlyLateTest() { seq = seq + (quint16)1; numSent++; - assert(stats.getDuplicate() == 0); assert(stats.getEarly() == numEarly); assert(stats.getLate() == numLate); assert(stats.getLost() == numLost); @@ -106,7 +103,6 @@ void SequenceNumberStatsTests::earlyLateTest() { numLost--; numRecovered++; - assert(stats.getDuplicate() == 0); assert(stats.getEarly() == numEarly); assert(stats.getLate() == numLate); assert(stats.getLost() == numLost); @@ -135,7 +131,7 @@ void SequenceNumberStatsTests::duplicateTest() { quint32 numLost = 0; for (int R = 0; R < 2; R++) { - for (int T = 0; T < 10000; T++) { + for (int T = 0; T < 5; T++) { quint16 duplicate = seq; @@ -145,7 +141,7 @@ void SequenceNumberStatsTests::duplicateTest() { seq = seq + (quint16)1; numSent++; - assert(stats.getDuplicate() == numDuplicate); + assert(stats.getUnreasonable() == numDuplicate); assert(stats.getEarly() == numEarly); assert(stats.getLate() == numLate); assert(stats.getLost() == numLost); @@ -167,7 +163,7 @@ void SequenceNumberStatsTests::duplicateTest() { seq = seq + (quint16)1; numSent++; - assert(stats.getDuplicate() == numDuplicate); + assert(stats.getUnreasonable() == numDuplicate); assert(stats.getEarly() == numEarly); assert(stats.getLate() == numLate); assert(stats.getLost() == numLost); @@ -183,7 +179,7 @@ void SequenceNumberStatsTests::duplicateTest() { numDuplicate++; numLate++; - assert(stats.getDuplicate() == numDuplicate); + assert(stats.getUnreasonable() == numDuplicate); assert(stats.getEarly() == numEarly); assert(stats.getLate() == numLate); assert(stats.getLost() == numLost); @@ -199,7 +195,7 @@ void SequenceNumberStatsTests::duplicateTest() { numDuplicate++; numLate++; - assert(stats.getDuplicate() == numDuplicate); + assert(stats.getUnreasonable() == numDuplicate); assert(stats.getEarly() == numEarly); assert(stats.getLate() == numLate); assert(stats.getLost() == numLost); @@ -279,7 +275,7 @@ void SequenceNumberStatsTests::pruneTest() { } } -void SequenceNumberStatsTests::recursiveTest() { +void SequenceNumberStatsTests::resyncTest() { SequenceNumberStats stats(0); @@ -302,9 +298,20 @@ void SequenceNumberStatsTests::recursiveTest() { sequence = 0; for (int R = 0; R < 7; R++) { stats.sequenceNumberReceived(sequence); - sequence += (quint16)2000; + sequence += (quint16)1; } - + + assert(stats.getUnreasonable() == 7); + + sequence = 6000; + for (int R = 0; R < 7; R++) { + stats.sequenceNumberReceived(sequence); + sequence += (quint16)1; + } + + assert(stats.getUnreasonable() == 14); + + sequence = 9000; for (int i = 0; i < 10; i++) { stats.sequenceNumberReceived(sequence); sequence += (quint16)1; diff --git a/tests/networking/src/SequenceNumberStatsTests.h b/tests/networking/src/SequenceNumberStatsTests.h index 80053fd822..6b1fa3dde7 100644 --- a/tests/networking/src/SequenceNumberStatsTests.h +++ b/tests/networking/src/SequenceNumberStatsTests.h @@ -23,7 +23,7 @@ namespace SequenceNumberStatsTests { void earlyLateTest(); void duplicateTest(); void pruneTest(); - void recursiveTest(); + void resyncTest(); }; #endif // hifi_SequenceNumberStatsTests_h From ad3bbc59f2764e56f8e3b710c6c6cb7dd93857fd Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 4 Aug 2014 11:15:42 -0700 Subject: [PATCH 190/407] added bot_procedural back in --- examples/bot_procedural.js | 674 +++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 examples/bot_procedural.js diff --git a/examples/bot_procedural.js b/examples/bot_procedural.js new file mode 100644 index 0000000000..265b887e0a --- /dev/null +++ b/examples/bot_procedural.js @@ -0,0 +1,674 @@ +// +// bot_procedural.js +// hifi +// +// Created by Ben Arnold on 7/29/2013 +// +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// +// This is an example script that demonstrates an NPC avatar. +// +// + +//For procedural walk animation +Script.include("http://s3-us-west-1.amazonaws.com/highfidelity-public/scripts/proceduralAnimationAPI.js"); + +var procAnimAPI = new ProcAnimAPI(); + +function getRandomFloat(min, max) { + return Math.random() * (max - min) + min; +} + +function getRandomInt (min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +function printVector(string, vector) { + print(string + " " + vector.x + ", " + vector.y + ", " + vector.z); +} + +var CHANCE_OF_MOVING = 0.005; +var CHANCE_OF_SOUND = 0.005; +var CHANCE_OF_HEAD_TURNING = 0.01; +var CHANCE_OF_BIG_MOVE = 1.0; + +var isMoving = false; +var isTurningHead = false; +var isPlayingAudio = false; + +var X_MIN = 0.50; +var X_MAX = 15.60; +var Z_MIN = 0.50; +var Z_MAX = 15.10; +var Y_FEET = 0.0; +var AVATAR_PELVIS_HEIGHT = 0.84; +var Y_PELVIS = Y_FEET + AVATAR_PELVIS_HEIGHT; +var MAX_PELVIS_DELTA = 2.5; + +var MOVE_RANGE_SMALL = 3.0; +var MOVE_RANGE_BIG = 10.0; +var TURN_RANGE = 70.0; +var STOP_TOLERANCE = 0.05; +var MOVE_RATE = 0.05; +var TURN_RATE = 0.2; +var HEAD_TURN_RATE = 0.05; +var PITCH_RANGE = 15.0; +var YAW_RANGE = 35.0; + +var firstPosition = { x: getRandomFloat(X_MIN, X_MAX), y: Y_PELVIS, z: getRandomFloat(Z_MIN, Z_MAX) }; +var targetPosition = { x: 0, y: 0, z: 0 }; +var targetOrientation = { x: 0, y: 0, z: 0, w: 0 }; +var currentOrientation = { x: 0, y: 0, z: 0, w: 0 }; +var targetHeadPitch = 0.0; +var targetHeadYaw = 0.0; + +var basePelvisHeight = 0.0; +var pelvisOscillatorPosition = 0.0; +var pelvisOscillatorVelocity = 0.0; + +function clamp(val, min, max){ + return Math.max(min, Math.min(max, val)) +} + +//Array of all valid bot numbers +var validBotNumbers = []; + +// right now we only use bot 63, since many other bots have messed up skeletons and LOD issues +var botNumber = 63;//getRandomInt(0, 99); + +var newFaceFilePrefix = "ron"; + +var newBodyFilePrefix = "bot" + botNumber; + +// set the face model fst using the bot number +// there is no need to change the body model - we're using the default +Avatar.faceModelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/" + newFaceFilePrefix + ".fst"; +Avatar.skeletonModelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/" + newBodyFilePrefix + "_a.fst"; +Avatar.billboardURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/billboards/bot" + botNumber + ".png"; + +Agent.isAvatar = true; +Agent.isListeningToAudioStream = true; + +// change the avatar's position to the random one +Avatar.position = firstPosition; +basePelvisHeight = firstPosition.y; +printVector("New dancer, position = ", Avatar.position); + +function loadSounds() { + var sound_filenames = ["AB1.raw", "Anchorman2.raw", "B1.raw", "B1.raw", "Bale1.raw", "Bandcamp.raw", + "Big1.raw", "Big2.raw", "Brian1.raw", "Buster1.raw", "CES1.raw", "CES2.raw", "CES3.raw", "CES4.raw", + "Carrie1.raw", "Carrie3.raw", "Charlotte1.raw", "EN1.raw", "EN2.raw", "EN3.raw", "Eugene1.raw", "Francesco1.raw", + "Italian1.raw", "Japanese1.raw", "Leigh1.raw", "Lucille1.raw", "Lucille2.raw", "MeanGirls.raw", "Murray2.raw", + "Nigel1.raw", "PennyLane.raw", "Pitt1.raw", "Ricardo.raw", "SN.raw", "Sake1.raw", "Samantha1.raw", "Samantha2.raw", + "Spicoli1.raw", "Supernatural.raw", "Swearengen1.raw", "TheDude.raw", "Tony.raw", "Triumph1.raw", "Uma1.raw", + "Walken1.raw", "Walken2.raw", "Z1.raw", "Z2.raw" + ]; + + var footstep_filenames = ["FootstepW2Left-12db.wav", "FootstepW2Right-12db.wav", "FootstepW3Left-12db.wav", "FootstepW3Right-12db.wav", + "FootstepW5Left-12db.wav", "FootstepW5Right-12db.wav"]; + + var SOUND_BASE_URL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Cocktail+Party+Snippets/Raws/"; + + var FOOTSTEP_BASE_URL = "http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Footsteps/"; + + for (var i = 0; i < sound_filenames.length; i++) { + sounds.push(new Sound(SOUND_BASE_URL + sound_filenames[i])); + } + + for (var i = 0; i < footstep_filenames.length; i++) { + footstepSounds.push(new Sound(FOOTSTEP_BASE_URL + footstep_filenames[i])); + } +} + +var sounds = []; +var footstepSounds = []; +loadSounds(); + + +function playRandomSound() { + if (!Agent.isPlayingAvatarSound) { + var whichSound = Math.floor((Math.random() * sounds.length)); + Agent.playAvatarSound(sounds[whichSound]); + } +} + +function playRandomFootstepSound() { + + var whichSound = Math.floor((Math.random() * footstepSounds.length)); + var options = new AudioInjectionOptions(); + options.position = Avatar.position; + options.volume = 1.0; + Audio.playSound(footstepSounds[whichSound], options); + +} + +// ************************************ Facial Animation ********************************** +var allBlendShapes = []; +var targetBlendCoefficient = []; +var currentBlendCoefficient = []; + +//Blendshape constructor +function addBlendshapeToPose(pose, shapeIndex, val) { + var index = pose.blendShapes.length; + pose.blendShapes[index] = {shapeIndex: shapeIndex, val: val }; +} +//The mood of the avatar, determines face. 0 = happy, 1 = angry, 2 = sad. + +//Randomly pick avatar mood. 80% happy, 10% mad 10% sad +var randMood = Math.floor(Math.random() * 11); +var avatarMood; +if (randMood == 0) { + avatarMood = 1; +} else if (randMood == 2) { + avatarMood = 2; +} else { + avatarMood = 0; +} + +var currentExpression = -1; +//Face pose constructor +var happyPoses = []; + +happyPoses[0] = {blendShapes: []}; +addBlendshapeToPose(happyPoses[0], 28, 0.7); //MouthSmile_L +addBlendshapeToPose(happyPoses[0], 29, 0.7); //MouthSmile_R + +happyPoses[1] = {blendShapes: []}; +addBlendshapeToPose(happyPoses[1], 28, 1.0); //MouthSmile_L +addBlendshapeToPose(happyPoses[1], 29, 1.0); //MouthSmile_R +addBlendshapeToPose(happyPoses[1], 21, 0.2); //JawOpen + +happyPoses[2] = {blendShapes: []}; +addBlendshapeToPose(happyPoses[2], 28, 1.0); //MouthSmile_L +addBlendshapeToPose(happyPoses[2], 29, 1.0); //MouthSmile_R +addBlendshapeToPose(happyPoses[2], 21, 0.5); //JawOpen +addBlendshapeToPose(happyPoses[2], 46, 1.0); //CheekSquint_L +addBlendshapeToPose(happyPoses[2], 47, 1.0); //CheekSquint_R +addBlendshapeToPose(happyPoses[2], 17, 1.0); //BrowsU_L +addBlendshapeToPose(happyPoses[2], 18, 1.0); //BrowsU_R + +var angryPoses = []; + +angryPoses[0] = {blendShapes: []}; +addBlendshapeToPose(angryPoses[0], 26, 0.6); //MouthFrown_L +addBlendshapeToPose(angryPoses[0], 27, 0.6); //MouthFrown_R +addBlendshapeToPose(angryPoses[0], 14, 0.6); //BrowsD_L +addBlendshapeToPose(angryPoses[0], 15, 0.6); //BrowsD_R + +angryPoses[1] = {blendShapes: []}; +addBlendshapeToPose(angryPoses[1], 26, 0.9); //MouthFrown_L +addBlendshapeToPose(angryPoses[1], 27, 0.9); //MouthFrown_R +addBlendshapeToPose(angryPoses[1], 14, 0.9); //BrowsD_L +addBlendshapeToPose(angryPoses[1], 15, 0.9); //BrowsD_R + +angryPoses[2] = {blendShapes: []}; +addBlendshapeToPose(angryPoses[2], 26, 1.0); //MouthFrown_L +addBlendshapeToPose(angryPoses[2], 27, 1.0); //MouthFrown_R +addBlendshapeToPose(angryPoses[2], 14, 1.0); //BrowsD_L +addBlendshapeToPose(angryPoses[2], 15, 1.0); //BrowsD_R +addBlendshapeToPose(angryPoses[2], 21, 0.5); //JawOpen +addBlendshapeToPose(angryPoses[2], 46, 1.0); //CheekSquint_L +addBlendshapeToPose(angryPoses[2], 47, 1.0); //CheekSquint_R + +var sadPoses = []; + +sadPoses[0] = {blendShapes: []}; +addBlendshapeToPose(sadPoses[0], 26, 0.6); //MouthFrown_L +addBlendshapeToPose(sadPoses[0], 27, 0.6); //MouthFrown_R +addBlendshapeToPose(sadPoses[0], 16, 0.2); //BrowsU_C +addBlendshapeToPose(sadPoses[0], 2, 0.6); //EyeSquint_L +addBlendshapeToPose(sadPoses[0], 3, 0.6); //EyeSquint_R + +sadPoses[1] = {blendShapes: []}; +addBlendshapeToPose(sadPoses[1], 26, 0.9); //MouthFrown_L +addBlendshapeToPose(sadPoses[1], 27, 0.9); //MouthFrown_R +addBlendshapeToPose(sadPoses[1], 16, 0.6); //BrowsU_C +addBlendshapeToPose(sadPoses[1], 2, 0.9); //EyeSquint_L +addBlendshapeToPose(sadPoses[1], 3, 0.9); //EyeSquint_R + +sadPoses[2] = {blendShapes: []}; +addBlendshapeToPose(sadPoses[2], 26, 1.0); //MouthFrown_L +addBlendshapeToPose(sadPoses[2], 27, 1.0); //MouthFrown_R +addBlendshapeToPose(sadPoses[2], 16, 0.1); //BrowsU_C +addBlendshapeToPose(sadPoses[2], 2, 1.0); //EyeSquint_L +addBlendshapeToPose(sadPoses[2], 3, 1.0); //EyeSquint_R +addBlendshapeToPose(sadPoses[2], 21, 0.3); //JawOpen + +var facePoses = []; +facePoses[0] = happyPoses; +facePoses[1] = angryPoses; +facePoses[2] = sadPoses; + + +function addBlendShape(s) { + allBlendShapes[allBlendShapes.length] = s; +} + +//It is imperative that the following blendshapes are all present and are in the correct order +addBlendShape("EyeBlink_L"); //0 +addBlendShape("EyeBlink_R"); //1 +addBlendShape("EyeSquint_L"); //2 +addBlendShape("EyeSquint_R"); //3 +addBlendShape("EyeDown_L"); //4 +addBlendShape("EyeDown_R"); //5 +addBlendShape("EyeIn_L"); //6 +addBlendShape("EyeIn_R"); //7 +addBlendShape("EyeOpen_L"); //8 +addBlendShape("EyeOpen_R"); //9 +addBlendShape("EyeOut_L"); //10 +addBlendShape("EyeOut_R"); //11 +addBlendShape("EyeUp_L"); //12 +addBlendShape("EyeUp_R"); //13 +addBlendShape("BrowsD_L"); //14 +addBlendShape("BrowsD_R"); //15 +addBlendShape("BrowsU_C"); //16 +addBlendShape("BrowsU_L"); //17 +addBlendShape("BrowsU_R"); //18 +addBlendShape("JawFwd"); //19 +addBlendShape("JawLeft"); //20 +addBlendShape("JawOpen"); //21 +addBlendShape("JawChew"); //22 +addBlendShape("JawRight"); //23 +addBlendShape("MouthLeft"); //24 +addBlendShape("MouthRight"); //25 +addBlendShape("MouthFrown_L"); //26 +addBlendShape("MouthFrown_R"); //27 +addBlendShape("MouthSmile_L"); //28 +addBlendShape("MouthSmile_R"); //29 +addBlendShape("MouthDimple_L"); //30 +addBlendShape("MouthDimple_R"); //31 +addBlendShape("LipsStretch_L"); //32 +addBlendShape("LipsStretch_R"); //33 +addBlendShape("LipsUpperClose"); //34 +addBlendShape("LipsLowerClose"); //35 +addBlendShape("LipsUpperUp"); //36 +addBlendShape("LipsLowerDown"); //37 +addBlendShape("LipsUpperOpen"); //38 +addBlendShape("LipsLowerOpen"); //39 +addBlendShape("LipsFunnel"); //40 +addBlendShape("LipsPucker"); //41 +addBlendShape("ChinLowerRaise"); //42 +addBlendShape("ChinUpperRaise"); //43 +addBlendShape("Sneer"); //44 +addBlendShape("Puff"); //45 +addBlendShape("CheekSquint_L"); //46 +addBlendShape("CheekSquint_R"); //47 + +for (var i = 0; i < allBlendShapes.length; i++) { + targetBlendCoefficient[i] = 0; + currentBlendCoefficient[i] = 0; +} + +function setRandomExpression() { + + //Clear all expression data for current expression + if (currentExpression != -1) { + var expression = facePoses[avatarMood][currentExpression]; + for (var i = 0; i < expression.blendShapes.length; i++) { + targetBlendCoefficient[expression.blendShapes[i].shapeIndex] = 0.0; + } + } + //Get a new current expression + currentExpression = Math.floor(Math.random() * facePoses[avatarMood].length); + var expression = facePoses[avatarMood][currentExpression]; + for (var i = 0; i < expression.blendShapes.length; i++) { + targetBlendCoefficient[expression.blendShapes[i].shapeIndex] = expression.blendShapes[i].val; + } +} + +var expressionChangeSpeed = 0.1; +function updateBlendShapes(deltaTime) { + + for (var i = 0; i < allBlendShapes.length; i++) { + currentBlendCoefficient[i] += (targetBlendCoefficient[i] - currentBlendCoefficient[i]) * expressionChangeSpeed; + Avatar.setBlendshape(allBlendShapes[i], currentBlendCoefficient[i]); + } +} + +var BLINK_SPEED = 0.15; +var CHANCE_TO_BLINK = 0.0025; +var MAX_BLINK = 0.85; +var blink = 0.0; +var isBlinking = false; +function updateBlinking(deltaTime) { + if (isBlinking == false) { + if (Math.random() < CHANCE_TO_BLINK) { + isBlinking = true; + } else { + blink -= BLINK_SPEED; + if (blink < 0.0) blink = 0.0; + } + } else { + blink += BLINK_SPEED; + if (blink > MAX_BLINK) { + blink = MAX_BLINK; + isBlinking = false; + } + } + + currentBlendCoefficient[0] = blink; + currentBlendCoefficient[1] = blink; + targetBlendCoefficient[0] = blink; + targetBlendCoefficient[1] = blink; +} + +// ************************************************************************************* + +//Procedural walk animation using two keyframes +//We use a separate array for front and back joints +//Pitch, yaw, and roll for the joints +var rightAngles = []; +var leftAngles = []; +//for non mirrored joints such as the spine +var middleAngles = []; + +//Actual joint mappings +var SHOULDER_JOINT_NUMBER = 15; +var ELBOW_JOINT_NUMBER = 16; +var JOINT_R_HIP = 1; +var JOINT_R_KNEE = 2; +var JOINT_L_HIP = 6; +var JOINT_L_KNEE = 7; +var JOINT_R_ARM = 15; +var JOINT_R_FOREARM = 16; +var JOINT_L_ARM = 39; +var JOINT_L_FOREARM = 40; +var JOINT_SPINE = 11; +var JOINT_R_FOOT = 3; +var JOINT_L_FOOT = 8; +var JOINT_R_TOE = 4; +var JOINT_L_TOE = 9; + +// ******************************* Animation Is Defined Below ************************************* + +var NUM_FRAMES = 2; +for (var i = 0; i < NUM_FRAMES; i++) { + rightAngles[i] = []; + leftAngles[i] = []; + middleAngles[i] = []; +} +//Joint order for actual joint mappings, should be interleaved R,L,R,L,...S,S,S for R = right, L = left, S = single +var JOINT_ORDER = []; +//*** right / left joints *** +var HIP = 0; +JOINT_ORDER.push(JOINT_R_HIP); +JOINT_ORDER.push(JOINT_L_HIP); +var KNEE = 1; +JOINT_ORDER.push(JOINT_R_KNEE); +JOINT_ORDER.push(JOINT_L_KNEE); +var ARM = 2; +JOINT_ORDER.push(JOINT_R_ARM); +JOINT_ORDER.push(JOINT_L_ARM); +var FOREARM = 3; +JOINT_ORDER.push(JOINT_R_FOREARM); +JOINT_ORDER.push(JOINT_L_FOREARM); +var FOOT = 4; +JOINT_ORDER.push(JOINT_R_FOOT); +JOINT_ORDER.push(JOINT_L_FOOT); +var TOE = 5; +JOINT_ORDER.push(JOINT_R_TOE); +JOINT_ORDER.push(JOINT_L_TOE); +//*** middle joints *** +var SPINE = 0; +JOINT_ORDER.push(JOINT_SPINE); + +//We have to store the angles so we can invert yaw and roll when making the animation +//symmetrical + +//Front refers to leg, not arm. +//Legs Extending +rightAngles[0][HIP] = [30.0, 0.0, 8.0]; +rightAngles[0][KNEE] = [-15.0, 0.0, 0.0]; +rightAngles[0][ARM] = [85.0, -25.0, 0.0]; +rightAngles[0][FOREARM] = [0.0, 0.0, -15.0]; +rightAngles[0][FOOT] = [0.0, 0.0, 0.0]; +rightAngles[0][TOE] = [0.0, 0.0, 0.0]; + +leftAngles[0][HIP] = [-15, 0.0, 8.0]; +leftAngles[0][KNEE] = [-26, 0.0, 0.0]; +leftAngles[0][ARM] = [85.0, 20.0, 0.0]; +leftAngles[0][FOREARM] = [10.0, 0.0, -25.0]; +leftAngles[0][FOOT] = [-13.0, 0.0, 0.0]; +leftAngles[0][TOE] = [34.0, 0.0, 0.0]; + +middleAngles[0][SPINE] = [0.0, -15.0, 5.0]; + +//Legs Passing +rightAngles[1][HIP] = [6.0, 0.0, 8.0]; +rightAngles[1][KNEE] = [-12.0, 0.0, 0.0]; +rightAngles[1][ARM] = [85.0, 0.0, 0.0]; +rightAngles[1][FOREARM] = [0.0, 0.0, -15.0]; +rightAngles[1][FOOT] = [6.0, -8.0, 0.0]; +rightAngles[1][TOE] = [0.0, 0.0, 0.0]; + +leftAngles[1][HIP] = [10.0, 0.0, 8.0]; +leftAngles[1][KNEE] = [-60.0, 0.0, 0.0]; +leftAngles[1][ARM] = [85.0, 0.0, 0.0]; +leftAngles[1][FOREARM] = [0.0, 0.0, -15.0]; +leftAngles[1][FOOT] = [0.0, 0.0, 0.0]; +leftAngles[1][TOE] = [0.0, 0.0, 0.0]; + +middleAngles[1][SPINE] = [0.0, 0.0, 0.0]; + +//Actual keyframes for the animation +var walkKeyFrames = procAnimAPI.generateKeyframes(rightAngles, leftAngles, middleAngles, NUM_FRAMES); + +// ******************************* Animation Is Defined Above ************************************* + +// ********************************** Standing Key Frame ****************************************** +//We don't have to do any mirroring or anything, since this is just a single pose. +var rightQuats = []; +var leftQuats = []; +var middleQuats = []; + +rightQuats[HIP] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 7.0); +rightQuats[KNEE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0); +rightQuats[ARM] = Quat.fromPitchYawRollDegrees(85.0, 0.0, 0.0); +rightQuats[FOREARM] = Quat.fromPitchYawRollDegrees(0.0, 0.0, -10.0); +rightQuats[FOOT] = Quat.fromPitchYawRollDegrees(0.0, -8.0, 0.0); +rightQuats[TOE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0); + +leftQuats[HIP] = Quat.fromPitchYawRollDegrees(0, 0.0, -7.0); +leftQuats[KNEE] = Quat.fromPitchYawRollDegrees(0, 0.0, 0.0); +leftQuats[ARM] = Quat.fromPitchYawRollDegrees(85.0, 0.0, 0.0); +leftQuats[FOREARM] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 10.0); +leftQuats[FOOT] = Quat.fromPitchYawRollDegrees(0.0, 8.0, 0.0); +leftQuats[TOE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0); + +middleQuats[SPINE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0); + +var standingKeyFrame = new procAnimAPI.KeyFrame(rightQuats, leftQuats, middleQuats); + +// ************************************************************************************************ + + +var currentFrame = 0; + +var walkTime = 0.0; + +var walkWheelRadius = 0.5; +var walkWheelRate = 2.0 * 3.141592 * walkWheelRadius / 8.0; + +var avatarAcceleration = 0.75; +var avatarVelocity = 0.0; +var avatarMaxVelocity = 1.4; + +function handleAnimation(deltaTime) { + + updateBlinking(deltaTime); + updateBlendShapes(deltaTime); + + if (Math.random() < 0.01) { + setRandomExpression(); + } + + if (avatarVelocity == 0.0) { + walkTime = 0.0; + currentFrame = 0; + } else { + walkTime += avatarVelocity * deltaTime; + if (walkTime > walkWheelRate) { + walkTime = 0.0; + currentFrame++; + if (currentFrame % 2 == 1) { + playRandomFootstepSound(); + } + if (currentFrame > 3) { + currentFrame = 0; + } + } + } + + var frame = walkKeyFrames[currentFrame]; + + var walkInterp = walkTime / walkWheelRate; + var animInterp = avatarVelocity / (avatarMaxVelocity / 1.3); + if (animInterp > 1.0) animInterp = 1.0; + + for (var i = 0; i < JOINT_ORDER.length; i++) { + var walkJoint = procAnimAPI.deCasteljau(frame.rotations[i], frame.nextFrame.rotations[i], frame.controlPoints[i][0], frame.controlPoints[i][1], walkInterp); + var standJoint = standingKeyFrame.rotations[i]; + var finalJoint = Quat.mix(standJoint, walkJoint, animInterp); + Avatar.setJointData(JOINT_ORDER[i], finalJoint); + } +} + +function jumpWithLoudness(deltaTime) { + // potentially change pelvis height depending on trailing average loudness + + pelvisOscillatorVelocity += deltaTime * Agent.lastReceivedAudioLoudness * 700.0 ; + + pelvisOscillatorVelocity -= pelvisOscillatorPosition * 0.75; + pelvisOscillatorVelocity *= 0.97; + pelvisOscillatorPosition += deltaTime * pelvisOscillatorVelocity; + Avatar.headPitch = pelvisOscillatorPosition * 60.0; + + var pelvisPosition = Avatar.position; + pelvisPosition.y = (Y_PELVIS - 0.35) + pelvisOscillatorPosition; + + if (pelvisPosition.y < Y_PELVIS) { + pelvisPosition.y = Y_PELVIS; + } else if (pelvisPosition.y > Y_PELVIS + 1.0) { + pelvisPosition.y = Y_PELVIS + 1.0; + } + + Avatar.position = pelvisPosition; +} + +var forcedMove = false; + +var wasMovingLastFrame = false; + +function handleHeadTurn() { + if (!isTurningHead && (Math.random() < CHANCE_OF_HEAD_TURNING)) { + targetHeadPitch = getRandomFloat(-PITCH_RANGE, PITCH_RANGE); + targetHeadYaw = getRandomFloat(-YAW_RANGE, YAW_RANGE); + isTurningHead = true; + } else { + Avatar.headPitch = Avatar.headPitch + (targetHeadPitch - Avatar.headPitch) * HEAD_TURN_RATE; + Avatar.headYaw = Avatar.headYaw + (targetHeadYaw - Avatar.headYaw) * HEAD_TURN_RATE; + if (Math.abs(Avatar.headPitch - targetHeadPitch) < STOP_TOLERANCE && + Math.abs(Avatar.headYaw - targetHeadYaw) < STOP_TOLERANCE) { + isTurningHead = false; + } + } +} + +function stopWalking() { + avatarVelocity = 0.0; + isMoving = false; +} + +var MAX_ATTEMPTS = 40; +function handleWalking(deltaTime) { + + if (forcedMove || (!isMoving && Math.random() < CHANCE_OF_MOVING)) { + // Set new target location + + var moveRange; + if (Math.random() < CHANCE_OF_BIG_MOVE) { + moveRange = MOVE_RANGE_BIG; + } else { + moveRange = MOVE_RANGE_SMALL; + } + + //Keep trying new orientations if the desired target location is out of bounds + var attempts = 0; + do { + targetOrientation = Quat.multiply(Avatar.orientation, Quat.angleAxis(getRandomFloat(-TURN_RANGE, TURN_RANGE), { x:0, y:1, z:0 })); + var front = Quat.getFront(targetOrientation); + + targetPosition = Vec3.sum(Avatar.position, Vec3.multiply(front, getRandomFloat(0.0, moveRange))); + } + while ((targetPosition.x < X_MIN || targetPosition.x > X_MAX || targetPosition.z < Z_MIN || targetPosition.z > Z_MAX) + && attempts < MAX_ATTEMPTS); + + targetPosition.x = clamp(targetPosition.x, X_MIN, X_MAX); + targetPosition.z = clamp(targetPosition.z, Z_MIN, Z_MAX); + targetPosition.y = Y_PELVIS; + + wasMovingLastFrame = true; + isMoving = true; + forcedMove = false; + } else if (isMoving) { + + var targetVector = Vec3.subtract(targetPosition, Avatar.position); + var distance = Vec3.length(targetVector); + if (distance <= avatarVelocity * deltaTime) { + Avatar.position = targetPosition; + stopWalking(); + } else { + var direction = Vec3.normalize(targetVector); + //Figure out if we should be slowing down + var t = avatarVelocity / avatarAcceleration; + var d = (avatarVelocity / 2.0) * t; + if (distance < d) { + avatarVelocity -= avatarAcceleration * deltaTime; + if (avatarVelocity <= 0) { + stopWalking(); + } + } else { + avatarVelocity += avatarAcceleration * deltaTime; + if (avatarVelocity > avatarMaxVelocity) avatarVelocity = avatarMaxVelocity; + } + Avatar.position = Vec3.sum(Avatar.position, Vec3.multiply(direction, avatarVelocity * deltaTime)); + Avatar.orientation = Quat.mix(Avatar.orientation, targetOrientation, TURN_RATE); + + wasMovingLastFrame = true; + + } + } +} + +function handleTalking() { + if (Math.random() < CHANCE_OF_SOUND) { + playRandomSound(); + } +} + +function changePelvisHeight(newHeight) { + var newPosition = Avatar.position; + newPosition.y = newHeight; + Avatar.position = newPosition; +} + +function updateBehavior(deltaTime) { + + if (AvatarList.containsAvatarWithDisplayName("mrdj")) { + if (wasMovingLastFrame) { + isMoving = false; + } + + // we have a DJ, shouldn't we be dancing? + jumpWithLoudness(deltaTime); + } else { + + // no DJ, let's just chill on the dancefloor - randomly walking and talking + handleHeadTurn(); + handleAnimation(deltaTime); + handleWalking(deltaTime); + handleTalking(); + } +} + +Script.update.connect(updateBehavior); \ No newline at end of file From 1d2cf3536b8baf4ef176547f5c87066f806a72dc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 4 Aug 2014 11:20:18 -0700 Subject: [PATCH 191/407] Coefficients tweaks --- interface/src/devices/DdeFaceTracker.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 23dad928d3..acaa6d4faf 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -172,6 +172,12 @@ float DdeFaceTracker::getBlendshapeCoefficient(int index) const { return (index >= 0 && index < (int)_blendshapeCoefficients.size()) ? _blendshapeCoefficients[index] : 0.0f; } +static const float DDE_MIN_RANGE = -0.2; +static const float DDE_MAX_RANGE = 1.5; +float rescaleCoef(float ddeCoef) { + return (ddeCoef - DDE_MIN_RANGE) / (DDE_MAX_RANGE - DDE_MIN_RANGE); +} + void DdeFaceTracker::decodePacket(const QByteArray& buffer) { if(buffer.size() > MIN_PACKET_SIZE) { Packet packet; @@ -203,14 +209,11 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { _headRotation = rotation; // Set blendshapes - _blendshapeCoefficients[_leftBlinkIndex] = packet.expressions[1]; - _blendshapeCoefficients[_rightBlinkIndex] = packet.expressions[0]; + _blendshapeCoefficients[_leftBlinkIndex] = rescaleCoef(packet.expressions[1]); + _blendshapeCoefficients[_rightBlinkIndex] = rescaleCoef(packet.expressions[0]); - _blendshapeCoefficients[_browDownLeftIndex] = packet.expressions[14]; - _blendshapeCoefficients[_browDownRightIndex] = packet.expressions[15]; - _blendshapeCoefficients[_browUpCenterIndex] = (packet.expressions[14] + packet.expressions[14]) / 2.0f; - _blendshapeCoefficients[_browUpLeftIndex] = packet.expressions[14]; - _blendshapeCoefficients[_browUpRightIndex] = packet.expressions[15]; + _blendshapeCoefficients[_browDownLeftIndex] = rescaleCoef(packet.expressions[14]); + _blendshapeCoefficients[_browDownRightIndex] = rescaleCoef(packet.expressions[15]); _blendshapeCoefficients[_jawOpenIndex] = packet.expressions[21]; From 46d4172157d5205456611694f6aabdf0609fffd6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 4 Aug 2014 11:41:56 -0700 Subject: [PATCH 192/407] Filter terrain, points, spanners by frustum intersection. --- interface/src/MetavoxelSystem.cpp | 38 ++++++++++++++++++++-- interface/src/MetavoxelSystem.h | 3 ++ libraries/metavoxels/src/MetavoxelUtil.cpp | 8 +++-- libraries/metavoxels/src/MetavoxelUtil.h | 2 +- 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index cff5497183..666a3336ac 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -108,6 +108,12 @@ int RenderVisitor::visit(MetavoxelInfo& info) { } void MetavoxelSystem::render() { + // update the frustum + ViewFrustum* viewFrustum = Application::getInstance()->getViewFrustum(); + _frustum.set(viewFrustum->getFarTopLeft(), viewFrustum->getFarTopRight(), viewFrustum->getFarBottomLeft(), + viewFrustum->getFarBottomRight(), viewFrustum->getNearTopLeft(), viewFrustum->getNearTopRight(), + viewFrustum->getNearBottomLeft(), viewFrustum->getNearBottomRight()); + RenderVisitor renderVisitor(getLOD()); guideToAugmented(renderVisitor); } @@ -628,13 +634,31 @@ public: SpannerRenderVisitor(const MetavoxelLOD& lod); + virtual int visit(MetavoxelInfo& info); virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize); + +private: + + int _containmentDepth; }; SpannerRenderVisitor::SpannerRenderVisitor(const MetavoxelLOD& lod) : SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), QVector(), QVector(), QVector(), - lod, encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())) { + lod, encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())), + _containmentDepth(INT_MAX) { +} + +int SpannerRenderVisitor::visit(MetavoxelInfo& info) { + if (_containmentDepth >= _depth) { + Frustum::IntersectionType intersection = Application::getInstance()->getMetavoxels()->getFrustum().getIntersectionType( + info.getBounds()); + if (intersection == Frustum::NO_INTERSECTION) { + return STOP_RECURSION; + } + _containmentDepth = (intersection == Frustum::CONTAINS_INTERSECTION) ? _depth : INT_MAX; + } + return SpannerVisitor::visit(info); } bool SpannerRenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) { @@ -652,14 +676,24 @@ public: private: int _order; + int _containmentDepth; }; BufferRenderVisitor::BufferRenderVisitor(const AttributePointer& attribute, const MetavoxelLOD& lod) : MetavoxelVisitor(QVector() << attribute, QVector(), lod), - _order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())) { + _order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())), + _containmentDepth(INT_MAX) { } int BufferRenderVisitor::visit(MetavoxelInfo& info) { + if (_containmentDepth >= _depth) { + Frustum::IntersectionType intersection = Application::getInstance()->getMetavoxels()->getFrustum().getIntersectionType( + info.getBounds()); + if (intersection == Frustum::NO_INTERSECTION) { + return STOP_RECURSION; + } + _containmentDepth = (intersection == Frustum::CONTAINS_INTERSECTION) ? _depth : INT_MAX; + } BufferDataPointer buffer = info.inputValues.at(0).getInlineValue(); if (buffer) { buffer->render(); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index bd05fc0f67..abcc929156 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -34,6 +34,8 @@ public: virtual void init(); virtual MetavoxelLOD getLOD(); + + const Frustum& getFrustum() const { return _frustum; } const AttributePointer& getPointBufferAttribute() { return _pointBufferAttribute; } const AttributePointer& getHeightfieldBufferAttribute() { return _heightfieldBufferAttribute; } @@ -56,6 +58,7 @@ private: MetavoxelLOD _lod; QReadWriteLock _lodLock; + Frustum _frustum; }; /// Describes contents of a point in a point buffer. diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index 2cfa3a5bc3..ca4edca3e5 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -327,10 +327,9 @@ AxisExtents::AxisExtents(const glm::vec3& axis, float minimum, float maximum) : maximum(maximum) { } -Frustum::Frustum(const glm::vec3& farTopLeft, const glm::vec3& farTopRight, const glm::vec3& farBottomLeft, +void Frustum::set(const glm::vec3& farTopLeft, const glm::vec3& farTopRight, const glm::vec3& farBottomLeft, const glm::vec3& farBottomRight, const glm::vec3& nearTopLeft, const glm::vec3& nearTopRight, - const glm::vec3& nearBottomLeft, const glm::vec3& nearBottomRight) : - _bounds(glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX), glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX)) { + const glm::vec3& nearBottomLeft, const glm::vec3& nearBottomRight) { _vertices[0] = farBottomLeft; _vertices[1] = farBottomRight; @@ -341,6 +340,9 @@ Frustum::Frustum(const glm::vec3& farTopLeft, const glm::vec3& farTopRight, cons _vertices[6] = nearTopLeft; _vertices[7] = nearTopRight; + // compute the bounds + _bounds.minimum = glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX); + _bounds.maximum = glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX); for (int i = 0; i < VERTEX_COUNT; i++) { _bounds.minimum = glm::min(_bounds.minimum, _vertices[i]); _bounds.maximum = glm::max(_bounds.maximum, _vertices[i]); diff --git a/libraries/metavoxels/src/MetavoxelUtil.h b/libraries/metavoxels/src/MetavoxelUtil.h index 6a7b15150e..aa9864b3c7 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.h +++ b/libraries/metavoxels/src/MetavoxelUtil.h @@ -82,7 +82,7 @@ public: class Frustum { public: - Frustum(const glm::vec3& farTopLeft, const glm::vec3& farTopRight, const glm::vec3& farBottomLeft, + void set(const glm::vec3& farTopLeft, const glm::vec3& farTopRight, const glm::vec3& farBottomLeft, const glm::vec3& farBottomRight, const glm::vec3& nearTopLeft, const glm::vec3& nearTopRight, const glm::vec3& nearBottomLeft, const glm::vec3& nearBottomRight); From 74edf6557f5915412939a86dbe7b86fe1c13d72b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 4 Aug 2014 12:05:31 -0700 Subject: [PATCH 193/407] turn off editModels by default --- examples/editModels.js | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index f55ea4bbbe..2b2e11756f 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -1051,6 +1051,11 @@ function checkController(deltaTime) { var numberOfTriggers = Controller.getNumberOfTriggers(); var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; + + if (!isActive) { + // So that we hide the lasers bellow and keep updating the overlays position + numberOfButtons = 0; + } // this is expected for hydras if (numberOfButtons==12 && numberOfTriggers == 2 && controllersPerTrigger == 2) { @@ -1072,11 +1077,21 @@ function checkController(deltaTime) { moveOverlays(); } + +var isActive = false; +var active; var newModel; var browser; function initToolBar() { toolBar = new ToolBar(0, 0, ToolBar.VERTICAL); // New Model + active = toolBar.addTool({ + imageURL: toolIconUrl + "models-tool.svg", + subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: toolWidth, height: toolHeight, + visible: true, + alpha: 0.9 + }, true, false); newModel = toolBar.addTool({ imageURL: toolIconUrl + "add-model-tool.svg", subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, @@ -1194,6 +1209,11 @@ function mousePressEvent(event) { modelSelected = false; var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + if (active == toolBar.clicked(clickedOverlay)) { + isActive = !isActive; + return; + } + if (newModel == toolBar.clicked(clickedOverlay)) { var url = Window.prompt("Model URL", modelURLs[Math.floor(Math.random() * modelURLs.length)]); if (url == null || url == "") { @@ -1229,6 +1249,11 @@ function mousePressEvent(event) { } } else { + // If we aren't active and didn't click on an overlay: quit + if (!isActive) { + return; + } + var pickRay = Camera.computePickRay(event.x, event.y); Vec3.print("[Mouse] Looking at: ", pickRay.origin); var foundIntersection = Models.findRayIntersection(pickRay); @@ -1313,7 +1338,7 @@ var oldModifier = 0; var modifier = 0; var wasShifted = false; function mouseMoveEvent(event) { - if (event.isAlt) { + if (event.isAlt || !isActive) { return; } @@ -1456,7 +1481,7 @@ function mouseMoveEvent(event) { function mouseReleaseEvent(event) { - if (event.isAlt) { + if (event.isAlt || !isActive) { return; } From 0a429681974b4f51fa0fed46baf2807088b0a8e4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 4 Aug 2014 12:40:12 -0700 Subject: [PATCH 194/407] DDE tweaks --- interface/src/devices/DdeFaceTracker.cpp | 29 ++++++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index acaa6d4faf..c22720c0c0 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -209,13 +209,32 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { _headRotation = rotation; // Set blendshapes - _blendshapeCoefficients[_leftBlinkIndex] = rescaleCoef(packet.expressions[1]); - _blendshapeCoefficients[_rightBlinkIndex] = rescaleCoef(packet.expressions[0]); + _blendshapeCoefficients[_leftBlinkIndex] = rescaleCoef(packet.expressions[1]) * 2.0f; + _blendshapeCoefficients[_rightBlinkIndex] = rescaleCoef(packet.expressions[0]) * 2.0f; - _blendshapeCoefficients[_browDownLeftIndex] = rescaleCoef(packet.expressions[14]); - _blendshapeCoefficients[_browDownRightIndex] = rescaleCoef(packet.expressions[15]); + float leftBrow = 1.0f - rescaleCoef(packet.expressions[14]); + if (leftBrow < 0.5f) { + _blendshapeCoefficients[_browDownLeftIndex] = 1.0f - 2.0f * leftBrow; + _blendshapeCoefficients[_browUpLeftIndex] = 0.0f; + } else { + _blendshapeCoefficients[_browDownLeftIndex] = 0.0f; + _blendshapeCoefficients[_browUpLeftIndex] = 2.0f * (leftBrow - 0.5f); + } + float rightBrow = 1.0f - rescaleCoef(packet.expressions[15]); + if (rightBrow < 0.5f) { + _blendshapeCoefficients[_browDownRightIndex] = 1.0f - 2.0f * rightBrow; + _blendshapeCoefficients[_browUpRightIndex] = 0.0f; + } else { + _blendshapeCoefficients[_browDownRightIndex] = 0.0f; + _blendshapeCoefficients[_browUpRightIndex] = 2.0f * (rightBrow - 0.5f); + } + + _blendshapeCoefficients[_jawOpenIndex] = rescaleCoef(packet.expressions[21]) * 1.4f; + + + _blendshapeCoefficients[_mouthSmileLeftIndex] = rescaleCoef(packet.expressions[24]); + _blendshapeCoefficients[_mouthSmileRightIndex] = rescaleCoef(packet.expressions[23]); - _blendshapeCoefficients[_jawOpenIndex] = packet.expressions[21]; } else { qDebug() << "[Error] DDE Face Tracker Decode Error"; From d1a1311979c37a44e7a73a3e9cd5fa27a0af4609 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 4 Aug 2014 12:44:23 -0700 Subject: [PATCH 195/407] Mode DDE tweaks --- interface/src/devices/DdeFaceTracker.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index c22720c0c0..3dc5a818cc 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -196,9 +196,9 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { } // Compute relative translation - float DAMPING_FACTOR = 40; + float LEAN_DAMPING_FACTOR = 40; translation -= _referenceTranslation; - translation /= DAMPING_FACTOR; + translation /= LEAN_DAMPING_FACTOR; translation.x *= -1; // Compute relative rotation @@ -209,8 +209,9 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { _headRotation = rotation; // Set blendshapes - _blendshapeCoefficients[_leftBlinkIndex] = rescaleCoef(packet.expressions[1]) * 2.0f; - _blendshapeCoefficients[_rightBlinkIndex] = rescaleCoef(packet.expressions[0]) * 2.0f; + float BLINK_MAGNIFIER = 2.0f; + _blendshapeCoefficients[_leftBlinkIndex] = rescaleCoef(packet.expressions[1]) * BLINK_MAGNIFIER; + _blendshapeCoefficients[_rightBlinkIndex] = rescaleCoef(packet.expressions[0]) * BLINK_MAGNIFIER; float leftBrow = 1.0f - rescaleCoef(packet.expressions[14]); if (leftBrow < 0.5f) { @@ -229,7 +230,8 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { _blendshapeCoefficients[_browUpRightIndex] = 2.0f * (rightBrow - 0.5f); } - _blendshapeCoefficients[_jawOpenIndex] = rescaleCoef(packet.expressions[21]) * 1.4f; + float JAW_OPEN_MAGNIFIER = 1.4f; + _blendshapeCoefficients[_jawOpenIndex] = rescaleCoef(packet.expressions[21]) * JAW_OPEN_MAGNIFIER; _blendshapeCoefficients[_mouthSmileLeftIndex] = rescaleCoef(packet.expressions[24]); From b1d6977112e4f25d197c122aff6062a2a45a01d8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 4 Aug 2014 12:58:01 -0700 Subject: [PATCH 196/407] Added simple "erase heightfield" tool. --- interface/src/ui/MetavoxelEditor.cpp | 124 +++++++++++++++------ interface/src/ui/MetavoxelEditor.h | 55 ++++++++- libraries/metavoxels/src/MetavoxelUtil.cpp | 4 + libraries/metavoxels/src/MetavoxelUtil.h | 1 + 4 files changed, 144 insertions(+), 40 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 3f3198116f..cf4fd0bba9 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -116,6 +117,7 @@ MetavoxelEditor::MetavoxelEditor() : addTool(new ClearSpannersTool(this)); addTool(new SetSpannerTool(this)); addTool(new ImportHeightfieldTool(this)); + addTool(new EraseHeightfieldTool(this)); updateAttributes(); @@ -895,40 +897,68 @@ void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedOb spannerData->getVoxelizationGranularity(), directionImages)); } -ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) : - MetavoxelTool(editor, "Import Heightfield", false) { +HeightfieldTool::HeightfieldTool(MetavoxelEditor* editor, const QString& name) : + MetavoxelTool(editor, name, false) { QWidget* widget = new QWidget(); - QFormLayout* form = new QFormLayout(); - widget->setLayout(form); + widget->setLayout(_form = new QFormLayout()); layout()->addWidget(widget); - form->addRow("Translation:", _translation = new Vec3Editor(widget)); - form->addRow("Scale:", _scale = new QDoubleSpinBox()); + _form->addRow("Translation:", _translation = new Vec3Editor(widget)); + _form->addRow("Scale:", _scale = new QDoubleSpinBox()); _scale->setMinimum(-FLT_MAX); _scale->setMaximum(FLT_MAX); _scale->setPrefix("2^"); _scale->setValue(3.0); - form->addRow("Height:", _height = new QPushButton()); - connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile); - form->addRow("Color:", _color = new QPushButton()); - connect(_color, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectColorFile); QPushButton* applyButton = new QPushButton("Apply"); layout()->addWidget(applyButton); - connect(applyButton, &QAbstractButton::clicked, this, &ImportHeightfieldTool::apply); + connect(applyButton, &QAbstractButton::clicked, this, &HeightfieldTool::apply); } -bool ImportHeightfieldTool::appliesTo(const AttributePointer& attribute) const { +bool HeightfieldTool::appliesTo(const AttributePointer& attribute) const { return attribute->inherits("HeightfieldAttribute"); } -void ImportHeightfieldTool::render() { +void HeightfieldTool::render() { float scale = pow(2.0, _scale->value()); _translation->setSingleStep(scale); glm::vec3 quantizedTranslation = scale * glm::floor(_translation->getValue() / scale); _translation->setValue(quantizedTranslation); - _preview.render(quantizedTranslation, scale); +} + +ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) : + HeightfieldTool(editor, "Import Heightfield") { + + _form->addRow("Height:", _height = new QPushButton()); + connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile); + _form->addRow("Color:", _color = new QPushButton()); + connect(_color, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectColorFile); +} + +void ImportHeightfieldTool::render() { + HeightfieldTool::render(); + _preview.render(_translation->getValue(), _translation->getSingleStep()); +} + +void ImportHeightfieldTool::apply() { + float scale = _translation->getSingleStep(); + foreach (const BufferDataPointer& bufferData, _preview.getBuffers()) { + HeightfieldBuffer* buffer = static_cast(bufferData.data()); + MetavoxelData data; + data.setSize(scale); + HeightfieldDataPointer heightPointer(new HeightfieldData(buffer->getHeight())); + data.setRoot(AttributeRegistry::getInstance()->getHeightfieldAttribute(), new MetavoxelNode(AttributeValue( + AttributeRegistry::getInstance()->getHeightfieldAttribute(), encodeInline(heightPointer)))); + if (!buffer->getColor().isEmpty()) { + HeightfieldDataPointer colorPointer(new HeightfieldData(buffer->getColor())); + data.setRoot(AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), new MetavoxelNode(AttributeValue( + AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), encodeInline(colorPointer)))); + } + MetavoxelEditMessage message = { QVariant::fromValue(SetDataEdit( + _translation->getValue() + buffer->getTranslation() * scale, data)) }; + Application::getInstance()->getMetavoxels()->applyEdit(message, true); + } } void ImportHeightfieldTool::selectHeightFile() { @@ -959,26 +989,6 @@ void ImportHeightfieldTool::selectColorFile() { updatePreview(); } -void ImportHeightfieldTool::apply() { - float scale = pow(2.0, _scale->value()); - foreach (const BufferDataPointer& bufferData, _preview.getBuffers()) { - HeightfieldBuffer* buffer = static_cast(bufferData.data()); - MetavoxelData data; - data.setSize(scale); - HeightfieldDataPointer heightPointer(new HeightfieldData(buffer->getHeight())); - data.setRoot(AttributeRegistry::getInstance()->getHeightfieldAttribute(), new MetavoxelNode(AttributeValue( - AttributeRegistry::getInstance()->getHeightfieldAttribute(), encodeInline(heightPointer)))); - if (!buffer->getColor().isEmpty()) { - HeightfieldDataPointer colorPointer(new HeightfieldData(buffer->getColor())); - data.setRoot(AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), new MetavoxelNode(AttributeValue( - AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), encodeInline(colorPointer)))); - } - MetavoxelEditMessage message = { QVariant::fromValue(SetDataEdit( - _translation->getValue() + buffer->getTranslation() * scale, data)) }; - Application::getInstance()->getMetavoxels()->applyEdit(message, true); - } -} - const int BLOCK_SIZE = 32; const int BLOCK_ADVANCEMENT = BLOCK_SIZE - 1; @@ -1018,3 +1028,49 @@ void ImportHeightfieldTool::updatePreview() { } _preview.setBuffers(buffers); } + +EraseHeightfieldTool::EraseHeightfieldTool(MetavoxelEditor* editor) : + HeightfieldTool(editor, "Erase Heightfield") { + + _form->addRow("Width:", _width = new QSpinBox()); + _width->setMinimum(1); + _width->setMaximum(INT_MAX); + _form->addRow("Length:", _length = new QSpinBox()); + _length->setMinimum(1); + _length->setMaximum(INT_MAX); +} + +void EraseHeightfieldTool::render() { + HeightfieldTool::render(); + + glColor3f(1.0f, 0.0f, 0.0f); + glLineWidth(4.0f); + + glPushMatrix(); + glm::vec3 translation = _translation->getValue(); + glTranslatef(translation.x, translation.y, translation.z); + float scale = _translation->getSingleStep(); + glScalef(scale * _width->value(), scale, scale * _length->value()); + glTranslatef(0.5f, 0.5f, 0.5f); + + glutWireCube(1.0); + + glPopMatrix(); + + glLineWidth(1.0f); +} + +void EraseHeightfieldTool::apply() { + // clear the heightfield + float scale = _translation->getSingleStep(); + BoxSetEdit edit(Box(_translation->getValue(), _translation->getValue() + + glm::vec3(_width->value() * scale, scale, _length->value() * scale)), scale, + OwnedAttributeValue(AttributeRegistry::getInstance()->getHeightfieldAttribute())); + MetavoxelEditMessage message = { QVariant::fromValue(edit) }; + Application::getInstance()->getMetavoxels()->applyEdit(message, true); + + // and the color + edit.value = OwnedAttributeValue(AttributeRegistry::getInstance()->getHeightfieldColorAttribute()); + message.edit = QVariant::fromValue(edit); + Application::getInstance()->getMetavoxels()->applyEdit(message, true); +} diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index 2545ff57ba..abb1450f40 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -24,6 +24,7 @@ class QGroupBox; class QListWidget; class QPushButton; class QScrollArea; +class QSpinBox; class MetavoxelTool; class Vec3Editor; @@ -225,30 +226,52 @@ protected: virtual void applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner); }; +/// Base class for heightfield tools. +class HeightfieldTool : public MetavoxelTool { + Q_OBJECT + +public: + + HeightfieldTool(MetavoxelEditor* editor, const QString& name); + + virtual bool appliesTo(const AttributePointer& attribute) const; + + virtual void render(); + +protected slots: + + virtual void apply() = 0; + +protected: + + QFormLayout* _form; + Vec3Editor* _translation; + QDoubleSpinBox* _scale; +}; + /// Allows importing a heightfield. -class ImportHeightfieldTool : public MetavoxelTool { +class ImportHeightfieldTool : public HeightfieldTool { Q_OBJECT public: ImportHeightfieldTool(MetavoxelEditor* editor); - virtual bool appliesTo(const AttributePointer& attribute) const; - virtual void render(); +protected: + + virtual void apply(); + private slots: void selectHeightFile(); void selectColorFile(); - void apply(); private: void updatePreview(); - Vec3Editor* _translation; - QDoubleSpinBox* _scale; QPushButton* _height; QPushButton* _color; @@ -258,4 +281,24 @@ private: HeightfieldPreview _preview; }; +// Allows clearing heighfield blocks. +class EraseHeightfieldTool : public HeightfieldTool { + Q_OBJECT + +public: + + EraseHeightfieldTool(MetavoxelEditor* editor); + + virtual void render(); + +protected: + + virtual void apply(); + +private: + + QSpinBox* _width; + QSpinBox* _length; +}; + #endif // hifi_MetavoxelEditor_h diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index ca4edca3e5..e414c8ebb9 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -537,6 +537,10 @@ void BaseVec3Editor::setSingleStep(double singleStep) { _z->setSingleStep(singleStep); } +double BaseVec3Editor::getSingleStep() const { + return _x->singleStep(); +} + QDoubleSpinBox* BaseVec3Editor::createComponentBox() { QDoubleSpinBox* box = new QDoubleSpinBox(); box->setMinimum(-FLT_MAX); diff --git a/libraries/metavoxels/src/MetavoxelUtil.h b/libraries/metavoxels/src/MetavoxelUtil.h index aa9864b3c7..a2b0586708 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.h +++ b/libraries/metavoxels/src/MetavoxelUtil.h @@ -191,6 +191,7 @@ public: BaseVec3Editor(QWidget* parent); void setSingleStep(double singleStep); + double getSingleStep() const; protected slots: From 40375b8c81a37a7a53dab5f67b45177b6ab15420 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 4 Aug 2014 14:46:33 -0700 Subject: [PATCH 197/407] add a navbar to domain-server web page --- domain-server/resources/web/header.html | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/domain-server/resources/web/header.html b/domain-server/resources/web/header.html index 2be603b00e..e1a9d1ea8a 100644 --- a/domain-server/resources/web/header.html +++ b/domain-server/resources/web/header.html @@ -8,4 +8,27 @@ +
\ No newline at end of file From 2c1277ef374db722ae7096ac695fefee0271b9fb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 4 Aug 2014 14:47:17 -0700 Subject: [PATCH 198/407] remove voxel settings from domain-server settings until ready to go --- .../resources/web/settings/describe.json | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/domain-server/resources/web/settings/describe.json b/domain-server/resources/web/settings/describe.json index 2d90680e01..f4920a7b50 100644 --- a/domain-server/resources/web/settings/describe.json +++ b/domain-server/resources/web/settings/describe.json @@ -28,33 +28,5 @@ "default": "" } } - }, - "voxels": { - "label": "Voxels", - "assignment-types": [2,3], - "settings": { - "voxel-wallet": { - "label": "Destination Wallet ID", - "help": "Wallet to be paid for voxel changes", - "placeholder": "00000000-0000-0000-0000-000000000000", - "default": "" - }, - "per-voxel-credits": { - "type": "double", - "label": "Per Voxel Cost", - "help": "Credit cost to change each voxel", - "placeholder": "0.0", - "default": "0.0", - "input_addon": "₵" - }, - "per-meter-cubed-credits": { - "type": "double", - "label": "Per Meter Cubed Cost", - "help": "Credit cost to change each cubed meter of voxel space", - "placeholder": "0.0", - "default": "0.0", - "input_addon": "₵" - } - } } } \ No newline at end of file From d9dde06c146496752e07d499fbd9ebdafb4c397e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 4 Aug 2014 14:59:15 -0700 Subject: [PATCH 199/407] Various tweaks to referentials --- interface/src/Application.cpp | 2 +- interface/src/avatar/Avatar.cpp | 22 +++++++++++++ interface/src/avatar/ModelReferential.cpp | 22 +++++++++---- interface/src/avatar/ModelReferential.h | 5 ++- interface/src/avatar/MyAvatar.cpp | 21 ++++++------ libraries/avatars/src/AvatarData.cpp | 35 ++++++++++++++++---- libraries/avatars/src/AvatarData.h | 4 +-- libraries/avatars/src/Referential.cpp | 39 +++++++++++++++-------- libraries/avatars/src/Referential.h | 9 ++++-- libraries/shared/src/SharedUtil.cpp | 8 ++--- libraries/shared/src/SharedUtil.h | 2 +- 11 files changed, 121 insertions(+), 48 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6ae2452c41..1ae29fcd88 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2176,7 +2176,7 @@ void Application::update(float deltaTime) { // Update _viewFrustum with latest camera and view frustum data... // NOTE: we get this from the view frustum, to make it simpler, since the - // loadViewFrumstum() method will get the correct details from the camera + // loadViewFrumstum() methodill get the correct details from the camera // We could optimize this to not actually load the viewFrustum, since we don't // actually need to calculate the view frustum planes to send these details // to the server. diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 27c4e39062..21d5e65a15 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -27,6 +27,7 @@ #include "Hand.h" #include "Head.h" #include "Menu.h" +#include "ModelReferential.h" #include "Physics.h" #include "world.h" #include "devices/OculusManager.h" @@ -179,6 +180,21 @@ void Avatar::simulate(float deltaTime) { } _displayNameAlpha = abs(_displayNameAlpha - _displayNameTargetAlpha) < 0.01f ? _displayNameTargetAlpha : _displayNameAlpha; } + if (_referential) { + if (_referential->hasExtraData()) { + switch (_referential->type()) { + case Referential::MODEL: + qDebug() << "[DEBUG] Switching to the right referential"; + _referential = new ModelReferential(_referential, this); + break; + default: + qDebug() << "Non handled referential type"; + break; + } + } + + _referential->update(); + } } void Avatar::updateAcceleration(float deltaTime) { @@ -440,6 +456,12 @@ void Avatar::renderBody(RenderMode renderMode, float glowLevel) { return; } + // make sure we have the right position + _skeletonModel.setTranslation(getPosition()); + static const glm::quat refOrientation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); + _skeletonModel.setRotation(getOrientation() * refOrientation); + const float MODEL_SCALE = 0.0006f; + _skeletonModel.setScale(glm::vec3(1.0f, 1.0f, 1.0f) * getScale() * MODEL_SCALE); _skeletonModel.render(1.0f, modelRenderMode, Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows)); renderAttachments(renderMode); getHand()->render(false, modelRenderMode); diff --git a/interface/src/avatar/ModelReferential.cpp b/interface/src/avatar/ModelReferential.cpp index bb1d66d730..85533603f2 100644 --- a/interface/src/avatar/ModelReferential.cpp +++ b/interface/src/avatar/ModelReferential.cpp @@ -16,6 +16,10 @@ #include "ModelReferential.h" +ModelReferential::ModelReferential(Referential* referential, AvatarData* avatar) : Referential(MODEL, avatar) { + +} + ModelReferential::ModelReferential(uint32_t modelID, ModelTree* tree, AvatarData* avatar) : Referential(MODEL, avatar), _modelID(modelID), @@ -40,7 +44,7 @@ _tree(tree) void ModelReferential::update() { const ModelItem* item = _tree->findModelByID(_modelID); - if (!_isValid || item == NULL || _avatar == NULL) { + if (item == NULL || _avatar == NULL) { qDebug() << "Not Valid"; _isValid = false; return; @@ -54,21 +58,25 @@ void ModelReferential::update() { } if (item->getModelRotation() != _refRotation) { _refRotation = item->getModelRotation(); - _avatar->setOrientation(_refRotation);// * _rotation); + _avatar->setOrientation(_refRotation * _rotation); somethingChanged = true; } if (item->getPosition() != _refPosition || somethingChanged) { _refPosition = item->getPosition(); - _avatar->setPosition(_refPosition * (float)TREE_SCALE);// + _refRotation * (_translation * _refScale)); + _avatar->setPosition(_refPosition * (float)TREE_SCALE + _refRotation * (_translation * _refScale)); //qDebug() << "Ref: " << item->getLastUpdated() << " " << item->getLastEdited(); somethingChanged = true; } } -int ModelReferential::packReferential(unsigned char* destinationBuffer) { - int size = packPosition(destinationBuffer); +int ModelReferential::packExtraData(unsigned char* destinationBuffer) { memcpy(destinationBuffer, &_modelID, sizeof(_modelID)); - return size + sizeof(_modelID); + return sizeof(_modelID); +} + +int ModelReferential::unpackExtraData(const unsigned char *sourceBuffer) { + memcpy(&_modelID, sourceBuffer, sizeof(_modelID)); + return sizeof(_modelID); } JointReferential::JointReferential(uint32_t jointIndex, uint32_t modelID, ModelTree* tree, AvatarData* avatar) : @@ -97,7 +105,7 @@ JointReferential::JointReferential(uint32_t jointIndex, uint32_t modelID, ModelT void JointReferential::update() { const ModelItem* item = _tree->findModelByID(_modelID); const Model* model = getModel(item); - if (!_isValid || model == NULL || _jointIndex >= model->getJointStateCount()) { + if (model == NULL || _jointIndex >= model->getJointStateCount()) { qDebug() << "Not Valid"; _isValid = false; return; diff --git a/interface/src/avatar/ModelReferential.h b/interface/src/avatar/ModelReferential.h index 5b0c92c767..e87a09594d 100644 --- a/interface/src/avatar/ModelReferential.h +++ b/interface/src/avatar/ModelReferential.h @@ -19,11 +19,14 @@ class Model; class ModelReferential : public Referential { public: - ModelReferential(Referential* ref); + ModelReferential(Referential* ref, AvatarData* avatar); ModelReferential(uint32_t modelID, ModelTree* tree, AvatarData* avatar); virtual void update(); protected: + virtual int packExtraData(unsigned char* destinationBuffer); + virtual int unpackExtraData(const unsigned char* sourceBuffer); + uint32_t _modelID; ModelTree* _tree; }; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 92f0a82cd9..3428f73ee7 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -128,15 +128,18 @@ void MyAvatar::update(float deltaTime) { simulate(deltaTime); - - const ModelItem* item = Application::getInstance()->getModels()->getTree()->findModelByID(278); - if (_referential) { - PerformanceTimer perfTimer("Referential"); - _referential->update(); - } else if (item != NULL) { - const Model* model = Application::getInstance()->getModels()->getModelForModelItem(*item); - if (model != NULL) { - _referential = new ModelReferential(278, Application::getInstance()->getModels()->getTree(), this); + bool WANT_REFERENTIAL = true; + if (WANT_REFERENTIAL) { + int id = 12340; + const ModelItem* item = Application::getInstance()->getModels()->getTree()->findModelByID(id); + if (_referential) { + PerformanceTimer perfTimer("Referential"); + _referential->update(); + } else if (item != NULL) { + const Model* model = Application::getInstance()->getModels()->getModelForModelItem(*item); + if (model != NULL) { + _referential = new ModelReferential(id, Application::getInstance()->getModels()->getTree(), this); + } } } } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index ef2ad581e0..67977996b8 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -66,6 +66,13 @@ AvatarData::~AvatarData() { delete _referential; } +const glm::vec3& AvatarData::getPosition() { + if (_referential) { + _referential->update(); + } + return _position; +} + glm::vec3 AvatarData::getHandPosition() const { return getOrientation() * _handPosition + _position; } @@ -148,6 +155,7 @@ QByteArray AvatarData::toByteArray() { } *destinationBuffer++ = bitItems; + // Add referential if (_referential != NULL && _referential->isValid()) { destinationBuffer += _referential->packReferential(destinationBuffer); } @@ -381,21 +389,36 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { } // 1 + chatMessageSize bytes { // bitFlags and face data - unsigned char bitItems = 0; - bitItems = (unsigned char)*sourceBuffer++; - + unsigned char bitItems = *sourceBuffer++; + // key state, stored as a semi-nibble in the bitItems _keyState = (KeyState)getSemiNibbleAt(bitItems,KEY_STATE_START_BIT); - // hand state, stored as a semi-nibble in the bitItems _handState = getSemiNibbleAt(bitItems,HAND_STATE_START_BIT); _headData->_isFaceshiftConnected = oneAtBit(bitItems, IS_FACESHIFT_CONNECTED); _isChatCirclingEnabled = oneAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED); - bool hasReferential = oneAtBit(bitItems, HAS_REFERENTIAL); + + // Referential if (hasReferential) { - _referential = new Referential(sourceBuffer); + qDebug() << "Has referencial: " << hasReferential; + if (_referential == NULL) { + _referential = new Referential(sourceBuffer, this); + } else { + Referential* ref = new Referential(sourceBuffer, this); + if (ref->createdAt() > _referential->createdAt()) { + qDebug() << "Replacing referential"; + delete _referential; + _referential = ref; + } else { + delete ref; + } + } + } else if (_referential != NULL) { + qDebug() << "Erasing referencial"; + delete _referential; + _referential = NULL; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 5462750ed4..c32faba977 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -82,7 +82,7 @@ const int KEY_STATE_START_BIT = 0; // 1st and 2nd bits const int HAND_STATE_START_BIT = 2; // 3rd and 4th bits const int IS_FACESHIFT_CONNECTED = 4; // 5th bit const int IS_CHAT_CIRCLING_ENABLED = 5; // 6th bit -const int HAS_REFERENTIAL = 6; +const int HAS_REFERENTIAL = 6; // 7th bit static const float MAX_AVATAR_SCALE = 1000.f; static const float MIN_AVATAR_SCALE = .005f; @@ -143,7 +143,7 @@ public: const QUuid& getSessionUUID() { return _sessionUUID; } - const glm::vec3& getPosition() const { return _position; } + const glm::vec3& getPosition(); void setPosition(const glm::vec3 position) { _position = position; } glm::vec3 getHandPosition() const; diff --git a/libraries/avatars/src/Referential.cpp b/libraries/avatars/src/Referential.cpp index f38fb97d99..91c3050e2f 100644 --- a/libraries/avatars/src/Referential.cpp +++ b/libraries/avatars/src/Referential.cpp @@ -23,11 +23,12 @@ Referential::Referential(Type type, AvatarData* avatar) : _isValid = false; return; } + qDebug() << "[DEBUG] New Referential"; } -Referential::Referential(const unsigned char*& sourceBuffer) : +Referential::Referential(const unsigned char*& sourceBuffer, AvatarData* avatar) : _isValid(false), - _avatar(NULL) + _avatar(avatar) { sourceBuffer += unpack(sourceBuffer); } @@ -38,23 +39,24 @@ Referential::~Referential() { int Referential::packReferential(unsigned char* destinationBuffer) { const unsigned char* startPosition = destinationBuffer; destinationBuffer += pack(destinationBuffer); - destinationBuffer += packExtraData(destinationBuffer); + + unsigned char* sizePosition = destinationBuffer++; + char size = packExtraData(destinationBuffer); + *sizePosition = size; + destinationBuffer += size; + return destinationBuffer - startPosition; } int Referential::unpackReferential(const unsigned char* sourceBuffer) { const unsigned char* startPosition = sourceBuffer; sourceBuffer += unpack(sourceBuffer); - sourceBuffer += unpackExtraData(sourceBuffer); - return sourceBuffer - startPosition; -} - -int Referential::unpackExtraData(const unsigned char* sourceBuffer) { - const unsigned char* startPosition = sourceBuffer; - int size = *sourceBuffer++; - _extraDataBuffer.clear(); - _extraDataBuffer.setRawData(reinterpret_cast(sourceBuffer), size); - sourceBuffer += size; + + char expectedSize = *sourceBuffer++; + char bytesRead = unpackExtraData(sourceBuffer); + _isValid = (bytesRead == expectedSize); + sourceBuffer += expectedSize; + return sourceBuffer - startPosition; } @@ -77,8 +79,17 @@ int Referential::unpack(const unsigned char* sourceBuffer) { sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, _translation, 0); sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, _rotation); - sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*)sourceBuffer, &_scale, 0); + sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((const int16_t*) sourceBuffer, &_scale, 0); return sourceBuffer - startPosition; } +int Referential::unpackExtraData(const unsigned char* sourceBuffer) { + const unsigned char* startPosition = sourceBuffer; + int size = *sourceBuffer; + _extraDataBuffer.clear(); + _extraDataBuffer.setRawData(reinterpret_cast(sourceBuffer), size + 1); + sourceBuffer += size + 1; + return sourceBuffer - startPosition; +} + diff --git a/libraries/avatars/src/Referential.h b/libraries/avatars/src/Referential.h index 06ddf457e4..b7e3a248e8 100644 --- a/libraries/avatars/src/Referential.h +++ b/libraries/avatars/src/Referential.h @@ -25,12 +25,13 @@ public: AVATAR }; - Referential(const unsigned char*& sourceBuffer); + Referential(const unsigned char*& sourceBuffer, AvatarData* avatar); virtual ~Referential(); Type type() { return _type; } quint64 createdAt() { return _createdAt; } bool isValid() { return _isValid; } + bool hasExtraData() { return !_extraDataBuffer.isEmpty(); } virtual void update() {} int packReferential(unsigned char* destinationBuffer); @@ -39,10 +40,12 @@ public: protected: Referential(Type type, AvatarData* avatar); + // packs the base class data int pack(unsigned char* destinationBuffer); int unpack(const unsigned char* sourceBuffer); - int packExtraData(unsigned char* destinationBuffer) { return 0; } - int unpackExtraData(const unsigned char* sourceBuffer); + // virtual functions that pack fthe extra data of subclasses (needs to be reimplemented in subclass) + virtual int packExtraData(unsigned char* destinationBuffer) { return 0; } + virtual int unpackExtraData(const unsigned char* sourceBuffer); Type _type; quint64 _createdAt; diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 57d1d7faac..2b8b9929e5 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -167,7 +167,7 @@ bool oneAtBit(unsigned char byte, int bitIndex) { } void setAtBit(unsigned char& byte, int bitIndex) { - byte += (1 << (7 - bitIndex)); + byte |= (1 << (7 - bitIndex)); } void clearAtBit(unsigned char& byte, int bitIndex) { @@ -176,7 +176,7 @@ void clearAtBit(unsigned char& byte, int bitIndex) { } } -int getSemiNibbleAt(unsigned char& byte, int bitIndex) { +int getSemiNibbleAt(unsigned char byte, int bitIndex) { return (byte >> (6 - bitIndex) & 3); // semi-nibbles store 00, 01, 10, or 11 } @@ -207,7 +207,7 @@ bool isBetween(int64_t value, int64_t max, int64_t min) { void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) { //assert(value <= 3 && value >= 0); - byte += ((value & 3) << (6 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11 + byte |= ((value & 3) << (6 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11 } bool isInEnvironment(const char* environment) { @@ -496,7 +496,7 @@ int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int return sizeof(uint16_t); } -int unpackFloatScalarFromSignedTwoByteFixed(int16_t* byteFixedPointer, float* destinationPointer, int radix) { +int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, float* destinationPointer, int radix) { *destinationPointer = *byteFixedPointer / (float)(1 << radix); return sizeof(int16_t); } diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 6bb39f7e12..18494d48e4 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -82,7 +82,7 @@ int numberOfOnes(unsigned char byte); bool oneAtBit(unsigned char byte, int bitIndex); void setAtBit(unsigned char& byte, int bitIndex); void clearAtBit(unsigned char& byte, int bitIndex); -int getSemiNibbleAt(unsigned char& byte, int bitIndex); +int getSemiNibbleAt(unsigned char byte, int bitIndex); void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value); int getNthBit(unsigned char byte, int ordinal); /// determines the bit placement 0-7 of the ordinal set bit From 10c94023f199be7ee79a48b94a8fe3b3e1ea9615 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 4 Aug 2014 15:25:14 -0700 Subject: [PATCH 200/407] handle basic authentication for domain-server admin --- domain-server/src/DomainServer.cpp | 64 +++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 2ecae73d0a..a76d3a916d 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1280,6 +1280,9 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl const QByteArray HTTP_COOKIE_HEADER_KEY = "Cookie"; const QString ADMIN_USERS_CONFIG_KEY = "admin-users"; const QString ADMIN_ROLES_CONFIG_KEY = "admin-roles"; + const QString BASIC_AUTH_CONFIG_KEY = "basic-auth"; + + const QByteArray UNAUTHENTICATED_BODY = "You do not have permission to access this domain-server."; if (!_oauthProviderURL.isEmpty() && (_argumentVariantMap.contains(ADMIN_USERS_CONFIG_KEY) || _argumentVariantMap.contains(ADMIN_ROLES_CONFIG_KEY))) { @@ -1293,6 +1296,11 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl cookieUUID = cookieUUIDRegex.cap(1); } + if (_argumentVariantMap.contains(BASIC_AUTH_CONFIG_KEY)) { + qDebug() << "Config file contains web admin settings for OAuth and basic HTTP authentication." + << "These cannot be combined - using OAuth for authentication."; + } + if (!cookieUUID.isNull() && _cookieSessionHash.contains(cookieUUID)) { // pull the QJSONObject for the user with this cookie UUID DomainServerWebSessionData sessionData = _cookieSessionHash.value(cookieUUID); @@ -1315,8 +1323,7 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl } } - QString unauthenticatedRequest = "You do not have permission to access this domain-server."; - connection->respond(HTTPConnection::StatusCode401, unauthenticatedRequest.toUtf8()); + connection->respond(HTTPConnection::StatusCode401, UNAUTHENTICATED_BODY); // the user does not have allowed username or role, return 401 return false; @@ -1340,6 +1347,59 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl // we don't know about this user yet, so they are not yet authenticated return false; } + } else if (_argumentVariantMap.contains(BASIC_AUTH_CONFIG_KEY)) { + // config file contains username and password combinations for basic auth + const QByteArray BASIC_AUTH_HEADER_KEY = "Authorization"; + + // check if a username and password have been provided with the request + QString basicAuthString = connection->requestHeaders().value(BASIC_AUTH_HEADER_KEY); + + if (!basicAuthString.isEmpty()) { + QStringList splitAuthString = basicAuthString.split(' '); + QString base64String = splitAuthString.size() == 2 ? splitAuthString[1] : ""; + QString credentialString = QByteArray::fromBase64(base64String.toLocal8Bit()); + + if (!credentialString.isEmpty()) { + QStringList credentialList = credentialString.split(':'); + if (credentialList.size() == 2) { + QString username = credentialList[0]; + QString password = credentialList[1]; + + // we've pulled a username and password - now check if there is a match in our basic auth hash + QJsonObject basicAuthObject = _argumentVariantMap.value(BASIC_AUTH_CONFIG_KEY).toJsonValue().toObject(); + + if (basicAuthObject.contains(username)) { + const QString BASIC_AUTH_USER_PASSWORD_KEY = "password"; + QJsonObject userObject = basicAuthObject.value(username).toObject(); + + if (userObject.contains(BASIC_AUTH_USER_PASSWORD_KEY) + && userObject.value(BASIC_AUTH_USER_PASSWORD_KEY).toString() == password) { + // this is username / password match - let this user in + return true; + } + } + } + } + } + + // basic HTTP auth being used but no username and password are present + // or the username and password are not correct + // send back a 401 and ask for basic auth + + const QByteArray HTTP_AUTH_REQUEST_HEADER_KEY = "WWW-Authenticate"; + static QString HTTP_AUTH_REALM_STRING = QString("Basic realm='%1 %2'") + .arg(_hostname.isEmpty() ? "localhost" : _hostname) + .arg("domain-server"); + + Headers basicAuthHeader; + basicAuthHeader.insert(HTTP_AUTH_REQUEST_HEADER_KEY, HTTP_AUTH_REALM_STRING.toUtf8()); + + connection->respond(HTTPConnection::StatusCode401, UNAUTHENTICATED_BODY, + HTTPConnection::DefaultContentType, basicAuthHeader); + + // not authenticated, bubble up false + return false; + } else { // we don't have an OAuth URL + admin roles/usernames, so all users are authenticated return true; From c786ee5c2698304f977b6895a3fae4187f01db16 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 4 Aug 2014 15:27:34 -0700 Subject: [PATCH 201/407] dynamically change active link in domain-server navbar --- domain-server/resources/web/footer.html | 3 ++- domain-server/resources/web/header.html | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/domain-server/resources/web/footer.html b/domain-server/resources/web/footer.html index d1a3fc29e8..aa6821a3b9 100644 --- a/domain-server/resources/web/footer.html +++ b/domain-server/resources/web/footer.html @@ -1,3 +1,4 @@
- \ No newline at end of file + + \ No newline at end of file diff --git a/domain-server/resources/web/header.html b/domain-server/resources/web/header.html index e1a9d1ea8a..c007642724 100644 --- a/domain-server/resources/web/header.html +++ b/domain-server/resources/web/header.html @@ -25,7 +25,7 @@ From 6febca3533824d5a2639b7330c81a6721a140ce7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 4 Aug 2014 15:37:06 -0700 Subject: [PATCH 202/407] add missing domain-server javascript file --- domain-server/resources/web/js/domain-server.js | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 domain-server/resources/web/js/domain-server.js diff --git a/domain-server/resources/web/js/domain-server.js b/domain-server/resources/web/js/domain-server.js new file mode 100644 index 0000000000..3f78d8f466 --- /dev/null +++ b/domain-server/resources/web/js/domain-server.js @@ -0,0 +1,10 @@ +$(document).ready(function(){ + var url = window.location; + // Will only work if string in href matches with location + $('ul.nav a[href="'+ url +'"]').parent().addClass('active'); + + // Will also work for relative and absolute hrefs + $('ul.nav a').filter(function() { + return this.href == url; + }).parent().addClass('active'); +}); \ No newline at end of file From 9fc545001cb563a9a1dfc015c23797b912a26715 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 4 Aug 2014 15:40:45 -0700 Subject: [PATCH 203/407] look for a config.json file by default in resources --- libraries/shared/src/HifiConfigVariantMap.cpp | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/libraries/shared/src/HifiConfigVariantMap.cpp b/libraries/shared/src/HifiConfigVariantMap.cpp index 02cce80104..6fe39a8ccf 100644 --- a/libraries/shared/src/HifiConfigVariantMap.cpp +++ b/libraries/shared/src/HifiConfigVariantMap.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include #include @@ -68,29 +69,35 @@ QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringL int configIndex = argumentList.indexOf(CONFIG_FILE_OPTION); + QString configFilePath; + if (configIndex != -1) { // we have a config file - try and read it - QString configFilePath = argumentList[configIndex + 1]; - QFile configFile(configFilePath); - - if (configFile.exists()) { - qDebug() << "Reading JSON config file at" << configFilePath; - configFile.open(QIODevice::ReadOnly); - - QJsonDocument configDocument = QJsonDocument::fromJson(configFile.readAll()); - QJsonObject rootObject = configDocument.object(); - - // enumerate the keys of the configDocument object - foreach(const QString& key, rootObject.keys()) { - - if (!mergedMap.contains(key)) { - // no match in existing list, add it - mergedMap.insert(key, QVariant(rootObject[key])); - } + configFilePath = argumentList[configIndex + 1]; + } else { + // no config file - try to read a file at resources/config.json + configFilePath = QCoreApplication::applicationDirPath() + "/resources/config.json"; + } + + QFile configFile(configFilePath); + + if (configFile.exists()) { + qDebug() << "Reading JSON config file at" << configFilePath; + configFile.open(QIODevice::ReadOnly); + + QJsonDocument configDocument = QJsonDocument::fromJson(configFile.readAll()); + QJsonObject rootObject = configDocument.object(); + + // enumerate the keys of the configDocument object + foreach(const QString& key, rootObject.keys()) { + + if (!mergedMap.contains(key)) { + // no match in existing list, add it + mergedMap.insert(key, QVariant(rootObject[key])); } - } else { - qDebug() << "Could not find JSON config file at" << configFilePath; } + } else { + qDebug() << "Could not find JSON config file at" << configFilePath; } return mergedMap; From 4407ea448070e5e960838e3175d2b3e4521c5e0d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 4 Aug 2014 16:02:13 -0700 Subject: [PATCH 204/407] make assignment selector a dropdown --- domain-server/resources/web/header.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/domain-server/resources/web/header.html b/domain-server/resources/web/header.html index c007642724..f687590df2 100644 --- a/domain-server/resources/web/header.html +++ b/domain-server/resources/web/header.html @@ -26,7 +26,13 @@ From 4d7d6f1e25e59b11dfe21096148123279d578534 Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 4 Aug 2014 16:23:17 -0700 Subject: [PATCH 205/407] changed downstream re-sampling to occur right after parsing packet --- .../src/audio/AudioMixerClientData.cpp | 2 +- examples/bot_procedural.js | 674 ++++++++++++++++++ interface/src/Audio.cpp | 170 ++++- interface/src/Audio.h | 31 +- libraries/audio/src/InboundAudioStream.cpp | 84 ++- libraries/audio/src/InboundAudioStream.h | 14 +- libraries/audio/src/InjectedAudioStream.cpp | 4 - libraries/audio/src/InjectedAudioStream.h | 1 - libraries/audio/src/MixedAudioStream.cpp | 4 - libraries/audio/src/MixedAudioStream.h | 1 - libraries/audio/src/RawMixedAudioStream.cpp | 24 + libraries/audio/src/RawMixedAudioStream.h | 32 + 12 files changed, 993 insertions(+), 48 deletions(-) create mode 100644 examples/bot_procedural.js create mode 100644 libraries/audio/src/RawMixedAudioStream.cpp create mode 100644 libraries/audio/src/RawMixedAudioStream.h diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 54c723243c..fb805e11d8 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -104,7 +104,7 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend(AABox* checkSourceZone, A QHash::ConstIterator i; for (i = _audioStreams.constBegin(); i != _audioStreams.constEnd(); i++) { PositionalAudioStream* stream = i.value(); - if (stream->popFrames(1)) { + if (stream->popFrames(1, true) > 0) { // this is a ring buffer that is ready to go // calculate the trailing avg loudness for the next frame diff --git a/examples/bot_procedural.js b/examples/bot_procedural.js new file mode 100644 index 0000000000..265b887e0a --- /dev/null +++ b/examples/bot_procedural.js @@ -0,0 +1,674 @@ +// +// bot_procedural.js +// hifi +// +// Created by Ben Arnold on 7/29/2013 +// +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// +// This is an example script that demonstrates an NPC avatar. +// +// + +//For procedural walk animation +Script.include("http://s3-us-west-1.amazonaws.com/highfidelity-public/scripts/proceduralAnimationAPI.js"); + +var procAnimAPI = new ProcAnimAPI(); + +function getRandomFloat(min, max) { + return Math.random() * (max - min) + min; +} + +function getRandomInt (min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +function printVector(string, vector) { + print(string + " " + vector.x + ", " + vector.y + ", " + vector.z); +} + +var CHANCE_OF_MOVING = 0.005; +var CHANCE_OF_SOUND = 0.005; +var CHANCE_OF_HEAD_TURNING = 0.01; +var CHANCE_OF_BIG_MOVE = 1.0; + +var isMoving = false; +var isTurningHead = false; +var isPlayingAudio = false; + +var X_MIN = 0.50; +var X_MAX = 15.60; +var Z_MIN = 0.50; +var Z_MAX = 15.10; +var Y_FEET = 0.0; +var AVATAR_PELVIS_HEIGHT = 0.84; +var Y_PELVIS = Y_FEET + AVATAR_PELVIS_HEIGHT; +var MAX_PELVIS_DELTA = 2.5; + +var MOVE_RANGE_SMALL = 3.0; +var MOVE_RANGE_BIG = 10.0; +var TURN_RANGE = 70.0; +var STOP_TOLERANCE = 0.05; +var MOVE_RATE = 0.05; +var TURN_RATE = 0.2; +var HEAD_TURN_RATE = 0.05; +var PITCH_RANGE = 15.0; +var YAW_RANGE = 35.0; + +var firstPosition = { x: getRandomFloat(X_MIN, X_MAX), y: Y_PELVIS, z: getRandomFloat(Z_MIN, Z_MAX) }; +var targetPosition = { x: 0, y: 0, z: 0 }; +var targetOrientation = { x: 0, y: 0, z: 0, w: 0 }; +var currentOrientation = { x: 0, y: 0, z: 0, w: 0 }; +var targetHeadPitch = 0.0; +var targetHeadYaw = 0.0; + +var basePelvisHeight = 0.0; +var pelvisOscillatorPosition = 0.0; +var pelvisOscillatorVelocity = 0.0; + +function clamp(val, min, max){ + return Math.max(min, Math.min(max, val)) +} + +//Array of all valid bot numbers +var validBotNumbers = []; + +// right now we only use bot 63, since many other bots have messed up skeletons and LOD issues +var botNumber = 63;//getRandomInt(0, 99); + +var newFaceFilePrefix = "ron"; + +var newBodyFilePrefix = "bot" + botNumber; + +// set the face model fst using the bot number +// there is no need to change the body model - we're using the default +Avatar.faceModelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/" + newFaceFilePrefix + ".fst"; +Avatar.skeletonModelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/" + newBodyFilePrefix + "_a.fst"; +Avatar.billboardURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/billboards/bot" + botNumber + ".png"; + +Agent.isAvatar = true; +Agent.isListeningToAudioStream = true; + +// change the avatar's position to the random one +Avatar.position = firstPosition; +basePelvisHeight = firstPosition.y; +printVector("New dancer, position = ", Avatar.position); + +function loadSounds() { + var sound_filenames = ["AB1.raw", "Anchorman2.raw", "B1.raw", "B1.raw", "Bale1.raw", "Bandcamp.raw", + "Big1.raw", "Big2.raw", "Brian1.raw", "Buster1.raw", "CES1.raw", "CES2.raw", "CES3.raw", "CES4.raw", + "Carrie1.raw", "Carrie3.raw", "Charlotte1.raw", "EN1.raw", "EN2.raw", "EN3.raw", "Eugene1.raw", "Francesco1.raw", + "Italian1.raw", "Japanese1.raw", "Leigh1.raw", "Lucille1.raw", "Lucille2.raw", "MeanGirls.raw", "Murray2.raw", + "Nigel1.raw", "PennyLane.raw", "Pitt1.raw", "Ricardo.raw", "SN.raw", "Sake1.raw", "Samantha1.raw", "Samantha2.raw", + "Spicoli1.raw", "Supernatural.raw", "Swearengen1.raw", "TheDude.raw", "Tony.raw", "Triumph1.raw", "Uma1.raw", + "Walken1.raw", "Walken2.raw", "Z1.raw", "Z2.raw" + ]; + + var footstep_filenames = ["FootstepW2Left-12db.wav", "FootstepW2Right-12db.wav", "FootstepW3Left-12db.wav", "FootstepW3Right-12db.wav", + "FootstepW5Left-12db.wav", "FootstepW5Right-12db.wav"]; + + var SOUND_BASE_URL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Cocktail+Party+Snippets/Raws/"; + + var FOOTSTEP_BASE_URL = "http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Footsteps/"; + + for (var i = 0; i < sound_filenames.length; i++) { + sounds.push(new Sound(SOUND_BASE_URL + sound_filenames[i])); + } + + for (var i = 0; i < footstep_filenames.length; i++) { + footstepSounds.push(new Sound(FOOTSTEP_BASE_URL + footstep_filenames[i])); + } +} + +var sounds = []; +var footstepSounds = []; +loadSounds(); + + +function playRandomSound() { + if (!Agent.isPlayingAvatarSound) { + var whichSound = Math.floor((Math.random() * sounds.length)); + Agent.playAvatarSound(sounds[whichSound]); + } +} + +function playRandomFootstepSound() { + + var whichSound = Math.floor((Math.random() * footstepSounds.length)); + var options = new AudioInjectionOptions(); + options.position = Avatar.position; + options.volume = 1.0; + Audio.playSound(footstepSounds[whichSound], options); + +} + +// ************************************ Facial Animation ********************************** +var allBlendShapes = []; +var targetBlendCoefficient = []; +var currentBlendCoefficient = []; + +//Blendshape constructor +function addBlendshapeToPose(pose, shapeIndex, val) { + var index = pose.blendShapes.length; + pose.blendShapes[index] = {shapeIndex: shapeIndex, val: val }; +} +//The mood of the avatar, determines face. 0 = happy, 1 = angry, 2 = sad. + +//Randomly pick avatar mood. 80% happy, 10% mad 10% sad +var randMood = Math.floor(Math.random() * 11); +var avatarMood; +if (randMood == 0) { + avatarMood = 1; +} else if (randMood == 2) { + avatarMood = 2; +} else { + avatarMood = 0; +} + +var currentExpression = -1; +//Face pose constructor +var happyPoses = []; + +happyPoses[0] = {blendShapes: []}; +addBlendshapeToPose(happyPoses[0], 28, 0.7); //MouthSmile_L +addBlendshapeToPose(happyPoses[0], 29, 0.7); //MouthSmile_R + +happyPoses[1] = {blendShapes: []}; +addBlendshapeToPose(happyPoses[1], 28, 1.0); //MouthSmile_L +addBlendshapeToPose(happyPoses[1], 29, 1.0); //MouthSmile_R +addBlendshapeToPose(happyPoses[1], 21, 0.2); //JawOpen + +happyPoses[2] = {blendShapes: []}; +addBlendshapeToPose(happyPoses[2], 28, 1.0); //MouthSmile_L +addBlendshapeToPose(happyPoses[2], 29, 1.0); //MouthSmile_R +addBlendshapeToPose(happyPoses[2], 21, 0.5); //JawOpen +addBlendshapeToPose(happyPoses[2], 46, 1.0); //CheekSquint_L +addBlendshapeToPose(happyPoses[2], 47, 1.0); //CheekSquint_R +addBlendshapeToPose(happyPoses[2], 17, 1.0); //BrowsU_L +addBlendshapeToPose(happyPoses[2], 18, 1.0); //BrowsU_R + +var angryPoses = []; + +angryPoses[0] = {blendShapes: []}; +addBlendshapeToPose(angryPoses[0], 26, 0.6); //MouthFrown_L +addBlendshapeToPose(angryPoses[0], 27, 0.6); //MouthFrown_R +addBlendshapeToPose(angryPoses[0], 14, 0.6); //BrowsD_L +addBlendshapeToPose(angryPoses[0], 15, 0.6); //BrowsD_R + +angryPoses[1] = {blendShapes: []}; +addBlendshapeToPose(angryPoses[1], 26, 0.9); //MouthFrown_L +addBlendshapeToPose(angryPoses[1], 27, 0.9); //MouthFrown_R +addBlendshapeToPose(angryPoses[1], 14, 0.9); //BrowsD_L +addBlendshapeToPose(angryPoses[1], 15, 0.9); //BrowsD_R + +angryPoses[2] = {blendShapes: []}; +addBlendshapeToPose(angryPoses[2], 26, 1.0); //MouthFrown_L +addBlendshapeToPose(angryPoses[2], 27, 1.0); //MouthFrown_R +addBlendshapeToPose(angryPoses[2], 14, 1.0); //BrowsD_L +addBlendshapeToPose(angryPoses[2], 15, 1.0); //BrowsD_R +addBlendshapeToPose(angryPoses[2], 21, 0.5); //JawOpen +addBlendshapeToPose(angryPoses[2], 46, 1.0); //CheekSquint_L +addBlendshapeToPose(angryPoses[2], 47, 1.0); //CheekSquint_R + +var sadPoses = []; + +sadPoses[0] = {blendShapes: []}; +addBlendshapeToPose(sadPoses[0], 26, 0.6); //MouthFrown_L +addBlendshapeToPose(sadPoses[0], 27, 0.6); //MouthFrown_R +addBlendshapeToPose(sadPoses[0], 16, 0.2); //BrowsU_C +addBlendshapeToPose(sadPoses[0], 2, 0.6); //EyeSquint_L +addBlendshapeToPose(sadPoses[0], 3, 0.6); //EyeSquint_R + +sadPoses[1] = {blendShapes: []}; +addBlendshapeToPose(sadPoses[1], 26, 0.9); //MouthFrown_L +addBlendshapeToPose(sadPoses[1], 27, 0.9); //MouthFrown_R +addBlendshapeToPose(sadPoses[1], 16, 0.6); //BrowsU_C +addBlendshapeToPose(sadPoses[1], 2, 0.9); //EyeSquint_L +addBlendshapeToPose(sadPoses[1], 3, 0.9); //EyeSquint_R + +sadPoses[2] = {blendShapes: []}; +addBlendshapeToPose(sadPoses[2], 26, 1.0); //MouthFrown_L +addBlendshapeToPose(sadPoses[2], 27, 1.0); //MouthFrown_R +addBlendshapeToPose(sadPoses[2], 16, 0.1); //BrowsU_C +addBlendshapeToPose(sadPoses[2], 2, 1.0); //EyeSquint_L +addBlendshapeToPose(sadPoses[2], 3, 1.0); //EyeSquint_R +addBlendshapeToPose(sadPoses[2], 21, 0.3); //JawOpen + +var facePoses = []; +facePoses[0] = happyPoses; +facePoses[1] = angryPoses; +facePoses[2] = sadPoses; + + +function addBlendShape(s) { + allBlendShapes[allBlendShapes.length] = s; +} + +//It is imperative that the following blendshapes are all present and are in the correct order +addBlendShape("EyeBlink_L"); //0 +addBlendShape("EyeBlink_R"); //1 +addBlendShape("EyeSquint_L"); //2 +addBlendShape("EyeSquint_R"); //3 +addBlendShape("EyeDown_L"); //4 +addBlendShape("EyeDown_R"); //5 +addBlendShape("EyeIn_L"); //6 +addBlendShape("EyeIn_R"); //7 +addBlendShape("EyeOpen_L"); //8 +addBlendShape("EyeOpen_R"); //9 +addBlendShape("EyeOut_L"); //10 +addBlendShape("EyeOut_R"); //11 +addBlendShape("EyeUp_L"); //12 +addBlendShape("EyeUp_R"); //13 +addBlendShape("BrowsD_L"); //14 +addBlendShape("BrowsD_R"); //15 +addBlendShape("BrowsU_C"); //16 +addBlendShape("BrowsU_L"); //17 +addBlendShape("BrowsU_R"); //18 +addBlendShape("JawFwd"); //19 +addBlendShape("JawLeft"); //20 +addBlendShape("JawOpen"); //21 +addBlendShape("JawChew"); //22 +addBlendShape("JawRight"); //23 +addBlendShape("MouthLeft"); //24 +addBlendShape("MouthRight"); //25 +addBlendShape("MouthFrown_L"); //26 +addBlendShape("MouthFrown_R"); //27 +addBlendShape("MouthSmile_L"); //28 +addBlendShape("MouthSmile_R"); //29 +addBlendShape("MouthDimple_L"); //30 +addBlendShape("MouthDimple_R"); //31 +addBlendShape("LipsStretch_L"); //32 +addBlendShape("LipsStretch_R"); //33 +addBlendShape("LipsUpperClose"); //34 +addBlendShape("LipsLowerClose"); //35 +addBlendShape("LipsUpperUp"); //36 +addBlendShape("LipsLowerDown"); //37 +addBlendShape("LipsUpperOpen"); //38 +addBlendShape("LipsLowerOpen"); //39 +addBlendShape("LipsFunnel"); //40 +addBlendShape("LipsPucker"); //41 +addBlendShape("ChinLowerRaise"); //42 +addBlendShape("ChinUpperRaise"); //43 +addBlendShape("Sneer"); //44 +addBlendShape("Puff"); //45 +addBlendShape("CheekSquint_L"); //46 +addBlendShape("CheekSquint_R"); //47 + +for (var i = 0; i < allBlendShapes.length; i++) { + targetBlendCoefficient[i] = 0; + currentBlendCoefficient[i] = 0; +} + +function setRandomExpression() { + + //Clear all expression data for current expression + if (currentExpression != -1) { + var expression = facePoses[avatarMood][currentExpression]; + for (var i = 0; i < expression.blendShapes.length; i++) { + targetBlendCoefficient[expression.blendShapes[i].shapeIndex] = 0.0; + } + } + //Get a new current expression + currentExpression = Math.floor(Math.random() * facePoses[avatarMood].length); + var expression = facePoses[avatarMood][currentExpression]; + for (var i = 0; i < expression.blendShapes.length; i++) { + targetBlendCoefficient[expression.blendShapes[i].shapeIndex] = expression.blendShapes[i].val; + } +} + +var expressionChangeSpeed = 0.1; +function updateBlendShapes(deltaTime) { + + for (var i = 0; i < allBlendShapes.length; i++) { + currentBlendCoefficient[i] += (targetBlendCoefficient[i] - currentBlendCoefficient[i]) * expressionChangeSpeed; + Avatar.setBlendshape(allBlendShapes[i], currentBlendCoefficient[i]); + } +} + +var BLINK_SPEED = 0.15; +var CHANCE_TO_BLINK = 0.0025; +var MAX_BLINK = 0.85; +var blink = 0.0; +var isBlinking = false; +function updateBlinking(deltaTime) { + if (isBlinking == false) { + if (Math.random() < CHANCE_TO_BLINK) { + isBlinking = true; + } else { + blink -= BLINK_SPEED; + if (blink < 0.0) blink = 0.0; + } + } else { + blink += BLINK_SPEED; + if (blink > MAX_BLINK) { + blink = MAX_BLINK; + isBlinking = false; + } + } + + currentBlendCoefficient[0] = blink; + currentBlendCoefficient[1] = blink; + targetBlendCoefficient[0] = blink; + targetBlendCoefficient[1] = blink; +} + +// ************************************************************************************* + +//Procedural walk animation using two keyframes +//We use a separate array for front and back joints +//Pitch, yaw, and roll for the joints +var rightAngles = []; +var leftAngles = []; +//for non mirrored joints such as the spine +var middleAngles = []; + +//Actual joint mappings +var SHOULDER_JOINT_NUMBER = 15; +var ELBOW_JOINT_NUMBER = 16; +var JOINT_R_HIP = 1; +var JOINT_R_KNEE = 2; +var JOINT_L_HIP = 6; +var JOINT_L_KNEE = 7; +var JOINT_R_ARM = 15; +var JOINT_R_FOREARM = 16; +var JOINT_L_ARM = 39; +var JOINT_L_FOREARM = 40; +var JOINT_SPINE = 11; +var JOINT_R_FOOT = 3; +var JOINT_L_FOOT = 8; +var JOINT_R_TOE = 4; +var JOINT_L_TOE = 9; + +// ******************************* Animation Is Defined Below ************************************* + +var NUM_FRAMES = 2; +for (var i = 0; i < NUM_FRAMES; i++) { + rightAngles[i] = []; + leftAngles[i] = []; + middleAngles[i] = []; +} +//Joint order for actual joint mappings, should be interleaved R,L,R,L,...S,S,S for R = right, L = left, S = single +var JOINT_ORDER = []; +//*** right / left joints *** +var HIP = 0; +JOINT_ORDER.push(JOINT_R_HIP); +JOINT_ORDER.push(JOINT_L_HIP); +var KNEE = 1; +JOINT_ORDER.push(JOINT_R_KNEE); +JOINT_ORDER.push(JOINT_L_KNEE); +var ARM = 2; +JOINT_ORDER.push(JOINT_R_ARM); +JOINT_ORDER.push(JOINT_L_ARM); +var FOREARM = 3; +JOINT_ORDER.push(JOINT_R_FOREARM); +JOINT_ORDER.push(JOINT_L_FOREARM); +var FOOT = 4; +JOINT_ORDER.push(JOINT_R_FOOT); +JOINT_ORDER.push(JOINT_L_FOOT); +var TOE = 5; +JOINT_ORDER.push(JOINT_R_TOE); +JOINT_ORDER.push(JOINT_L_TOE); +//*** middle joints *** +var SPINE = 0; +JOINT_ORDER.push(JOINT_SPINE); + +//We have to store the angles so we can invert yaw and roll when making the animation +//symmetrical + +//Front refers to leg, not arm. +//Legs Extending +rightAngles[0][HIP] = [30.0, 0.0, 8.0]; +rightAngles[0][KNEE] = [-15.0, 0.0, 0.0]; +rightAngles[0][ARM] = [85.0, -25.0, 0.0]; +rightAngles[0][FOREARM] = [0.0, 0.0, -15.0]; +rightAngles[0][FOOT] = [0.0, 0.0, 0.0]; +rightAngles[0][TOE] = [0.0, 0.0, 0.0]; + +leftAngles[0][HIP] = [-15, 0.0, 8.0]; +leftAngles[0][KNEE] = [-26, 0.0, 0.0]; +leftAngles[0][ARM] = [85.0, 20.0, 0.0]; +leftAngles[0][FOREARM] = [10.0, 0.0, -25.0]; +leftAngles[0][FOOT] = [-13.0, 0.0, 0.0]; +leftAngles[0][TOE] = [34.0, 0.0, 0.0]; + +middleAngles[0][SPINE] = [0.0, -15.0, 5.0]; + +//Legs Passing +rightAngles[1][HIP] = [6.0, 0.0, 8.0]; +rightAngles[1][KNEE] = [-12.0, 0.0, 0.0]; +rightAngles[1][ARM] = [85.0, 0.0, 0.0]; +rightAngles[1][FOREARM] = [0.0, 0.0, -15.0]; +rightAngles[1][FOOT] = [6.0, -8.0, 0.0]; +rightAngles[1][TOE] = [0.0, 0.0, 0.0]; + +leftAngles[1][HIP] = [10.0, 0.0, 8.0]; +leftAngles[1][KNEE] = [-60.0, 0.0, 0.0]; +leftAngles[1][ARM] = [85.0, 0.0, 0.0]; +leftAngles[1][FOREARM] = [0.0, 0.0, -15.0]; +leftAngles[1][FOOT] = [0.0, 0.0, 0.0]; +leftAngles[1][TOE] = [0.0, 0.0, 0.0]; + +middleAngles[1][SPINE] = [0.0, 0.0, 0.0]; + +//Actual keyframes for the animation +var walkKeyFrames = procAnimAPI.generateKeyframes(rightAngles, leftAngles, middleAngles, NUM_FRAMES); + +// ******************************* Animation Is Defined Above ************************************* + +// ********************************** Standing Key Frame ****************************************** +//We don't have to do any mirroring or anything, since this is just a single pose. +var rightQuats = []; +var leftQuats = []; +var middleQuats = []; + +rightQuats[HIP] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 7.0); +rightQuats[KNEE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0); +rightQuats[ARM] = Quat.fromPitchYawRollDegrees(85.0, 0.0, 0.0); +rightQuats[FOREARM] = Quat.fromPitchYawRollDegrees(0.0, 0.0, -10.0); +rightQuats[FOOT] = Quat.fromPitchYawRollDegrees(0.0, -8.0, 0.0); +rightQuats[TOE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0); + +leftQuats[HIP] = Quat.fromPitchYawRollDegrees(0, 0.0, -7.0); +leftQuats[KNEE] = Quat.fromPitchYawRollDegrees(0, 0.0, 0.0); +leftQuats[ARM] = Quat.fromPitchYawRollDegrees(85.0, 0.0, 0.0); +leftQuats[FOREARM] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 10.0); +leftQuats[FOOT] = Quat.fromPitchYawRollDegrees(0.0, 8.0, 0.0); +leftQuats[TOE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0); + +middleQuats[SPINE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0); + +var standingKeyFrame = new procAnimAPI.KeyFrame(rightQuats, leftQuats, middleQuats); + +// ************************************************************************************************ + + +var currentFrame = 0; + +var walkTime = 0.0; + +var walkWheelRadius = 0.5; +var walkWheelRate = 2.0 * 3.141592 * walkWheelRadius / 8.0; + +var avatarAcceleration = 0.75; +var avatarVelocity = 0.0; +var avatarMaxVelocity = 1.4; + +function handleAnimation(deltaTime) { + + updateBlinking(deltaTime); + updateBlendShapes(deltaTime); + + if (Math.random() < 0.01) { + setRandomExpression(); + } + + if (avatarVelocity == 0.0) { + walkTime = 0.0; + currentFrame = 0; + } else { + walkTime += avatarVelocity * deltaTime; + if (walkTime > walkWheelRate) { + walkTime = 0.0; + currentFrame++; + if (currentFrame % 2 == 1) { + playRandomFootstepSound(); + } + if (currentFrame > 3) { + currentFrame = 0; + } + } + } + + var frame = walkKeyFrames[currentFrame]; + + var walkInterp = walkTime / walkWheelRate; + var animInterp = avatarVelocity / (avatarMaxVelocity / 1.3); + if (animInterp > 1.0) animInterp = 1.0; + + for (var i = 0; i < JOINT_ORDER.length; i++) { + var walkJoint = procAnimAPI.deCasteljau(frame.rotations[i], frame.nextFrame.rotations[i], frame.controlPoints[i][0], frame.controlPoints[i][1], walkInterp); + var standJoint = standingKeyFrame.rotations[i]; + var finalJoint = Quat.mix(standJoint, walkJoint, animInterp); + Avatar.setJointData(JOINT_ORDER[i], finalJoint); + } +} + +function jumpWithLoudness(deltaTime) { + // potentially change pelvis height depending on trailing average loudness + + pelvisOscillatorVelocity += deltaTime * Agent.lastReceivedAudioLoudness * 700.0 ; + + pelvisOscillatorVelocity -= pelvisOscillatorPosition * 0.75; + pelvisOscillatorVelocity *= 0.97; + pelvisOscillatorPosition += deltaTime * pelvisOscillatorVelocity; + Avatar.headPitch = pelvisOscillatorPosition * 60.0; + + var pelvisPosition = Avatar.position; + pelvisPosition.y = (Y_PELVIS - 0.35) + pelvisOscillatorPosition; + + if (pelvisPosition.y < Y_PELVIS) { + pelvisPosition.y = Y_PELVIS; + } else if (pelvisPosition.y > Y_PELVIS + 1.0) { + pelvisPosition.y = Y_PELVIS + 1.0; + } + + Avatar.position = pelvisPosition; +} + +var forcedMove = false; + +var wasMovingLastFrame = false; + +function handleHeadTurn() { + if (!isTurningHead && (Math.random() < CHANCE_OF_HEAD_TURNING)) { + targetHeadPitch = getRandomFloat(-PITCH_RANGE, PITCH_RANGE); + targetHeadYaw = getRandomFloat(-YAW_RANGE, YAW_RANGE); + isTurningHead = true; + } else { + Avatar.headPitch = Avatar.headPitch + (targetHeadPitch - Avatar.headPitch) * HEAD_TURN_RATE; + Avatar.headYaw = Avatar.headYaw + (targetHeadYaw - Avatar.headYaw) * HEAD_TURN_RATE; + if (Math.abs(Avatar.headPitch - targetHeadPitch) < STOP_TOLERANCE && + Math.abs(Avatar.headYaw - targetHeadYaw) < STOP_TOLERANCE) { + isTurningHead = false; + } + } +} + +function stopWalking() { + avatarVelocity = 0.0; + isMoving = false; +} + +var MAX_ATTEMPTS = 40; +function handleWalking(deltaTime) { + + if (forcedMove || (!isMoving && Math.random() < CHANCE_OF_MOVING)) { + // Set new target location + + var moveRange; + if (Math.random() < CHANCE_OF_BIG_MOVE) { + moveRange = MOVE_RANGE_BIG; + } else { + moveRange = MOVE_RANGE_SMALL; + } + + //Keep trying new orientations if the desired target location is out of bounds + var attempts = 0; + do { + targetOrientation = Quat.multiply(Avatar.orientation, Quat.angleAxis(getRandomFloat(-TURN_RANGE, TURN_RANGE), { x:0, y:1, z:0 })); + var front = Quat.getFront(targetOrientation); + + targetPosition = Vec3.sum(Avatar.position, Vec3.multiply(front, getRandomFloat(0.0, moveRange))); + } + while ((targetPosition.x < X_MIN || targetPosition.x > X_MAX || targetPosition.z < Z_MIN || targetPosition.z > Z_MAX) + && attempts < MAX_ATTEMPTS); + + targetPosition.x = clamp(targetPosition.x, X_MIN, X_MAX); + targetPosition.z = clamp(targetPosition.z, Z_MIN, Z_MAX); + targetPosition.y = Y_PELVIS; + + wasMovingLastFrame = true; + isMoving = true; + forcedMove = false; + } else if (isMoving) { + + var targetVector = Vec3.subtract(targetPosition, Avatar.position); + var distance = Vec3.length(targetVector); + if (distance <= avatarVelocity * deltaTime) { + Avatar.position = targetPosition; + stopWalking(); + } else { + var direction = Vec3.normalize(targetVector); + //Figure out if we should be slowing down + var t = avatarVelocity / avatarAcceleration; + var d = (avatarVelocity / 2.0) * t; + if (distance < d) { + avatarVelocity -= avatarAcceleration * deltaTime; + if (avatarVelocity <= 0) { + stopWalking(); + } + } else { + avatarVelocity += avatarAcceleration * deltaTime; + if (avatarVelocity > avatarMaxVelocity) avatarVelocity = avatarMaxVelocity; + } + Avatar.position = Vec3.sum(Avatar.position, Vec3.multiply(direction, avatarVelocity * deltaTime)); + Avatar.orientation = Quat.mix(Avatar.orientation, targetOrientation, TURN_RATE); + + wasMovingLastFrame = true; + + } + } +} + +function handleTalking() { + if (Math.random() < CHANCE_OF_SOUND) { + playRandomSound(); + } +} + +function changePelvisHeight(newHeight) { + var newPosition = Avatar.position; + newPosition.y = newHeight; + Avatar.position = newPosition; +} + +function updateBehavior(deltaTime) { + + if (AvatarList.containsAvatarWithDisplayName("mrdj")) { + if (wasMovingLastFrame) { + isMoving = false; + } + + // we have a DJ, shouldn't we be dancing? + jumpWithLoudness(deltaTime); + } else { + + // no DJ, let's just chill on the dancefloor - randomly walking and talking + handleHeadTurn(); + handleAnimation(deltaTime); + handleWalking(deltaTime); + handleTalking(); + } +} + +Script.update.connect(updateBehavior); \ No newline at end of file diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index c16424e69c..419a649b3b 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -64,7 +64,7 @@ Audio::Audio(QObject* parent) : _audioOutput(NULL), _desiredOutputFormat(), _outputFormat(), - _outputDevice(NULL), + //_outputDevice(NULL), _numOutputCallbackBytes(0), _loopbackAudioOutput(NULL), _loopbackOutputDevice(NULL), @@ -76,7 +76,7 @@ Audio::Audio(QObject* parent) : // slower than real time (or at least the desired sample rate). If you increase the size of the ring buffer, then it // this delay will slowly add up and the longer someone runs, they more delayed their audio will be. _inputRingBuffer(0), - _receivedAudioStream(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, 100, true, 0, 0, true), + _receivedAudioStream(0, 100, true, 0, 0, true), _isStereoInput(false), _averagedLatency(0.0), _lastInputLoudness(0), @@ -115,8 +115,8 @@ Audio::Audio(QObject* parent) : _inputRingBufferMsecsAvailableStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS), _audioOutputMsecsUnplayedStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS), _lastSentAudioPacket(0), - _packetSentTimeGaps(1, APPROXIMATELY_30_SECONDS_OF_AUDIO_PACKETS) - + _packetSentTimeGaps(1, APPROXIMATELY_30_SECONDS_OF_AUDIO_PACKETS), + _audioOutputIODevice(*this) { // clear the array of locally injected samples memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); @@ -128,6 +128,8 @@ void Audio::init(QGLWidget *parent) { _micTextureId = parent->bindTexture(QImage(Application::resourcesPath() + "images/mic.svg")); _muteTextureId = parent->bindTexture(QImage(Application::resourcesPath() + "images/mic-mute.svg")); _boxTextureId = parent->bindTexture(QImage(Application::resourcesPath() + "images/audio-box.svg")); + + connect(&_receivedAudioStream, &RawMixedAudioStream::processSamples, this, &Audio::receivedAudioStreamProcessSamples, Qt::DirectConnection); } void Audio::reset() { @@ -724,12 +726,90 @@ void Audio::handleAudioInput() { delete[] inputAudioSamples; } - if (_receivedAudioStream.getPacketsReceived() > 0) { + /*if (_receivedAudioStream.getPacketsReceived() > 0) { pushAudioToOutput(); + }*/ +} + +void Audio::receivedAudioStreamProcessSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer) { + + printf("receivedAudioStreamProcessSamples()\n"); + + static const int numNetworkOutputSamples = NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; + static const int numDeviceOutputSamples = numNetworkOutputSamples * (_outputFormat.sampleRate() * _outputFormat.channelCount()) + / (_desiredOutputFormat.sampleRate() * _desiredOutputFormat.channelCount()); + + + outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); + + int16_t* receivedSamples = new int16_t[numNetworkOutputSamples]; + if (_processSpatialAudio) { + unsigned int sampleTime = _spatialAudioStart; + QByteArray buffer = inputBuffer.left(numNetworkOutputSamples * sizeof(int16_t)); + + // Accumulate direct transmission of audio from sender to receiver + if (Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingIncludeOriginal)) { + emit preProcessOriginalInboundAudio(sampleTime, buffer, _desiredOutputFormat); + addSpatialAudioToBuffer(sampleTime, buffer, numNetworkOutputSamples); + } + + // Send audio off for spatial processing + emit processInboundAudio(sampleTime, buffer, _desiredOutputFormat); + + // copy the samples we'll resample from the spatial audio ring buffer - this also + // pushes the read pointer of the spatial audio ring buffer forwards + _spatialAudioRingBuffer.readSamples(receivedSamples, numNetworkOutputSamples); + + // Advance the start point for the next packet of audio to arrive + _spatialAudioStart += numNetworkOutputSamples / _desiredOutputFormat.channelCount(); + } else { + // copy the samples we'll resample from the ring buffer - this also + // pushes the read pointer of the ring buffer forwards + //receivedAudioStreamPopOutput.readSamples(receivedSamples, numNetworkOutputSamples); + + memcpy(receivedSamples, inputBuffer.data(), numNetworkOutputSamples * sizeof(int16_t)); } + + // copy the packet from the RB to the output + linearResampling(receivedSamples, + (int16_t*)outputBuffer.data(), + numNetworkOutputSamples, + numDeviceOutputSamples, + _desiredOutputFormat, _outputFormat); + + /*if (_outputDevice) { + _outputDevice->write(outputBuffer); + }*/ + printf("\t outputBuffer now size %d\n", outputBuffer.size()); + + if (_scopeEnabled && !_scopeEnabledPause) { + unsigned int numAudioChannels = _desiredOutputFormat.channelCount(); + int16_t* samples = receivedSamples; + for (int numSamples = numNetworkOutputSamples / numAudioChannels; numSamples > 0; numSamples -= NETWORK_SAMPLES_PER_FRAME) { + + unsigned int audioChannel = 0; + addBufferToScope( + _scopeOutputLeft, + _scopeOutputOffset, + samples, audioChannel, numAudioChannels); + + audioChannel = 1; + addBufferToScope( + _scopeOutputRight, + _scopeOutputOffset, + samples, audioChannel, numAudioChannels); + + _scopeOutputOffset += NETWORK_SAMPLES_PER_FRAME; + _scopeOutputOffset %= _samplesPerScope; + samples += NETWORK_SAMPLES_PER_FRAME * numAudioChannels; + } + } + + delete[] receivedSamples; } void Audio::addReceivedAudioToStream(const QByteArray& audioByteArray) { + if (_audioOutput) { // Audio output must exist and be correctly set up if we're going to process received audio processReceivedAudio(audioByteArray); @@ -738,6 +818,9 @@ void Audio::addReceivedAudioToStream(const QByteArray& audioByteArray) { Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AUDIO).updateValue(audioByteArray.size()); } + + + void Audio::parseAudioStreamStatsPacket(const QByteArray& packet) { int numBytesPacketHeader = numBytesForPacketHeader(packet); @@ -917,7 +1000,7 @@ void Audio::processReceivedAudio(const QByteArray& audioByteArray) { void Audio::pushAudioToOutput() { - if (_audioOutput->bytesFree() == _audioOutput->bufferSize()) { + /*if (_audioOutput->bytesFree() == _audioOutput->bufferSize()) { // the audio output has no samples to play. set the downstream audio to starved so that it // refills to its desired size before pushing frames _receivedAudioStream.setToStarved(); @@ -1011,7 +1094,7 @@ void Audio::pushAudioToOutput() { } delete[] receivedSamples; - } + }*/ } void Audio::processProceduralAudio(int16_t* monoInput, int numSamples) { @@ -1631,6 +1714,11 @@ void Audio::renderLineStrip(const float* color, int x, int y, int n, int offset, } +void Audio::outputFormatChanged() { + int deviceOutputFrameSize = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * _outputFormat.channelCount() * _outputFormat.sampleRate() / _desiredOutputFormat.sampleRate(); + _receivedAudioStream.resizeFrame(deviceOutputFrameSize); +} + bool Audio::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo) { bool supportedFormat = false; @@ -1681,7 +1769,7 @@ bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo) // cleanup any previously initialized device if (_audioOutput) { _audioOutput->stop(); - _outputDevice = NULL; + //_outputDevice = NULL; delete _audioOutput; _audioOutput = NULL; @@ -1703,13 +1791,21 @@ bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo) if (adjustedFormatForAudioDevice(outputDeviceInfo, _desiredOutputFormat, _outputFormat)) { qDebug() << "The format to be used for audio output is" << _outputFormat; - const int AUDIO_OUTPUT_BUFFER_SIZE_FRAMES = 10; + outputFormatChanged(); + + const int AUDIO_OUTPUT_BUFFER_SIZE_FRAMES = 3; // setup our general output device for audio-mixer audio _audioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this); _audioOutput->setBufferSize(AUDIO_OUTPUT_BUFFER_SIZE_FRAMES * _outputFormat.bytesForDuration(BUFFER_SEND_INTERVAL_USECS)); - qDebug() << "Ring Buffer capacity in frames: " << AUDIO_OUTPUT_BUFFER_SIZE_FRAMES; - _outputDevice = _audioOutput->start(); + + printf("\n\n"); + qDebug() << "Ring Buffer capacity in frames: " << (float)_outputFormat.durationForBytes(_audioOutput->bufferSize()) / (float)BUFFER_SEND_INTERVAL_USECS; + printf("\n\n"); + //_outputDevice = _audioOutput->start(); + + _audioOutputIODevice.start(); + _audioOutput->start(&_audioOutputIODevice); // setup a loopback audio output device _loopbackAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this); @@ -1779,3 +1875,55 @@ float Audio::getInputRingBufferMsecsAvailable() const { float msecsInInputRingBuffer = bytesInInputRingBuffer / (float)(_inputFormat.bytesForDuration(USECS_PER_MSEC)); return msecsInInputRingBuffer; } + +qint64 Audio::AudioOutputIODevice::readData(char * data, qint64 maxSize) { + printf("readData() request %d bytes\n", maxSize); + /* + float framesRequested = (float)_parent._outputFormat.durationForBytes(maxSize) / (float)BUFFER_SEND_INTERVAL_USECS; + + if (framesRequested > 67.0f) { + maxSize /= 2; + } + + + quint64 now = usecTimestampNow(); + printf("%llu\n", now - _lastReadTime); + _lastReadTime = now; + + int16_t* buffer; + + + + buffer = (int16_t*)data; + + for (int i = 0; i < maxSize / 2; i++) { + *(buffer++) = (int16_t)randIntInRange(0, 10000); + } + + + return 2 * (maxSize / 2); + */ + + int samplesRequested = maxSize / sizeof(int16_t); + + printf("requesting %d samples\n", samplesRequested); + + int samplesPopped; + int bytesWritten; + if ((samplesPopped = _parent._receivedAudioStream.popSamples(samplesRequested, false, false)) > 0) { + printf("\t pop succeeded: %d samples\n", samplesPopped); + + AudioRingBuffer::ConstIterator lastPopOutput = _parent._receivedAudioStream.getLastPopOutput(); + lastPopOutput.readSamples((int16_t*)data, samplesPopped); + + bytesWritten = samplesPopped * sizeof(int16_t); + } else { + printf("\t pop failed\n"); + memset(data, 0, maxSize); + bytesWritten = maxSize; + } + printf("\t wrote %d bytes\n", bytesWritten); + + return bytesWritten; +} + diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 9dad3b82d7..f35912deb1 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -33,7 +33,7 @@ #include #include -#include "MixedAudioStream.h" +#include "RawMixedAudioStream.h" static const int NUM_AUDIO_CHANNELS = 2; @@ -45,6 +45,23 @@ class QIODevice; class Audio : public AbstractAudioInterface { Q_OBJECT public: + + class AudioOutputIODevice : public QIODevice { + public: + AudioOutputIODevice(Audio& parent) : _parent(parent) {}; + + void start() { open(QIODevice::ReadOnly); } + void stop() { close(); } + + qint64 readData(char * data, qint64 maxSize); + qint64 writeData(const char * data, qint64 maxSize) { return 0; } + + private: + Audio& _parent; + quint64 _lastReadTime; + }; + + // setup for audio I/O Audio(QObject* parent = 0); @@ -94,6 +111,7 @@ public slots: void addReceivedAudioToStream(const QByteArray& audioByteArray); void parseAudioStreamStatsPacket(const QByteArray& packet); void addSpatialAudioToBuffer(unsigned int sampleTime, const QByteArray& spatialAudio, unsigned int numSamples); + void receivedAudioStreamProcessSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer); void handleAudioInput(); void reset(); void resetStats(); @@ -133,7 +151,10 @@ signals: void preProcessOriginalInboundAudio(unsigned int sampleTime, QByteArray& samples, const QAudioFormat& format); void processInboundAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format); void processLocalAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format); - + +private: + void outputFormatChanged(); + private: QByteArray firstInputFrame; @@ -146,14 +167,14 @@ private: QAudioOutput* _audioOutput; QAudioFormat _desiredOutputFormat; QAudioFormat _outputFormat; - QIODevice* _outputDevice; + //QIODevice* _outputDevice; int _numOutputCallbackBytes; QAudioOutput* _loopbackAudioOutput; QIODevice* _loopbackOutputDevice; QAudioOutput* _proceduralAudioOutput; QIODevice* _proceduralOutputDevice; AudioRingBuffer _inputRingBuffer; - MixedAudioStream _receivedAudioStream; + RawMixedAudioStream _receivedAudioStream; bool _isStereoInput; QString _inputAudioDeviceName; @@ -282,6 +303,8 @@ private: quint64 _lastSentAudioPacket; MovingMinMaxAvg _packetSentTimeGaps; + + AudioOutputIODevice _audioOutputIODevice; }; diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 36145a35f6..bc563d649e 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -70,7 +70,12 @@ void InboundAudioStream::clearBuffer() { _currentJitterBufferFrames = 0; } +int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) { + return _ringBuffer.writeData(packetAfterStreamProperties.data(), numAudioSamples * sizeof(int16_t)); +} + int InboundAudioStream::parseData(const QByteArray& packet) { + PacketType packetType = packetTypeForPacket(packet); QUuid senderUUID = uuidFromPacketHeader(packet); @@ -82,7 +87,10 @@ int InboundAudioStream::parseData(const QByteArray& packet) { // parse sequence number and track it quint16 sequence = *(reinterpret_cast(sequenceAt)); readBytes += sizeof(quint16); - SequenceNumberStats::ArrivalInfo arrivalInfo = frameReceivedUpdateNetworkStats(sequence, senderUUID); + SequenceNumberStats::ArrivalInfo arrivalInfo = _incomingSequenceNumberStats.sequenceNumberReceived(sequence, senderUUID); + + frameReceivedUpdateTimingStats(); + // TODO: handle generalized silent packet here????? @@ -130,32 +138,78 @@ int InboundAudioStream::parseData(const QByteArray& packet) { return readBytes; } -bool InboundAudioStream::popFrames(int numFrames, bool starveOnFail) { - int numSamplesRequested = numFrames * _ringBuffer.getNumFrameSamples(); +int InboundAudioStream::popSamples(int maxSamples, bool allOrNothing, bool starveOnFail) { + int samplesPopped = 0; + int samplesAvailable = _ringBuffer.samplesAvailable(); if (_isStarved) { // we're still refilling; don't pop _consecutiveNotMixedCount++; _lastPopSucceeded = false; } else { - if (_ringBuffer.samplesAvailable() >= numSamplesRequested) { + if (samplesAvailable >= maxSamples) { // we have enough samples to pop, so we're good to mix - _lastPopOutput = _ringBuffer.nextOutput(); - _ringBuffer.shiftReadPosition(numSamplesRequested); - framesAvailableChanged(); + popSamplesNoCheck(maxSamples); + samplesPopped = maxSamples; - _hasStarted = true; - _lastPopSucceeded = true; } else { - // we don't have enough samples, so set this stream to starve + // we don't have enough frames, so set this stream to starve // if starveOnFail is true if (starveOnFail) { starved(); _consecutiveNotMixedCount++; } - _lastPopSucceeded = false; + + if (!allOrNothing && samplesAvailable > 0) { + popSamplesNoCheck(samplesAvailable); + samplesPopped = samplesAvailable; + } else { + _lastPopSucceeded = false; + } } } - return _lastPopSucceeded; + return samplesPopped; +} + + +int InboundAudioStream::popFrames(int maxFrames, bool allOrNothing, bool starveOnFail) { + int framesPopped = 0; + int framesAvailable = _ringBuffer.framesAvailable(); + if (_isStarved) { + // we're still refilling; don't pop + _consecutiveNotMixedCount++; + _lastPopSucceeded = false; + } else { + if (framesAvailable >= maxFrames) { + // we have enough samples to pop, so we're good to mix + popSamplesNoCheck(maxFrames * _ringBuffer.getNumFrameSamples()); + framesPopped = maxFrames; + + } else { + // we don't have enough frames, so set this stream to starve + // if starveOnFail is true + if (starveOnFail) { + starved(); + _consecutiveNotMixedCount++; + } + + if (!allOrNothing && framesAvailable > 0) { + popSamplesNoCheck(framesAvailable * _ringBuffer.getNumFrameSamples()); + framesPopped = framesAvailable; + } else { + _lastPopSucceeded = false; + } + } + } + return framesPopped; +} + +void InboundAudioStream::popSamplesNoCheck(int samples) { + _lastPopOutput = _ringBuffer.nextOutput(); + _ringBuffer.shiftReadPosition(samples); + framesAvailableChanged(); + + _hasStarted = true; + _lastPopSucceeded = true; } void InboundAudioStream::framesAvailableChanged() { @@ -204,9 +258,7 @@ int InboundAudioStream::clampDesiredJitterBufferFramesValue(int desired) const { return glm::clamp(desired, MIN_FRAMES_DESIRED, MAX_FRAMES_DESIRED); } -SequenceNumberStats::ArrivalInfo InboundAudioStream::frameReceivedUpdateNetworkStats(quint16 sequenceNumber, const QUuid& senderUUID) { - // track the sequence number we received - SequenceNumberStats::ArrivalInfo arrivalInfo = _incomingSequenceNumberStats.sequenceNumberReceived(sequenceNumber, senderUUID); +void InboundAudioStream::frameReceivedUpdateTimingStats() { // update our timegap stats and desired jitter buffer frames if necessary // discard the first few packets we receive since they usually have gaps that aren't represensative of normal jitter @@ -243,8 +295,6 @@ SequenceNumberStats::ArrivalInfo InboundAudioStream::frameReceivedUpdateNetworkS } } _lastFrameReceivedTime = now; - - return arrivalInfo; } int InboundAudioStream::writeDroppableSilentSamples(int numSilentSamples) { diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index 1a196a1c61..c44edf65cc 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -63,8 +63,8 @@ public: virtual int parseData(const QByteArray& packet); - - bool popFrames(int numFrames, bool starveOnFail = true); + int popFrames(int maxFrames, bool allOrNothing, bool starveOnFail = true); + int popSamples(int maxSamples, bool allOrNothing, bool starveOnFail = true); bool lastPopSucceeded() const { return _lastPopSucceeded; }; const AudioRingBuffer::ConstIterator& getLastPopOutput() const { return _lastPopOutput; } @@ -81,6 +81,8 @@ public: void setMaxFramesOverDesired(int maxFramesOverDesired) { _maxFramesOverDesired = maxFramesOverDesired; } + void resizeFrame(int numFrameSamples) { _ringBuffer.resizeForFrameSize(numFrameSamples); } + virtual AudioStreamStats getAudioStreamStats() const; /// returns the desired number of jitter buffer frames under the dyanmic jitter buffers scheme @@ -113,11 +115,12 @@ public: private: void starved(); - SequenceNumberStats::ArrivalInfo frameReceivedUpdateNetworkStats(quint16 sequenceNumber, const QUuid& senderUUID); + void frameReceivedUpdateTimingStats(); int clampDesiredJitterBufferFramesValue(int desired) const; int writeSamplesForDroppedPackets(int numSamples); + void popSamplesNoCheck(int samples); void framesAvailableChanged(); protected: @@ -129,8 +132,9 @@ protected: /// how many audio samples this packet contains virtual int parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) = 0; - /// parses the audio data in the network packet - virtual int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) = 0; + /// parses the audio data in the network packet. + /// default implementation assumes packet contains raw audio samples after stream properties + virtual int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples); int writeDroppableSilentSamples(int numSilentSamples); diff --git a/libraries/audio/src/InjectedAudioStream.cpp b/libraries/audio/src/InjectedAudioStream.cpp index 37190abc73..5c1c2ed269 100644 --- a/libraries/audio/src/InjectedAudioStream.cpp +++ b/libraries/audio/src/InjectedAudioStream.cpp @@ -58,10 +58,6 @@ int InjectedAudioStream::parseStreamProperties(PacketType type, const QByteArray return packetStream.device()->pos(); } -int InjectedAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) { - return _ringBuffer.writeData(packetAfterStreamProperties.data(), numAudioSamples * sizeof(int16_t)); -} - AudioStreamStats InjectedAudioStream::getAudioStreamStats() const { AudioStreamStats streamStats = PositionalAudioStream::getAudioStreamStats(); streamStats._streamIdentifier = _streamIdentifier; diff --git a/libraries/audio/src/InjectedAudioStream.h b/libraries/audio/src/InjectedAudioStream.h index 3cbfad9276..d8d9a54c6e 100644 --- a/libraries/audio/src/InjectedAudioStream.h +++ b/libraries/audio/src/InjectedAudioStream.h @@ -32,7 +32,6 @@ private: AudioStreamStats getAudioStreamStats() const; int parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples); - int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples); const QUuid _streamIdentifier; float _radius; diff --git a/libraries/audio/src/MixedAudioStream.cpp b/libraries/audio/src/MixedAudioStream.cpp index b9e2abfe0b..821cf1e428 100644 --- a/libraries/audio/src/MixedAudioStream.cpp +++ b/libraries/audio/src/MixedAudioStream.cpp @@ -11,7 +11,3 @@ int MixedAudioStream::parseStreamProperties(PacketType type, const QByteArray& p numAudioSamples = packetAfterSeqNum.size() / sizeof(int16_t); return 0; } - -int MixedAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) { - return _ringBuffer.writeData(packetAfterStreamProperties.data(), numAudioSamples * sizeof(int16_t)); -} diff --git a/libraries/audio/src/MixedAudioStream.h b/libraries/audio/src/MixedAudioStream.h index 5b79519ac5..cfb8f9d380 100644 --- a/libraries/audio/src/MixedAudioStream.h +++ b/libraries/audio/src/MixedAudioStream.h @@ -23,7 +23,6 @@ public: protected: int parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples); - int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples); }; #endif // hifi_MixedAudioStream_h diff --git a/libraries/audio/src/RawMixedAudioStream.cpp b/libraries/audio/src/RawMixedAudioStream.cpp new file mode 100644 index 0000000000..3b78f2b2de --- /dev/null +++ b/libraries/audio/src/RawMixedAudioStream.cpp @@ -0,0 +1,24 @@ + +#include "RawMixedAudioStream.h" + +RawMixedAudioStream ::RawMixedAudioStream (int numFrameSamples, int numFramesCapacity, bool dynamicJitterBuffers, int staticDesiredJitterBufferFrames, int maxFramesOverDesired, bool useStDevForJitterCalc) + : InboundAudioStream(numFrameSamples, numFramesCapacity, dynamicJitterBuffers, staticDesiredJitterBufferFrames, maxFramesOverDesired, useStDevForJitterCalc) +{ +} + +int RawMixedAudioStream ::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { + // mixed audio packets do not have any info between the seq num and the audio data. + numAudioSamples = packetAfterSeqNum.size() / sizeof(int16_t); + return 0; +} + +int RawMixedAudioStream ::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) { + + QByteArray outputBuffer; + emit processSamples(packetAfterStreamProperties, outputBuffer); + + int bytesWritten = _ringBuffer.writeData(outputBuffer.data(), outputBuffer.size()); + printf("wrote %d samples to ringbuffer\n", bytesWritten / 2); + + return packetAfterStreamProperties.size(); +} diff --git a/libraries/audio/src/RawMixedAudioStream.h b/libraries/audio/src/RawMixedAudioStream.h new file mode 100644 index 0000000000..2db922d489 --- /dev/null +++ b/libraries/audio/src/RawMixedAudioStream.h @@ -0,0 +1,32 @@ +// +// RawMixedAudioStream.h +// libraries/audio/src +// +// Created by Stephen Birarda on 6/5/13. +// Copyright 2013 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 +// + +#ifndef hifi_RawMixedAudioStream_h +#define hifi_RawMixedAudioStream_h + +#include "InboundAudioStream.h" +#include "PacketHeaders.h" + +class RawMixedAudioStream : public InboundAudioStream { + Q_OBJECT +public: + RawMixedAudioStream (int numFrameSamples, int numFramesCapacity, bool dynamicJitterBuffers, int staticDesiredJitterBufferFrames, int maxFramesOverDesired, bool useStDevForJitterCalc); + +signals: + + void processSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer); + +protected: + int parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples); + int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples); +}; + +#endif // hifi_RawMixedAudioStream_h From 4f0218090c564e7d61867c481f46146634eaa5a1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 4 Aug 2014 16:23:26 -0700 Subject: [PATCH 206/407] have the domain-server brand in navbar link back to home --- domain-server/resources/web/header.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/web/header.html b/domain-server/resources/web/header.html index f687590df2..a2aebc1189 100644 --- a/domain-server/resources/web/header.html +++ b/domain-server/resources/web/header.html @@ -18,7 +18,7 @@ - domain-server + domain-server From f8afdba92216fe46080f2c4b72ec5d37e7d023a5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 4 Aug 2014 16:56:30 -0700 Subject: [PATCH 207/407] Allow configurable block sizes, merging children with different resolutions. --- interface/src/ui/MetavoxelEditor.cpp | 32 +++++--- interface/src/ui/MetavoxelEditor.h | 5 +- .../metavoxels/src/AttributeRegistry.cpp | 79 ++++++++++++++----- 3 files changed, 81 insertions(+), 35 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index cf4fd0bba9..096798e77e 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -930,6 +930,13 @@ void HeightfieldTool::render() { ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) : HeightfieldTool(editor, "Import Heightfield") { + _form->addRow("Block Size:", _blockSize = new QSpinBox()); + _blockSize->setPrefix("2^"); + _blockSize->setMinimum(1); + _blockSize->setValue(5); + + connect(_blockSize, static_cast(&QSpinBox::valueChanged), this, + &ImportHeightfieldTool::updatePreview); _form->addRow("Height:", _height = new QPushButton()); connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile); _form->addRow("Color:", _color = new QPushButton()); @@ -989,23 +996,22 @@ void ImportHeightfieldTool::selectColorFile() { updatePreview(); } -const int BLOCK_SIZE = 32; -const int BLOCK_ADVANCEMENT = BLOCK_SIZE - 1; - void ImportHeightfieldTool::updatePreview() { QVector buffers; if (_heightImage.width() > 0 && _heightImage.height() > 0) { float z = 0.0f; - for (int i = 0; i < _heightImage.height(); i += BLOCK_ADVANCEMENT, z++) { + int blockSize = pow(2.0, _blockSize->value()); + int blockAdvancement = blockSize - 1; + for (int i = 0; i < _heightImage.height(); i += blockAdvancement, z++) { float x = 0.0f; - for (int j = 0; j < _heightImage.width(); j += BLOCK_ADVANCEMENT, x++) { - QByteArray height(BLOCK_SIZE * BLOCK_SIZE, 0); - int rows = qMin(BLOCK_SIZE, _heightImage.height() - i); - int columns = qMin(BLOCK_SIZE, _heightImage.width() - j); + for (int j = 0; j < _heightImage.width(); j += blockAdvancement, x++) { + QByteArray height(blockSize * blockSize, 0); + int rows = qMin(blockSize, _heightImage.height() - i); + int columns = qMin(blockSize, _heightImage.width() - j); const int BYTES_PER_COLOR = 3; for (int y = 0; y < rows; y++) { uchar* src = _heightImage.scanLine(i + y) + j * BYTES_PER_COLOR; - char* dest = height.data() + y * BLOCK_SIZE; + char* dest = height.data() + y * blockSize; for (int x = 0; x < columns; x++) { *dest++ = *src; src += BYTES_PER_COLOR; @@ -1014,11 +1020,11 @@ void ImportHeightfieldTool::updatePreview() { QByteArray color; if (!_colorImage.isNull()) { - color = QByteArray(BLOCK_SIZE * BLOCK_SIZE * BYTES_PER_COLOR, 0); - rows = qMax(0, qMin(BLOCK_SIZE, _colorImage.height() - i)); - columns = qMax(0, qMin(BLOCK_SIZE, _colorImage.width() - j)); + color = QByteArray(blockSize * blockSize * BYTES_PER_COLOR, 0); + rows = qMax(0, qMin(blockSize, _colorImage.height() - i)); + columns = qMax(0, qMin(blockSize, _colorImage.width() - j)); for (int y = 0; y < rows; y++) { - memcpy(color.data() + y * BLOCK_SIZE * BYTES_PER_COLOR, + memcpy(color.data() + y * blockSize * BYTES_PER_COLOR, _colorImage.scanLine(i + y) + j * BYTES_PER_COLOR, columns * BYTES_PER_COLOR); } } diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index abb1450f40..cc30896c49 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -267,10 +267,11 @@ private slots: void selectHeightFile(); void selectColorFile(); - + void updatePreview(); + private: - void updatePreview(); + QSpinBox* _blockSize; QPushButton* _height; QPushButton* _color; diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 7219e9da41..40b6195ada 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -559,9 +559,6 @@ bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead) } const QByteArray& childContents = child->getContents(); int childSize = glm::sqrt((float)childContents.size()); - if (childSize != size) { - continue; // TODO: handle differently-sized children - } const int INDEX_MASK = 1; int xIndex = i & INDEX_MASK; const int Y_SHIFT = 1; @@ -576,13 +573,33 @@ bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead) char* dest = contents.data() + (zIndex * halfSize * size) + (xIndex * halfSize); uchar* src = (uchar*)childContents.data(); int childSizePlusOne = childSize + 1; - for (int z = 0; z < halfSize; z++) { - for (char* end = dest + halfSize; dest != end; src += 2) { - int max = qMax(qMax(src[0], src[1]), qMax(src[childSize], src[childSizePlusOne])); - *dest++ = (max == 0) ? 0 : (yOffset + (max >> 1)); + if (childSize == size) { + // simple case: one destination value for four child values + for (int z = 0; z < halfSize; z++) { + for (char* end = dest + halfSize; dest != end; src += 2) { + int max = qMax(qMax(src[0], src[1]), qMax(src[childSize], src[childSizePlusOne])); + *dest++ = (max == 0) ? 0 : (yOffset + (max >> 1)); + } + dest += halfSize; + src += childSize; + } + } else { + // more complex: N destination values for four child values + int halfChildSize = childSize / 2; + int destPerSrc = size / childSize; + for (int z = 0; z < halfChildSize; z++) { + for (uchar* end = src + childSize; src != end; src += 2) { + int max = qMax(qMax(src[0], src[1]), qMax(src[childSize], src[childSizePlusOne])); + memset(dest, (max == 0) ? 0 : (yOffset + (max >> 1)), destPerSrc); + dest += destPerSrc; + } + dest += halfSize; + for (int j = 1; j < destPerSrc; j++) { + memcpy(dest, dest - size, halfSize); + dest += size; + } + src += childSize; } - dest += halfSize; - src += childSize; } } *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(new HeightfieldData(contents)); @@ -638,9 +655,6 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post } const QByteArray& childContents = child->getContents(); int childSize = glm::sqrt(childContents.size() / (float)BYTES_PER_PIXEL); - if (childSize != size) { - continue; // TODO: handle differently-sized children - } const int INDEX_MASK = 1; int xIndex = i & INDEX_MASK; const int Y_SHIFT = 1; @@ -653,7 +667,8 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post char* dest = contents.data() + ((zIndex * halfSize * size) + (xIndex * halfSize)) * BYTES_PER_PIXEL; uchar* src = (uchar*)childContents.data(); int childStride = childSize * BYTES_PER_PIXEL; - int halfStride = halfSize * BYTES_PER_PIXEL; + int stride = size * BYTES_PER_PIXEL; + int halfStride = stride / 2; int childStep = 2 * BYTES_PER_PIXEL; int redOffset3 = childStride + BYTES_PER_PIXEL; int greenOffset1 = BYTES_PER_PIXEL + 1; @@ -662,14 +677,38 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post int blueOffset1 = BYTES_PER_PIXEL + 2; int blueOffset2 = childStride + 2; int blueOffset3 = childStride + BYTES_PER_PIXEL + 2; - for (int z = 0; z < halfSize; z++) { - for (char* end = dest + halfSize * BYTES_PER_PIXEL; dest != end; src += childStep) { - *dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2; - *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2; - *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2; + if (childSize == size) { + // simple case: one destination value for four child values + for (int z = 0; z < halfSize; z++) { + for (char* end = dest + halfSize * BYTES_PER_PIXEL; dest != end; src += childStep) { + *dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2; + *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2; + *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2; + } + dest += halfStride; + src += childStride; + } + } else { + // more complex: N destination values for four child values + int halfChildSize = childSize / 2; + int destPerSrc = size / childSize; + for (int z = 0; z < halfChildSize; z++) { + for (uchar* end = src + childSize * BYTES_PER_PIXEL; src != end; src += childStep) { + *dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2; + *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2; + *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2; + for (int j = 1; j < destPerSrc; j++) { + memcpy(dest, dest - BYTES_PER_PIXEL, BYTES_PER_PIXEL); + dest += BYTES_PER_PIXEL; + } + } + dest += halfStride; + for (int j = 1; j < destPerSrc; j++) { + memcpy(dest, dest - stride, halfStride); + dest += stride; + } + src += childStride; } - dest += halfStride; - src += childStride; } } *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(new HeightfieldData(contents)); From 3fe4c2984831992ebcf266e3ac437d3d5a8df7b7 Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 4 Aug 2014 17:14:26 -0700 Subject: [PATCH 208/407] removed heap alloc of receivedSamples; cleaned up code --- interface/src/Audio.cpp | 205 +++--------------- interface/src/Audio.h | 17 +- libraries/audio/src/MixedAudioStream.cpp | 10 + libraries/audio/src/MixedAudioStream.h | 2 +- .../audio/src/MixedProcessedAudioStream.cpp | 27 +++ .../audio/src/MixedProcessedAudioStream.h | 30 +++ libraries/audio/src/RawMixedAudioStream.cpp | 24 -- libraries/audio/src/RawMixedAudioStream.h | 32 --- 8 files changed, 100 insertions(+), 247 deletions(-) create mode 100644 libraries/audio/src/MixedProcessedAudioStream.cpp create mode 100644 libraries/audio/src/MixedProcessedAudioStream.h delete mode 100644 libraries/audio/src/RawMixedAudioStream.cpp delete mode 100644 libraries/audio/src/RawMixedAudioStream.h diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 419a649b3b..82b8fe3941 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -64,7 +64,7 @@ Audio::Audio(QObject* parent) : _audioOutput(NULL), _desiredOutputFormat(), _outputFormat(), - //_outputDevice(NULL), + _outputFrameSize(0), _numOutputCallbackBytes(0), _loopbackAudioOutput(NULL), _loopbackOutputDevice(NULL), @@ -129,7 +129,7 @@ void Audio::init(QGLWidget *parent) { _muteTextureId = parent->bindTexture(QImage(Application::resourcesPath() + "images/mic-mute.svg")); _boxTextureId = parent->bindTexture(QImage(Application::resourcesPath() + "images/audio-box.svg")); - connect(&_receivedAudioStream, &RawMixedAudioStream::processSamples, this, &Audio::receivedAudioStreamProcessSamples, Qt::DirectConnection); + connect(&_receivedAudioStream, &MixedProcessedAudioStream::processSamples, this, &Audio::processReceivedAudioStreamSamples, Qt::DirectConnection); } void Audio::reset() { @@ -314,7 +314,7 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, } } -void linearResampling(int16_t* sourceSamples, int16_t* destinationSamples, +void linearResampling(const int16_t* sourceSamples, int16_t* destinationSamples, unsigned int numSourceSamples, unsigned int numDestinationSamples, const QAudioFormat& sourceAudioFormat, const QAudioFormat& destinationAudioFormat) { if (sourceAudioFormat == destinationAudioFormat) { @@ -725,24 +725,20 @@ void Audio::handleAudioInput() { } delete[] inputAudioSamples; } - - /*if (_receivedAudioStream.getPacketsReceived() > 0) { - pushAudioToOutput(); - }*/ } -void Audio::receivedAudioStreamProcessSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer) { +void Audio::processReceivedAudioStreamSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer) { - printf("receivedAudioStreamProcessSamples()\n"); - - static const int numNetworkOutputSamples = NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; - static const int numDeviceOutputSamples = numNetworkOutputSamples * (_outputFormat.sampleRate() * _outputFormat.channelCount()) + // NOTE: we assume inputBuffer contains NETWORK_BUFFER_LENGTH_SAMPLES_STEREO audio samples + + const int numNetworkOutputSamples = NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; + const int numDeviceOutputSamples = numNetworkOutputSamples * (_outputFormat.sampleRate() * _outputFormat.channelCount()) / (_desiredOutputFormat.sampleRate() * _desiredOutputFormat.channelCount()); outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); - int16_t* receivedSamples = new int16_t[numNetworkOutputSamples]; + const int16_t* receivedSamples; if (_processSpatialAudio) { unsigned int sampleTime = _spatialAudioStart; QByteArray buffer = inputBuffer.left(numNetworkOutputSamples * sizeof(int16_t)); @@ -758,16 +754,18 @@ void Audio::receivedAudioStreamProcessSamples(const QByteArray& inputBuffer, QBy // copy the samples we'll resample from the spatial audio ring buffer - this also // pushes the read pointer of the spatial audio ring buffer forwards - _spatialAudioRingBuffer.readSamples(receivedSamples, numNetworkOutputSamples); + _spatialAudioRingBuffer.readSamples(_spatialProcessingBuffer, numNetworkOutputSamples); // Advance the start point for the next packet of audio to arrive _spatialAudioStart += numNetworkOutputSamples / _desiredOutputFormat.channelCount(); + + receivedSamples = _spatialProcessingBuffer; } else { // copy the samples we'll resample from the ring buffer - this also // pushes the read pointer of the ring buffer forwards //receivedAudioStreamPopOutput.readSamples(receivedSamples, numNetworkOutputSamples); - memcpy(receivedSamples, inputBuffer.data(), numNetworkOutputSamples * sizeof(int16_t)); + receivedSamples = reinterpret_cast(inputBuffer.data()); } // copy the packet from the RB to the output @@ -777,14 +775,10 @@ void Audio::receivedAudioStreamProcessSamples(const QByteArray& inputBuffer, QBy numDeviceOutputSamples, _desiredOutputFormat, _outputFormat); - /*if (_outputDevice) { - _outputDevice->write(outputBuffer); - }*/ - printf("\t outputBuffer now size %d\n", outputBuffer.size()); if (_scopeEnabled && !_scopeEnabledPause) { unsigned int numAudioChannels = _desiredOutputFormat.channelCount(); - int16_t* samples = receivedSamples; + const int16_t* samples = receivedSamples; for (int numSamples = numNetworkOutputSamples / numAudioChannels; numSamples > 0; numSamples -= NETWORK_SAMPLES_PER_FRAME) { unsigned int audioChannel = 0; @@ -804,15 +798,13 @@ void Audio::receivedAudioStreamProcessSamples(const QByteArray& inputBuffer, QBy samples += NETWORK_SAMPLES_PER_FRAME * numAudioChannels; } } - - delete[] receivedSamples; } void Audio::addReceivedAudioToStream(const QByteArray& audioByteArray) { if (_audioOutput) { // Audio output must exist and be correctly set up if we're going to process received audio - processReceivedAudio(audioByteArray); + _receivedAudioStream.parseData(audioByteArray); } Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AUDIO).updateValue(audioByteArray.size()); @@ -984,119 +976,6 @@ void Audio::toggleStereoInput() { } } -void Audio::processReceivedAudio(const QByteArray& audioByteArray) { - - // parse audio data - _receivedAudioStream.parseData(audioByteArray); - - - // This call has been moved to handleAudioInput. handleAudioInput is called at a much more regular interval - // than processReceivedAudio since handleAudioInput does not experience network-related jitter. - // This way, we reduce the jitter of the frames being pushed to the audio output, allowing us to use a reduced - // buffer size for it, which reduces latency. - - //pushAudioToOutput(); -} - -void Audio::pushAudioToOutput() { - - /*if (_audioOutput->bytesFree() == _audioOutput->bufferSize()) { - // the audio output has no samples to play. set the downstream audio to starved so that it - // refills to its desired size before pushing frames - _receivedAudioStream.setToStarved(); - } - - float networkOutputToOutputRatio = (_desiredOutputFormat.sampleRate() / (float)_outputFormat.sampleRate()) - * (_desiredOutputFormat.channelCount() / (float)_outputFormat.channelCount()); - - int numFramesToPush; - if (Menu::getInstance()->isOptionChecked(MenuOption::DisableQAudioOutputOverflowCheck)) { - numFramesToPush = _receivedAudioStream.getFramesAvailable(); - } else { - // make sure to push a whole number of frames to the audio output - int numFramesAudioOutputRoomFor = (int)(_audioOutput->bytesFree() / sizeof(int16_t) * networkOutputToOutputRatio) / _receivedAudioStream.getNumFrameSamples(); - numFramesToPush = std::min(_receivedAudioStream.getFramesAvailable(), numFramesAudioOutputRoomFor); - } - - // if there is data in the received stream and room in the audio output, decide what to do - - if (numFramesToPush > 0 && _receivedAudioStream.popFrames(numFramesToPush, false)) { - - int numNetworkOutputSamples = numFramesToPush * NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; - int numDeviceOutputSamples = numNetworkOutputSamples / networkOutputToOutputRatio; - - QByteArray outputBuffer; - outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); - - AudioRingBuffer::ConstIterator receivedAudioStreamPopOutput = _receivedAudioStream.getLastPopOutput(); - - int16_t* receivedSamples = new int16_t[numNetworkOutputSamples]; - if (_processSpatialAudio) { - unsigned int sampleTime = _spatialAudioStart; - QByteArray buffer; - buffer.resize(numNetworkOutputSamples * sizeof(int16_t)); - - receivedAudioStreamPopOutput.readSamples((int16_t*)buffer.data(), numNetworkOutputSamples); - - // Accumulate direct transmission of audio from sender to receiver - if (Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingIncludeOriginal)) { - emit preProcessOriginalInboundAudio(sampleTime, buffer, _desiredOutputFormat); - addSpatialAudioToBuffer(sampleTime, buffer, numNetworkOutputSamples); - } - - // Send audio off for spatial processing - emit processInboundAudio(sampleTime, buffer, _desiredOutputFormat); - - // copy the samples we'll resample from the spatial audio ring buffer - this also - // pushes the read pointer of the spatial audio ring buffer forwards - _spatialAudioRingBuffer.readSamples(receivedSamples, numNetworkOutputSamples); - - // Advance the start point for the next packet of audio to arrive - _spatialAudioStart += numNetworkOutputSamples / _desiredOutputFormat.channelCount(); - } else { - // copy the samples we'll resample from the ring buffer - this also - // pushes the read pointer of the ring buffer forwards - receivedAudioStreamPopOutput.readSamples(receivedSamples, numNetworkOutputSamples); - } - - // copy the packet from the RB to the output - linearResampling(receivedSamples, - (int16_t*)outputBuffer.data(), - numNetworkOutputSamples, - numDeviceOutputSamples, - _desiredOutputFormat, _outputFormat); - - if (_outputDevice) { - _outputDevice->write(outputBuffer); - } - - if (_scopeEnabled && !_scopeEnabledPause) { - unsigned int numAudioChannels = _desiredOutputFormat.channelCount(); - int16_t* samples = receivedSamples; - for (int numSamples = numNetworkOutputSamples / numAudioChannels; numSamples > 0; numSamples -= NETWORK_SAMPLES_PER_FRAME) { - - unsigned int audioChannel = 0; - addBufferToScope( - _scopeOutputLeft, - _scopeOutputOffset, - samples, audioChannel, numAudioChannels); - - audioChannel = 1; - addBufferToScope( - _scopeOutputRight, - _scopeOutputOffset, - samples, audioChannel, numAudioChannels); - - _scopeOutputOffset += NETWORK_SAMPLES_PER_FRAME; - _scopeOutputOffset %= _samplesPerScope; - samples += NETWORK_SAMPLES_PER_FRAME * numAudioChannels; - } - } - - delete[] receivedSamples; - }*/ -} - void Audio::processProceduralAudio(int16_t* monoInput, int numSamples) { // zero out the locally injected audio in preparation for audio procedural sounds @@ -1715,8 +1594,8 @@ void Audio::renderLineStrip(const float* color, int x, int y, int n, int offset, void Audio::outputFormatChanged() { - int deviceOutputFrameSize = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * _outputFormat.channelCount() * _outputFormat.sampleRate() / _desiredOutputFormat.sampleRate(); - _receivedAudioStream.resizeFrame(deviceOutputFrameSize); + _outputFrameSize = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * _outputFormat.channelCount() * _outputFormat.sampleRate() / _desiredOutputFormat.sampleRate(); + _receivedAudioStream.resizeFrame(_outputFrameSize); } bool Audio::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo) { @@ -1798,12 +1677,8 @@ bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo) // setup our general output device for audio-mixer audio _audioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this); _audioOutput->setBufferSize(AUDIO_OUTPUT_BUFFER_SIZE_FRAMES * _outputFormat.bytesForDuration(BUFFER_SEND_INTERVAL_USECS)); - - printf("\n\n"); qDebug() << "Ring Buffer capacity in frames: " << (float)_outputFormat.durationForBytes(_audioOutput->bufferSize()) / (float)BUFFER_SEND_INTERVAL_USECS; - printf("\n\n"); - //_outputDevice = _audioOutput->start(); - + _audioOutputIODevice.start(); _audioOutput->start(&_audioOutputIODevice); @@ -1877,53 +1752,25 @@ float Audio::getInputRingBufferMsecsAvailable() const { } qint64 Audio::AudioOutputIODevice::readData(char * data, qint64 maxSize) { - printf("readData() request %d bytes\n", maxSize); - /* - float framesRequested = (float)_parent._outputFormat.durationForBytes(maxSize) / (float)BUFFER_SEND_INTERVAL_USECS; - - if (framesRequested > 67.0f) { - maxSize /= 2; + + MixedProcessedAudioStream& receivedAUdioStream = _parent._receivedAudioStream; + + const QAudioOutput* audioOutput = _parent._audioOutput; + if (audioOutput->bytesFree() == audioOutput->bufferSize()) { + receivedAUdioStream.setToStarved(); } - - quint64 now = usecTimestampNow(); - printf("%llu\n", now - _lastReadTime); - _lastReadTime = now; - - int16_t* buffer; - - - - buffer = (int16_t*)data; - - for (int i = 0; i < maxSize / 2; i++) { - *(buffer++) = (int16_t)randIntInRange(0, 10000); - } - - - return 2 * (maxSize / 2); - */ - int samplesRequested = maxSize / sizeof(int16_t); - - printf("requesting %d samples\n", samplesRequested); - int samplesPopped; int bytesWritten; - if ((samplesPopped = _parent._receivedAudioStream.popSamples(samplesRequested, false, false)) > 0) { - printf("\t pop succeeded: %d samples\n", samplesPopped); - - AudioRingBuffer::ConstIterator lastPopOutput = _parent._receivedAudioStream.getLastPopOutput(); + if ((samplesPopped = receivedAUdioStream.popSamples(samplesRequested, false, false)) > 0) { + AudioRingBuffer::ConstIterator lastPopOutput = receivedAUdioStream.getLastPopOutput(); lastPopOutput.readSamples((int16_t*)data, samplesPopped); - bytesWritten = samplesPopped * sizeof(int16_t); } else { - printf("\t pop failed\n"); memset(data, 0, maxSize); bytesWritten = maxSize; } - printf("\t wrote %d bytes\n", bytesWritten); return bytesWritten; } - diff --git a/interface/src/Audio.h b/interface/src/Audio.h index f35912deb1..3ff0412788 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -33,7 +33,7 @@ #include #include -#include "RawMixedAudioStream.h" +#include "MixedProcessedAudioStream.h" static const int NUM_AUDIO_CHANNELS = 2; @@ -58,7 +58,6 @@ public: private: Audio& _parent; - quint64 _lastReadTime; }; @@ -111,7 +110,7 @@ public slots: void addReceivedAudioToStream(const QByteArray& audioByteArray); void parseAudioStreamStatsPacket(const QByteArray& packet); void addSpatialAudioToBuffer(unsigned int sampleTime, const QByteArray& spatialAudio, unsigned int numSamples); - void receivedAudioStreamProcessSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer); + void processReceivedAudioStreamSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer); void handleAudioInput(); void reset(); void resetStats(); @@ -167,14 +166,15 @@ private: QAudioOutput* _audioOutput; QAudioFormat _desiredOutputFormat; QAudioFormat _outputFormat; - //QIODevice* _outputDevice; + int _outputFrameSize; + int16_t _spatialProcessingBuffer[NETWORK_BUFFER_LENGTH_SAMPLES_STEREO]; int _numOutputCallbackBytes; QAudioOutput* _loopbackAudioOutput; QIODevice* _loopbackOutputDevice; QAudioOutput* _proceduralAudioOutput; QIODevice* _proceduralOutputDevice; AudioRingBuffer _inputRingBuffer; - RawMixedAudioStream _receivedAudioStream; + MixedProcessedAudioStream _receivedAudioStream; bool _isStereoInput; QString _inputAudioDeviceName; @@ -232,12 +232,6 @@ private: // Add sounds that we want the user to not hear themselves, by adding on top of mic input signal void addProceduralSounds(int16_t* monoInput, int numSamples); - - // Process received audio - void processReceivedAudio(const QByteArray& audioByteArray); - - // Pushes frames from the output ringbuffer to the audio output device - void pushAudioToOutput(); bool switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo); bool switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo); @@ -305,6 +299,7 @@ private: MovingMinMaxAvg _packetSentTimeGaps; AudioOutputIODevice _audioOutputIODevice; + }; diff --git a/libraries/audio/src/MixedAudioStream.cpp b/libraries/audio/src/MixedAudioStream.cpp index 821cf1e428..38c4ae641d 100644 --- a/libraries/audio/src/MixedAudioStream.cpp +++ b/libraries/audio/src/MixedAudioStream.cpp @@ -1,3 +1,13 @@ +// +// MixedAudioStream.cpp +// libraries/audio/src +// +// Created by Yixin Wang on 8/4/14. +// Copyright 2013 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 +// #include "MixedAudioStream.h" diff --git a/libraries/audio/src/MixedAudioStream.h b/libraries/audio/src/MixedAudioStream.h index cfb8f9d380..d19f19af07 100644 --- a/libraries/audio/src/MixedAudioStream.h +++ b/libraries/audio/src/MixedAudioStream.h @@ -2,7 +2,7 @@ // MixedAudioStream.h // libraries/audio/src // -// Created by Stephen Birarda on 6/5/13. +// Created by Yixin Wang on 8/4/14. // Copyright 2013 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. diff --git a/libraries/audio/src/MixedProcessedAudioStream.cpp b/libraries/audio/src/MixedProcessedAudioStream.cpp new file mode 100644 index 0000000000..f3cf252b19 --- /dev/null +++ b/libraries/audio/src/MixedProcessedAudioStream.cpp @@ -0,0 +1,27 @@ +// +// MixedProcessedAudioStream.cpp +// libraries/audio/src +// +// Created by Yixin Wang on 8/4/14. +// Copyright 2013 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 +// + +#include "MixedProcessedAudioStream.h" + +MixedProcessedAudioStream ::MixedProcessedAudioStream (int numFrameSamples, int numFramesCapacity, bool dynamicJitterBuffers, int staticDesiredJitterBufferFrames, int maxFramesOverDesired, bool useStDevForJitterCalc) + : MixedAudioStream(numFrameSamples, numFramesCapacity, dynamicJitterBuffers, staticDesiredJitterBufferFrames, maxFramesOverDesired, useStDevForJitterCalc) +{ +} + +int MixedProcessedAudioStream ::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) { + + QByteArray outputBuffer; + emit processSamples(packetAfterStreamProperties, outputBuffer); + + _ringBuffer.writeData(outputBuffer.data(), outputBuffer.size()); + + return packetAfterStreamProperties.size(); +} diff --git a/libraries/audio/src/MixedProcessedAudioStream.h b/libraries/audio/src/MixedProcessedAudioStream.h new file mode 100644 index 0000000000..1c125f74f9 --- /dev/null +++ b/libraries/audio/src/MixedProcessedAudioStream.h @@ -0,0 +1,30 @@ +// +// MixedProcessedAudioStream.h +// libraries/audio/src +// +// Created by Yixin Wang on 8/4/14. +// Copyright 2013 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 +// + +#ifndef hifi_MixedProcessedAudioStream_h +#define hifi_MixedProcessedAudioStream_h + +#include "MixedAudioStream.h" + +class MixedProcessedAudioStream : public MixedAudioStream { + Q_OBJECT +public: + MixedProcessedAudioStream (int numFrameSamples, int numFramesCapacity, bool dynamicJitterBuffers, int staticDesiredJitterBufferFrames, int maxFramesOverDesired, bool useStDevForJitterCalc); + +signals: + + void processSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer); + +protected: + int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples); +}; + +#endif // hifi_MixedProcessedAudioStream_h diff --git a/libraries/audio/src/RawMixedAudioStream.cpp b/libraries/audio/src/RawMixedAudioStream.cpp deleted file mode 100644 index 3b78f2b2de..0000000000 --- a/libraries/audio/src/RawMixedAudioStream.cpp +++ /dev/null @@ -1,24 +0,0 @@ - -#include "RawMixedAudioStream.h" - -RawMixedAudioStream ::RawMixedAudioStream (int numFrameSamples, int numFramesCapacity, bool dynamicJitterBuffers, int staticDesiredJitterBufferFrames, int maxFramesOverDesired, bool useStDevForJitterCalc) - : InboundAudioStream(numFrameSamples, numFramesCapacity, dynamicJitterBuffers, staticDesiredJitterBufferFrames, maxFramesOverDesired, useStDevForJitterCalc) -{ -} - -int RawMixedAudioStream ::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { - // mixed audio packets do not have any info between the seq num and the audio data. - numAudioSamples = packetAfterSeqNum.size() / sizeof(int16_t); - return 0; -} - -int RawMixedAudioStream ::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) { - - QByteArray outputBuffer; - emit processSamples(packetAfterStreamProperties, outputBuffer); - - int bytesWritten = _ringBuffer.writeData(outputBuffer.data(), outputBuffer.size()); - printf("wrote %d samples to ringbuffer\n", bytesWritten / 2); - - return packetAfterStreamProperties.size(); -} diff --git a/libraries/audio/src/RawMixedAudioStream.h b/libraries/audio/src/RawMixedAudioStream.h deleted file mode 100644 index 2db922d489..0000000000 --- a/libraries/audio/src/RawMixedAudioStream.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// RawMixedAudioStream.h -// libraries/audio/src -// -// Created by Stephen Birarda on 6/5/13. -// Copyright 2013 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 -// - -#ifndef hifi_RawMixedAudioStream_h -#define hifi_RawMixedAudioStream_h - -#include "InboundAudioStream.h" -#include "PacketHeaders.h" - -class RawMixedAudioStream : public InboundAudioStream { - Q_OBJECT -public: - RawMixedAudioStream (int numFrameSamples, int numFramesCapacity, bool dynamicJitterBuffers, int staticDesiredJitterBufferFrames, int maxFramesOverDesired, bool useStDevForJitterCalc); - -signals: - - void processSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer); - -protected: - int parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples); - int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples); -}; - -#endif // hifi_RawMixedAudioStream_h From 4355ca83285dbb3375e89e378342d205f53e3cd9 Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 4 Aug 2014 17:24:18 -0700 Subject: [PATCH 209/407] minor member rename --- interface/src/Audio.cpp | 4 ++-- interface/src/Audio.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 82b8fe3941..1711055270 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -754,12 +754,12 @@ void Audio::processReceivedAudioStreamSamples(const QByteArray& inputBuffer, QBy // copy the samples we'll resample from the spatial audio ring buffer - this also // pushes the read pointer of the spatial audio ring buffer forwards - _spatialAudioRingBuffer.readSamples(_spatialProcessingBuffer, numNetworkOutputSamples); + _spatialAudioRingBuffer.readSamples(_outputProcessingBuffer, numNetworkOutputSamples); // Advance the start point for the next packet of audio to arrive _spatialAudioStart += numNetworkOutputSamples / _desiredOutputFormat.channelCount(); - receivedSamples = _spatialProcessingBuffer; + receivedSamples = _outputProcessingBuffer; } else { // copy the samples we'll resample from the ring buffer - this also // pushes the read pointer of the ring buffer forwards diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 3ff0412788..ab16a77632 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -167,7 +167,7 @@ private: QAudioFormat _desiredOutputFormat; QAudioFormat _outputFormat; int _outputFrameSize; - int16_t _spatialProcessingBuffer[NETWORK_BUFFER_LENGTH_SAMPLES_STEREO]; + int16_t _outputProcessingBuffer[NETWORK_BUFFER_LENGTH_SAMPLES_STEREO]; int _numOutputCallbackBytes; QAudioOutput* _loopbackAudioOutput; QIODevice* _loopbackOutputDevice; From d1b2ba4a430418c97f3b6cf1cede02a0a7c6d039 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 4 Aug 2014 17:30:23 -0700 Subject: [PATCH 210/407] fix bug: false positive capsuleCapsule() collision for capsules with parallel axes and negative pojection of center-to-center separation also replace fabs() with fabsf() --- libraries/shared/src/ShapeCollider.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index 5e4eff67ec..805e7f30f6 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -189,7 +189,7 @@ bool sphereCapsule(const SphereShape* sphereA, const CapsuleShape* capsuleB, Col glm::vec3 capsuleAxis; capsuleB->computeNormalizedAxis(capsuleAxis); float axialDistance = - glm::dot(BA, capsuleAxis); - float absAxialDistance = fabs(axialDistance); + float absAxialDistance = fabsf(axialDistance); float totalRadius = sphereA->getRadius() + capsuleB->getRadius(); if (absAxialDistance < totalRadius + capsuleB->getHalfHeight()) { glm::vec3 radialAxis = BA + axialDistance * capsuleAxis; // points from A to axis of B @@ -274,7 +274,7 @@ bool capsuleSphere(const CapsuleShape* capsuleA, const SphereShape* sphereB, Col glm::vec3 capsuleAxis; capsuleA->computeNormalizedAxis(capsuleAxis); float axialDistance = - glm::dot(AB, capsuleAxis); - float absAxialDistance = fabs(axialDistance); + float absAxialDistance = fabsf(axialDistance); float totalRadius = sphereB->getRadius() + capsuleA->getRadius(); if (absAxialDistance < totalRadius + capsuleA->getHalfHeight()) { glm::vec3 radialAxis = AB + axialDistance * capsuleAxis; // from sphereB to axis of capsuleA @@ -501,7 +501,7 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB, // capsules are approximiately parallel but might still collide glm::vec3 BA = centerB - centerA; float axialDistance = glm::dot(BA, axisB); - if (axialDistance > totalRadius + capsuleA->getHalfHeight() + capsuleB->getHalfHeight()) { + if (fabsf(axialDistance) > totalRadius + capsuleA->getHalfHeight() + capsuleB->getHalfHeight()) { return false; } BA = BA - axialDistance * axisB; // BA now points from centerA to axisB (perp to axis) @@ -847,7 +847,7 @@ bool sphereAACube_StarkAngles(const glm::vec3& sphereCenter, float sphereRadius, // compute the nearest point on sphere glm::vec3 surfaceA = sphereCenter + sphereRadius * BA; // compute the nearest point on cube - float maxBA = glm::max(glm::max(fabs(BA.x), fabs(BA.y)), fabs(BA.z)); + float maxBA = glm::max(glm::max(fabsf(BA.x), fabsf(BA.y)), fabsf(BA.z)); glm::vec3 surfaceB = cubeCenter - (0.5f * cubeSide / maxBA) * BA; // collision happens when "vector to surfaceA from surfaceB" dots with BA to produce a positive value glm::vec3 surfaceAB = surfaceA - surfaceB; From ed3240fbad4d13f58541f230408281d9083412ce Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 4 Aug 2014 17:31:14 -0700 Subject: [PATCH 211/407] minor change to _audioOutput->setBufferSize() --- interface/src/Audio.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 1711055270..fdf3d796bd 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1676,8 +1676,8 @@ bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo) // setup our general output device for audio-mixer audio _audioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this); - _audioOutput->setBufferSize(AUDIO_OUTPUT_BUFFER_SIZE_FRAMES * _outputFormat.bytesForDuration(BUFFER_SEND_INTERVAL_USECS)); - qDebug() << "Ring Buffer capacity in frames: " << (float)_outputFormat.durationForBytes(_audioOutput->bufferSize()) / (float)BUFFER_SEND_INTERVAL_USECS; + _audioOutput->setBufferSize(AUDIO_OUTPUT_BUFFER_SIZE_FRAMES * _outputFrameSize * sizeof(int16_t)); + qDebug() << "Ring Buffer capacity in frames: " << _audioOutput->bufferSize() / sizeof(int16_t) / (float)_outputFrameSize; _audioOutputIODevice.start(); _audioOutput->start(&_audioOutputIODevice); From 4beee3fecfbd51bb9ac0f4ef666c5545a9e4d122 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 4 Aug 2014 17:33:24 -0700 Subject: [PATCH 212/407] add Shape::getVerletPoints() --- libraries/shared/src/Shape.h | 4 ++++ libraries/shared/src/VerletCapsuleShape.cpp | 5 +++++ libraries/shared/src/VerletCapsuleShape.h | 1 + libraries/shared/src/VerletSphereShape.cpp | 4 ++++ libraries/shared/src/VerletSphereShape.h | 2 ++ 5 files changed, 16 insertions(+) diff --git a/libraries/shared/src/Shape.h b/libraries/shared/src/Shape.h index b1efe6d9ce..2efa5b824f 100644 --- a/libraries/shared/src/Shape.h +++ b/libraries/shared/src/Shape.h @@ -15,8 +15,10 @@ #include #include #include +#include class PhysicsEntity; +class VerletPoint; const float MAX_SHAPE_MASS = 1.0e18f; // something less than sqrt(FLT_MAX) @@ -73,6 +75,8 @@ public: /// \return volume of shape in cubic meters virtual float getVolume() const { return 1.0; } + virtual void getVerletPoints(QVector& points) {} + protected: // these ctors are protected (used by derived classes only) Shape(Type type) : _type(type), _owningEntity(NULL), _boundingRadius(0.f), _translation(0.f), _rotation() { diff --git a/libraries/shared/src/VerletCapsuleShape.cpp b/libraries/shared/src/VerletCapsuleShape.cpp index ab956264b5..6f547d2048 100644 --- a/libraries/shared/src/VerletCapsuleShape.cpp +++ b/libraries/shared/src/VerletCapsuleShape.cpp @@ -111,6 +111,11 @@ void VerletCapsuleShape::applyAccumulatedDelta() { _endPoint->applyAccumulatedDelta(); } +void VerletCapsuleShape::getVerletPoints(QVector& points) { + points.push_back(_startPoint); + points.push_back(_endPoint); +} + // virtual float VerletCapsuleShape::getHalfHeight() const { return 0.5f * glm::distance(_startPoint->_position, _endPoint->_position); diff --git a/libraries/shared/src/VerletCapsuleShape.h b/libraries/shared/src/VerletCapsuleShape.h index 1fd84f5b1e..828e5def6c 100644 --- a/libraries/shared/src/VerletCapsuleShape.h +++ b/libraries/shared/src/VerletCapsuleShape.h @@ -47,6 +47,7 @@ public: float computeEffectiveMass(const glm::vec3& penetration, const glm::vec3& contactPoint); void accumulateDelta(float relativeMassFactor, const glm::vec3& penetration); void applyAccumulatedDelta(); + virtual void getVerletPoints(QVector& points); //float getRadius() const { return _radius; } virtual float getHalfHeight() const; diff --git a/libraries/shared/src/VerletSphereShape.cpp b/libraries/shared/src/VerletSphereShape.cpp index 10c40c6611..e24465fd89 100644 --- a/libraries/shared/src/VerletSphereShape.cpp +++ b/libraries/shared/src/VerletSphereShape.cpp @@ -48,3 +48,7 @@ void VerletSphereShape::accumulateDelta(float relativeMassFactor, const glm::vec void VerletSphereShape::applyAccumulatedDelta() { _point->applyAccumulatedDelta(); } + +void VerletSphereShape::getVerletPoints(QVector& points) { + points.push_back(_point); +} diff --git a/libraries/shared/src/VerletSphereShape.h b/libraries/shared/src/VerletSphereShape.h index 65da3b2597..c9a23faef2 100644 --- a/libraries/shared/src/VerletSphereShape.h +++ b/libraries/shared/src/VerletSphereShape.h @@ -38,6 +38,8 @@ public: float computeEffectiveMass(const glm::vec3& penetration, const glm::vec3& contactPoint); void accumulateDelta(float relativeMassFactor, const glm::vec3& penetration); void applyAccumulatedDelta(); + void getVerletPoints(QVector& points); + protected: // NOTE: VerletSphereShape does NOT own its _point From f126ce299a6a56f7b7e9e2f03c5c02f21a6f4564 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 4 Aug 2014 17:34:24 -0700 Subject: [PATCH 213/407] ContactPoint = set of assymetric distance consraints --- libraries/shared/src/ContactPoint.cpp | 111 +++++++++++++++++---- libraries/shared/src/ContactPoint.h | 8 ++ libraries/shared/src/PhysicsSimulation.cpp | 65 +++++------- libraries/shared/src/PhysicsSimulation.h | 3 +- 4 files changed, 127 insertions(+), 60 deletions(-) diff --git a/libraries/shared/src/ContactPoint.cpp b/libraries/shared/src/ContactPoint.cpp index 1f6dbcdb11..c34d248035 100644 --- a/libraries/shared/src/ContactPoint.cpp +++ b/libraries/shared/src/ContactPoint.cpp @@ -18,8 +18,10 @@ ContactPoint::ContactPoint() : _lastFrame(0), _shapeA(NULL), _shapeB(NULL), } ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : _lastFrame(frame), - _shapeA(collision.getShapeA()), _shapeB(collision.getShapeB()), _offsetA(0.0f), _offsetB(0.0f), _normal(0.0f) { + _shapeA(collision.getShapeA()), _shapeB(collision.getShapeB()), _offsetA(0.0f), _offsetB(0.0f), + _numPointsA(0), _numPoints(0), _normal(0.0f) { + _contactPoint = collision._contactPoint - 0.5f * collision._penetration; _offsetA = collision._contactPoint - _shapeA->getTranslation(); _offsetB = collision._contactPoint - collision._penetration - _shapeB->getTranslation(); float pLength = glm::length(collision._penetration); @@ -37,36 +39,94 @@ ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : _las _offsetB = temp; _normal = - _normal; } + + _shapeA->getVerletPoints(_points); + _numPointsA = _points.size(); + _shapeB->getVerletPoints(_points); + _numPoints = _points.size(); + + // compute offsets for shapeA + for (int i = 0; i < _numPointsA; ++i) { + glm::vec3 offset = _points[i]->_position - collision._contactPoint; + _offsets.push_back(offset); + _distances.push_back(glm::length(offset)); + } + // compute offsets for shapeB + for (int i = _numPointsA; i < _numPoints; ++i) { + glm::vec3 offset = _points[i]->_position - collision._contactPoint + collision._penetration; + _offsets.push_back(offset); + _distances.push_back(glm::length(offset)); + } } // virtual float ContactPoint::enforce() { - glm::vec3 pointA = _shapeA->getTranslation() + _offsetA; - glm::vec3 pointB = _shapeB->getTranslation() + _offsetB; - glm::vec3 penetration = pointA - pointB; - float pDotN = glm::dot(penetration, _normal); - if (pDotN > EPSILON) { - penetration = (0.99f * pDotN) * _normal; - // NOTE: Shape::computeEffectiveMass() has side effects: computes and caches partial Lagrangian coefficients - // which are then used in the accumulateDelta() calls below. - float massA = _shapeA->computeEffectiveMass(penetration, pointA); - float massB = _shapeB->computeEffectiveMass(-penetration, pointB); - float totalMass = massA + massB; - if (totalMass < EPSILON) { - massA = massB = 1.0f; - totalMass = 2.0f; + int numPoints = _points.size(); + for (int i = 0; i < numPoints; ++i) { + glm::vec3& position = _points[i]->_position; + // TODO: use a fast distance approximation + float newDistance = glm::distance(_contactPoint, position); + float constrainedDistance = _distances[i]; + // NOTE: these "distance" constraints only push OUT, don't pull IN. + if (newDistance > EPSILON && newDistance < constrainedDistance) { + glm::vec3 direction = (_contactPoint - position) / newDistance; + glm::vec3 center = 0.5f * (_contactPoint + position); + _contactPoint = center + (0.5f * constrainedDistance) * direction; + position = center - (0.5f * constrainedDistance) * direction; } - // NOTE: Shape::accumulateDelta() uses the coefficients from previous call to Shape::computeEffectiveMass() - // and remember that penetration points from A into B - _shapeA->accumulateDelta(massB / totalMass, -penetration); - _shapeB->accumulateDelta(massA / totalMass, penetration); - return pDotN; } return 0.0f; } +void ContactPoint::buildConstraints() { + glm::vec3 pointA = _shapeA->getTranslation() + _offsetA; + glm::vec3 pointB = _shapeB->getTranslation() + _offsetB; + glm::vec3 penetration = pointA - pointB; + float pDotN = glm::dot(penetration, _normal); + bool actuallyMovePoints = (pDotN > EPSILON); + + // the contact point will be the average of the two points on the shapes + _contactPoint = 0.5f * (pointA + pointB); + + // TODO: Andrew to compute more correct lagrangian weights that provide a more realistic response. + // + // HACK: since the weights are naively equal for all points (which is what the above TODO is about) we + // don't want to use the full-strength delta because otherwise there can be annoying oscillations. We + // reduce this problem by in the short-term by attenuating the delta that is applied, the tradeoff is + // that this makes it easier for limbs to tunnel through during collisions. + const float HACK_STRENGTH = 0.5f; + + int numPoints = _points.size(); + for (int i = 0; i < numPoints; ++i) { + VerletPoint* point = _points[i]; + glm::vec3 offset = _offsets[i]; + + // split delta into parallel and perpendicular components + glm::vec3 delta = _contactPoint + offset - point->_position; + glm::vec3 paraDelta = glm::dot(delta, _normal) * _normal; + glm::vec3 perpDelta = delta - paraDelta; + + // use the relative sizes of the components to decide how much perpenducular delta to use + // perpendicular < parallel ==> static friciton ==> perpFactor = 1.0 + // perpendicular > parallel ==> dynamic friciton ==> cap to length of paraDelta ==> perpFactor < 1.0 + float paraLength = glm::length(paraDelta); + float perpLength = glm::length(perpDelta); + float perpFactor = (perpLength > paraLength && perpLength > EPSILON) ? (paraLength / perpLength) : 1.0f; + + // recombine the two components to get the final delta + delta = paraDelta + perpFactor * perpDelta; + + glm::vec3 targetPosition = point->_position + delta; + _distances[i] = glm::distance(_contactPoint, targetPosition); + if (actuallyMovePoints) { + point->_position += HACK_STRENGTH * delta; + } + } +} + void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) { _lastFrame = frame; + _contactPoint = collision._contactPoint - 0.5f * collision._penetration; _offsetA = collision._contactPoint - collision._shapeA->getTranslation(); _offsetB = collision._contactPoint - collision._penetration - collision._shapeB->getTranslation(); float pLength = glm::length(collision._penetration); @@ -75,6 +135,7 @@ void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) } else { _normal = glm::vec3(0.0f); } + if (collision._shapeA->getID() > collision._shapeB->getID()) { // our _shapeA always has lower ID glm::vec3 temp = _offsetA; @@ -82,4 +143,14 @@ void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) _offsetB = temp; _normal = - _normal; } + + // compute offsets for shapeA + assert(_offsets.size() == _numPoints); + for (int i = 0; i < _numPointsA; ++i) { + _offsets[i] = (_points[i]->_position - collision._contactPoint); + } + // compute offsets for shapeB + for (int i = _numPointsA; i < _numPoints; ++i) { + _offsets[i] = (_points[i]->_position - collision._contactPoint + collision._penetration); + } } diff --git a/libraries/shared/src/ContactPoint.h b/libraries/shared/src/ContactPoint.h index 84e15a85ee..b7e0775bc1 100644 --- a/libraries/shared/src/ContactPoint.h +++ b/libraries/shared/src/ContactPoint.h @@ -16,6 +16,7 @@ #include #include "CollisionInfo.h" +#include "VerletPoint.h" class Shape; @@ -26,6 +27,7 @@ public: virtual float enforce(); + void buildConstraints(); void updateContact(const CollisionInfo& collision, quint32 frame); quint32 getLastFrame() const { return _lastFrame; } @@ -38,6 +40,12 @@ protected: Shape* _shapeB; glm::vec3 _offsetA; // contact point relative to A's center glm::vec3 _offsetB; // contact point relative to B's center + glm::vec3 _contactPoint; // a "virtual" point that is added to the simulation + int _numPointsA; // number of VerletPoints that belong to _shapeA + int _numPoints; // total number of VerletPoints + QVector _points; // points that belong to colliding shapes + QVector _offsets; // offsets to _points from contactPoint + QVector _distances; // distances to _points from contactPoint (during enforcement stage) glm::vec3 _normal; // (points from A toward B) }; diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index 8bcbb7255a..bac4f2ad77 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -10,7 +10,6 @@ // #include -#include #include "PhysicsSimulation.h" @@ -143,11 +142,13 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter quint64 expiry = startTime + maxUsec; moveRagdolls(deltaTime); - computeCollisions(); - enforceContacts(); + buildContactConstraints(); int numDolls = _dolls.size(); - for (int i = 0; i < numDolls; ++i) { - _dolls[i]->enforceRagdollConstraints(); + { + PerformanceTimer perfTimer("enforce"); + for (int i = 0; i < numDolls; ++i) { + _dolls[i]->enforceRagdollConstraints(); + } } int iterations = 0; @@ -158,30 +159,23 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter resolveCollisions(); { // enforce constraints - PerformanceTimer perfTimer("5-enforce"); + PerformanceTimer perfTimer("enforce"); error = 0.0f; for (int i = 0; i < numDolls; ++i) { error = glm::max(error, _dolls[i]->enforceRagdollConstraints()); } } + enforceContactConstraints(); ++iterations; now = usecTimestampNow(); } while (_collisions.size() != 0 && (iterations < maxIterations) && (error > minError) && (now < expiry)); - -#ifdef ANDREW_DEBUG - quint64 stepTime = usecTimestampNow()- startTime; - // temporary debug info for watching simulation performance - if (0 == (_frame % 100)) { - std::cout << "Ni = " << iterations << " E = " << error << " t = " << stepTime << std::endl; - } -#endif // ANDREW_DEBUG pruneContacts(); } void PhysicsSimulation::moveRagdolls(float deltaTime) { - PerformanceTimer perfTimer("1-integrate"); + PerformanceTimer perfTimer("integrate"); int numDolls = _dolls.size(); for (int i = 0; i < numDolls; ++i) { _dolls.at(i)->stepRagdollForward(deltaTime); @@ -189,7 +183,7 @@ void PhysicsSimulation::moveRagdolls(float deltaTime) { } void PhysicsSimulation::computeCollisions() { - PerformanceTimer perfTimer("2-collide"); + PerformanceTimer perfTimer("collide"); _collisions.clear(); // TODO: keep track of QSet collidedEntities; int numEntities = _entities.size(); @@ -220,7 +214,7 @@ void PhysicsSimulation::computeCollisions() { } void PhysicsSimulation::resolveCollisions() { - PerformanceTimer perfTimer("4-resolve"); + PerformanceTimer perfTimer("resolve"); // walk all collisions, accumulate movement on shapes, and build a list of affected shapes QSet shapes; int numCollisions = _collisions.size(); @@ -242,33 +236,26 @@ void PhysicsSimulation::resolveCollisions() { } } -void PhysicsSimulation::enforceContacts() { - QSet shapes; - int numCollisions = _collisions.size(); - for (int i = 0; i < numCollisions; ++i) { - CollisionInfo* collision = _collisions.getCollision(i); - quint64 key = collision->getShapePairKey(); - if (key == 0) { - continue; - } - QMap::iterator itr = _contacts.find(key); - if (itr != _contacts.end()) { - if (itr.value().enforce() > 0.0f) { - shapes.insert(collision->getShapeA()); - shapes.insert(collision->getShapeB()); - } - } +void PhysicsSimulation::buildContactConstraints() { + PerformanceTimer perfTimer("contacts"); + QMap::iterator itr = _contacts.begin(); + while (itr != _contacts.end()) { + itr.value().buildConstraints(); + ++itr; } - // walk all affected shapes and apply accumulated movement - QSet::const_iterator shapeItr = shapes.constBegin(); - while (shapeItr != shapes.constEnd()) { - (*shapeItr)->applyAccumulatedDelta(); - ++shapeItr; +} + +void PhysicsSimulation::enforceContactConstraints() { + PerformanceTimer perfTimer("contacts"); + QMap::iterator itr = _contacts.begin(); + while (itr != _contacts.end()) { + itr.value().enforce(); + ++itr; } } void PhysicsSimulation::updateContacts() { - PerformanceTimer perfTimer("3-updateContacts"); + PerformanceTimer perfTimer("contacts"); int numCollisions = _collisions.size(); for (int i = 0; i < numCollisions; ++i) { CollisionInfo* collision = _collisions.getCollision(i); diff --git a/libraries/shared/src/PhysicsSimulation.h b/libraries/shared/src/PhysicsSimulation.h index 8cbc39b9d3..fc6d518d62 100644 --- a/libraries/shared/src/PhysicsSimulation.h +++ b/libraries/shared/src/PhysicsSimulation.h @@ -49,7 +49,8 @@ protected: void computeCollisions(); void resolveCollisions(); - void enforceContacts(); + void buildContactConstraints(); + void enforceContactConstraints(); void updateContacts(); void pruneContacts(); From f0af2f022e099f347a146cf215582f079b0a03f0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 4 Aug 2014 17:52:20 -0700 Subject: [PATCH 214/407] Pack/Unpack asymetry fix + added forgotten consts --- interface/src/avatar/ModelReferential.cpp | 4 ++-- interface/src/avatar/ModelReferential.h | 4 ++-- libraries/avatars/src/Referential.cpp | 27 ++++++++++++++--------- libraries/avatars/src/Referential.h | 16 +++++++------- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/interface/src/avatar/ModelReferential.cpp b/interface/src/avatar/ModelReferential.cpp index 85533603f2..8f1360a705 100644 --- a/interface/src/avatar/ModelReferential.cpp +++ b/interface/src/avatar/ModelReferential.cpp @@ -69,12 +69,12 @@ void ModelReferential::update() { } } -int ModelReferential::packExtraData(unsigned char* destinationBuffer) { +int ModelReferential::packExtraData(unsigned char* destinationBuffer) const { memcpy(destinationBuffer, &_modelID, sizeof(_modelID)); return sizeof(_modelID); } -int ModelReferential::unpackExtraData(const unsigned char *sourceBuffer) { +int ModelReferential::unpackExtraData(const unsigned char *sourceBuffer, int size) { memcpy(&_modelID, sourceBuffer, sizeof(_modelID)); return sizeof(_modelID); } diff --git a/interface/src/avatar/ModelReferential.h b/interface/src/avatar/ModelReferential.h index e87a09594d..806e4edfcb 100644 --- a/interface/src/avatar/ModelReferential.h +++ b/interface/src/avatar/ModelReferential.h @@ -24,8 +24,8 @@ public: virtual void update(); protected: - virtual int packExtraData(unsigned char* destinationBuffer); - virtual int unpackExtraData(const unsigned char* sourceBuffer); + virtual int packExtraData(unsigned char* destinationBuffer) const; + virtual int unpackExtraData(const unsigned char* sourceBuffer, int size); uint32_t _modelID; ModelTree* _tree; diff --git a/libraries/avatars/src/Referential.cpp b/libraries/avatars/src/Referential.cpp index 91c3050e2f..12a0f59186 100644 --- a/libraries/avatars/src/Referential.cpp +++ b/libraries/avatars/src/Referential.cpp @@ -36,7 +36,7 @@ Referential::Referential(const unsigned char*& sourceBuffer, AvatarData* avatar) Referential::~Referential() { } -int Referential::packReferential(unsigned char* destinationBuffer) { +int Referential::packReferential(unsigned char* destinationBuffer) const { const unsigned char* startPosition = destinationBuffer; destinationBuffer += pack(destinationBuffer); @@ -53,17 +53,21 @@ int Referential::unpackReferential(const unsigned char* sourceBuffer) { sourceBuffer += unpack(sourceBuffer); char expectedSize = *sourceBuffer++; - char bytesRead = unpackExtraData(sourceBuffer); + char bytesRead = unpackExtraData(sourceBuffer, expectedSize); _isValid = (bytesRead == expectedSize); + if (!_isValid) { + qDebug() << "[ERROR] Referential extra data overflow"; + } sourceBuffer += expectedSize; return sourceBuffer - startPosition; } -int Referential::pack(unsigned char* destinationBuffer) { +int Referential::pack(unsigned char* destinationBuffer) const { unsigned char* startPosition = destinationBuffer; *destinationBuffer++ = (unsigned char)_type; memcpy(destinationBuffer, &_createdAt, sizeof(_createdAt)); + destinationBuffer += sizeof(_createdAt); destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, _translation, 0); destinationBuffer += packOrientationQuatToBytes(destinationBuffer, _rotation); @@ -83,13 +87,14 @@ int Referential::unpack(const unsigned char* sourceBuffer) { return sourceBuffer - startPosition; } - -int Referential::unpackExtraData(const unsigned char* sourceBuffer) { - const unsigned char* startPosition = sourceBuffer; - int size = *sourceBuffer; - _extraDataBuffer.clear(); - _extraDataBuffer.setRawData(reinterpret_cast(sourceBuffer), size + 1); - sourceBuffer += size + 1; - return sourceBuffer - startPosition; +int Referential::packExtraData(unsigned char *destinationBuffer) const { + memcpy(destinationBuffer, _extraDataBuffer.data(), _extraDataBuffer.size()); + return _extraDataBuffer.size(); +} + +int Referential::unpackExtraData(const unsigned char* sourceBuffer, int size) { + _extraDataBuffer.clear(); + _extraDataBuffer.setRawData(reinterpret_cast(sourceBuffer), size); + return size; } diff --git a/libraries/avatars/src/Referential.h b/libraries/avatars/src/Referential.h index b7e3a248e8..713b6a028f 100644 --- a/libraries/avatars/src/Referential.h +++ b/libraries/avatars/src/Referential.h @@ -28,24 +28,24 @@ public: Referential(const unsigned char*& sourceBuffer, AvatarData* avatar); virtual ~Referential(); - Type type() { return _type; } - quint64 createdAt() { return _createdAt; } - bool isValid() { return _isValid; } - bool hasExtraData() { return !_extraDataBuffer.isEmpty(); } + Type type() const { return _type; } + quint64 createdAt() const { return _createdAt; } + bool isValid() const { return _isValid; } + bool hasExtraData() const { return !_extraDataBuffer.isEmpty(); } virtual void update() {} - int packReferential(unsigned char* destinationBuffer); + int packReferential(unsigned char* destinationBuffer) const; int unpackReferential(const unsigned char* sourceBuffer); protected: Referential(Type type, AvatarData* avatar); // packs the base class data - int pack(unsigned char* destinationBuffer); + int pack(unsigned char* destinationBuffer) const; int unpack(const unsigned char* sourceBuffer); // virtual functions that pack fthe extra data of subclasses (needs to be reimplemented in subclass) - virtual int packExtraData(unsigned char* destinationBuffer) { return 0; } - virtual int unpackExtraData(const unsigned char* sourceBuffer); + virtual int packExtraData(unsigned char* destinationBuffer) const; + virtual int unpackExtraData(const unsigned char* sourceBuffer, int size); Type _type; quint64 _createdAt; From 2b8b15e32d7ce7cd513414b831e59a4fae22e093 Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 4 Aug 2014 17:56:14 -0700 Subject: [PATCH 215/407] made audioscope easier to see --- interface/src/Audio.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index fdf3d796bd..a8cc7f387e 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1476,11 +1476,11 @@ void Audio::renderScope(int width, int height) { if (!_scopeEnabled) return; - static const float backgroundColor[4] = { 0.2f, 0.2f, 0.2f, 0.6f }; + static const float backgroundColor[4] = { 0.4f, 0.4f, 0.4f, 0.6f }; static const float gridColor[4] = { 0.3f, 0.3f, 0.3f, 0.6f }; - static const float inputColor[4] = { 0.3f, .7f, 0.3f, 0.6f }; - static const float outputLeftColor[4] = { 0.7f, .3f, 0.3f, 0.6f }; - static const float outputRightColor[4] = { 0.3f, .3f, 0.7f, 0.6f }; + static const float inputColor[4] = { 0.3f, 1.0f, 0.3f, 1.0f }; + static const float outputLeftColor[4] = { 1.0f, 0.3f, 0.3f, 1.0f }; + static const float outputRightColor[4] = { 0.3f, 0.3f, 1.0f, 1.0f }; static const int gridRows = 2; int gridCols = _framesPerScope; From a1fccdb17711897aa37385e471482b3e2e342a68 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 5 Aug 2014 08:32:14 -0700 Subject: [PATCH 216/407] remove dangling shape pointers from PhysicsSimulation --- libraries/shared/src/PhysicsEntity.cpp | 3 +++ libraries/shared/src/PhysicsSimulation.cpp | 6 +++++- libraries/shared/src/PhysicsSimulation.h | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/PhysicsEntity.cpp b/libraries/shared/src/PhysicsEntity.cpp index 37d1a88d67..09b00c201c 100644 --- a/libraries/shared/src/PhysicsEntity.cpp +++ b/libraries/shared/src/PhysicsEntity.cpp @@ -65,6 +65,9 @@ void PhysicsEntity::setEnableShapes(bool enable) { } void PhysicsEntity::clearShapes() { + if (_simulation) { + _simulation->removeShapes(this); + } for (int i = 0; i < _shapes.size(); ++i) { delete _shapes[i]; } diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index bac4f2ad77..c2a852c32b 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -70,6 +70,7 @@ void PhysicsSimulation::removeEntity(PhysicsEntity* entity) { if (!entity || !entity->_simulation || !(entity->_simulation == this)) { return; } + removeShapes(entity); int numEntities = _entities.size(); for (int i = 0; i < numEntities; ++i) { if (entity == _entities.at(i)) { @@ -86,7 +87,10 @@ void PhysicsSimulation::removeEntity(PhysicsEntity* entity) { break; } } - // remove corresponding contacts +} + +void PhysicsSimulation::removeShapes(const PhysicsEntity* entity) { + // remove data structures with pointers to entity's shapes QMap::iterator itr = _contacts.begin(); while (itr != _contacts.end()) { if (entity == itr.value().getShapeA()->getEntity() || entity == itr.value().getShapeB()->getEntity()) { diff --git a/libraries/shared/src/PhysicsSimulation.h b/libraries/shared/src/PhysicsSimulation.h index fc6d518d62..506b37533a 100644 --- a/libraries/shared/src/PhysicsSimulation.h +++ b/libraries/shared/src/PhysicsSimulation.h @@ -32,6 +32,7 @@ public: bool addEntity(PhysicsEntity* entity); void removeEntity(PhysicsEntity* entity); + void removeShapes(const PhysicsEntity* entity); /// \return true if doll was added to or is already in the list bool addRagdoll(Ragdoll* doll); From 748c9e2065401a1713fd1a4077036db9a0e1f1d5 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 5 Aug 2014 10:13:34 -0700 Subject: [PATCH 217/407] numAudioSamples now calculated to be device samples instead of network samples --- interface/src/Audio.cpp | 9 +++----- interface/src/Audio.h | 3 --- libraries/audio/src/InboundAudioStream.cpp | 2 -- libraries/audio/src/InboundAudioStream.h | 4 +--- .../audio/src/MixedProcessedAudioStream.cpp | 22 +++++++++++++++++-- .../audio/src/MixedProcessedAudioStream.h | 13 ++++++++--- 6 files changed, 34 insertions(+), 19 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index a8cc7f387e..ddd2cf799a 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -729,9 +729,7 @@ void Audio::handleAudioInput() { void Audio::processReceivedAudioStreamSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer) { - // NOTE: we assume inputBuffer contains NETWORK_BUFFER_LENGTH_SAMPLES_STEREO audio samples - - const int numNetworkOutputSamples = NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; + const int numNetworkOutputSamples = inputBuffer.size() / sizeof(int16_t); const int numDeviceOutputSamples = numNetworkOutputSamples * (_outputFormat.sampleRate() * _outputFormat.channelCount()) / (_desiredOutputFormat.sampleRate() * _desiredOutputFormat.channelCount()); @@ -741,7 +739,7 @@ void Audio::processReceivedAudioStreamSamples(const QByteArray& inputBuffer, QBy const int16_t* receivedSamples; if (_processSpatialAudio) { unsigned int sampleTime = _spatialAudioStart; - QByteArray buffer = inputBuffer.left(numNetworkOutputSamples * sizeof(int16_t)); + QByteArray buffer = inputBuffer; // Accumulate direct transmission of audio from sender to receiver if (Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingIncludeOriginal)) { @@ -1595,7 +1593,7 @@ void Audio::renderLineStrip(const float* color, int x, int y, int n, int offset, void Audio::outputFormatChanged() { _outputFrameSize = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * _outputFormat.channelCount() * _outputFormat.sampleRate() / _desiredOutputFormat.sampleRate(); - _receivedAudioStream.resizeFrame(_outputFrameSize); + _receivedAudioStream.outputFormatChanged(_outputFormat); } bool Audio::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo) { @@ -1648,7 +1646,6 @@ bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo) // cleanup any previously initialized device if (_audioOutput) { _audioOutput->stop(); - //_outputDevice = NULL; delete _audioOutput; _audioOutput = NULL; diff --git a/interface/src/Audio.h b/interface/src/Audio.h index ab16a77632..8fae6f3bdd 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -52,10 +52,8 @@ public: void start() { open(QIODevice::ReadOnly); } void stop() { close(); } - qint64 readData(char * data, qint64 maxSize); qint64 writeData(const char * data, qint64 maxSize) { return 0; } - private: Audio& _parent; }; @@ -299,7 +297,6 @@ private: MovingMinMaxAvg _packetSentTimeGaps; AudioOutputIODevice _audioOutputIODevice; - }; diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index bc563d649e..4b76aaeeb5 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -91,7 +91,6 @@ int InboundAudioStream::parseData(const QByteArray& packet) { frameReceivedUpdateTimingStats(); - // TODO: handle generalized silent packet here????? // parse the info after the seq number and before the audio data.(the stream properties) @@ -170,7 +169,6 @@ int InboundAudioStream::popSamples(int maxSamples, bool allOrNothing, bool starv return samplesPopped; } - int InboundAudioStream::popFrames(int maxFrames, bool allOrNothing, bool starveOnFail) { int framesPopped = 0; int framesAvailable = _ringBuffer.framesAvailable(); diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index c44edf65cc..590421e50f 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -81,8 +81,6 @@ public: void setMaxFramesOverDesired(int maxFramesOverDesired) { _maxFramesOverDesired = maxFramesOverDesired; } - void resizeFrame(int numFrameSamples) { _ringBuffer.resizeForFrameSize(numFrameSamples); } - virtual AudioStreamStats getAudioStreamStats() const; /// returns the desired number of jitter buffer frames under the dyanmic jitter buffers scheme @@ -129,7 +127,7 @@ protected: InboundAudioStream& operator= (const InboundAudioStream&); /// parses the info between the seq num and the audio data in the network packet and calculates - /// how many audio samples this packet contains + /// how many audio samples this packet contains (used when filling in samples for dropped packets). virtual int parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) = 0; /// parses the audio data in the network packet. diff --git a/libraries/audio/src/MixedProcessedAudioStream.cpp b/libraries/audio/src/MixedProcessedAudioStream.cpp index f3cf252b19..582456739e 100644 --- a/libraries/audio/src/MixedProcessedAudioStream.cpp +++ b/libraries/audio/src/MixedProcessedAudioStream.cpp @@ -12,11 +12,29 @@ #include "MixedProcessedAudioStream.h" MixedProcessedAudioStream ::MixedProcessedAudioStream (int numFrameSamples, int numFramesCapacity, bool dynamicJitterBuffers, int staticDesiredJitterBufferFrames, int maxFramesOverDesired, bool useStDevForJitterCalc) - : MixedAudioStream(numFrameSamples, numFramesCapacity, dynamicJitterBuffers, staticDesiredJitterBufferFrames, maxFramesOverDesired, useStDevForJitterCalc) + : InboundAudioStream(numFrameSamples, numFramesCapacity, dynamicJitterBuffers, staticDesiredJitterBufferFrames, maxFramesOverDesired, useStDevForJitterCalc) { } -int MixedProcessedAudioStream ::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) { +void MixedProcessedAudioStream::outputFormatChanged(const QAudioFormat& outputFormat) { + _outputFormatChannelsTimesSampleRate = outputFormat.channelCount() * outputFormat.sampleRate(); + int deviceOutputFrameSize = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * _outputFormatChannelsTimesSampleRate / SAMPLE_RATE; + _ringBuffer.resizeForFrameSize(deviceOutputFrameSize); +} + +int MixedProcessedAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { + // mixed audio packets do not have any info between the seq num and the audio data. + int numNetworkSamples = packetAfterSeqNum.size() / sizeof(int16_t); + + // since numAudioSamples is used to know how many samples to add for each dropped packet before this one, + // we want to set it to the number of device audio samples since this stream contains device audio samples, not network samples. + const int STEREO_DIVIDER = 2; + numAudioSamples = numNetworkSamples * _outputFormatChannelsTimesSampleRate / (STEREO_DIVIDER * SAMPLE_RATE); + + return 0; +} + +int MixedProcessedAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) { QByteArray outputBuffer; emit processSamples(packetAfterStreamProperties, outputBuffer); diff --git a/libraries/audio/src/MixedProcessedAudioStream.h b/libraries/audio/src/MixedProcessedAudioStream.h index 1c125f74f9..e624903b88 100644 --- a/libraries/audio/src/MixedProcessedAudioStream.h +++ b/libraries/audio/src/MixedProcessedAudioStream.h @@ -12,19 +12,26 @@ #ifndef hifi_MixedProcessedAudioStream_h #define hifi_MixedProcessedAudioStream_h -#include "MixedAudioStream.h" +#include +#include "InboundAudioStream.h" -class MixedProcessedAudioStream : public MixedAudioStream { +class MixedProcessedAudioStream : public InboundAudioStream { Q_OBJECT public: MixedProcessedAudioStream (int numFrameSamples, int numFramesCapacity, bool dynamicJitterBuffers, int staticDesiredJitterBufferFrames, int maxFramesOverDesired, bool useStDevForJitterCalc); -signals: + void outputFormatChanged(const QAudioFormat& outputFormat); +signals: + void processSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer); protected: + int parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples); int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples); + +private: + int _outputFormatChannelsTimesSampleRate; }; #endif // hifi_MixedProcessedAudioStream_h From 1eaf175a92b11abd1019b1f22c4620369d39a1ef Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 5 Aug 2014 10:21:53 -0700 Subject: [PATCH 218/407] removed disable audio output overflow check menu option --- interface/src/Menu.cpp | 2 -- interface/src/Menu.h | 1 - 2 files changed, 3 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8fa5183d02..43d9fde01a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -606,8 +606,6 @@ Menu::Menu() : appInstance->getAudio(), SLOT(toggleStatsShowInjectedStreams())); - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::DisableQAudioOutputOverflowCheck, 0, false); - addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel, Qt::CTRL | Qt::SHIFT | Qt::Key_V, this, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 35e3e75d6a..3bef306bef 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -353,7 +353,6 @@ namespace MenuOption { const QString DisableActivityLogger = "Disable Activity Logger"; const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD"; const QString DisableNackPackets = "Disable NACK Packets"; - const QString DisableQAudioOutputOverflowCheck = "Disable Audio Output Device Overflow Check"; const QString DisplayFrustum = "Display Frustum"; const QString DisplayHands = "Display Hands"; const QString DisplayHandTargets = "Display Hand Targets"; From 779e7631a1cacfa347a72acbb0e1d39264246473 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 5 Aug 2014 10:27:16 -0700 Subject: [PATCH 219/407] magic number 100 changed in Audio.cpp --- interface/src/Audio.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index ddd2cf799a..a4ba64824b 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -54,6 +54,8 @@ static const int APPROXIMATELY_30_SECONDS_OF_AUDIO_PACKETS = (int)(30.0f * 1000. // Mute icon configration static const int MUTE_ICON_SIZE = 24; +static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 100; + Audio::Audio(QObject* parent) : AbstractAudioInterface(parent), @@ -70,13 +72,8 @@ Audio::Audio(QObject* parent) : _loopbackOutputDevice(NULL), _proceduralAudioOutput(NULL), _proceduralOutputDevice(NULL), - - // NOTE: Be very careful making changes to the initializers of these ring buffers. There is a known problem with some - // Mac audio devices that slowly introduce additional delay in the audio device because they play out audio slightly - // slower than real time (or at least the desired sample rate). If you increase the size of the ring buffer, then it - // this delay will slowly add up and the longer someone runs, they more delayed their audio will be. _inputRingBuffer(0), - _receivedAudioStream(0, 100, true, 0, 0, true), + _receivedAudioStream(0, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, true, 0, 0, true), _isStereoInput(false), _averagedLatency(0.0), _lastInputLoudness(0), From 77dad6fe65b88063862e8dcc3e40bc696b79af92 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 5 Aug 2014 11:00:27 -0700 Subject: [PATCH 220/407] change to fix Mac linker error --- interface/src/Audio.cpp | 5 +++-- libraries/audio/src/MixedProcessedAudioStream.cpp | 4 ++-- libraries/audio/src/MixedProcessedAudioStream.h | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index a4ba64824b..1af76c3342 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1589,8 +1589,9 @@ void Audio::renderLineStrip(const float* color, int x, int y, int n, int offset, void Audio::outputFormatChanged() { - _outputFrameSize = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * _outputFormat.channelCount() * _outputFormat.sampleRate() / _desiredOutputFormat.sampleRate(); - _receivedAudioStream.outputFormatChanged(_outputFormat); + int outputFormatChannelCountTimesSampleRate = _outputFormat.channelCount() * _outputFormat.sampleRate(); + _outputFrameSize = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * outputFormatChannelCountTimesSampleRate / _desiredOutputFormat.sampleRate(); + _receivedAudioStream.outputFormatChanged(outputFormatChannelCountTimesSampleRate); } bool Audio::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo) { diff --git a/libraries/audio/src/MixedProcessedAudioStream.cpp b/libraries/audio/src/MixedProcessedAudioStream.cpp index 582456739e..49990dcd22 100644 --- a/libraries/audio/src/MixedProcessedAudioStream.cpp +++ b/libraries/audio/src/MixedProcessedAudioStream.cpp @@ -16,8 +16,8 @@ MixedProcessedAudioStream ::MixedProcessedAudioStream (int numFrameSamples, int { } -void MixedProcessedAudioStream::outputFormatChanged(const QAudioFormat& outputFormat) { - _outputFormatChannelsTimesSampleRate = outputFormat.channelCount() * outputFormat.sampleRate(); +void MixedProcessedAudioStream::outputFormatChanged(int outputFormatChannelCountTimesSampleRate) { + _outputFormatChannelsTimesSampleRate = outputFormatChannelCountTimesSampleRate; int deviceOutputFrameSize = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * _outputFormatChannelsTimesSampleRate / SAMPLE_RATE; _ringBuffer.resizeForFrameSize(deviceOutputFrameSize); } diff --git a/libraries/audio/src/MixedProcessedAudioStream.h b/libraries/audio/src/MixedProcessedAudioStream.h index e624903b88..5a5b73115d 100644 --- a/libraries/audio/src/MixedProcessedAudioStream.h +++ b/libraries/audio/src/MixedProcessedAudioStream.h @@ -12,7 +12,6 @@ #ifndef hifi_MixedProcessedAudioStream_h #define hifi_MixedProcessedAudioStream_h -#include #include "InboundAudioStream.h" class MixedProcessedAudioStream : public InboundAudioStream { @@ -20,12 +19,13 @@ class MixedProcessedAudioStream : public InboundAudioStream { public: MixedProcessedAudioStream (int numFrameSamples, int numFramesCapacity, bool dynamicJitterBuffers, int staticDesiredJitterBufferFrames, int maxFramesOverDesired, bool useStDevForJitterCalc); - void outputFormatChanged(const QAudioFormat& outputFormat); - signals: void processSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer); +public: + void outputFormatChanged(int outputFormatChannelCountTimesSampleRate); + protected: int parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples); int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples); From c42fc15999aa853f08a4bfc7178e0ea3be8ca2a1 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 5 Aug 2014 11:13:15 -0700 Subject: [PATCH 221/407] Use back face culling on the heightfields. --- interface/src/MetavoxelSystem.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 666a3336ac..7aa6bc4080 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -359,9 +359,9 @@ void HeightfieldBuffer::render() { int nextLineIndex = (i + 1) * sizeWithSkirt; for (int j = 0; j < rows; j++) { *index++ = lineIndex + j; - *index++ = lineIndex + j + 1; - *index++ = nextLineIndex + j + 1; *index++ = nextLineIndex + j; + *index++ = nextLineIndex + j + 1; + *index++ = lineIndex + j + 1; } } @@ -405,6 +405,7 @@ QHash HeightfieldBuffer::_bufferPairs; void HeightfieldPreview::render(const glm::vec3& translation, float scale) const { glDisable(GL_BLEND); + glEnable(GL_CULL_FACE); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_EQUAL, 0.0f); @@ -431,6 +432,7 @@ void HeightfieldPreview::render(const glm::vec3& translation, float scale) const glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_ALPHA_TEST); + glDisable(GL_CULL_FACE); glEnable(GL_BLEND); } @@ -737,6 +739,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox _pointProgram.release(); + glEnable(GL_CULL_FACE); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_EQUAL, 0.0f); @@ -756,6 +759,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_ALPHA_TEST); + glDisable(GL_CULL_FACE); glEnable(GL_BLEND); } From 84c517c073f19bdcde327c4914d3d7009fc732b4 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 5 Aug 2014 11:57:34 -0700 Subject: [PATCH 222/407] tweaked starve behavior of InboundAudioStream --- interface/src/Audio.cpp | 8 +-- libraries/audio/src/InboundAudioStream.cpp | 62 +++++++++------------- libraries/audio/src/InboundAudioStream.h | 6 +-- 3 files changed, 29 insertions(+), 47 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 1af76c3342..fe2ac4b2a0 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1747,18 +1747,12 @@ float Audio::getInputRingBufferMsecsAvailable() const { } qint64 Audio::AudioOutputIODevice::readData(char * data, qint64 maxSize) { - MixedProcessedAudioStream& receivedAUdioStream = _parent._receivedAudioStream; - const QAudioOutput* audioOutput = _parent._audioOutput; - if (audioOutput->bytesFree() == audioOutput->bufferSize()) { - receivedAUdioStream.setToStarved(); - } - int samplesRequested = maxSize / sizeof(int16_t); int samplesPopped; int bytesWritten; - if ((samplesPopped = receivedAUdioStream.popSamples(samplesRequested, false, false)) > 0) { + if ((samplesPopped = receivedAUdioStream.popSamples(samplesRequested, false)) > 0) { AudioRingBuffer::ConstIterator lastPopOutput = receivedAUdioStream.getLastPopOutput(); lastPopOutput.readSamples((int16_t*)data, samplesPopped); bytesWritten = samplesPopped * sizeof(int16_t); diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 4b76aaeeb5..0cd9be4a18 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -137,7 +137,7 @@ int InboundAudioStream::parseData(const QByteArray& packet) { return readBytes; } -int InboundAudioStream::popSamples(int maxSamples, bool allOrNothing, bool starveOnFail) { +int InboundAudioStream::popSamples(int maxSamples, bool allOrNothing, bool starveIfNoSamplesPopped) { int samplesPopped = 0; int samplesAvailable = _ringBuffer.samplesAvailable(); if (_isStarved) { @@ -146,30 +146,27 @@ int InboundAudioStream::popSamples(int maxSamples, bool allOrNothing, bool starv _lastPopSucceeded = false; } else { if (samplesAvailable >= maxSamples) { - // we have enough samples to pop, so we're good to mix + // we have enough samples to pop, so we're good to pop popSamplesNoCheck(maxSamples); samplesPopped = maxSamples; - + } else if (!allOrNothing && samplesAvailable > 0) { + // we don't have the requested number of samples, but we do have some + // samples available, so pop all those (except in all-or-nothing mode) + popSamplesNoCheck(samplesAvailable); + samplesPopped = samplesAvailable; } else { - // we don't have enough frames, so set this stream to starve - // if starveOnFail is true - if (starveOnFail) { - starved(); + // we can't pop any samples. set this stream to starved if needed + if (starveIfNoSamplesPopped) { + setToStarved(); _consecutiveNotMixedCount++; } - - if (!allOrNothing && samplesAvailable > 0) { - popSamplesNoCheck(samplesAvailable); - samplesPopped = samplesAvailable; - } else { - _lastPopSucceeded = false; - } + _lastPopSucceeded = false; } } return samplesPopped; } -int InboundAudioStream::popFrames(int maxFrames, bool allOrNothing, bool starveOnFail) { +int InboundAudioStream::popFrames(int maxFrames, bool allOrNothing, bool starveIfNoFramesPopped) { int framesPopped = 0; int framesAvailable = _ringBuffer.framesAvailable(); if (_isStarved) { @@ -178,24 +175,21 @@ int InboundAudioStream::popFrames(int maxFrames, bool allOrNothing, bool starveO _lastPopSucceeded = false; } else { if (framesAvailable >= maxFrames) { - // we have enough samples to pop, so we're good to mix + // we have enough frames to pop, so we're good to pop popSamplesNoCheck(maxFrames * _ringBuffer.getNumFrameSamples()); framesPopped = maxFrames; - + } else if (!allOrNothing && framesAvailable > 0) { + // we don't have the requested number of frames, but we do have some + // frames available, so pop all those (except in all-or-nothing mode) + popSamplesNoCheck(framesAvailable * _ringBuffer.getNumFrameSamples()); + framesPopped = framesAvailable; } else { - // we don't have enough frames, so set this stream to starve - // if starveOnFail is true - if (starveOnFail) { - starved(); - _consecutiveNotMixedCount++; - } - - if (!allOrNothing && framesAvailable > 0) { - popSamplesNoCheck(framesAvailable * _ringBuffer.getNumFrameSamples()); - framesPopped = framesAvailable; - } else { - _lastPopSucceeded = false; + // we can't pop any frames. set this stream to starved if needed + if (starveIfNoFramesPopped) { + setToStarved(); + _consecutiveNotMixedCount = 1; } + _lastPopSucceeded = false; } } return framesPopped; @@ -220,16 +214,12 @@ void InboundAudioStream::framesAvailableChanged() { } void InboundAudioStream::setToStarved() { - starved(); - if (_ringBuffer.framesAvailable() >= _desiredJitterBufferFrames) { - _isStarved = false; - } -} - -void InboundAudioStream::starved() { _isStarved = true; _consecutiveNotMixedCount = 0; _starveCount++; + // if we have more than the desired frames when setToStarved() is called, then we'll immediately + // be considered refilled. in that case, there's no need to set _isStarved to true. + _isStarved = (_ringBuffer.framesAvailable() < _desiredJitterBufferFrames); } void InboundAudioStream::setDynamicJitterBuffers(bool dynamicJitterBuffers) { diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index 590421e50f..b65d5c5de0 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -63,8 +63,8 @@ public: virtual int parseData(const QByteArray& packet); - int popFrames(int maxFrames, bool allOrNothing, bool starveOnFail = true); - int popSamples(int maxSamples, bool allOrNothing, bool starveOnFail = true); + int popFrames(int maxFrames, bool allOrNothing, bool starveIfNoFramesPopped = true); + int popSamples(int maxSamples, bool allOrNothing, bool starveIfNoSamplesPopped = true); bool lastPopSucceeded() const { return _lastPopSucceeded; }; const AudioRingBuffer::ConstIterator& getLastPopOutput() const { return _lastPopOutput; } @@ -111,8 +111,6 @@ public: int getPacketsReceived() const { return _incomingSequenceNumberStats.getReceived(); } private: - void starved(); - void frameReceivedUpdateTimingStats(); int clampDesiredJitterBufferFramesValue(int desired) const; From 9999c88d84276e869975333a5961e0b00ba3ba68 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 5 Aug 2014 12:01:47 -0700 Subject: [PATCH 223/407] Added Referential getters + fixed stupid unpacking bug --- libraries/avatars/src/Referential.cpp | 2 +- libraries/avatars/src/Referential.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/avatars/src/Referential.cpp b/libraries/avatars/src/Referential.cpp index 12a0f59186..722c54cbe3 100644 --- a/libraries/avatars/src/Referential.cpp +++ b/libraries/avatars/src/Referential.cpp @@ -30,7 +30,7 @@ Referential::Referential(const unsigned char*& sourceBuffer, AvatarData* avatar) _isValid(false), _avatar(avatar) { - sourceBuffer += unpack(sourceBuffer); + sourceBuffer += unpackReferential(sourceBuffer); } Referential::~Referential() { diff --git a/libraries/avatars/src/Referential.h b/libraries/avatars/src/Referential.h index 713b6a028f..9353ea0871 100644 --- a/libraries/avatars/src/Referential.h +++ b/libraries/avatars/src/Referential.h @@ -33,6 +33,11 @@ public: bool isValid() const { return _isValid; } bool hasExtraData() const { return !_extraDataBuffer.isEmpty(); } + glm::vec3 getTranslation() const { return _translation; } + glm::quat getRotation() const { return _rotation; } + float getScale() const {return _scale; } + QByteArray getExtraData() const { return _extraDataBuffer; } + virtual void update() {} int packReferential(unsigned char* destinationBuffer) const; int unpackReferential(const unsigned char* sourceBuffer); From 283beab05daab56a7aac116e708adfaa3e1369ea Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 5 Aug 2014 12:03:16 -0700 Subject: [PATCH 224/407] ModelReferential copy constructor --- interface/src/avatar/ModelReferential.cpp | 38 ++++++++++++++++------- interface/src/avatar/ModelReferential.h | 2 +- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/interface/src/avatar/ModelReferential.cpp b/interface/src/avatar/ModelReferential.cpp index 8f1360a705..fb80d7f2ef 100644 --- a/interface/src/avatar/ModelReferential.cpp +++ b/interface/src/avatar/ModelReferential.cpp @@ -16,8 +16,26 @@ #include "ModelReferential.h" -ModelReferential::ModelReferential(Referential* referential, AvatarData* avatar) : Referential(MODEL, avatar) { - +ModelReferential::ModelReferential(Referential* referential, ModelTree* tree, AvatarData* avatar) : + Referential(MODEL, avatar), + _tree(tree) { + unpackExtraData(reinterpret_cast(referential->getExtraData().data()), + referential->getExtraData().size()); + if (!isValid()) { + qDebug() << "ModelReferential::copyConstructo(): Not Valid"; + return; + } + + const ModelItem* item = _tree->findModelByID(_modelID); + if (item != NULL) { + _refScale = item->getRadius(); + _refRotation = item->getModelRotation(); + _refPosition = item->getPosition() * (float)TREE_SCALE; + } + + _scale = referential->getScale(); + _rotation = referential->getRotation(); + _translation = referential->getTranslation(); } ModelReferential::ModelReferential(uint32_t modelID, ModelTree* tree, AvatarData* avatar) : @@ -26,8 +44,8 @@ _modelID(modelID), _tree(tree) { const ModelItem* item = _tree->findModelByID(_modelID); - if (!_isValid || item == NULL) { - qDebug() << "Not Validd"; + if (!isValid() || item == NULL) { + qDebug() << "ModelReferential::constructor(): Not Valid"; _isValid = false; return; } @@ -44,9 +62,8 @@ _tree(tree) void ModelReferential::update() { const ModelItem* item = _tree->findModelByID(_modelID); - if (item == NULL || _avatar == NULL) { - qDebug() << "Not Valid"; - _isValid = false; + if (!isValid() || item == NULL || _avatar == NULL) { + //qDebug() << "ModelReferential::update(): Not Valid"; return; } @@ -58,13 +75,12 @@ void ModelReferential::update() { } if (item->getModelRotation() != _refRotation) { _refRotation = item->getModelRotation(); - _avatar->setOrientation(_refRotation * _rotation); + _avatar->setOrientation(_refRotation * _rotation, true); somethingChanged = true; } if (item->getPosition() != _refPosition || somethingChanged) { _refPosition = item->getPosition(); - _avatar->setPosition(_refPosition * (float)TREE_SCALE + _refRotation * (_translation * _refScale)); - //qDebug() << "Ref: " << item->getLastUpdated() << " " << item->getLastEdited(); + _avatar->setPosition(_refPosition * (float)TREE_SCALE + _refRotation * (_translation * _refScale), true); somethingChanged = true; } } @@ -87,7 +103,7 @@ JointReferential::JointReferential(uint32_t jointIndex, uint32_t modelID, ModelT const ModelItem* item = _tree->findModelByID(_modelID); const Model* model = getModel(item); if (!_isValid || model == NULL || _jointIndex >= model->getJointStateCount()) { - qDebug() << "Not Validd"; + qDebug() << "Not Valid"; _isValid = false; return; } diff --git a/interface/src/avatar/ModelReferential.h b/interface/src/avatar/ModelReferential.h index 806e4edfcb..53170bcf41 100644 --- a/interface/src/avatar/ModelReferential.h +++ b/interface/src/avatar/ModelReferential.h @@ -19,7 +19,7 @@ class Model; class ModelReferential : public Referential { public: - ModelReferential(Referential* ref, AvatarData* avatar); + ModelReferential(Referential* ref, ModelTree* tree, AvatarData* avatar); ModelReferential(uint32_t modelID, ModelTree* tree, AvatarData* avatar); virtual void update(); From 39a74cbc288500ff1087b8b7b4d3c3a2986337e3 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 5 Aug 2014 12:03:53 -0700 Subject: [PATCH 225/407] Few modifications to how avatars update their positions --- interface/src/avatar/Avatar.cpp | 16 +++++++------ interface/src/avatar/MyAvatar.cpp | 5 ++-- libraries/avatars/src/AvatarData.cpp | 35 +++++++++++++++++++++------- libraries/avatars/src/AvatarData.h | 6 ++--- 4 files changed, 42 insertions(+), 20 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 21d5e65a15..d4df5b21f0 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -182,10 +182,12 @@ void Avatar::simulate(float deltaTime) { } if (_referential) { if (_referential->hasExtraData()) { + qDebug() << "Has extra data"; switch (_referential->type()) { case Referential::MODEL: qDebug() << "[DEBUG] Switching to the right referential"; - _referential = new ModelReferential(_referential, this); + _referential = new ModelReferential(_referential, + Application::getInstance()->getModels()->getTree(), this); break; default: qDebug() << "Non handled referential type"; @@ -234,6 +236,12 @@ static TextRenderer* textRenderer(TextRendererType type) { } void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { + // make sure we have the right position + _skeletonModel.setTranslation(getPosition()); + static const glm::quat refOrientation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); + _skeletonModel.setRotation(getOrientation() * refOrientation); + const float MODEL_SCALE = 0.0006f; + _skeletonModel.setScale(glm::vec3(1.0f, 1.0f, 1.0f) * getScale() * MODEL_SCALE); if (glm::distance(Application::getInstance()->getAvatar()->getPosition(), _position) < 10.0f) { @@ -456,12 +464,6 @@ void Avatar::renderBody(RenderMode renderMode, float glowLevel) { return; } - // make sure we have the right position - _skeletonModel.setTranslation(getPosition()); - static const glm::quat refOrientation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - _skeletonModel.setRotation(getOrientation() * refOrientation); - const float MODEL_SCALE = 0.0006f; - _skeletonModel.setScale(glm::vec3(1.0f, 1.0f, 1.0f) * getScale() * MODEL_SCALE); _skeletonModel.render(1.0f, modelRenderMode, Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows)); renderAttachments(renderMode); getHand()->render(false, modelRenderMode); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 3428f73ee7..7c899fcc0a 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -128,7 +128,7 @@ void MyAvatar::update(float deltaTime) { simulate(deltaTime); - bool WANT_REFERENTIAL = true; + bool WANT_REFERENTIAL = false; if (WANT_REFERENTIAL) { int id = 12340; const ModelItem* item = Application::getInstance()->getModels()->getTree()->findModelByID(id); @@ -138,7 +138,8 @@ void MyAvatar::update(float deltaTime) { } else if (item != NULL) { const Model* model = Application::getInstance()->getModels()->getModelForModelItem(*item); if (model != NULL) { - _referential = new ModelReferential(id, Application::getInstance()->getModels()->getTree(), this); + _referential = new ModelReferential(id, + Application::getInstance()->getModels()->getTree(), this); } } } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 67977996b8..1bcc46639e 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -73,6 +73,29 @@ const glm::vec3& AvatarData::getPosition() { return _position; } +void AvatarData::setPosition(const glm::vec3 position, bool overideReferential) { + if (!_referential || overideReferential) { + _position = position; + } +} + +glm::quat AvatarData::getOrientation() const { + if (_referential) { + _referential->update(); + } + + return glm::quat(glm::radians(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll))); +} + +void AvatarData::setOrientation(const glm::quat& orientation, bool overideReferential) { + if (!_referential || overideReferential) { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(orientation)); + _bodyPitch = eulerAngles.x; + _bodyYaw = eulerAngles.y; + _bodyRoll = eulerAngles.z; + } +} + glm::vec3 AvatarData::getHandPosition() const { return getOrientation() * _handPosition + _position; } @@ -402,8 +425,9 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { // Referential if (hasReferential) { - qDebug() << "Has referencial: " << hasReferential; + const unsigned char* start = sourceBuffer; if (_referential == NULL) { + qDebug() << "New referential"; _referential = new Referential(sourceBuffer, this); } else { Referential* ref = new Referential(sourceBuffer, this); @@ -415,6 +439,8 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { delete ref; } } + //qDebug() << "Read " << sourceBuffer - start << " bytes."; + _referential->update(); } else if (_referential != NULL) { qDebug() << "Erasing referencial"; delete _referential; @@ -851,13 +877,6 @@ void AvatarData::setClampedTargetScale(float targetScale) { qDebug() << "Changed scale to " << _targetScale; } -void AvatarData::setOrientation(const glm::quat& orientation) { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(orientation)); - _bodyPitch = eulerAngles.x; - _bodyYaw = eulerAngles.y; - _bodyRoll = eulerAngles.z; -} - void AvatarData::sendIdentityPacket() { QByteArray identityPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarIdentity); identityPacket.append(identityByteArray()); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index c32faba977..a0aeb94670 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -144,7 +144,7 @@ public: const QUuid& getSessionUUID() { return _sessionUUID; } const glm::vec3& getPosition(); - void setPosition(const glm::vec3 position) { _position = position; } + void setPosition(const glm::vec3 position, bool overideReferential = false); glm::vec3 getHandPosition() const; void setHandPosition(const glm::vec3& handPosition); @@ -167,8 +167,8 @@ public: float getBodyRoll() const { return _bodyRoll; } void setBodyRoll(float bodyRoll) { _bodyRoll = bodyRoll; } - glm::quat getOrientation() const { return glm::quat(glm::radians(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll))); } - void setOrientation(const glm::quat& orientation); + glm::quat getOrientation() const; + void setOrientation(const glm::quat& orientation, bool overideReferential = false); glm::quat getHeadOrientation() const { return _headData->getOrientation(); } void setHeadOrientation(const glm::quat& orientation) { _headData->setOrientation(orientation); } From 212316aed63475438d6e947c2fefce9b6282e3af Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 5 Aug 2014 12:14:10 -0700 Subject: [PATCH 226/407] moved connect to Audio constructor --- interface/src/Audio.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index fe2ac4b2a0..2cba22b630 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -119,14 +119,14 @@ Audio::Audio(QObject* parent) : memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); // Create the noise sample array _noiseSampleFrames = new float[NUMBER_OF_NOISE_SAMPLE_FRAMES]; + + connect(&_receivedAudioStream, &MixedProcessedAudioStream::processSamples, this, &Audio::processReceivedAudioStreamSamples, Qt::DirectConnection); } void Audio::init(QGLWidget *parent) { _micTextureId = parent->bindTexture(QImage(Application::resourcesPath() + "images/mic.svg")); _muteTextureId = parent->bindTexture(QImage(Application::resourcesPath() + "images/mic-mute.svg")); _boxTextureId = parent->bindTexture(QImage(Application::resourcesPath() + "images/audio-box.svg")); - - connect(&_receivedAudioStream, &MixedProcessedAudioStream::processSamples, this, &Audio::processReceivedAudioStreamSamples, Qt::DirectConnection); } void Audio::reset() { From 96302ca271bdf0c66d29e29756b2db4d9f99e1b4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 5 Aug 2014 14:10:39 -0700 Subject: [PATCH 227/407] Provide for custom expansion according to attribute, tweak spanner attribute. --- .../metavoxels/src/AttributeRegistry.cpp | 47 +++++++++++++++++++ libraries/metavoxels/src/AttributeRegistry.h | 6 +++ libraries/metavoxels/src/MetavoxelData.cpp | 30 +++--------- libraries/metavoxels/src/MetavoxelData.h | 2 + 4 files changed, 61 insertions(+), 24 deletions(-) diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 40b6195ada..9f656ef5d3 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -242,6 +242,30 @@ bool Attribute::metavoxelRootsEqual(const MetavoxelNode& firstRoot, const Metavo return firstRoot.deepEquals(this, secondRoot, minimum, size, lod); } +MetavoxelNode* Attribute::expandMetavoxelRoot(const MetavoxelNode& root) { + AttributePointer attribute(this); + MetavoxelNode* newParent = new MetavoxelNode(attribute); + for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { + MetavoxelNode* newChild = new MetavoxelNode(attribute); + newParent->setChild(i, newChild); + int index = MetavoxelNode::getOppositeChildIndex(i); + if (root.isLeaf()) { + newChild->setChild(index, new MetavoxelNode(root.getAttributeValue(attribute))); + } else { + MetavoxelNode* grandchild = root.getChild(i); + grandchild->incrementReferenceCount(); + newChild->setChild(index, grandchild); + } + for (int j = 1; j < MetavoxelNode::CHILD_COUNT; j++) { + MetavoxelNode* newGrandchild = new MetavoxelNode(attribute); + newChild->setChild((index + j) % MetavoxelNode::CHILD_COUNT, newGrandchild); + } + newChild->mergeChildren(attribute); + } + newParent->mergeChildren(attribute); + return newParent; +} + FloatAttribute::FloatAttribute(const QString& name, float defaultValue) : SimpleInlineAttribute(name, defaultValue) { } @@ -809,6 +833,29 @@ bool SharedObjectSetAttribute::deepEqual(void* first, void* second) const { return setsEqual(decodeInline(first), decodeInline(second)); } +MetavoxelNode* SharedObjectSetAttribute::expandMetavoxelRoot(const MetavoxelNode& root) { + AttributePointer attribute(this); + MetavoxelNode* newParent = new MetavoxelNode(attribute); + for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { + MetavoxelNode* newChild = new MetavoxelNode(root.getAttributeValue(attribute)); + newParent->setChild(i, newChild); + if (root.isLeaf()) { + continue; + } + MetavoxelNode* grandchild = root.getChild(i); + grandchild->incrementReferenceCount(); + int index = MetavoxelNode::getOppositeChildIndex(i); + newChild->setChild(index, grandchild); + for (int j = 1; j < MetavoxelNode::CHILD_COUNT; j++) { + MetavoxelNode* newGrandchild = new MetavoxelNode(attribute); + newChild->setChild((index + j) % MetavoxelNode::CHILD_COUNT, newGrandchild); + } + newChild->mergeChildren(attribute); + } + newParent->mergeChildren(attribute); + return newParent; +} + bool SharedObjectSetAttribute::merge(void*& parent, void* children[], bool postRead) const { for (int i = 0; i < MERGE_COUNT; i++) { if (!decodeInline(children[i]).isEmpty()) { diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 767ebf6527..5d973341ad 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -238,6 +238,10 @@ public: virtual bool metavoxelRootsEqual(const MetavoxelNode& firstRoot, const MetavoxelNode& secondRoot, const glm::vec3& minimum, float size, const MetavoxelLOD& lod); + /// Expands the specified root, doubling its size in each dimension. + /// \return a new node representing the result + virtual MetavoxelNode* expandMetavoxelRoot(const MetavoxelNode& root); + /// Merges the value of a parent and its children. /// \param postRead whether or not the merge is happening after a read /// \return whether or not the children and parent values are all equal @@ -511,6 +515,8 @@ public: virtual bool deepEqual(void* first, void* second) const; + virtual MetavoxelNode* expandMetavoxelRoot(const MetavoxelNode& root); + virtual bool merge(void*& parent, void* children[], bool postRead = false) const; virtual AttributeValue inherit(const AttributeValue& parentValue) const; diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index a0b1f1efb0..3607441461 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -512,33 +512,11 @@ void MetavoxelData::set(const glm::vec3& minimum, const MetavoxelData& data, boo } } -static int getOppositeIndex(int index) { - return index ^ MAXIMUM_FLAG_MASK; -} - void MetavoxelData::expand() { for (QHash::iterator it = _roots.begin(); it != _roots.end(); it++) { - MetavoxelNode* newParent = new MetavoxelNode(it.key()); - for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { - MetavoxelNode* newChild = new MetavoxelNode(it.key()); - newParent->setChild(i, newChild); - int index = getOppositeIndex(i); - if (it.value()->isLeaf()) { - newChild->setChild(index, new MetavoxelNode(it.value()->getAttributeValue(it.key()))); - } else { - MetavoxelNode* grandchild = it.value()->getChild(i); - grandchild->incrementReferenceCount(); - newChild->setChild(index, grandchild); - } - for (int j = 1; j < MetavoxelNode::CHILD_COUNT; j++) { - MetavoxelNode* newGrandchild = new MetavoxelNode(it.key()); - newChild->setChild((index + j) % MetavoxelNode::CHILD_COUNT, newGrandchild); - } - newChild->mergeChildren(it.key()); - } - newParent->mergeChildren(it.key()); + MetavoxelNode* newNode = it.key()->expandMetavoxelRoot(*it.value()); it.value()->decrementReferenceCount(it.key()); - it.value() = newParent; + it.value() = newNode; } _size *= 2.0f; } @@ -823,6 +801,10 @@ void MetavoxelStreamState::setMinimum(const glm::vec3& lastMinimum, int index) { minimum = getNextMinimum(lastMinimum, size, index); } +int MetavoxelNode::getOppositeChildIndex(int index) { + return index ^ MAXIMUM_FLAG_MASK; +} + MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue, const MetavoxelNode* copyChildren) : _referenceCount(1) { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 24eb09763c..9e5b2f04d1 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -197,6 +197,8 @@ public: static const int CHILD_COUNT = 8; + static int getOppositeChildIndex(int index); + MetavoxelNode(const AttributeValue& attributeValue, const MetavoxelNode* copyChildren = NULL); MetavoxelNode(const AttributePointer& attribute, const MetavoxelNode* copy); From 4696832ec6e072eb0d1b1e3eb79734e3322afd98 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 5 Aug 2014 15:13:50 -0700 Subject: [PATCH 228/407] Compute heightfield normals from adjacent values in vertex shader. --- .../resources/shaders/metavoxel_heightfield.vert | 12 ++++++++++-- interface/src/MetavoxelSystem.cpp | 5 +++++ interface/src/MetavoxelSystem.h | 2 ++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/interface/resources/shaders/metavoxel_heightfield.vert b/interface/resources/shaders/metavoxel_heightfield.vert index 3cf43e87cd..cc4f68e9e0 100644 --- a/interface/resources/shaders/metavoxel_heightfield.vert +++ b/interface/resources/shaders/metavoxel_heightfield.vert @@ -14,18 +14,26 @@ // the height texture uniform sampler2D heightMap; +// the distance between height points in texture space +uniform float heightScale; + // the interpolated normal varying vec4 normal; void main(void) { // transform and store the normal for interpolation - normal = normalize(gl_ModelViewMatrix * vec4(0.0, 1.0, 0.0, 0.0)); + vec2 heightCoord = gl_MultiTexCoord0.st; + float deltaX = texture2D(heightMap, heightCoord - vec2(heightScale, 0.0)).r - + texture2D(heightMap, heightCoord + vec2(heightScale, 0.0)).r; + float deltaZ = texture2D(heightMap, heightCoord - vec2(0.0, heightScale)).r - + texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r; + normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0)); // pass along the texture coordinates gl_TexCoord[0] = gl_MultiTexCoord0; // add the height to the position - float height = texture2D(heightMap, gl_MultiTexCoord0.st).r; + float height = texture2D(heightMap, heightCoord).r; gl_Position = gl_ModelViewProjectionMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0)); // the zero height should be invisible diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 7aa6bc4080..f66d71070a 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -388,6 +388,9 @@ void HeightfieldBuffer::render() { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _colorTextureID); + DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue( + DefaultMetavoxelRendererImplementation::getHeightScaleLocation(), 1.0f / _heightSize); + glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); glBindTexture(GL_TEXTURE_2D, 0); @@ -470,6 +473,7 @@ void DefaultMetavoxelRendererImplementation::init() { _heightfieldProgram.bind(); _heightfieldProgram.setUniformValue("heightMap", 0); _heightfieldProgram.setUniformValue("diffuseMap", 1); + _heightScaleLocation = _heightfieldProgram.uniformLocation("heightScale"); _heightfieldProgram.release(); } } @@ -766,6 +770,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox ProgramObject DefaultMetavoxelRendererImplementation::_pointProgram; int DefaultMetavoxelRendererImplementation::_pointScaleLocation; ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldProgram; +int DefaultMetavoxelRendererImplementation::_heightScaleLocation; static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { GLdouble coefficients[] = { x, y, z, w }; diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index abcc929156..e7ee0d2c18 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -191,6 +191,7 @@ public: static void init(); static ProgramObject& getHeightfieldProgram() { return _heightfieldProgram; } + static int getHeightScaleLocation() { return _heightScaleLocation; } Q_INVOKABLE DefaultMetavoxelRendererImplementation(); @@ -204,6 +205,7 @@ private: static int _pointScaleLocation; static ProgramObject _heightfieldProgram; + static int _heightScaleLocation; }; /// Base class for spanner renderers; provides clipping. From b360b6c55ddf2ee5822e9a3e7d6894126f6db3ab Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 5 Aug 2014 17:07:03 -0700 Subject: [PATCH 229/407] PR cleanup + JS API --- examples/sit.js | 19 +++++-- interface/src/Application.cpp | 2 +- interface/src/avatar/Avatar.cpp | 13 +++-- interface/src/avatar/Avatar.h | 2 +- interface/src/avatar/ModelReferential.cpp | 60 +++++++++++++++++------ interface/src/avatar/ModelReferential.h | 4 +- interface/src/avatar/MyAvatar.cpp | 47 +++++++++++------- interface/src/avatar/MyAvatar.h | 6 ++- libraries/avatars/src/AvatarData.cpp | 35 +++++++------ libraries/avatars/src/AvatarData.h | 3 ++ libraries/avatars/src/Referential.cpp | 12 +++-- libraries/avatars/src/Referential.h | 1 + libraries/models/CMakeLists.txt | 1 - libraries/models/src/ModelItem.h | 1 - 14 files changed, 139 insertions(+), 67 deletions(-) diff --git a/examples/sit.js b/examples/sit.js index 0f4b199855..072471aa30 100644 --- a/examples/sit.js +++ b/examples/sit.js @@ -89,7 +89,12 @@ var sittingDownAnimation = function(deltaTime) { var pos = { x: startPosition.x - 0.3 * factor, y: startPosition.y - 0.5 * factor, z: startPosition.z}; MyAvatar.position = pos; - } + } else { + Script.update.disconnect(sittingDownAnimation); + if (seat.model) { + MyAvatar.setModelReferential(seat.model.id); + } + } } var standingUpAnimation = function(deltaTime) { @@ -103,7 +108,10 @@ var standingUpAnimation = function(deltaTime) { var pos = { x: startPosition.x + 0.3 * (passedTime/animationLenght), y: startPosition.y + 0.5 * (passedTime/animationLenght), z: startPosition.z}; MyAvatar.position = pos; - } + } else { + Script.update.disconnect(standingUpAnimation); + + } } var goToSeatAnimation = function(deltaTime) { @@ -147,7 +155,8 @@ function standUp() { print("standUp sitting status: " + Settings.getValue(sittingSettingsHandle, false)); passedTime = 0.0; startPosition = MyAvatar.position; - try{ + MyAvatar.clearReferential(); + try{ Script.update.disconnect(sittingDownAnimation); } catch (e){} Script.update.connect(standingUpAnimation); @@ -197,8 +206,10 @@ Controller.mousePressEvent.connect(function(event) { var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); if (clickedOverlay == sitDownButton) { + seat.model = null; sitDown(); } else if (clickedOverlay == standUpButton) { + seat.model = null; standUp(); } else { var pickRay = Camera.computePickRay(event.x, event.y); @@ -214,6 +225,7 @@ Controller.mousePressEvent.connect(function(event) { model.properties.sittingPoints[i].indicator.position, model.properties.sittingPoints[i].indicator.scale / 2)) { clickedOnSeat = true; + seat.model = model; seat.position = model.properties.sittingPoints[i].indicator.position; seat.rotation = model.properties.sittingPoints[i].indicator.orientation; } @@ -355,6 +367,7 @@ Script.update.connect(update); Controller.keyPressEvent.connect(keyPressEvent); Script.scriptEnding.connect(function() { + MyAvatar.clearReferential(); for (var i = 0; i < pose.length; i++){ MyAvatar.clearJointData(pose[i].joint); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1ae29fcd88..6ae2452c41 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2176,7 +2176,7 @@ void Application::update(float deltaTime) { // Update _viewFrustum with latest camera and view frustum data... // NOTE: we get this from the view frustum, to make it simpler, since the - // loadViewFrumstum() methodill get the correct details from the camera + // loadViewFrumstum() method will get the correct details from the camera // We could optimize this to not actually load the viewFrustum, since we don't // actually need to calculate the view frustum planes to send these details // to the server. diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index d4df5b21f0..f4ed442aeb 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -182,15 +182,20 @@ void Avatar::simulate(float deltaTime) { } if (_referential) { if (_referential->hasExtraData()) { - qDebug() << "Has extra data"; + ModelTree* tree = Application::getInstance()->getModels()->getTree(); switch (_referential->type()) { case Referential::MODEL: - qDebug() << "[DEBUG] Switching to the right referential"; _referential = new ModelReferential(_referential, - Application::getInstance()->getModels()->getTree(), this); + tree, + this); + break; + case Referential::JOINT: + _referential = new JointReferential(_referential, + tree, + this); break; default: - qDebug() << "Non handled referential type"; + qDebug() << "[WARNING] Avatar::simulate(): Unknown referential type."; break; } } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 6b7408309d..555a0f6d32 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -209,7 +209,7 @@ protected: virtual void renderAttachments(RenderMode renderMode); virtual void updateJointMappings(); - + private: bool _initialized; diff --git a/interface/src/avatar/ModelReferential.cpp b/interface/src/avatar/ModelReferential.cpp index fb80d7f2ef..88a02a909b 100644 --- a/interface/src/avatar/ModelReferential.cpp +++ b/interface/src/avatar/ModelReferential.cpp @@ -22,20 +22,18 @@ ModelReferential::ModelReferential(Referential* referential, ModelTree* tree, Av unpackExtraData(reinterpret_cast(referential->getExtraData().data()), referential->getExtraData().size()); if (!isValid()) { - qDebug() << "ModelReferential::copyConstructo(): Not Valid"; + qDebug() << "ModelReferential::copyConstructor(): Not Valid"; return; } - const ModelItem* item = _tree->findModelByID(_modelID); + const ModelItem* item = _tr + ree->findModelByID(_modelID); if (item != NULL) { _refScale = item->getRadius(); _refRotation = item->getModelRotation(); _refPosition = item->getPosition() * (float)TREE_SCALE; } - - _scale = referential->getScale(); - _rotation = referential->getRotation(); - _translation = referential->getTranslation(); + update(); } ModelReferential::ModelReferential(uint32_t modelID, ModelTree* tree, AvatarData* avatar) : @@ -63,7 +61,6 @@ _tree(tree) void ModelReferential::update() { const ModelItem* item = _tree->findModelByID(_modelID); if (!isValid() || item == NULL || _avatar == NULL) { - //qDebug() << "ModelReferential::update(): Not Valid"; return; } @@ -95,6 +92,25 @@ int ModelReferential::unpackExtraData(const unsigned char *sourceBuffer, int siz return sizeof(_modelID); } +JointReferential::JointReferential(Referential* referential, ModelTree* tree, AvatarData* avatar) : + ModelReferential(referential, tree, avatar) +{ + _type = JOINT; + if (!isValid()) { + qDebug() << "JointReferential::copyConstructor(): Not Valid"; + return; + } + + const ModelItem* item = _tree->findModelByID(_modelID); + const Model* model = getModel(item); + if (!isValid() || model == NULL || _jointIndex >= model->getJointStateCount()) { + _refScale = item->getRadius(); + model->getJointRotationInWorldFrame(_jointIndex, _refRotation); + model->getJointPositionInWorldFrame(_jointIndex, _refPosition); + } + update(); +} + JointReferential::JointReferential(uint32_t jointIndex, uint32_t modelID, ModelTree* tree, AvatarData* avatar) : ModelReferential(modelID, tree, avatar), _jointIndex(jointIndex) @@ -102,8 +118,8 @@ JointReferential::JointReferential(uint32_t jointIndex, uint32_t modelID, ModelT _type = JOINT; const ModelItem* item = _tree->findModelByID(_modelID); const Model* model = getModel(item); - if (!_isValid || model == NULL || _jointIndex >= model->getJointStateCount()) { - qDebug() << "Not Valid"; + if (!isValid() || model == NULL || _jointIndex >= model->getJointStateCount()) { + qDebug() << "JointReferential::constructor(): Not Valid"; _isValid = false; return; } @@ -121,9 +137,7 @@ JointReferential::JointReferential(uint32_t jointIndex, uint32_t modelID, ModelT void JointReferential::update() { const ModelItem* item = _tree->findModelByID(_modelID); const Model* model = getModel(item); - if (model == NULL || _jointIndex >= model->getJointStateCount()) { - qDebug() << "Not Valid"; - _isValid = false; + if (!isValid() || model == NULL || _jointIndex >= model->getJointStateCount()) { return; } @@ -150,7 +164,25 @@ const Model* JointReferential::getModel(const ModelItem* item) { if (item != NULL && fbxService != NULL) { return fbxService->getModelForModelItem(*item); } - qDebug() << "No Model"; - return NULL; } + +int JointReferential::packExtraData(unsigned char* destinationBuffer) const { + unsigned char* startPosition = destinationBuffer; + destinationBuffer += ModelReferential::packExtraData(destinationBuffer); + + memcpy(destinationBuffer, &_jointIndex, sizeof(_jointIndex)); + destinationBuffer += sizeof(_jointIndex); + + return destinationBuffer - startPosition; +} + +int JointReferential::unpackExtraData(const unsigned char *sourceBuffer, int size) { + const unsigned char* startPosition = sourceBuffer; + sourceBuffer += ModelReferential::unpackExtraData(sourceBuffer, size); + + memcpy(&_jointIndex, sourceBuffer, sizeof(_jointIndex)); + sourceBuffer += sizeof(_jointIndex); + + return sourceBuffer - startPosition; +} \ No newline at end of file diff --git a/interface/src/avatar/ModelReferential.h b/interface/src/avatar/ModelReferential.h index 53170bcf41..b3a718d728 100644 --- a/interface/src/avatar/ModelReferential.h +++ b/interface/src/avatar/ModelReferential.h @@ -33,12 +33,14 @@ protected: class JointReferential : public ModelReferential { public: - JointReferential(Referential* ref); + JointReferential(Referential* ref, ModelTree* tree, AvatarData* avatar); JointReferential(uint32_t jointIndex, uint32_t modelID, ModelTree* tree, AvatarData* avatar); virtual void update(); protected: const Model* getModel(const ModelItem* item); + virtual int packExtraData(unsigned char* destinationBuffer) const; + virtual int unpackExtraData(const unsigned char* sourceBuffer, int size); uint32_t _jointIndex; }; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7c899fcc0a..a8dfe1feb6 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -109,6 +109,10 @@ void MyAvatar::reset() { } void MyAvatar::update(float deltaTime) { + if (_referential) { + _referential->update(); + } + Head* head = getHead(); head->relaxLean(deltaTime); updateFromTrackers(deltaTime); @@ -127,22 +131,6 @@ void MyAvatar::update(float deltaTime) { } simulate(deltaTime); - - bool WANT_REFERENTIAL = false; - if (WANT_REFERENTIAL) { - int id = 12340; - const ModelItem* item = Application::getInstance()->getModels()->getTree()->findModelByID(id); - if (_referential) { - PerformanceTimer perfTimer("Referential"); - _referential->update(); - } else if (item != NULL) { - const Model* model = Application::getInstance()->getModels()->getModelForModelItem(*item); - if (model != NULL) { - _referential = new ModelReferential(id, - Application::getInstance()->getModels()->getTree(), this); - } - } - } } void MyAvatar::simulate(float deltaTime) { @@ -461,9 +449,30 @@ glm::vec3 MyAvatar::getRightPalmPosition() { return rightHandPosition; } -void MyAvatar::changeReferential(Referential *ref) { - delete _referential; - _referential = ref; +void MyAvatar::clearReferential() { + changeReferential(NULL); +} + +bool MyAvatar::setModelReferential(int id) { + ModelTree* tree = Application::getInstance()->getModels()->getTree(); + changeReferential(new ModelReferential(id, tree, this)); + if (_referential->isValid()) { + return true; + } else { + changeReferential(NULL); + return false; + } +} + +bool MyAvatar::setJointReferential(int id, int jointIndex) { + ModelTree* tree = Application::getInstance()->getModels()->getTree(); + changeReferential(new JointReferential(jointIndex, id, tree, this)); + if (!_referential->isValid()) { + return true; + } else { + changeReferential(NULL); + return false; + } } void MyAvatar::setLocalGravity(glm::vec3 gravity) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 4744ca80b8..4f2802a35a 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -18,6 +18,8 @@ #include "Avatar.h" +class ModelItemID; + enum AvatarHandState { HAND_STATE_NULL = 0, @@ -149,7 +151,9 @@ public slots: glm::vec3 getLeftPalmPosition(); glm::vec3 getRightPalmPosition(); - void changeReferential(Referential* ref); + void clearReferential(); + bool setModelReferential(int id); + bool setJointReferential(int id, int jointIndex); signals: void transformChanged(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 1bcc46639e..59f9a440f0 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -425,29 +425,19 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { // Referential if (hasReferential) { - const unsigned char* start = sourceBuffer; - if (_referential == NULL) { - qDebug() << "New referential"; - _referential = new Referential(sourceBuffer, this); + Referential* ref = new Referential(sourceBuffer, this); + if (_referential == NULL || + ref->createdAt() > _referential->createdAt()) { + changeReferential(ref); } else { - Referential* ref = new Referential(sourceBuffer, this); - if (ref->createdAt() > _referential->createdAt()) { - qDebug() << "Replacing referential"; - delete _referential; - _referential = ref; - } else { - delete ref; - } + delete ref; } - //qDebug() << "Read " << sourceBuffer - start << " bytes."; _referential->update(); } else if (_referential != NULL) { - qDebug() << "Erasing referencial"; - delete _referential; - _referential = NULL; + changeReferential(NULL); } - - + + if (_headData->_isFaceshiftConnected) { float leftEyeBlink, rightEyeBlink, averageLoudness, browAudioLift; minPossibleSize += sizeof(leftEyeBlink) + sizeof(rightEyeBlink) + sizeof(averageLoudness) + sizeof(browAudioLift); @@ -569,6 +559,15 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { return sourceBuffer - startPosition; } +bool AvatarData::hasReferential() { + return _referential != NULL; +} + +void AvatarData::changeReferential(Referential *ref) { + delete _referential; + _referential = ref; +} + void AvatarData::setJointData(int index, const glm::quat& rotation) { if (index == -1) { return; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a0aeb94670..767c905322 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -289,6 +289,8 @@ public slots: void setBillboardFromNetworkReply(); void setJointMappingsFromNetworkReply(); void setSessionUUID(const QUuid& id) { _sessionUUID = id; } + bool hasReferential(); + protected: QUuid _sessionUUID; glm::vec3 _position; @@ -344,6 +346,7 @@ protected: /// Loads the joint indices, names from the FST file (if any) virtual void updateJointMappings(); + void changeReferential(Referential* ref); private: // privatize the copy constructor and assignment operator so they cannot be called diff --git a/libraries/avatars/src/Referential.cpp b/libraries/avatars/src/Referential.cpp index 722c54cbe3..63510da732 100644 --- a/libraries/avatars/src/Referential.cpp +++ b/libraries/avatars/src/Referential.cpp @@ -23,14 +23,17 @@ Referential::Referential(Type type, AvatarData* avatar) : _isValid = false; return; } - qDebug() << "[DEBUG] New Referential"; } Referential::Referential(const unsigned char*& sourceBuffer, AvatarData* avatar) : _isValid(false), _avatar(avatar) { + // Since we can't return how many byte have been read + // We take a reference to the pointer as argument and increment the pointer ouself. sourceBuffer += unpackReferential(sourceBuffer); + // The actual unpacking to the right referential type happens in Avatar::simulate() + // If subclassed, make sure to add a case there to unpack the new referential type correctly } Referential::~Referential() { @@ -40,9 +43,9 @@ int Referential::packReferential(unsigned char* destinationBuffer) const { const unsigned char* startPosition = destinationBuffer; destinationBuffer += pack(destinationBuffer); - unsigned char* sizePosition = destinationBuffer++; + unsigned char* sizePosition = destinationBuffer++; // Save a spot for the extra data size char size = packExtraData(destinationBuffer); - *sizePosition = size; + *sizePosition = size; // write extra data size in saved spot here destinationBuffer += size; return destinationBuffer - startPosition; @@ -56,6 +59,7 @@ int Referential::unpackReferential(const unsigned char* sourceBuffer) { char bytesRead = unpackExtraData(sourceBuffer, expectedSize); _isValid = (bytesRead == expectedSize); if (!_isValid) { + // Will occur if the new instance unpacking is of the wrong type qDebug() << "[ERROR] Referential extra data overflow"; } sourceBuffer += expectedSize; @@ -88,10 +92,12 @@ int Referential::unpack(const unsigned char* sourceBuffer) { } int Referential::packExtraData(unsigned char *destinationBuffer) const { + // Since we can't interpret that data, just store it in a buffer for later use. memcpy(destinationBuffer, _extraDataBuffer.data(), _extraDataBuffer.size()); return _extraDataBuffer.size(); } + int Referential::unpackExtraData(const unsigned char* sourceBuffer, int size) { _extraDataBuffer.clear(); _extraDataBuffer.setRawData(reinterpret_cast(sourceBuffer), size); diff --git a/libraries/avatars/src/Referential.h b/libraries/avatars/src/Referential.h index 9353ea0871..905447dcbb 100644 --- a/libraries/avatars/src/Referential.h +++ b/libraries/avatars/src/Referential.h @@ -17,6 +17,7 @@ class AvatarData; +/// Stores and enforce the relative position of an avatar to a given referential (ie. model, joint, ...) class Referential { public: enum Type { diff --git a/libraries/models/CMakeLists.txt b/libraries/models/CMakeLists.txt index 603bb02a11..8056d215da 100644 --- a/libraries/models/CMakeLists.txt +++ b/libraries/models/CMakeLists.txt @@ -23,7 +23,6 @@ link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(avatars ${TARGET_NAME} "${ROOT_DIR}") # for streamable link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 3e3c46a12d..4a9a2af2c4 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -179,7 +179,6 @@ void ModelItemIDfromScriptValue(const QScriptValue &object, ModelItemID& propert /// ModelItem class - this is the actual model item class. class ModelItem { - public: ModelItem(); From 2e7d34a8862988153240035e097887517bfb817d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 5 Aug 2014 17:08:23 -0700 Subject: [PATCH 230/407] typing error --- interface/src/avatar/ModelReferential.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/avatar/ModelReferential.cpp b/interface/src/avatar/ModelReferential.cpp index 88a02a909b..6cf22a11ce 100644 --- a/interface/src/avatar/ModelReferential.cpp +++ b/interface/src/avatar/ModelReferential.cpp @@ -26,8 +26,7 @@ ModelReferential::ModelReferential(Referential* referential, ModelTree* tree, Av return; } - const ModelItem* item = _tr - ree->findModelByID(_modelID); + const ModelItem* item = _tree->findModelByID(_modelID); if (item != NULL) { _refScale = item->getRadius(); _refRotation = item->getModelRotation(); From 293c2e94ad645a370ba2050a0bbd0f1287721a31 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 5 Aug 2014 18:17:49 -0700 Subject: [PATCH 231/407] Correct member initialisation --- interface/src/avatar/Avatar.cpp | 6 ++++++ interface/src/avatar/ModelReferential.cpp | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index f4ed442aeb..1f84d3255b 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -248,6 +248,12 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { const float MODEL_SCALE = 0.0006f; _skeletonModel.setScale(glm::vec3(1.0f, 1.0f, 1.0f) * getScale() * MODEL_SCALE); + glm::vec3 headPosition = _position; + _skeletonModel.getHeadPosition(headPosition); + Head* head = getHead(); + head->setPosition(headPosition); + head->setScale(_scale); + if (glm::distance(Application::getInstance()->getAvatar()->getPosition(), _position) < 10.0f) { // render pointing lasers diff --git a/interface/src/avatar/ModelReferential.cpp b/interface/src/avatar/ModelReferential.cpp index 6cf22a11ce..a6e611107f 100644 --- a/interface/src/avatar/ModelReferential.cpp +++ b/interface/src/avatar/ModelReferential.cpp @@ -19,8 +19,12 @@ ModelReferential::ModelReferential(Referential* referential, ModelTree* tree, AvatarData* avatar) : Referential(MODEL, avatar), _tree(tree) { + _translation = referential->getTranslation(); + _rotation = referential->getRotation(); + _scale = referential->getScale(); unpackExtraData(reinterpret_cast(referential->getExtraData().data()), referential->getExtraData().size()); + if (!isValid()) { qDebug() << "ModelReferential::copyConstructor(): Not Valid"; return; @@ -31,8 +35,8 @@ ModelReferential::ModelReferential(Referential* referential, ModelTree* tree, Av _refScale = item->getRadius(); _refRotation = item->getModelRotation(); _refPosition = item->getPosition() * (float)TREE_SCALE; + update(); } - update(); } ModelReferential::ModelReferential(uint32_t modelID, ModelTree* tree, AvatarData* avatar) : From 110b034bcbdcd70beb47a131e0bd359daf3a8fa6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 5 Aug 2014 18:41:48 -0700 Subject: [PATCH 232/407] Changed updates locations --- interface/src/avatar/Avatar.cpp | 64 ++++++++++------------- interface/src/avatar/ModelReferential.cpp | 8 +-- libraries/avatars/src/AvatarData.cpp | 32 ++++++++---- libraries/avatars/src/AvatarData.h | 6 +-- 4 files changed, 59 insertions(+), 51 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 1f84d3255b..c9e03d15cc 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -103,6 +103,31 @@ float Avatar::getLODDistance() const { void Avatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); + + // update the avatar's position according to its referential + if (_referential) { + if (_referential->hasExtraData()) { + ModelTree* tree = Application::getInstance()->getModels()->getTree(); + switch (_referential->type()) { + case Referential::MODEL: + _referential = new ModelReferential(_referential, + tree, + this); + break; + case Referential::JOINT: + _referential = new JointReferential(_referential, + tree, + this); + break; + default: + qDebug() << "[WARNING] Avatar::simulate(): Unknown referential type."; + break; + } + } + + _referential->update(); + } + if (_scale != _targetScale) { setScale(_targetScale); } @@ -180,28 +205,6 @@ void Avatar::simulate(float deltaTime) { } _displayNameAlpha = abs(_displayNameAlpha - _displayNameTargetAlpha) < 0.01f ? _displayNameTargetAlpha : _displayNameAlpha; } - if (_referential) { - if (_referential->hasExtraData()) { - ModelTree* tree = Application::getInstance()->getModels()->getTree(); - switch (_referential->type()) { - case Referential::MODEL: - _referential = new ModelReferential(_referential, - tree, - this); - break; - case Referential::JOINT: - _referential = new JointReferential(_referential, - tree, - this); - break; - default: - qDebug() << "[WARNING] Avatar::simulate(): Unknown referential type."; - break; - } - } - - _referential->update(); - } } void Avatar::updateAcceleration(float deltaTime) { @@ -241,18 +244,9 @@ static TextRenderer* textRenderer(TextRendererType type) { } void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { - // make sure we have the right position - _skeletonModel.setTranslation(getPosition()); - static const glm::quat refOrientation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - _skeletonModel.setRotation(getOrientation() * refOrientation); - const float MODEL_SCALE = 0.0006f; - _skeletonModel.setScale(glm::vec3(1.0f, 1.0f, 1.0f) * getScale() * MODEL_SCALE); - - glm::vec3 headPosition = _position; - _skeletonModel.getHeadPosition(headPosition); - Head* head = getHead(); - head->setPosition(headPosition); - head->setScale(_scale); + if (_referential) { + _referential->update(); + } if (glm::distance(Application::getInstance()->getAvatar()->getPosition(), _position) < 10.0f) { @@ -303,7 +297,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { float boundingRadius = getBillboardSize(); ViewFrustum* frustum = (renderMode == Avatar::SHADOW_RENDER_MODE) ? Application::getInstance()->getShadowViewFrustum() : Application::getInstance()->getViewFrustum(); - if (frustum->sphereInFrustum(_position, boundingRadius) == ViewFrustum::OUTSIDE) { + if (frustum->sphereInFrustum(getPosition(), boundingRadius) == ViewFrustum::OUTSIDE) { return; } diff --git a/interface/src/avatar/ModelReferential.cpp b/interface/src/avatar/ModelReferential.cpp index a6e611107f..1b9e6a9f52 100644 --- a/interface/src/avatar/ModelReferential.cpp +++ b/interface/src/avatar/ModelReferential.cpp @@ -70,7 +70,7 @@ void ModelReferential::update() { bool somethingChanged = false; if (item->getRadius() != _refScale) { _refScale = item->getRadius(); - _avatar->setTargetScale(_refScale * _scale); + _avatar->setTargetScale(_refScale * _scale, true); somethingChanged = true; } if (item->getModelRotation() != _refRotation) { @@ -147,17 +147,17 @@ void JointReferential::update() { bool somethingChanged = false; if (item->getRadius() != _refScale) { _refScale = item->getRadius(); - _avatar->setTargetScale(_refScale * _scale); + _avatar->setTargetScale(_refScale * _scale, true); somethingChanged = true; } if (item->getModelRotation() != _refRotation) { model->getJointRotationInWorldFrame(_jointIndex, _refRotation); - _avatar->setOrientation(_refRotation * _rotation); + _avatar->setOrientation(_refRotation * _rotation, true); somethingChanged = true; } if (item->getPosition() != _refPosition || somethingChanged) { model->getJointPositionInWorldFrame(_jointIndex, _refPosition); - _avatar->setPosition(_refPosition + _refRotation * (_translation * _refScale)); + _avatar->setPosition(_refPosition + _refRotation * (_translation * _refScale), true); somethingChanged = true; } } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 59f9a440f0..0b41e0ffaa 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -94,7 +94,29 @@ void AvatarData::setOrientation(const glm::quat& orientation, bool overideRefere _bodyYaw = eulerAngles.y; _bodyRoll = eulerAngles.z; } -} +} + +float AvatarData::getTargetScale() const { + if (_referential) { + _referential->update(); + } + + return _targetScale; +} + +void AvatarData::setTargetScale(float targetScale, bool overideReferential) { + if (!_referential || overideReferential) { + _targetScale = targetScale; + } +} + +void AvatarData::setClampedTargetScale(float targetScale, bool overideReferential) { + + targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); + + setTargetScale(targetScale, overideReferential); + qDebug() << "Changed scale to " << _targetScale; +} glm::vec3 AvatarData::getHandPosition() const { return getOrientation() * _handPosition + _position; @@ -868,14 +890,6 @@ void AvatarData::setJointMappingsFromNetworkReply() { networkReply->deleteLater(); } -void AvatarData::setClampedTargetScale(float targetScale) { - - targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); - - _targetScale = targetScale; - qDebug() << "Changed scale to " << _targetScale; -} - void AvatarData::sendIdentityPacket() { QByteArray identityPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarIdentity); identityPacket.append(identityByteArray()); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 767c905322..df64813a28 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -190,9 +190,9 @@ public: void setAudioAverageLoudness(float value) { _headData->setAudioAverageLoudness(value); } // Scale - float getTargetScale() const { return _targetScale; } - void setTargetScale(float targetScale) { _targetScale = targetScale; } - void setClampedTargetScale(float targetScale); + float getTargetScale() const; + void setTargetScale(float targetScale, bool overideReferential = false); + void setClampedTargetScale(float targetScale, bool overideReferential = false); // Hand State Q_INVOKABLE void setHandState(char s) { _handState = s; } From fe8839b4b8f536e1971355a9e7ebc7642fbc0c02 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 6 Aug 2014 10:40:55 -0700 Subject: [PATCH 233/407] CR --- interface/src/avatar/ModelReferential.cpp | 8 +++----- libraries/avatars/src/AvatarData.cpp | 2 +- libraries/avatars/src/AvatarData.h | 2 ++ libraries/avatars/src/Referential.cpp | 17 ++++++++++++----- libraries/avatars/src/Referential.h | 9 ++++++--- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/interface/src/avatar/ModelReferential.cpp b/interface/src/avatar/ModelReferential.cpp index 1b9e6a9f52..d38abae70a 100644 --- a/interface/src/avatar/ModelReferential.cpp +++ b/interface/src/avatar/ModelReferential.cpp @@ -40,9 +40,9 @@ ModelReferential::ModelReferential(Referential* referential, ModelTree* tree, Av } ModelReferential::ModelReferential(uint32_t modelID, ModelTree* tree, AvatarData* avatar) : -Referential(MODEL, avatar), -_modelID(modelID), -_tree(tree) + Referential(MODEL, avatar), + _modelID(modelID), + _tree(tree) { const ModelItem* item = _tree->findModelByID(_modelID); if (!isValid() || item == NULL) { @@ -81,7 +81,6 @@ void ModelReferential::update() { if (item->getPosition() != _refPosition || somethingChanged) { _refPosition = item->getPosition(); _avatar->setPosition(_refPosition * (float)TREE_SCALE + _refRotation * (_translation * _refScale), true); - somethingChanged = true; } } @@ -158,7 +157,6 @@ void JointReferential::update() { if (item->getPosition() != _refPosition || somethingChanged) { model->getJointPositionInWorldFrame(_jointIndex, _refPosition); _avatar->setPosition(_refPosition + _refRotation * (_translation * _refScale), true); - somethingChanged = true; } } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 0b41e0ffaa..96a5f2425b 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -449,7 +449,7 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { if (hasReferential) { Referential* ref = new Referential(sourceBuffer, this); if (_referential == NULL || - ref->createdAt() > _referential->createdAt()) { + ref->version() != _referential->version()) { changeReferential(ref); } else { delete ref; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index df64813a28..2971598c1d 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -282,6 +282,8 @@ public: QElapsedTimer& getLastUpdateTimer() { return _lastUpdateTimer; } virtual float getBoundingRadius() const { return 1.f; } + + const Referential* getReferential() const { return _referential; } public slots: void sendIdentityPacket(); diff --git a/libraries/avatars/src/Referential.cpp b/libraries/avatars/src/Referential.cpp index 63510da732..a5a7e7e3e5 100644 --- a/libraries/avatars/src/Referential.cpp +++ b/libraries/avatars/src/Referential.cpp @@ -11,11 +11,12 @@ #include +#include "AvatarData.h" #include "Referential.h" Referential::Referential(Type type, AvatarData* avatar) : _type(type), - _createdAt(usecTimestampNow()), + _version(0), _isValid(true), _avatar(avatar) { @@ -23,6 +24,9 @@ Referential::Referential(Type type, AvatarData* avatar) : _isValid = false; return; } + if (_avatar->hasReferential()) { + _version = _avatar->getReferential()->version() + 1; + } } Referential::Referential(const unsigned char*& sourceBuffer, AvatarData* avatar) : @@ -70,8 +74,8 @@ int Referential::unpackReferential(const unsigned char* sourceBuffer) { int Referential::pack(unsigned char* destinationBuffer) const { unsigned char* startPosition = destinationBuffer; *destinationBuffer++ = (unsigned char)_type; - memcpy(destinationBuffer, &_createdAt, sizeof(_createdAt)); - destinationBuffer += sizeof(_createdAt); + memcpy(destinationBuffer, &_version, sizeof(_version)); + destinationBuffer += sizeof(_version); destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, _translation, 0); destinationBuffer += packOrientationQuatToBytes(destinationBuffer, _rotation); @@ -82,8 +86,11 @@ int Referential::pack(unsigned char* destinationBuffer) const { int Referential::unpack(const unsigned char* sourceBuffer) { const unsigned char* startPosition = sourceBuffer; _type = (Type)*sourceBuffer++; - memcpy(&_createdAt, sourceBuffer, sizeof(_createdAt)); - sourceBuffer += sizeof(_createdAt); + if (_type < 0 || _type >= NUM_TYPE) { + _type = UNKNOWN; + } + memcpy(&_version, sourceBuffer, sizeof(_version)); + sourceBuffer += sizeof(_version); sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, _translation, 0); sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, _rotation); diff --git a/libraries/avatars/src/Referential.h b/libraries/avatars/src/Referential.h index 905447dcbb..f24d66c160 100644 --- a/libraries/avatars/src/Referential.h +++ b/libraries/avatars/src/Referential.h @@ -21,16 +21,19 @@ class AvatarData; class Referential { public: enum Type { + UNKNOWN, MODEL, JOINT, - AVATAR + AVATAR, + + NUM_TYPE }; Referential(const unsigned char*& sourceBuffer, AvatarData* avatar); virtual ~Referential(); Type type() const { return _type; } - quint64 createdAt() const { return _createdAt; } + quint8 version() const { return _version; } bool isValid() const { return _isValid; } bool hasExtraData() const { return !_extraDataBuffer.isEmpty(); } @@ -54,7 +57,7 @@ protected: virtual int unpackExtraData(const unsigned char* sourceBuffer, int size); Type _type; - quint64 _createdAt; + quint8 _version; bool _isValid; AvatarData* _avatar; QByteArray _extraDataBuffer; From cb8c0792b2c9977281b103a30f0124f4eded97cc Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 6 Aug 2014 10:43:56 -0700 Subject: [PATCH 234/407] make main ragdoll and entity special also addded some logic (unused) to add ragdolls of other avatars --- interface/src/avatar/MyAvatar.cpp | 68 ++++++----- libraries/shared/src/PhysicsSimulation.cpp | 127 ++++++++++++--------- libraries/shared/src/PhysicsSimulation.h | 10 +- 3 files changed, 121 insertions(+), 84 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4d2d679956..41eba45ac4 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -85,12 +85,12 @@ MyAvatar::MyAvatar() : _skeletonModel.setEnableShapes(true); // The skeleton is both a PhysicsEntity and Ragdoll, so we add it to the simulation once for each type. _physicsSimulation.addEntity(&_skeletonModel); - _physicsSimulation.addRagdoll(&_skeletonModel); + _physicsSimulation.setRagdoll(&_skeletonModel); } MyAvatar::~MyAvatar() { + _physicsSimulation.setRagdoll(NULL); _physicsSimulation.removeEntity(&_skeletonModel); - _physicsSimulation.removeRagdoll(&_skeletonModel); _lookAtTargetAvatar.clear(); } @@ -1532,41 +1532,53 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { } float myBoundingRadius = getBoundingRadius(); - const float BODY_COLLISION_RESOLUTION_FACTOR = glm::max(1.0f, deltaTime / BODY_COLLISION_RESOLUTION_TIMESCALE); - + // find nearest avatar + float nearestDistance2 = std::numeric_limits::max(); + Avatar* nearestAvatar = NULL; foreach (const AvatarSharedPointer& avatarPointer, avatars) { Avatar* avatar = static_cast(avatarPointer.data()); if (static_cast(this) == avatar) { // don't collide with ourselves continue; } - float distance = glm::length(_position - avatar->getPosition()); - if (_distanceToNearestAvatar > distance) { - _distanceToNearestAvatar = distance; + float distance2 = glm::distance2(_position, avatar->getPosition()); + if (nearestDistance2 > distance2) { + nearestDistance2 = distance2; + nearestAvatar = avatar; } - float theirBoundingRadius = avatar->getBoundingRadius(); - if (distance < myBoundingRadius + theirBoundingRadius) { - // collide our body against theirs - QVector myShapes; - _skeletonModel.getBodyShapes(myShapes); - QVector theirShapes; - avatar->getSkeletonModel().getBodyShapes(theirShapes); + } + _distanceToNearestAvatar = glm::sqrt(nearestDistance2); - CollisionInfo collision; - if (ShapeCollider::collideShapesCoarse(myShapes, theirShapes, collision)) { - float penetrationDepth = glm::length(collision._penetration); - if (penetrationDepth > myBoundingRadius) { - qDebug() << "WARNING: ignoring avatar-avatar penetration depth " << penetrationDepth; - } - else if (penetrationDepth > EPSILON) { - setPosition(getPosition() - BODY_COLLISION_RESOLUTION_FACTOR * collision._penetration); - _lastBodyPenetration += collision._penetration; - emit collisionWithAvatar(getSessionUUID(), avatar->getSessionUUID(), collision); - } + if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { + if (nearestAvatar != NULL) { + if (_distanceToNearestAvatar > myBoundingRadius + nearestAvatar->getBoundingRadius()) { + // they aren't close enough to put into the _physicsSimulation + // so we clear the pointer + nearestAvatar = NULL; + } + } + + foreach (const AvatarSharedPointer& avatarPointer, avatars) { + Avatar* avatar = static_cast(avatarPointer.data()); + if (static_cast(this) == avatar) { + // don't collide with ourselves + continue; + } + SkeletonModel* skeleton = &(avatar->getSkeletonModel()); + PhysicsSimulation* simulation = skeleton->getSimulation(); + if (avatar == nearestAvatar) { + if (simulation != &(_physicsSimulation)) { + std::cout << "adebug adding other avatar " << avatar << " to simulation" << std::endl; // adebug + skeleton->setEnableShapes(true); + _physicsSimulation.addEntity(skeleton); + _physicsSimulation.addRagdoll(skeleton); + } + } else if (simulation == &(_physicsSimulation)) { + std::cout << "adebug removing other avatar " << avatar << " from simulation" << std::endl; // adebug + _physicsSimulation.removeRagdoll(skeleton); + _physicsSimulation.removeEntity(skeleton); + skeleton->setEnableShapes(false); } - - // collide their hands against us - avatar->getHand()->collideAgainstAvatar(this, false); } } } diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index c2a852c32b..5fd40543e7 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -24,19 +24,37 @@ int MAX_ENTITIES_PER_SIMULATION = 64; int MAX_COLLISIONS_PER_SIMULATION = 256; -PhysicsSimulation::PhysicsSimulation() : _frame(0), _collisions(MAX_COLLISIONS_PER_SIMULATION) { +PhysicsSimulation::PhysicsSimulation() : _frame(0), _entity(NULL), _ragdoll(NULL), _collisions(MAX_COLLISIONS_PER_SIMULATION) { } PhysicsSimulation::~PhysicsSimulation() { // entities have a backpointer to this simulator that must be cleaned up - int numEntities = _entities.size(); + int numEntities = _otherEntities.size(); for (int i = 0; i < numEntities; ++i) { - _entities[i]->_simulation = NULL; + _otherEntities[i]->_simulation = NULL; + } + _otherEntities.clear(); + if (_entity) { + _entity->_simulation = NULL; } - _entities.clear(); // but Ragdolls do not - _dolls.clear(); + _ragdoll = NULL; + _otherRagdolls.clear(); +} + +void PhysicsSimulation::setEntity(PhysicsEntity* entity) { + if (_entity != entity) { + if (_entity) { + assert(_entity->_simulation == this); + _entity->_simulation = NULL; + } + _entity = entity; + if (_entity) { + assert(!(_entity->_simulation)); + _entity->_simulation = this; + } + } } bool PhysicsSimulation::addEntity(PhysicsEntity* entity) { @@ -44,25 +62,24 @@ bool PhysicsSimulation::addEntity(PhysicsEntity* entity) { return false; } if (entity->_simulation == this) { - int numEntities = _entities.size(); + int numEntities = _otherEntities.size(); for (int i = 0; i < numEntities; ++i) { - if (entity == _entities.at(i)) { + if (entity == _otherEntities.at(i)) { // already in list - assert(entity->_simulation == this); return true; } } // belongs to some other simulation return false; } - int numEntities = _entities.size(); + int numEntities = _otherEntities.size(); if (numEntities > MAX_ENTITIES_PER_SIMULATION) { // list is full return false; } // add to list entity->_simulation = this; - _entities.push_back(entity); + _otherEntities.push_back(entity); return true; } @@ -71,17 +88,17 @@ void PhysicsSimulation::removeEntity(PhysicsEntity* entity) { return; } removeShapes(entity); - int numEntities = _entities.size(); + int numEntities = _otherEntities.size(); for (int i = 0; i < numEntities; ++i) { - if (entity == _entities.at(i)) { + if (entity == _otherEntities.at(i)) { if (i == numEntities - 1) { // remove it - _entities.pop_back(); + _otherEntities.pop_back(); } else { // swap the last for this one - PhysicsEntity* lastEntity = _entities[numEntities - 1]; - _entities.pop_back(); - _entities[i] = lastEntity; + PhysicsEntity* lastEntity = _otherEntities[numEntities - 1]; + _otherEntities.pop_back(); + _otherEntities[i] = lastEntity; } entity->_simulation = NULL; break; @@ -105,34 +122,34 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { if (!doll) { return false; } - int numDolls = _dolls.size(); + int numDolls = _otherRagdolls.size(); if (numDolls > MAX_DOLLS_PER_SIMULATION) { // list is full return false; } for (int i = 0; i < numDolls; ++i) { - if (doll == _dolls[i]) { + if (doll == _otherRagdolls[i]) { // already in list return true; } } // add to list - _dolls.push_back(doll); + _otherRagdolls.push_back(doll); return true; } void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { - int numDolls = _dolls.size(); + int numDolls = _otherRagdolls.size(); for (int i = 0; i < numDolls; ++i) { - if (doll == _dolls[i]) { + if (doll == _otherRagdolls[i]) { if (i == numDolls - 1) { // remove it - _dolls.pop_back(); + _otherRagdolls.pop_back(); } else { // swap the last for this one - Ragdoll* lastDoll = _dolls[numDolls - 1]; - _dolls.pop_back(); - _dolls[i] = lastDoll; + Ragdoll* lastDoll = _otherRagdolls[numDolls - 1]; + _otherRagdolls.pop_back(); + _otherRagdolls[i] = lastDoll; } break; } @@ -141,17 +158,21 @@ void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIterations, quint64 maxUsec) { ++_frame; + if (!_ragdoll) { + return; + } quint64 now = usecTimestampNow(); quint64 startTime = now; quint64 expiry = startTime + maxUsec; moveRagdolls(deltaTime); buildContactConstraints(); - int numDolls = _dolls.size(); + int numDolls = _otherRagdolls.size(); { PerformanceTimer perfTimer("enforce"); + _ragdoll->enforceRagdollConstraints(); for (int i = 0; i < numDolls; ++i) { - _dolls[i]->enforceRagdollConstraints(); + _otherRagdolls[i]->enforceRagdollConstraints(); } } @@ -164,9 +185,9 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter { // enforce constraints PerformanceTimer perfTimer("enforce"); - error = 0.0f; + error = _ragdoll->enforceRagdollConstraints(); for (int i = 0; i < numDolls; ++i) { - error = glm::max(error, _dolls[i]->enforceRagdollConstraints()); + error = glm::max(error, _otherRagdolls[i]->enforceRagdollConstraints()); } } enforceContactConstraints(); @@ -180,40 +201,38 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter void PhysicsSimulation::moveRagdolls(float deltaTime) { PerformanceTimer perfTimer("integrate"); - int numDolls = _dolls.size(); + _ragdoll->stepRagdollForward(deltaTime); + int numDolls = _otherRagdolls.size(); for (int i = 0; i < numDolls; ++i) { - _dolls.at(i)->stepRagdollForward(deltaTime); + _otherRagdolls.at(i)->stepRagdollForward(deltaTime); } } void PhysicsSimulation::computeCollisions() { PerformanceTimer perfTimer("collide"); _collisions.clear(); - // TODO: keep track of QSet collidedEntities; - int numEntities = _entities.size(); - for (int i = 0; i < numEntities; ++i) { - PhysicsEntity* entity = _entities.at(i); - const QVector shapes = entity->getShapes(); - int numShapes = shapes.size(); - // collide with self - for (int j = 0; j < numShapes; ++j) { - const Shape* shape = shapes.at(j); - if (!shape) { - continue; - } - for (int k = j+1; k < numShapes; ++k) { - const Shape* otherShape = shapes.at(k); - if (otherShape && entity->collisionsAreEnabled(j, k)) { - ShapeCollider::collideShapes(shape, otherShape, _collisions); - } - } - } - // collide with others - for (int j = i+1; j < numEntities; ++j) { - const QVector otherShapes = _entities.at(j)->getShapes(); - ShapeCollider::collideShapesWithShapes(shapes, otherShapes, _collisions); + const QVector shapes = _entity->getShapes(); + int numShapes = shapes.size(); + // collide with self + for (int i = 0; i < numShapes; ++i) { + const Shape* shape = shapes.at(i); + if (!shape) { + continue; } + for (int j = i+1; j < numShapes; ++j) { + const Shape* otherShape = shapes.at(j); + if (otherShape && _entity->collisionsAreEnabled(i, j)) { + ShapeCollider::collideShapes(shape, otherShape, _collisions); + } + } + } + + // collide with others + int numEntities = _otherEntities.size(); + for (int i = 0; i < numEntities; ++i) { + const QVector otherShapes = _otherEntities.at(i)->getShapes(); + ShapeCollider::collideShapesWithShapes(shapes, otherShapes, _collisions); } } diff --git a/libraries/shared/src/PhysicsSimulation.h b/libraries/shared/src/PhysicsSimulation.h index 506b37533a..c8f41bb656 100644 --- a/libraries/shared/src/PhysicsSimulation.h +++ b/libraries/shared/src/PhysicsSimulation.h @@ -28,6 +28,9 @@ public: PhysicsSimulation(); ~PhysicsSimulation(); + void setRagdoll(Ragdoll* ragdoll) { _ragdoll = ragdoll; } + void setEntity(PhysicsEntity* entity); + /// \return true if entity was added to or is already in the list bool addEntity(PhysicsEntity* entity); @@ -58,8 +61,11 @@ protected: private: quint32 _frame; - QVector _dolls; - QVector _entities; + PhysicsEntity* _entity; + Ragdoll* _ragdoll; + + QVector _otherRagdolls; + QVector _otherEntities; CollisionList _collisions; QMap _contacts; }; From a8999d7db72ddfc1283f1d957d54fa7ec661407e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 6 Aug 2014 11:23:48 -0700 Subject: [PATCH 235/407] fix voxel bug --- examples/editVoxels.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 77cec87b15..1ed3dcc0c3 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -752,7 +752,7 @@ function calculateVoxelFromIntersection(intersection, operation) { highlightAt.z = z + zFightingSizeAdjust; voxelSize -= 2 * zFightingSizeAdjust; if (wantAddAdjust) { - resultVoxel.y += voxelSize; + resultVoxel.y += resultVoxel.s; } resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z }; @@ -782,7 +782,7 @@ function calculateVoxelFromIntersection(intersection, operation) { highlightAt.z = z + voxelSize + zFightingSizeAdjust; voxelSize -= 2 * zFightingSizeAdjust; if (wantAddAdjust) { - resultVoxel.z += voxelSize; + resultVoxel.z += resultVoxel.s; } resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z }; From de8c7fb204cfb2d767cc6afcaf512eadc4552865 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 6 Aug 2014 12:14:36 -0700 Subject: [PATCH 236/407] Fix avatar not fading out --- interface/src/avatar/AvatarManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 0db12276ad..5cc8812b40 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -41,7 +41,7 @@ void AvatarManager::init() { } void AvatarManager::updateOtherAvatars(float deltaTime) { - if (_avatarHash.size() < 2) { + if (_avatarHash.size() < 2 && _avatarFades.isEmpty()) { return; } bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); From 62e6493456711da6c71f999c0154b0caa3f9c6c6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 6 Aug 2014 17:09:22 -0700 Subject: [PATCH 237/407] Started on heightfield brush tool, added simple query for heightfield height (accessible from scripts). --- interface/src/ui/MetavoxelEditor.cpp | 44 +++++++++++ interface/src/ui/MetavoxelEditor.h | 31 +++++++- .../metavoxels/src/MetavoxelClientManager.cpp | 73 +++++++++++++++++++ .../metavoxels/src/MetavoxelClientManager.h | 2 + 4 files changed, 149 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 096798e77e..32ffedf0c8 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -118,6 +118,7 @@ MetavoxelEditor::MetavoxelEditor() : addTool(new SetSpannerTool(this)); addTool(new ImportHeightfieldTool(this)); addTool(new EraseHeightfieldTool(this)); + addTool(new HeightBrushTool(this)); updateAttributes(); @@ -1080,3 +1081,46 @@ void EraseHeightfieldTool::apply() { message.edit = QVariant::fromValue(edit); Application::getInstance()->getMetavoxels()->applyEdit(message, true); } + +HeightfieldBrushTool::HeightfieldBrushTool(MetavoxelEditor* editor, const QString& name) : + MetavoxelTool(editor, name, false) { + + QWidget* widget = new QWidget(); + widget->setLayout(_form = new QFormLayout()); + layout()->addWidget(widget); + + _form->addRow("Radius:", _radius = new QDoubleSpinBox()); + _radius->setSingleStep(0.01); + _radius->setMaximum(FLT_MAX); + _radius->setValue(1.0); +} + +void HeightfieldBrushTool::render() { + // find the intersection with the heightfield + glm::vec3 origin = Application::getInstance()->getMouseRayOrigin(); + glm::vec3 direction = Application::getInstance()->getMouseRayDirection(); + + float distance = -origin.y / direction.y; + glm::vec3 point = origin + distance * direction; + + point.y = Application::getInstance()->getMetavoxels()->getHeight(point); + + glPushMatrix(); + glTranslatef(point.x, point.y, point.z); + + glColor4f(1.0f, 0.0f, 0.0f, 1.0f); + + glutSolidSphere(0.1f, 8, 8); + + glPopMatrix(); +} + +HeightBrushTool::HeightBrushTool(MetavoxelEditor* editor) : + HeightfieldBrushTool(editor, "Height Brush") { + + _form->addRow("Height:", _height = new QDoubleSpinBox()); + _height->setMinimum(-FLT_MAX); + _height->setMaximum(FLT_MAX); + _height->setValue(1.0); +} + diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index cc30896c49..50b477a2bf 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -282,7 +282,7 @@ private: HeightfieldPreview _preview; }; -// Allows clearing heighfield blocks. +/// Allows clearing heighfield blocks. class EraseHeightfieldTool : public HeightfieldTool { Q_OBJECT @@ -302,4 +302,33 @@ private: QSpinBox* _length; }; +/// Base class for tools that allow painting on heightfields. +class HeightfieldBrushTool : public MetavoxelTool { + Q_OBJECT + +public: + + HeightfieldBrushTool(MetavoxelEditor* editor, const QString& name); + + virtual void render(); + +protected: + + QFormLayout* _form; + QDoubleSpinBox* _radius; +}; + +/// Allows raising or lowering parts of the heightfield. +class HeightBrushTool : public HeightfieldBrushTool { + Q_OBJECT + +public: + + HeightBrushTool(MetavoxelEditor* editor); + +private: + + QDoubleSpinBox* _height; +}; + #endif // hifi_MetavoxelEditor_h diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index a2d3410314..d86ad86df4 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -78,6 +78,79 @@ void MetavoxelClientManager::applyEdit(const MetavoxelEditMessage& edit, bool re QMetaObject::invokeMethod(_updater, "applyEdit", Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, reliable)); } +class HeightVisitor : public MetavoxelVisitor { +public: + + float height; + + HeightVisitor(const MetavoxelLOD& lod, const glm::vec3& location); + + virtual int visit(MetavoxelInfo& info); + +private: + + glm::vec3 _location; +}; + +HeightVisitor::HeightVisitor(const MetavoxelLOD& lod, const glm::vec3& location) : + MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getHeightfieldAttribute(), + QVector(), lod), + height(-FLT_MAX), + _location(location) { +} + +static const int REVERSE_ORDER = MetavoxelVisitor::encodeOrder(7, 6, 5, 4, 3, 2, 1, 0); +static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / 255.0f; + +int HeightVisitor::visit(MetavoxelInfo& info) { + glm::vec3 relative = _location - info.minimum; + if (relative.x < 0.0f || relative.z < 0.0f || relative.x > info.size || relative.z > info.size || + height >= info.minimum.y + info.size) { + return STOP_RECURSION; + } + if (!info.isLeaf) { + return REVERSE_ORDER; + } + HeightfieldDataPointer pointer = info.inputValues.at(0).getInlineValue(); + if (!pointer) { + return STOP_RECURSION; + } + const QByteArray& contents = pointer->getContents(); + const uchar* src = (const uchar*)contents.constData(); + int size = glm::sqrt((float)contents.size()); + int highest = size - 1; + relative *= highest / info.size; + glm::vec3 floors = glm::floor(relative); + glm::vec3 ceils = glm::ceil(relative); + glm::vec3 fracts = glm::fract(relative); + int floorX = qMin(qMax((int)floors.x, 0), highest); + int floorZ = qMin(qMax((int)floors.z, 0), highest); + int ceilX = qMin(qMax((int)ceils.x, 0), highest); + int ceilZ = qMin(qMax((int)ceils.z, 0), highest); + float upperLeft = src[floorZ * size + floorX]; + float lowerRight = src[ceilZ * size + ceilX]; + float interpolatedHeight; + if (fracts.x > fracts.z) { + float upperRight = src[floorZ * size + ceilX]; + interpolatedHeight = glm::mix(glm::mix(upperLeft, upperRight, fracts.x), lowerRight, fracts.z); + + } else { + float lowerLeft = src[ceilZ * size + floorX]; + interpolatedHeight = glm::mix(upperLeft, glm::mix(lowerLeft, lowerRight, fracts.x), fracts.z); + } + if (interpolatedHeight == 0.0f) { + return STOP_RECURSION; + } + height = qMax(height, info.minimum.y + interpolatedHeight * info.size * EIGHT_BIT_MAXIMUM_RECIPROCAL); + return SHORT_CIRCUIT; +} + +float MetavoxelClientManager::getHeight(const glm::vec3& location) { + HeightVisitor visitor(getLOD(), location); + guide(visitor); + return visitor.height; +} + MetavoxelLOD MetavoxelClientManager::getLOD() { return MetavoxelLOD(); } diff --git a/libraries/metavoxels/src/MetavoxelClientManager.h b/libraries/metavoxels/src/MetavoxelClientManager.h index 333b709b9e..22c71bd63b 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.h +++ b/libraries/metavoxels/src/MetavoxelClientManager.h @@ -43,6 +43,8 @@ public: Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false); + Q_INVOKABLE float getHeight(const glm::vec3& location); + /// Returns the current LOD. This must be thread-safe, as it will be called from the updater thread. virtual MetavoxelLOD getLOD(); From acb973d245475d00f29970ee23685563bc0f7019 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 6 Aug 2014 19:41:25 -0700 Subject: [PATCH 238/407] Working on ray intersection testing. --- interface/src/ui/MetavoxelEditor.cpp | 2 +- .../metavoxels/src/MetavoxelClientManager.cpp | 91 +++++++++++++++++-- .../metavoxels/src/MetavoxelClientManager.h | 4 +- 3 files changed, 88 insertions(+), 9 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 32ffedf0c8..a2bb1770b2 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -1103,7 +1103,7 @@ void HeightfieldBrushTool::render() { float distance = -origin.y / direction.y; glm::vec3 point = origin + distance * direction; - point.y = Application::getInstance()->getMetavoxels()->getHeight(point); + point.y = Application::getInstance()->getMetavoxels()->getHeightfieldHeight(point); glPushMatrix(); glTranslatef(point.x, point.y, point.z); diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index d86ad86df4..51eb4c653c 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -61,6 +61,84 @@ SharedObjectPointer MetavoxelClientManager::findFirstRaySpannerIntersection(cons return closestSpanner; } +class RayHeightfieldIntersectionVisitor : public RayIntersectionVisitor { +public: + + RayHeightfieldIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, const MetavoxelLOD& lod); + + virtual int visit(MetavoxelInfo& info, float distance); +}; + +RayHeightfieldIntersectionVisitor::RayHeightfieldIntersectionVisitor(const glm::vec3& origin, + const glm::vec3& direction, const MetavoxelLOD& lod) : + RayIntersectionVisitor(origin, direction, QVector() << + AttributeRegistry::getInstance()->getHeightfieldAttribute(), QVector(), lod) { +} + +static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / 255.0f; + +int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance) { + if (!info.isLeaf) { + return _order; + } + HeightfieldDataPointer pointer = info.inputValues.at(0).getInlineValue(); + if (!pointer) { + return STOP_RECURSION; + } + const QByteArray& contents = pointer->getContents(); + const uchar* src = (const uchar*)contents.constData(); + int size = glm::sqrt((float)contents.size()); + int highest = size - 1; + float heightScale = highest / EIGHT_BIT_MAXIMUM_RECIPROCAL; + + // find the initial location + glm::vec3 location = (_origin + distance * _direction - info.minimum) * (float)highest / info.size; + + glm::vec3 floors = glm::floor(location); + glm::vec3 ceils = glm::ceil(location); + int floorX = qMin(qMax((int)floors.x, 0), highest); + int floorZ = qMin(qMax((int)floors.z, 0), highest); + int ceilX = qMin(qMax((int)ceils.x, 0), highest); + int ceilZ = qMin(qMax((int)ceils.z, 0), highest); + float upperLeft = src[floorZ * size + floorX] * heightScale; + float upperRight = src[floorZ * size + ceilX] * heightScale; + float lowerLeft = src[ceilZ * size + floorX] * heightScale; + float lowerRight = src[ceilZ * size + ceilX] * heightScale; + + glm::vec3 relativeLocation = location - glm::vec3(floors.x, upperLeft, floors.z); + + glm::vec3 lowerNormal(lowerLeft - lowerRight, 1.0f, upperLeft - lowerLeft); + float lowerProduct = glm::dot(lowerNormal, _direction); + if (lowerProduct < EPSILON) { + float distance = -glm::dot(lowerNormal, relativeLocation) / lowerProduct; + glm::vec3 intersection = relativeLocation + distance * _direction; + if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && + intersection.z >= intersection.x) { + return SHORT_CIRCUIT; + } + } + + glm::vec3 upperNormal(upperLeft - upperRight, 1.0f, upperRight - lowerRight); + float upperProduct = glm::dot(upperNormal, _direction); + if (upperProduct < EPSILON) { + float distance = -glm::dot(upperNormal, relativeLocation) / upperProduct; + glm::vec3 intersection = relativeLocation + distance * _direction; + if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && + intersection.x >= intersection.z) { + return SHORT_CIRCUIT; + } + } + + return STOP_RECURSION; +} + +bool MetavoxelClientManager::findFirstRayHeightfieldIntersection(const glm::vec3& origin, + const glm::vec3& direction, float& distance) { + RayHeightfieldIntersectionVisitor visitor(origin, direction, getLOD()); + guide(visitor); + return false; +} + void MetavoxelClientManager::setSphere(const glm::vec3& center, float radius, const QColor& color) { Sphere* sphere = new Sphere(); sphere->setTranslation(center); @@ -78,12 +156,12 @@ void MetavoxelClientManager::applyEdit(const MetavoxelEditMessage& edit, bool re QMetaObject::invokeMethod(_updater, "applyEdit", Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, reliable)); } -class HeightVisitor : public MetavoxelVisitor { +class HeightfieldHeightVisitor : public MetavoxelVisitor { public: float height; - HeightVisitor(const MetavoxelLOD& lod, const glm::vec3& location); + HeightfieldHeightVisitor(const MetavoxelLOD& lod, const glm::vec3& location); virtual int visit(MetavoxelInfo& info); @@ -92,7 +170,7 @@ private: glm::vec3 _location; }; -HeightVisitor::HeightVisitor(const MetavoxelLOD& lod, const glm::vec3& location) : +HeightfieldHeightVisitor::HeightfieldHeightVisitor(const MetavoxelLOD& lod, const glm::vec3& location) : MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getHeightfieldAttribute(), QVector(), lod), height(-FLT_MAX), @@ -100,9 +178,8 @@ HeightVisitor::HeightVisitor(const MetavoxelLOD& lod, const glm::vec3& location) } static const int REVERSE_ORDER = MetavoxelVisitor::encodeOrder(7, 6, 5, 4, 3, 2, 1, 0); -static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / 255.0f; -int HeightVisitor::visit(MetavoxelInfo& info) { +int HeightfieldHeightVisitor::visit(MetavoxelInfo& info) { glm::vec3 relative = _location - info.minimum; if (relative.x < 0.0f || relative.z < 0.0f || relative.x > info.size || relative.z > info.size || height >= info.minimum.y + info.size) { @@ -145,8 +222,8 @@ int HeightVisitor::visit(MetavoxelInfo& info) { return SHORT_CIRCUIT; } -float MetavoxelClientManager::getHeight(const glm::vec3& location) { - HeightVisitor visitor(getLOD(), location); +float MetavoxelClientManager::getHeightfieldHeight(const glm::vec3& location) { + HeightfieldHeightVisitor visitor(getLOD(), location); guide(visitor); return visitor.height; } diff --git a/libraries/metavoxels/src/MetavoxelClientManager.h b/libraries/metavoxels/src/MetavoxelClientManager.h index 22c71bd63b..8fc9bcd38d 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.h +++ b/libraries/metavoxels/src/MetavoxelClientManager.h @@ -37,13 +37,15 @@ public: SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, float& distance); + bool findFirstRayHeightfieldIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance); + Q_INVOKABLE void setSphere(const glm::vec3& center, float radius, const QColor& color = QColor(Qt::gray)); Q_INVOKABLE void setSpanner(const SharedObjectPointer& object, bool reliable = false); Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false); - Q_INVOKABLE float getHeight(const glm::vec3& location); + Q_INVOKABLE float getHeightfieldHeight(const glm::vec3& location); /// Returns the current LOD. This must be thread-safe, as it will be called from the updater thread. virtual MetavoxelLOD getLOD(); From 6191db3a7f590ae6ee8d95ba4a1ae866a6e694e3 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Thu, 7 Aug 2014 09:59:07 -0600 Subject: [PATCH 239/407] Fixing bug with visage find_library --- cmake/modules/FindVisage.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/FindVisage.cmake b/cmake/modules/FindVisage.cmake index b461926604..070905d6ff 100644 --- a/cmake/modules/FindVisage.cmake +++ b/cmake/modules/FindVisage.cmake @@ -30,7 +30,7 @@ if (APPLE) find_library(VISAGE_CORE_LIBRARY NAME vscore PATH_SUFFIXES lib HINTS ${VISAGE_SEARCH_DIRS}) find_library(VISAGE_VISION_LIBRARY NAME vsvision PATH_SUFFIXES lib HINTS ${VISAGE_SEARCH_DIRS}) - find_library(VISAGE_OPENCV_LIBRARY NAME OpenCV PATH_SUFFIXES dependencies/OpenCV_MacOSX/lib ${VISAGE_SEARCH_DIRS}) + find_library(VISAGE_OPENCV_LIBRARY NAME OpenCV PATH_SUFFIXES dependencies/OpenCV_MacOSX/lib HINTS ${VISAGE_SEARCH_DIRS}) elseif (WIN32) find_path(VISAGE_XML_INCLUDE_DIR libxml/xmlreader.h PATH_SUFFIXES dependencies/libxml2/include HINTS ${VISAGE_SEARCH_DIRS}) From 27b876e84cc40342e7b982ee33b3fead0c03ca19 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Aug 2014 09:02:31 -0700 Subject: [PATCH 240/407] namechange _frame --> _frameCount --- libraries/shared/src/PhysicsSimulation.cpp | 10 +++++----- libraries/shared/src/PhysicsSimulation.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index 5fd40543e7..8fed575889 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -24,7 +24,7 @@ int MAX_ENTITIES_PER_SIMULATION = 64; int MAX_COLLISIONS_PER_SIMULATION = 256; -PhysicsSimulation::PhysicsSimulation() : _frame(0), _entity(NULL), _ragdoll(NULL), _collisions(MAX_COLLISIONS_PER_SIMULATION) { +PhysicsSimulation::PhysicsSimulation() : _frameCount(0), _entity(NULL), _ragdoll(NULL), _collisions(MAX_COLLISIONS_PER_SIMULATION) { } PhysicsSimulation::~PhysicsSimulation() { @@ -157,7 +157,7 @@ void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { } void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIterations, quint64 maxUsec) { - ++_frame; + ++_frameCount; if (!_ragdoll) { return; } @@ -288,9 +288,9 @@ void PhysicsSimulation::updateContacts() { } QMap::iterator itr = _contacts.find(key); if (itr == _contacts.end()) { - _contacts.insert(key, ContactPoint(*collision, _frame)); + _contacts.insert(key, ContactPoint(*collision, _frameCount)); } else { - itr.value().updateContact(*collision, _frame); + itr.value().updateContact(*collision, _frameCount); } } } @@ -300,7 +300,7 @@ const quint32 MAX_CONTACT_FRAME_LIFETIME = 2; void PhysicsSimulation::pruneContacts() { QMap::iterator itr = _contacts.begin(); while (itr != _contacts.end()) { - if (_frame - itr.value().getLastFrame() > MAX_CONTACT_FRAME_LIFETIME) { + if (_frameCount - itr.value().getLastFrame() > MAX_CONTACT_FRAME_LIFETIME) { itr = _contacts.erase(itr); } else { ++itr; diff --git a/libraries/shared/src/PhysicsSimulation.h b/libraries/shared/src/PhysicsSimulation.h index c8f41bb656..613440e71c 100644 --- a/libraries/shared/src/PhysicsSimulation.h +++ b/libraries/shared/src/PhysicsSimulation.h @@ -59,7 +59,7 @@ protected: void pruneContacts(); private: - quint32 _frame; + quint32 _frameCount; PhysicsEntity* _entity; Ragdoll* _ragdoll; From db1d6c8b49885113e9fe0ff394fae2e5fc0d2ed4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Aug 2014 09:23:05 -0700 Subject: [PATCH 241/407] MyAvatar's ragdoll is the main simulation ragdoll --- interface/src/avatar/MyAvatar.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 41eba45ac4..de85f1fe63 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -84,13 +84,13 @@ MyAvatar::MyAvatar() : } _skeletonModel.setEnableShapes(true); // The skeleton is both a PhysicsEntity and Ragdoll, so we add it to the simulation once for each type. - _physicsSimulation.addEntity(&_skeletonModel); + _physicsSimulation.setEntity(&_skeletonModel); _physicsSimulation.setRagdoll(&_skeletonModel); } MyAvatar::~MyAvatar() { _physicsSimulation.setRagdoll(NULL); - _physicsSimulation.removeEntity(&_skeletonModel); + _physicsSimulation.setEntity(NULL); _lookAtTargetAvatar.clear(); } @@ -1520,8 +1520,6 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float return false; } -const float BODY_COLLISION_RESOLUTION_TIMESCALE = 0.5f; // seconds - void MyAvatar::updateCollisionWithAvatars(float deltaTime) { // Reset detector for nearest avatar _distanceToNearestAvatar = std::numeric_limits::max(); From 87350ad2d0e03213e6d8da964ee5cdd7e85707a1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Aug 2014 11:45:06 -0700 Subject: [PATCH 242/407] ragdoll simulation now in model-relative frame (same rotation as world-frame, but translated to MyAvatar origin) --- interface/src/avatar/SkeletonModel.cpp | 85 +++++++++++++++++++--- interface/src/avatar/SkeletonModel.h | 1 + interface/src/renderer/Model.cpp | 50 +------------ interface/src/renderer/Model.h | 2 +- libraries/shared/src/FixedConstraint.cpp | 21 +++--- libraries/shared/src/FixedConstraint.h | 10 ++- libraries/shared/src/PhysicsSimulation.cpp | 5 +- libraries/shared/src/PhysicsSimulation.h | 5 ++ libraries/shared/src/Ragdoll.cpp | 67 +++++++++++++++-- libraries/shared/src/Ragdoll.h | 29 +++++++- libraries/shared/src/VerletPoint.cpp | 7 ++ libraries/shared/src/VerletPoint.h | 3 + 12 files changed, 199 insertions(+), 86 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index c8e7451fc1..463ed28faf 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -490,11 +490,13 @@ void SkeletonModel::renderRagdoll() { float alpha = 0.3f; float radius1 = 0.008f; float radius2 = 0.01f; + glm::vec3 simulationTranslation = getTranslationInSimulationFrame(); for (int i = 0; i < numPoints; ++i) { glPushMatrix(); - // draw each point as a yellow hexagon with black border - glm::vec3 position = _rotation * _ragdollPoints[i]._position; + // NOTE: ragdollPoints are in simulation-frame but we want them to be model-relative + glm::vec3 position = _ragdollPoints[i]._position - simulationTranslation; glTranslatef(position.x, position.y, position.z); + // draw each point as a yellow hexagon with black border glColor4f(0.0f, 0.0f, 0.0f, alpha); glutSolidSphere(radius2, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); glColor4f(1.0f, 1.0f, 0.0f, alpha); @@ -511,13 +513,14 @@ void SkeletonModel::initRagdollPoints() { clearRagdollConstraintsAndPoints(); _muscleConstraints.clear(); + initRagdollTransform(); // one point for each joint int numJoints = _jointStates.size(); _ragdollPoints.fill(VerletPoint(), numJoints); for (int i = 0; i < numJoints; ++i) { const JointState& state = _jointStates.at(i); - glm::vec3 position = state.getPosition(); - _ragdollPoints[i].initPosition(position); + // _ragdollPoints start in model-frame + _ragdollPoints[i].initPosition(state.getPosition()); } } @@ -534,12 +537,12 @@ void SkeletonModel::buildRagdollConstraints() { const JointState& state = _jointStates.at(i); int parentIndex = state.getParentIndex(); if (parentIndex == -1) { - FixedConstraint* anchor = new FixedConstraint(&(_ragdollPoints[i]), glm::vec3(0.0f)); - _ragdollConstraints.push_back(anchor); + FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_ragdollPoints[i])); + _fixedConstraints.push_back(anchor); } else { DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[i]), &(_ragdollPoints[parentIndex])); bone->setDistance(state.getDistanceToParent()); - _ragdollConstraints.push_back(bone); + _boneConstraints.push_back(bone); families.insert(parentIndex, i); } float boneLength = glm::length(state.getPositionInParentFrame()); @@ -558,11 +561,11 @@ void SkeletonModel::buildRagdollConstraints() { if (numChildren > 1) { for (int i = 1; i < numChildren; ++i) { DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[i-1]]), &(_ragdollPoints[children[i]])); - _ragdollConstraints.push_back(bone); + _boneConstraints.push_back(bone); } if (numChildren > 2) { DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[numChildren-1]]), &(_ragdollPoints[children[0]])); - _ragdollConstraints.push_back(bone); + _boneConstraints.push_back(bone); } } ++itr; @@ -604,6 +607,7 @@ void SkeletonModel::updateVisibleJointStates() { } QVector points; points.reserve(_jointStates.size()); + glm::quat invRotation = glm::inverse(_rotation); for (int i = 0; i < _jointStates.size(); i++) { JointState& state = _jointStates[i]; points.push_back(_ragdollPoints[i]._position); @@ -628,8 +632,9 @@ void SkeletonModel::updateVisibleJointStates() { // we're looking for the rotation that moves visible bone parallel to ragdoll bone // rotationBetween(jointTip - jointPivot, shapeTip - shapePivot) + // NOTE: points are in simulation-frame so rotate line segment into model-frame glm::quat delta = rotationBetween(state.getVisiblePosition() - extractTranslation(parentTransform), - points[i] - points[parentIndex]); + invRotation * (points[i] - points[parentIndex])); // apply parentState.mixVisibleRotationDelta(delta, 0.01f); @@ -641,6 +646,7 @@ void SkeletonModel::updateVisibleJointStates() { // virtual void SkeletonModel::stepRagdollForward(float deltaTime) { + setRagdollTransform(_translation, _rotation); Ragdoll::stepRagdollForward(deltaTime); updateMuscles(); int numConstraints = _muscleConstraints.size(); @@ -714,6 +720,7 @@ void SkeletonModel::buildShapes() { if (_ragdollPoints.size() == numStates) { int numJoints = _jointStates.size(); for (int i = 0; i < numJoints; ++i) { + // ragdollPoints start in model-frame _ragdollPoints[i].initPosition(_jointStates.at(i).getPosition()); } } @@ -735,9 +742,11 @@ void SkeletonModel::moveShapesTowardJoints(float deltaTime) { float fraction = glm::clamp(deltaTime / RAGDOLL_FOLLOWS_JOINTS_TIMESCALE, 0.0f, 1.0f); float oneMinusFraction = 1.0f - fraction; + glm::vec3 simulationTranslation = getTranslationInSimulationFrame(); for (int i = 0; i < numStates; ++i) { + // ragdollPoints are in simulation-frame but jointStates are in model-frame _ragdollPoints[i].initPosition(oneMinusFraction * _ragdollPoints[i]._position + - fraction * _jointStates.at(i).getPosition()); + fraction * (simulationTranslation + _rotation * (_jointStates.at(i).getPosition()))); } } @@ -748,7 +757,8 @@ void SkeletonModel::updateMuscles() { int j = constraint->getParentIndex(); int k = constraint->getChildIndex(); assert(j != -1 && k != -1); - constraint->setChildOffset(_jointStates.at(k).getPosition() - _jointStates.at(j).getPosition()); + // ragdollPoints are in simulation-frame but jointStates are in model-frame + constraint->setChildOffset(_rotation * (_jointStates.at(k).getPosition() - _jointStates.at(j).getPosition())); } } @@ -891,3 +901,54 @@ void SkeletonModel::renderBoundingCollisionShapes(float alpha) { glPopMatrix(); } +const int BALL_SUBDIVISIONS = 10; + +// virtual +void SkeletonModel::renderJointCollisionShapes(float alpha) { + glPushMatrix(); + Application::getInstance()->loadTranslatedViewMatrix(_translation); + glm::vec3 simulationTranslation = getTranslationInSimulationFrame(); + for (int i = 0; i < _shapes.size(); i++) { + Shape* shape = _shapes[i]; + if (!shape) { + continue; + } + + glPushMatrix(); + // shapes are stored in simulation-frame but we want position to be model-relative + if (shape->getType() == Shape::SPHERE_SHAPE) { + glm::vec3 position = shape->getTranslation() - simulationTranslation; + glTranslatef(position.x, position.y, position.z); + // draw a grey sphere at shape position + glColor4f(0.75f, 0.75f, 0.75f, alpha); + glutSolidSphere(shape->getBoundingRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); + } else if (shape->getType() == Shape::CAPSULE_SHAPE) { + CapsuleShape* capsule = static_cast(shape); + + // draw a blue sphere at the capsule endpoint + glm::vec3 endPoint; + capsule->getEndPoint(endPoint); + endPoint = endPoint - simulationTranslation; + glTranslatef(endPoint.x, endPoint.y, endPoint.z); + glColor4f(0.6f, 0.6f, 0.8f, alpha); + glutSolidSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); + + // draw a yellow sphere at the capsule startpoint + glm::vec3 startPoint; + capsule->getStartPoint(startPoint); + startPoint = startPoint - simulationTranslation; + glm::vec3 axis = endPoint - startPoint; + glTranslatef(-axis.x, -axis.y, -axis.z); + glColor4f(0.8f, 0.8f, 0.6f, alpha); + glutSolidSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); + + // draw a green cylinder between the two points + glm::vec3 origin(0.0f); + glColor4f(0.6f, 0.8f, 0.6f, alpha); + Avatar::renderJointConnectingCone( origin, axis, capsule->getRadius(), capsule->getRadius()); + } + glPopMatrix(); + } + glPopMatrix(); +} + diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 5cb89f5e44..55fedbcb6b 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -105,6 +105,7 @@ public: void computeBoundingShape(const FBXGeometry& geometry); void renderBoundingCollisionShapes(float alpha); + void renderJointCollisionShapes(float alpha); float getBoundingShapeRadius() const { return _boundingShape.getRadius(); } const CapsuleShape& getBoundingShape() const { return _boundingShape; } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 63a94772a7..025971db4b 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1243,55 +1243,7 @@ float Model::getLimbLength(int jointIndex) const { const int BALL_SUBDIVISIONS = 10; void Model::renderJointCollisionShapes(float alpha) { - glPushMatrix(); - Application::getInstance()->loadTranslatedViewMatrix(_translation); - for (int i = 0; i < _shapes.size(); i++) { - Shape* shape = _shapes[i]; - if (!shape) { - continue; - } - - glPushMatrix(); - // NOTE: the shapes are in the avatar local-frame - if (shape->getType() == Shape::SPHERE_SHAPE) { - // shapes are stored in world-frame, so we have to transform into model frame - glm::vec3 position = _rotation * shape->getTranslation(); - glTranslatef(position.x, position.y, position.z); - const glm::quat& rotation = shape->getRotation(); - glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - - // draw a grey sphere at shape position - glColor4f(0.75f, 0.75f, 0.75f, alpha); - glutSolidSphere(shape->getBoundingRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); - } else if (shape->getType() == Shape::CAPSULE_SHAPE) { - CapsuleShape* capsule = static_cast(shape); - - // draw a blue sphere at the capsule endpoint - glm::vec3 endPoint; - capsule->getEndPoint(endPoint); - endPoint = _rotation * endPoint; - glTranslatef(endPoint.x, endPoint.y, endPoint.z); - glColor4f(0.6f, 0.6f, 0.8f, alpha); - glutSolidSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); - - // draw a yellow sphere at the capsule startpoint - glm::vec3 startPoint; - capsule->getStartPoint(startPoint); - startPoint = _rotation * startPoint; - glm::vec3 axis = endPoint - startPoint; - glTranslatef(-axis.x, -axis.y, -axis.z); - glColor4f(0.8f, 0.8f, 0.6f, alpha); - glutSolidSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); - - // draw a green cylinder between the two points - glm::vec3 origin(0.0f); - glColor4f(0.6f, 0.8f, 0.6f, alpha); - Avatar::renderJointConnectingCone( origin, axis, capsule->getRadius(), capsule->getRadius()); - } - glPopMatrix(); - } - glPopMatrix(); + // implement this when we have shapes for regular models } void Model::setBlendedVertices(const QVector& vertices, const QVector& normals) { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index cbed941791..7a29b61420 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -149,7 +149,7 @@ public: virtual void buildShapes(); virtual void updateShapePositions(); - void renderJointCollisionShapes(float alpha); + virtual void renderJointCollisionShapes(float alpha); /// Sets blended vertices computed in a separate thread. void setBlendedVertices(const QVector& vertices, const QVector& normals); diff --git a/libraries/shared/src/FixedConstraint.cpp b/libraries/shared/src/FixedConstraint.cpp index 099c6d7bac..539978db5d 100644 --- a/libraries/shared/src/FixedConstraint.cpp +++ b/libraries/shared/src/FixedConstraint.cpp @@ -13,15 +13,22 @@ #include "Shape.h" // for MAX_SHAPE_MASS #include "VerletPoint.h" -FixedConstraint::FixedConstraint(VerletPoint* point, const glm::vec3& anchor) : _point(point), _anchor(anchor) { +FixedConstraint::FixedConstraint(glm::vec3* anchor, VerletPoint* point) : _anchor(anchor), _point(point) { + assert(anchor); + assert(point); + _point->_mass = MAX_SHAPE_MASS; } float FixedConstraint::enforce() { assert(_point != NULL); - // TODO: use fast approximate sqrt here - float distance = glm::distance(_anchor, _point->_position); - _point->_position = _anchor; - return distance; + _point->_position = *_anchor; + _point->_lastPosition = *_anchor; + return 0.0f; +} + +void FixedConstraint::setAnchor(glm::vec3* anchor) { + assert(anchor); + _anchor = anchor; } void FixedConstraint::setPoint(VerletPoint* point) { @@ -29,7 +36,3 @@ void FixedConstraint::setPoint(VerletPoint* point) { _point = point; _point->_mass = MAX_SHAPE_MASS; } - -void FixedConstraint::setAnchor(const glm::vec3& anchor) { - _anchor = anchor; -} diff --git a/libraries/shared/src/FixedConstraint.h b/libraries/shared/src/FixedConstraint.h index 050232a027..66a27369ce 100644 --- a/libraries/shared/src/FixedConstraint.h +++ b/libraries/shared/src/FixedConstraint.h @@ -18,15 +18,19 @@ class VerletPoint; +// FixedConstraint takes pointers to a glm::vec3 and a VerletPoint. +// The enforcement will copy the value of the vec3 into the VerletPoint. + class FixedConstraint : public Constraint { public: - FixedConstraint(VerletPoint* point, const glm::vec3& anchor); + FixedConstraint(glm::vec3* anchor, VerletPoint* point); + ~FixedConstraint() {} float enforce(); + void setAnchor(glm::vec3* anchor); void setPoint(VerletPoint* point); - void setAnchor(const glm::vec3& anchor); private: + glm::vec3* _anchor; VerletPoint* _point; - glm::vec3 _anchor; }; #endif // hifi_FixedConstraint_h diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index 8fed575889..8ae30ce699 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -24,7 +24,8 @@ int MAX_ENTITIES_PER_SIMULATION = 64; int MAX_COLLISIONS_PER_SIMULATION = 256; -PhysicsSimulation::PhysicsSimulation() : _frameCount(0), _entity(NULL), _ragdoll(NULL), _collisions(MAX_COLLISIONS_PER_SIMULATION) { +PhysicsSimulation::PhysicsSimulation() : _translation(0.0f), _frameCount(0), _entity(NULL), _ragdoll(NULL), + _collisions(MAX_COLLISIONS_PER_SIMULATION) { } PhysicsSimulation::~PhysicsSimulation() { @@ -204,7 +205,7 @@ void PhysicsSimulation::moveRagdolls(float deltaTime) { _ragdoll->stepRagdollForward(deltaTime); int numDolls = _otherRagdolls.size(); for (int i = 0; i < numDolls; ++i) { - _otherRagdolls.at(i)->stepRagdollForward(deltaTime); + _otherRagdolls[i]->stepRagdollForward(deltaTime); } } diff --git a/libraries/shared/src/PhysicsSimulation.h b/libraries/shared/src/PhysicsSimulation.h index 613440e71c..be1f2fb366 100644 --- a/libraries/shared/src/PhysicsSimulation.h +++ b/libraries/shared/src/PhysicsSimulation.h @@ -28,6 +28,9 @@ public: PhysicsSimulation(); ~PhysicsSimulation(); + void setTranslation(const glm::vec3& translation) { _translation = translation; } + const glm::vec3& getTranslation() const { return _translation; } + void setRagdoll(Ragdoll* ragdoll) { _ragdoll = ragdoll; } void setEntity(PhysicsEntity* entity); @@ -59,6 +62,8 @@ protected: void pruneContacts(); private: + glm::vec3 _translation; // origin of simulation in world-frame + quint32 _frameCount; PhysicsEntity* _entity; diff --git a/libraries/shared/src/Ragdoll.cpp b/libraries/shared/src/Ragdoll.cpp index 6282db4dfb..5b21687bbd 100644 --- a/libraries/shared/src/Ragdoll.cpp +++ b/libraries/shared/src/Ragdoll.cpp @@ -9,13 +9,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "Ragdoll.h" #include "Constraint.h" #include "DistanceConstraint.h" #include "FixedConstraint.h" +#include "PhysicsSimulation.h" +#include "SharedUtil.h" // for EPSILON -Ragdoll::Ragdoll() { +Ragdoll::Ragdoll() : _ragdollTranslation(0.0f), _translationInSimulationFrame(0.0f), _ragdollSimulation(NULL) { } Ragdoll::~Ragdoll() { @@ -23,6 +27,9 @@ Ragdoll::~Ragdoll() { } void Ragdoll::stepRagdollForward(float deltaTime) { + if (_ragdollSimulation) { + updateSimulationTransforms(_ragdollTranslation - _ragdollSimulation->getTranslation(), _ragdollRotation); + } int numPoints = _ragdollPoints.size(); for (int i = 0; i < numPoints; ++i) { _ragdollPoints[i].integrateForward(); @@ -30,21 +37,65 @@ void Ragdoll::stepRagdollForward(float deltaTime) { } void Ragdoll::clearRagdollConstraintsAndPoints() { - int numConstraints = _ragdollConstraints.size(); + int numConstraints = _boneConstraints.size(); for (int i = 0; i < numConstraints; ++i) { - delete _ragdollConstraints[i]; + delete _boneConstraints[i]; } - _ragdollConstraints.clear(); + _boneConstraints.clear(); + numConstraints = _fixedConstraints.size(); + for (int i = 0; i < numConstraints; ++i) { + delete _fixedConstraints[i]; + } + _fixedConstraints.clear(); _ragdollPoints.clear(); } float Ragdoll::enforceRagdollConstraints() { float maxDistance = 0.0f; - const int numConstraints = _ragdollConstraints.size(); + // enforce the bone constraints first + int numConstraints = _boneConstraints.size(); for (int i = 0; i < numConstraints; ++i) { - DistanceConstraint* c = static_cast(_ragdollConstraints[i]); - //maxDistance = glm::max(maxDistance, _ragdollConstraints[i]->enforce()); - maxDistance = glm::max(maxDistance, c->enforce()); + maxDistance = glm::max(maxDistance, _boneConstraints[i]->enforce()); + } + // enforce FixedConstraints second + numConstraints = _fixedConstraints.size(); + for (int i = 0; i < _fixedConstraints.size(); ++i) { + maxDistance = glm::max(maxDistance, _fixedConstraints[i]->enforce()); } return maxDistance; } + +void Ragdoll::initRagdollTransform() { + _ragdollTranslation = glm::vec3(0.0f); + _ragdollRotation = glm::quat(); + _translationInSimulationFrame = glm::vec3(0.0f); + _rotationInSimulationFrame = glm::quat(); +} + +void Ragdoll::setRagdollTransform(const glm::vec3& translation, const glm::quat& rotation) { + _ragdollTranslation = translation; + _ragdollRotation = rotation; +} + +void Ragdoll::updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation) { + const float EPSILON2 = EPSILON * EPSILON; + if (glm::distance2(translation, _translationInSimulationFrame) < EPSILON2 && + glm::abs(1.0f - glm::abs(glm::dot(rotation, _rotationInSimulationFrame))) < EPSILON2) { + // nothing to do + return; + } + + // compute linear and angular deltas + glm::vec3 deltaPosition = translation - _translationInSimulationFrame; + glm::quat deltaRotation = rotation * glm::inverse(_rotationInSimulationFrame); + + // apply the deltas to all ragdollPoints + int numPoints = _ragdollPoints.size(); + for (int i = 0; i < numPoints; ++i) { + _ragdollPoints[i].move(deltaPosition, deltaRotation, _translationInSimulationFrame); + } + + // remember the current transform + _translationInSimulationFrame = translation; + _rotationInSimulationFrame = rotation; +} diff --git a/libraries/shared/src/Ragdoll.h b/libraries/shared/src/Ragdoll.h index 91a7e7330e..421e8e3ff8 100644 --- a/libraries/shared/src/Ragdoll.h +++ b/libraries/shared/src/Ragdoll.h @@ -18,7 +18,14 @@ #include -class Constraint; +//#include "PhysicsSimulation.h" + +class DistanceConstraint; +class FixedConstraint; +class PhysicsSimulation; + +// TODO: don't derive SkeletonModel from Ragdoll so we can clean up the Ragdoll API +// (==> won't need to worry about namespace conflicts between Entity and Ragdoll). class Ragdoll { public: @@ -35,13 +42,31 @@ public: const QVector& getRagdollPoints() const { return _ragdollPoints; } QVector& getRagdollPoints() { return _ragdollPoints; } + void initRagdollTransform(); + + /// set the translation and rotation of the Ragdoll and adjust all VerletPoints. + void setRagdollTransform(const glm::vec3& translation, const glm::quat& rotation); + + const glm::vec3& getTranslationInSimulationFrame() const { return _translationInSimulationFrame; } + protected: void clearRagdollConstraintsAndPoints(); virtual void initRagdollPoints() = 0; virtual void buildRagdollConstraints() = 0; + glm::vec3 _ragdollTranslation; // world-frame + glm::quat _ragdollRotation; // world-frame + glm::vec3 _translationInSimulationFrame; + glm::quat _rotationInSimulationFrame; + QVector _ragdollPoints; - QVector _ragdollConstraints; + QVector _boneConstraints; + QVector _fixedConstraints; +private: + void updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation); + + friend class PhysicsSimulation; + PhysicsSimulation* _ragdollSimulation; }; #endif // hifi_Ragdoll_h diff --git a/libraries/shared/src/VerletPoint.cpp b/libraries/shared/src/VerletPoint.cpp index 654a74d7ac..dae861a7ab 100644 --- a/libraries/shared/src/VerletPoint.cpp +++ b/libraries/shared/src/VerletPoint.cpp @@ -31,3 +31,10 @@ void VerletPoint::applyAccumulatedDelta() { _numDeltas = 0; } } + +void VerletPoint::move(const glm::vec3& deltaPosition, const glm::quat& deltaRotation, const glm::vec3& oldPivot) { + glm::vec3 arm = _position - oldPivot; + _position += deltaPosition + (deltaRotation * arm - arm); + arm = _lastPosition - oldPivot; + _lastPosition += deltaPosition + (deltaRotation * arm - arm); +} diff --git a/libraries/shared/src/VerletPoint.h b/libraries/shared/src/VerletPoint.h index f59afb16c5..a1dca3e955 100644 --- a/libraries/shared/src/VerletPoint.h +++ b/libraries/shared/src/VerletPoint.h @@ -13,6 +13,8 @@ #define hifi_VerletPoint_h #include +#include + class VerletPoint { public: @@ -22,6 +24,7 @@ public: void integrateForward(); void accumulateDelta(const glm::vec3& delta); void applyAccumulatedDelta(); + void move(const glm::vec3& deltaPosition, const glm::quat& deltaRotation, const glm::vec3& oldPivot); glm::vec3 _position; glm::vec3 _lastPosition; From 0f784a9cc514ec38887e7d25a48c0a1b35be31be Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Aug 2014 13:09:05 -0700 Subject: [PATCH 243/407] add other ragdolls to simulation --- interface/src/avatar/MyAvatar.cpp | 5 +--- libraries/shared/src/PhysicsSimulation.cpp | 30 +++++++++++++++++++--- libraries/shared/src/PhysicsSimulation.h | 2 +- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index de85f1fe63..33c053464c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -204,6 +204,7 @@ void MyAvatar::simulate(float deltaTime) { const int minError = 0.01f; const float maxIterations = 10; const quint64 maxUsec = 2000; + _physicsSimulation.setTranslation(_position); _physicsSimulation.stepForward(deltaTime, minError, maxIterations, maxUsec); } else { _skeletonModel.moveShapesTowardJoints(1.0f); @@ -230,12 +231,10 @@ void MyAvatar::simulate(float deltaTime) { } else { _trapDuration = 0.0f; } - /* TODO: Andrew to make this work if (_collisionGroups & COLLISION_GROUP_AVATARS) { PerformanceTimer perfTimer("avatars"); updateCollisionWithAvatars(deltaTime); } - */ } // consider updating our billboard @@ -1566,13 +1565,11 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { PhysicsSimulation* simulation = skeleton->getSimulation(); if (avatar == nearestAvatar) { if (simulation != &(_physicsSimulation)) { - std::cout << "adebug adding other avatar " << avatar << " to simulation" << std::endl; // adebug skeleton->setEnableShapes(true); _physicsSimulation.addEntity(skeleton); _physicsSimulation.addRagdoll(skeleton); } } else if (simulation == &(_physicsSimulation)) { - std::cout << "adebug removing other avatar " << avatar << " from simulation" << std::endl; // adebug _physicsSimulation.removeRagdoll(skeleton); _physicsSimulation.removeEntity(skeleton); skeleton->setEnableShapes(false); diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index 8ae30ce699..1007998b56 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -44,6 +44,19 @@ PhysicsSimulation::~PhysicsSimulation() { _otherRagdolls.clear(); } +void PhysicsSimulation::setRagdoll(Ragdoll* ragdoll) { + if (_ragdoll != ragdoll) { + if (_ragdoll) { + _ragdoll->_ragdollSimulation = NULL; + } + _ragdoll = ragdoll; + if (_ragdoll) { + assert(!(_ragdoll->_ragdollSimulation)); + _ragdoll->_ragdollSimulation = this; + } + } +} + void PhysicsSimulation::setEntity(PhysicsEntity* entity) { if (_entity != entity) { if (_entity) { @@ -79,6 +92,7 @@ bool PhysicsSimulation::addEntity(PhysicsEntity* entity) { return false; } // add to list + assert(!(entity->_simulation)); entity->_simulation = this; _otherEntities.push_back(entity); return true; @@ -128,19 +142,26 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { // list is full return false; } - for (int i = 0; i < numDolls; ++i) { - if (doll == _otherRagdolls[i]) { - // already in list - return true; + if (doll->_ragdollSimulation == this) { + for (int i = 0; i < numDolls; ++i) { + if (doll == _otherRagdolls[i]) { + // already in list + return true; + } } } // add to list + assert(!(doll->_ragdollSimulation)); + doll->_ragdollSimulation = this; _otherRagdolls.push_back(doll); return true; } void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { int numDolls = _otherRagdolls.size(); + if (doll->_ragdollSimulation != this) { + return; + } for (int i = 0; i < numDolls; ++i) { if (doll == _otherRagdolls[i]) { if (i == numDolls - 1) { @@ -152,6 +173,7 @@ void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { _otherRagdolls.pop_back(); _otherRagdolls[i] = lastDoll; } + doll->_ragdollSimulation = NULL; break; } } diff --git a/libraries/shared/src/PhysicsSimulation.h b/libraries/shared/src/PhysicsSimulation.h index be1f2fb366..61ab1bf177 100644 --- a/libraries/shared/src/PhysicsSimulation.h +++ b/libraries/shared/src/PhysicsSimulation.h @@ -31,7 +31,7 @@ public: void setTranslation(const glm::vec3& translation) { _translation = translation; } const glm::vec3& getTranslation() const { return _translation; } - void setRagdoll(Ragdoll* ragdoll) { _ragdoll = ragdoll; } + void setRagdoll(Ragdoll* ragdoll); void setEntity(PhysicsEntity* entity); /// \return true if entity was added to or is already in the list From 94da63006c420e79b759a7d9ee62b4b2d63a4d8b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Aug 2014 14:35:32 -0700 Subject: [PATCH 244/407] VerletPoint::_mass is now private We set the mass of other avatars artificially high so they are less movable. --- interface/src/avatar/SkeletonModel.cpp | 7 ++++--- libraries/shared/src/FixedConstraint.cpp | 3 --- libraries/shared/src/PhysicsSimulation.cpp | 10 ++++++++-- libraries/shared/src/Ragdoll.cpp | 16 +++++++++++++++- libraries/shared/src/Ragdoll.h | 4 ++++ libraries/shared/src/VerletCapsuleShape.cpp | 2 +- libraries/shared/src/VerletPoint.cpp | 9 +++++++++ libraries/shared/src/VerletPoint.h | 5 ++++- libraries/shared/src/VerletSphereShape.cpp | 2 +- 9 files changed, 46 insertions(+), 12 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 463ed28faf..6b77e1c2f1 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -671,6 +671,7 @@ void SkeletonModel::buildShapes() { } initRagdollPoints(); + float massScale = getMassScale(); float uniformScale = extractUniformScale(_scale); const int numStates = _jointStates.size(); @@ -689,12 +690,12 @@ void SkeletonModel::buildShapes() { if (type == Shape::SPHERE_SHAPE) { shape = new VerletSphereShape(radius, &(_ragdollPoints[i])); shape->setEntity(this); - _ragdollPoints[i]._mass = glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()); + _ragdollPoints[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); } else if (type == Shape::CAPSULE_SHAPE) { assert(parentIndex != -1); shape = new VerletCapsuleShape(radius, &(_ragdollPoints[parentIndex]), &(_ragdollPoints[i])); shape->setEntity(this); - _ragdollPoints[i]._mass = glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()); + _ragdollPoints[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); } if (parentIndex != -1) { // always disable collisions between joint and its parent @@ -702,7 +703,7 @@ void SkeletonModel::buildShapes() { } else { // give the base joint a very large mass since it doesn't actually move // in the local-frame simulation (it defines the origin) - _ragdollPoints[i]._mass = VERY_BIG_MASS; + _ragdollPoints[i].setMass(VERY_BIG_MASS); } _shapes.push_back(shape); } diff --git a/libraries/shared/src/FixedConstraint.cpp b/libraries/shared/src/FixedConstraint.cpp index 539978db5d..8f1edc1fb5 100644 --- a/libraries/shared/src/FixedConstraint.cpp +++ b/libraries/shared/src/FixedConstraint.cpp @@ -10,13 +10,11 @@ // #include "FixedConstraint.h" -#include "Shape.h" // for MAX_SHAPE_MASS #include "VerletPoint.h" FixedConstraint::FixedConstraint(glm::vec3* anchor, VerletPoint* point) : _anchor(anchor), _point(point) { assert(anchor); assert(point); - _point->_mass = MAX_SHAPE_MASS; } float FixedConstraint::enforce() { @@ -34,5 +32,4 @@ void FixedConstraint::setAnchor(glm::vec3* anchor) { void FixedConstraint::setPoint(VerletPoint* point) { assert(point); _point = point; - _point->_mass = MAX_SHAPE_MASS; } diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index 1007998b56..6dcafc6a54 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -133,6 +133,8 @@ void PhysicsSimulation::removeShapes(const PhysicsEntity* entity) { } } +const float OTHER_RAGDOLL_MASS_SCALE = 10.0f; + bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { if (!doll) { return false; @@ -154,6 +156,9 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { assert(!(doll->_ragdollSimulation)); doll->_ragdollSimulation = this; _otherRagdolls.push_back(doll); + + // set the massScale of otherRagdolls artificially high + doll->setMassScale(OTHER_RAGDOLL_MASS_SCALE); return true; } @@ -174,6 +179,7 @@ void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { _otherRagdolls[i] = lastDoll; } doll->_ragdollSimulation = NULL; + doll->setMassScale(1.0f); break; } } @@ -237,7 +243,7 @@ void PhysicsSimulation::computeCollisions() { const QVector shapes = _entity->getShapes(); int numShapes = shapes.size(); - // collide with self + // collide main ragdoll with self for (int i = 0; i < numShapes; ++i) { const Shape* shape = shapes.at(i); if (!shape) { @@ -251,7 +257,7 @@ void PhysicsSimulation::computeCollisions() { } } - // collide with others + // collide main ragdoll with others int numEntities = _otherEntities.size(); for (int i = 0; i < numEntities; ++i) { const QVector otherShapes = _otherEntities.at(i)->getShapes(); diff --git a/libraries/shared/src/Ragdoll.cpp b/libraries/shared/src/Ragdoll.cpp index 5b21687bbd..e10e1620ae 100644 --- a/libraries/shared/src/Ragdoll.cpp +++ b/libraries/shared/src/Ragdoll.cpp @@ -19,7 +19,7 @@ #include "PhysicsSimulation.h" #include "SharedUtil.h" // for EPSILON -Ragdoll::Ragdoll() : _ragdollTranslation(0.0f), _translationInSimulationFrame(0.0f), _ragdollSimulation(NULL) { +Ragdoll::Ragdoll() : _massScale(1.0f), _ragdollTranslation(0.0f), _translationInSimulationFrame(0.0f), _ragdollSimulation(NULL) { } Ragdoll::~Ragdoll() { @@ -99,3 +99,17 @@ void Ragdoll::updateSimulationTransforms(const glm::vec3& translation, const glm _translationInSimulationFrame = translation; _rotationInSimulationFrame = rotation; } + +void Ragdoll::setMassScale(float scale) { + const float MIN_SCALE = 1.0e-2f; + const float MAX_SCALE = 1.0e6f; + scale = glm::clamp(glm::abs(scale), MIN_SCALE, MAX_SCALE); + if (scale != _massScale) { + float rescale = scale / _massScale; + int numPoints = _ragdollPoints.size(); + for (int i = 0; i < numPoints; ++i) { + _ragdollPoints[i].setMass(rescale * _ragdollPoints[i].getMass()); + } + _massScale = scale; + } +} diff --git a/libraries/shared/src/Ragdoll.h b/libraries/shared/src/Ragdoll.h index 421e8e3ff8..ec5a561d1a 100644 --- a/libraries/shared/src/Ragdoll.h +++ b/libraries/shared/src/Ragdoll.h @@ -49,11 +49,15 @@ public: const glm::vec3& getTranslationInSimulationFrame() const { return _translationInSimulationFrame; } + void setMassScale(float scale); + float getMassScale() const { return _massScale; } + protected: void clearRagdollConstraintsAndPoints(); virtual void initRagdollPoints() = 0; virtual void buildRagdollConstraints() = 0; + float _massScale; glm::vec3 _ragdollTranslation; // world-frame glm::quat _ragdollRotation; // world-frame glm::vec3 _translationInSimulationFrame; diff --git a/libraries/shared/src/VerletCapsuleShape.cpp b/libraries/shared/src/VerletCapsuleShape.cpp index 6f547d2048..ce324a781a 100644 --- a/libraries/shared/src/VerletCapsuleShape.cpp +++ b/libraries/shared/src/VerletCapsuleShape.cpp @@ -97,7 +97,7 @@ float VerletCapsuleShape::computeEffectiveMass(const glm::vec3& penetration, con _endLagrangeCoef = 1.0f; } // the effective mass is the weighted sum of the two endpoints - return _startLagrangeCoef * _startPoint->_mass + _endLagrangeCoef * _endPoint->_mass; + return _startLagrangeCoef * _startPoint->getMass() + _endLagrangeCoef * _endPoint->getMass(); } void VerletCapsuleShape::accumulateDelta(float relativeMassFactor, const glm::vec3& penetration) { diff --git a/libraries/shared/src/VerletPoint.cpp b/libraries/shared/src/VerletPoint.cpp index dae861a7ab..d2dd985587 100644 --- a/libraries/shared/src/VerletPoint.cpp +++ b/libraries/shared/src/VerletPoint.cpp @@ -38,3 +38,12 @@ void VerletPoint::move(const glm::vec3& deltaPosition, const glm::quat& deltaRot arm = _lastPosition - oldPivot; _lastPosition += deltaPosition + (deltaRotation * arm - arm); } + +void VerletPoint::setMass(float mass) { + const float MIN_MASS = 1.0e-6f; + const float MAX_MASS = 1.0e18f; + if (glm::isnan(mass)) { + mass = MIN_MASS; + } + _mass = glm::clamp(glm::abs(mass), MIN_MASS, MAX_MASS); +} diff --git a/libraries/shared/src/VerletPoint.h b/libraries/shared/src/VerletPoint.h index a1dca3e955..6f94656966 100644 --- a/libraries/shared/src/VerletPoint.h +++ b/libraries/shared/src/VerletPoint.h @@ -26,11 +26,14 @@ public: void applyAccumulatedDelta(); void move(const glm::vec3& deltaPosition, const glm::quat& deltaRotation, const glm::vec3& oldPivot); + void setMass(float mass); + float getMass() const { return _mass; } + glm::vec3 _position; glm::vec3 _lastPosition; - float _mass; private: + float _mass; glm::vec3 _accumulatedDelta; int _numDeltas; }; diff --git a/libraries/shared/src/VerletSphereShape.cpp b/libraries/shared/src/VerletSphereShape.cpp index e24465fd89..da8242f26a 100644 --- a/libraries/shared/src/VerletSphereShape.cpp +++ b/libraries/shared/src/VerletSphereShape.cpp @@ -36,7 +36,7 @@ const glm::vec3& VerletSphereShape::getTranslation() const { // virtual float VerletSphereShape::computeEffectiveMass(const glm::vec3& penetration, const glm::vec3& contactPoint) { - return _point->_mass; + return _point->getMass(); } // virtual From 8de2dd9485373a5f5e2cdcde0cbab2756f2b2fed Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 7 Aug 2014 14:38:47 -0700 Subject: [PATCH 245/407] Working on ray intersection testing. --- interface/src/ui/MetavoxelEditor.cpp | 8 +- .../metavoxels/src/MetavoxelClientManager.cpp | 170 ++++++++++++++---- 2 files changed, 140 insertions(+), 38 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index a2bb1770b2..a5186567bd 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -1100,11 +1100,13 @@ void HeightfieldBrushTool::render() { glm::vec3 origin = Application::getInstance()->getMouseRayOrigin(); glm::vec3 direction = Application::getInstance()->getMouseRayDirection(); - float distance = -origin.y / direction.y; + float distance; + if (!Application::getInstance()->getMetavoxels()->findFirstRayHeightfieldIntersection(origin, direction, distance)) { + return; + } + qDebug() << distance; glm::vec3 point = origin + distance * direction; - point.y = Application::getInstance()->getMetavoxels()->getHeightfieldHeight(point); - glPushMatrix(); glTranslatef(point.x, point.y, point.z); diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index 51eb4c653c..a9eff58f33 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -64,6 +64,8 @@ SharedObjectPointer MetavoxelClientManager::findFirstRaySpannerIntersection(cons class RayHeightfieldIntersectionVisitor : public RayIntersectionVisitor { public: + float intersectionDistance; + RayHeightfieldIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, const MetavoxelLOD& lod); virtual int visit(MetavoxelInfo& info, float distance); @@ -72,7 +74,8 @@ public: RayHeightfieldIntersectionVisitor::RayHeightfieldIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, const MetavoxelLOD& lod) : RayIntersectionVisitor(origin, direction, QVector() << - AttributeRegistry::getInstance()->getHeightfieldAttribute(), QVector(), lod) { + AttributeRegistry::getInstance()->getHeightfieldAttribute(), QVector(), lod), + intersectionDistance(FLT_MAX) { } static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / 255.0f; @@ -91,42 +94,129 @@ int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance int highest = size - 1; float heightScale = highest / EIGHT_BIT_MAXIMUM_RECIPROCAL; - // find the initial location - glm::vec3 location = (_origin + distance * _direction - info.minimum) * (float)highest / info.size; - - glm::vec3 floors = glm::floor(location); - glm::vec3 ceils = glm::ceil(location); - int floorX = qMin(qMax((int)floors.x, 0), highest); - int floorZ = qMin(qMax((int)floors.z, 0), highest); - int ceilX = qMin(qMax((int)ceils.x, 0), highest); - int ceilZ = qMin(qMax((int)ceils.z, 0), highest); - float upperLeft = src[floorZ * size + floorX] * heightScale; - float upperRight = src[floorZ * size + ceilX] * heightScale; - float lowerLeft = src[ceilZ * size + floorX] * heightScale; - float lowerRight = src[ceilZ * size + ceilX] * heightScale; - - glm::vec3 relativeLocation = location - glm::vec3(floors.x, upperLeft, floors.z); - - glm::vec3 lowerNormal(lowerLeft - lowerRight, 1.0f, upperLeft - lowerLeft); - float lowerProduct = glm::dot(lowerNormal, _direction); - if (lowerProduct < EPSILON) { - float distance = -glm::dot(lowerNormal, relativeLocation) / lowerProduct; - glm::vec3 intersection = relativeLocation + distance * _direction; - if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && - intersection.z >= intersection.x) { - return SHORT_CIRCUIT; + // find the initial location in heightfield coordinates + glm::vec3 entry = (_origin + distance * _direction - info.minimum) * (float)highest / info.size; + glm::vec3 floors = glm::floor(entry); + glm::vec3 ceils = glm::ceil(entry); + if (floors.x == ceils.x) { + if (_direction.x > 0.0f) { + ceils.x += 1.0f; + } else { + floors.x -= 1.0f; + } + } + if (floors.z == ceils.z) { + if (_direction.z > 0.0f) { + ceils.z += 1.0f; + } else { + floors.z -= 1.0f; } } - glm::vec3 upperNormal(upperLeft - upperRight, 1.0f, upperRight - lowerRight); - float upperProduct = glm::dot(upperNormal, _direction); - if (upperProduct < EPSILON) { - float distance = -glm::dot(upperNormal, relativeLocation) / upperProduct; - glm::vec3 intersection = relativeLocation + distance * _direction; - if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && - intersection.x >= intersection.z) { - return SHORT_CIRCUIT; + bool withinBounds = true; + float accumulatedDistance = 0.0f; + while (withinBounds) { + // find the heights at the corners of the current cell + int floorX = qMin(qMax((int)floors.x, 0), highest); + int floorZ = qMin(qMax((int)floors.z, 0), highest); + int ceilX = qMin(qMax((int)ceils.x, 0), highest); + int ceilZ = qMin(qMax((int)ceils.z, 0), highest); + float upperLeft = src[floorZ * size + floorX] * heightScale; + float upperRight = src[floorZ * size + ceilX] * heightScale; + float lowerLeft = src[ceilZ * size + floorX] * heightScale; + float lowerRight = src[ceilZ * size + ceilX] * heightScale; + + // find the distance to the next x coordinate + float xDistance = FLT_MAX; + if (_direction.x > 0.0f) { + xDistance = (ceils.x - entry.x) / _direction.x; + } else if (_direction.x < 0.0f) { + xDistance = (floors.x - entry.x) / _direction.x; } + + // and the distance to the next z coordinate + float zDistance = FLT_MAX; + if (_direction.z > 0.0f) { + zDistance = (ceils.z - entry.z) / _direction.z; + } else if (_direction.z < 0.0f) { + zDistance = (floors.z - entry.z) / _direction.z; + } + + // the exit distance is the lower of those two + float exitDistance = qMin(xDistance, zDistance); + glm::vec3 exit, nextFloors = floors, nextCeils = ceils; + if (exitDistance == FLT_MAX) { + if (_direction.y > 0.0f) { + return SHORT_CIRCUIT; // line points upwards; no collisions possible + } + withinBounds = false; // line points downwards; check this cell only + + } else { + // find the exit point and the next cell, and determine whether it's still within the bounds + exit = entry + exitDistance * _direction; + withinBounds = (exit.y >= 0.0f && exit.y <= highest); + if (exitDistance == xDistance) { + if (_direction.x > 0.0f) { + nextFloors.x += 1.0f; + withinBounds &= (nextCeils.x += 1.0f) <= highest; + } else { + withinBounds &= (nextFloors.x -= 1.0f) >= 0.0f; + nextCeils.x -= 1.0f; + } + } + if (exitDistance == zDistance) { + if (_direction.z > 0.0f) { + nextFloors.z += 1.0f; + withinBounds &= (nextCeils.z += 1.0f) <= highest; + } else { + withinBounds &= (nextFloors.z -= 1.0f) >= 0.0f; + nextCeils.z -= 1.0f; + } + } + // check the vertical range of the ray against the ranges of the cell heights + if (qMin(entry.y, exit.y) > qMax(qMax(upperLeft, upperRight), qMax(lowerLeft, lowerRight)) || + qMax(entry.y, exit.y) < qMin(qMin(upperLeft, upperRight), qMin(lowerLeft, lowerRight))) { + entry = exit; + floors = nextFloors; + ceils = nextCeils; + accumulatedDistance += exitDistance; + continue; + } + } + // having passed the bounds check, we must check against the planes + glm::vec3 relativeEntry = entry - glm::vec3(floors.x, upperLeft, floors.z); + + // first check the triangle including the Z+ segment + glm::vec3 lowerNormal(lowerLeft - lowerRight, 1.0f, upperLeft - lowerLeft); + float lowerProduct = glm::dot(lowerNormal, _direction); + if (lowerProduct < 0.0f) { + float planeDistance = -glm::dot(lowerNormal, relativeEntry) / lowerProduct; + glm::vec3 intersection = relativeEntry + planeDistance * _direction; + if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && + intersection.z >= intersection.x) { + intersectionDistance = distance + (accumulatedDistance + planeDistance) * (info.size / highest); + return SHORT_CIRCUIT; + } + } + + // then the one with the X+ segment + glm::vec3 upperNormal(upperLeft - upperRight, 1.0f, upperRight - lowerRight); + float upperProduct = glm::dot(upperNormal, _direction); + if (upperProduct < 0.0f) { + float planeDistance = -glm::dot(upperNormal, relativeEntry) / upperProduct; + glm::vec3 intersection = relativeEntry + planeDistance * _direction; + if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && + intersection.x >= intersection.z) { + intersectionDistance = distance + (accumulatedDistance + planeDistance) * (info.size / highest); + return SHORT_CIRCUIT; + } + } + + // no joy; continue on our way + entry = exit; + floors = nextFloors; + ceils = nextCeils; + accumulatedDistance += exitDistance; } return STOP_RECURSION; @@ -136,7 +226,11 @@ bool MetavoxelClientManager::findFirstRayHeightfieldIntersection(const glm::vec3 const glm::vec3& direction, float& distance) { RayHeightfieldIntersectionVisitor visitor(origin, direction, getLOD()); guide(visitor); - return false; + if (visitor.intersectionDistance == FLT_MAX) { + return false; + } + distance = visitor.intersectionDistance; + return true; } void MetavoxelClientManager::setSphere(const glm::vec3& center, float radius, const QColor& color) { @@ -197,6 +291,8 @@ int HeightfieldHeightVisitor::visit(MetavoxelInfo& info) { int size = glm::sqrt((float)contents.size()); int highest = size - 1; relative *= highest / info.size; + + // find the bounds of the cell containing the point and the shared vertex heights glm::vec3 floors = glm::floor(relative); glm::vec3 ceils = glm::ceil(relative); glm::vec3 fracts = glm::fract(relative); @@ -207,6 +303,8 @@ int HeightfieldHeightVisitor::visit(MetavoxelInfo& info) { float upperLeft = src[floorZ * size + floorX]; float lowerRight = src[ceilZ * size + ceilX]; float interpolatedHeight; + + // the final vertex (and thus which triangle we check) depends on which half we're on if (fracts.x > fracts.z) { float upperRight = src[floorZ * size + ceilX]; interpolatedHeight = glm::mix(glm::mix(upperLeft, upperRight, fracts.x), lowerRight, fracts.z); @@ -216,8 +314,10 @@ int HeightfieldHeightVisitor::visit(MetavoxelInfo& info) { interpolatedHeight = glm::mix(upperLeft, glm::mix(lowerLeft, lowerRight, fracts.x), fracts.z); } if (interpolatedHeight == 0.0f) { - return STOP_RECURSION; + return STOP_RECURSION; // ignore zero values } + + // convert the interpolated height into world space height = qMax(height, info.minimum.y + interpolatedHeight * info.size * EIGHT_BIT_MAXIMUM_RECIPROCAL); return SHORT_CIRCUIT; } From 8c2dad1476bb4d2f9467be7f96f4030ebd53b783 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 7 Aug 2014 14:40:06 -0700 Subject: [PATCH 246/407] remove animation server --- animation-server/CMakeLists.txt | 39 -- animation-server/src/AnimationServer.cpp | 852 ----------------------- animation-server/src/AnimationServer.h | 27 - animation-server/src/main.cpp | 17 - 4 files changed, 935 deletions(-) delete mode 100644 animation-server/CMakeLists.txt delete mode 100644 animation-server/src/AnimationServer.cpp delete mode 100644 animation-server/src/AnimationServer.h delete mode 100644 animation-server/src/main.cpp diff --git a/animation-server/CMakeLists.txt b/animation-server/CMakeLists.txt deleted file mode 100644 index 116ee0e942..0000000000 --- a/animation-server/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ -if (WIN32) - cmake_policy (SET CMP0020 NEW) -endif (WIN32) - -set(TARGET_NAME animation-server) - -set(ROOT_DIR ..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") - -find_package(Qt5 COMPONENTS Script) -include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}") - -# set up the external glm library -include("${MACRO_DIR}/IncludeGLM.cmake") -include_glm(${TARGET_NAME} "${ROOT_DIR}") - -include("${MACRO_DIR}/SetupHifiProject.cmake") -setup_hifi_project(${TARGET_NAME} TRUE) - -# link in the shared library -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") - -# link in the hifi octree library -link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") - -# link in the hifi voxels library -link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") - -# link the hifi networking library -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") - -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () diff --git a/animation-server/src/AnimationServer.cpp b/animation-server/src/AnimationServer.cpp deleted file mode 100644 index 32a95b48ea..0000000000 --- a/animation-server/src/AnimationServer.cpp +++ /dev/null @@ -1,852 +0,0 @@ -// -// AnimationServer.cpp -// animation-server/src -// -// Created by Stephen Birarda on 12/5/2013. -// Copyright 2013 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 -// - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AnimationServer.h" - -bool shouldShowPacketsPerSecond = false; // do we want to debug packets per second -bool includeBillboard = true; -bool includeBorderTracer = true; -bool includeMovingBug = true; -bool includeBlinkingVoxel = false; -bool includeDanceFloor = true; -bool buildStreet = false; -bool nonThreadedPacketSender = false; -int packetsPerSecond = PacketSender::DEFAULT_PACKETS_PER_SECOND; -bool waitForVoxelServer = true; - - -const int ANIMATION_LISTEN_PORT = 40107; -int ANIMATE_FPS = 60; -double ANIMATE_FPS_IN_MILLISECONDS = 1000.0/ANIMATE_FPS; // determines FPS from our desired FPS -quint64 ANIMATE_VOXELS_INTERVAL_USECS = (ANIMATE_FPS_IN_MILLISECONDS * 1000); // converts from milliseconds to usecs - - -int PROCESSING_FPS = 60; -double PROCESSING_FPS_IN_MILLISECONDS = 1000.0/PROCESSING_FPS; // determines FPS from our desired FPS -int FUDGE_USECS = 650; // a little bit of fudge to actually do some processing -quint64 PROCESSING_INTERVAL_USECS = (PROCESSING_FPS_IN_MILLISECONDS * 1000) - FUDGE_USECS; // converts from milliseconds to usecs - -bool wantLocalDomain = false; - -unsigned long packetsSent = 0; -unsigned long bytesSent = 0; - -JurisdictionListener* jurisdictionListener = NULL; -VoxelEditPacketSender* voxelEditPacketSender = NULL; -pthread_t animateVoxelThread; - -glm::vec3 rotatePoint(glm::vec3 point, float angle) { - // First, create the quaternion based on this angle of rotation - glm::quat q(glm::vec3(0, -angle, 0)); - - // Next, create a rotation matrix from that quaternion - glm::mat4 rotation = glm::mat4_cast(q); - - // Transform the original vectors by the rotation matrix to get the new vectors - glm::vec4 quatPoint(point.x, point.y, point.z, 0); - glm::vec4 newPoint = quatPoint * rotation; - - return glm::vec3(newPoint.x, newPoint.y, newPoint.z); -} - - -const float BUG_VOXEL_SIZE = 0.0625f / TREE_SCALE; -glm::vec3 bugPosition = glm::vec3(BUG_VOXEL_SIZE * 20.0, BUG_VOXEL_SIZE * 30.0, BUG_VOXEL_SIZE * 20.0); -glm::vec3 bugDirection = glm::vec3(0, 0, 1); -const int VOXELS_PER_BUG = 18; -glm::vec3 bugPathCenter = glm::vec3(0.25f,0.15f,0.25f); // glm::vec3(BUG_VOXEL_SIZE * 150.0, BUG_VOXEL_SIZE * 30.0, BUG_VOXEL_SIZE * 150.0); -float bugPathRadius = 0.2f; //BUG_VOXEL_SIZE * 140.0; -float bugPathTheta = 0.0f * RADIANS_PER_DEGREE; -float bugRotation = 0.0f * RADIANS_PER_DEGREE; -float bugAngleDelta = 0.2f * RADIANS_PER_DEGREE; -bool moveBugInLine = false; - -class BugPart { -public: - glm::vec3 partLocation; - unsigned char partColor[3]; - - BugPart(const glm::vec3& location, unsigned char red, unsigned char green, unsigned char blue ) { - partLocation = location; - partColor[0] = red; - partColor[1] = green; - partColor[2] = blue; - } -}; - -const BugPart bugParts[VOXELS_PER_BUG] = { - - // tail - BugPart(glm::vec3( 0, 0, -3), 51, 51, 153) , - BugPart(glm::vec3( 0, 0, -2), 51, 51, 153) , - BugPart(glm::vec3( 0, 0, -1), 51, 51, 153) , - - // body - BugPart(glm::vec3( 0, 0, 0), 255, 200, 0) , - BugPart(glm::vec3( 0, 0, 1), 255, 200, 0) , - - // head - BugPart(glm::vec3( 0, 0, 2), 200, 0, 0) , - - // eyes - BugPart(glm::vec3( 1, 0, 3), 64, 64, 64) , - BugPart(glm::vec3(-1, 0, 3), 64, 64, 64) , - - // wings - BugPart(glm::vec3( 3, 1, 1), 0, 153, 0) , - BugPart(glm::vec3( 2, 1, 1), 0, 153, 0) , - BugPart(glm::vec3( 1, 0, 1), 0, 153, 0) , - BugPart(glm::vec3(-1, 0, 1), 0, 153, 0) , - BugPart(glm::vec3(-2, 1, 1), 0, 153, 0) , - BugPart(glm::vec3(-3, 1, 1), 0, 153, 0) , - - - BugPart(glm::vec3( 2, -1, 0), 153, 200, 0) , - BugPart(glm::vec3( 1, -1, 0), 153, 200, 0) , - BugPart(glm::vec3(-1, -1, 0), 153, 200, 0) , - BugPart(glm::vec3(-2, -1, 0), 153, 200, 0) , -}; - -static void renderMovingBug() { - VoxelDetail details[VOXELS_PER_BUG]; - - // Generate voxels for where bug used to be - for (int i = 0; i < VOXELS_PER_BUG; i++) { - details[i].s = BUG_VOXEL_SIZE; - - glm::vec3 partAt = bugParts[i].partLocation * BUG_VOXEL_SIZE * (bugDirection.x < 0 ? -1.0f : 1.0f); - glm::vec3 rotatedPartAt = rotatePoint(partAt, bugRotation); - glm::vec3 offsetPartAt = rotatedPartAt + bugPosition; - - details[i].x = offsetPartAt.x; - details[i].y = offsetPartAt.y; - details[i].z = offsetPartAt.z; - - details[i].red = bugParts[i].partColor[0]; - details[i].green = bugParts[i].partColor[1]; - details[i].blue = bugParts[i].partColor[2]; - } - - // send the "erase message" first... - PacketType message = PacketTypeVoxelErase; - ::voxelEditPacketSender->queueVoxelEditMessages(message, VOXELS_PER_BUG, (VoxelDetail*)&details); - - // Move the bug... - if (moveBugInLine) { - bugPosition.x += (bugDirection.x * BUG_VOXEL_SIZE); - bugPosition.y += (bugDirection.y * BUG_VOXEL_SIZE); - bugPosition.z += (bugDirection.z * BUG_VOXEL_SIZE); - - // Check boundaries - if (bugPosition.z > 1.0f) { - bugDirection.z = -1.f; - } - if (bugPosition.z < BUG_VOXEL_SIZE) { - bugDirection.z = 1.f; - } - } else { - - //qDebug("bugPathCenter=(%f,%f,%f)", bugPathCenter.x, bugPathCenter.y, bugPathCenter.z); - - bugPathTheta += bugAngleDelta; // move slightly - bugRotation -= bugAngleDelta; // rotate slightly - - // If we loop past end of circle, just reset back into normal range - if (bugPathTheta > TWO_PI) { - bugPathTheta = 0.f; - bugRotation = 0.f; - } - - float x = bugPathCenter.x + bugPathRadius * cos(bugPathTheta); - float z = bugPathCenter.z + bugPathRadius * sin(bugPathTheta); - float y = bugPathCenter.y; - - bugPosition = glm::vec3(x, y, z); - //qDebug("bugPathTheta=%f", bugPathTheta); - //qDebug("bugRotation=%f", bugRotation); - } - - //qDebug("bugPosition=(%f,%f,%f)", bugPosition.x, bugPosition.y, bugPosition.z); - //qDebug("bugDirection=(%f,%f,%f)", bugDirection.x, bugDirection.y, bugDirection.z); - // would be nice to add some randomness here... - - // Generate voxels for where bug is going to - for (int i = 0; i < VOXELS_PER_BUG; i++) { - details[i].s = BUG_VOXEL_SIZE; - - glm::vec3 partAt = bugParts[i].partLocation * BUG_VOXEL_SIZE * (bugDirection.x < 0 ? -1.0f : 1.0f); - glm::vec3 rotatedPartAt = rotatePoint(partAt, bugRotation); - glm::vec3 offsetPartAt = rotatedPartAt + bugPosition; - - details[i].x = offsetPartAt.x; - details[i].y = offsetPartAt.y; - details[i].z = offsetPartAt.z; - - details[i].red = bugParts[i].partColor[0]; - details[i].green = bugParts[i].partColor[1]; - details[i].blue = bugParts[i].partColor[2]; - } - - // send the "create message" ... - message = PacketTypeVoxelSetDestructive; - ::voxelEditPacketSender->queueVoxelEditMessages(message, VOXELS_PER_BUG, (VoxelDetail*)&details); -} - - -float intensity = 0.5f; -float intensityIncrement = 0.1f; -const float MAX_INTENSITY = 1.0f; -const float MIN_INTENSITY = 0.5f; -const float BEACON_SIZE = 0.25f / TREE_SCALE; // approximately 1/4th meter - -static void sendVoxelBlinkMessage() { - VoxelDetail detail; - detail.s = BEACON_SIZE; - - glm::vec3 position = glm::vec3(0.f, 0.f, detail.s); - - detail.x = detail.s * floor(position.x / detail.s); - detail.y = detail.s * floor(position.y / detail.s); - detail.z = detail.s * floor(position.z / detail.s); - - ::intensity += ::intensityIncrement; - if (::intensity >= MAX_INTENSITY) { - ::intensity = MAX_INTENSITY; - ::intensityIncrement = -::intensityIncrement; - } - if (::intensity <= MIN_INTENSITY) { - ::intensity = MIN_INTENSITY; - ::intensityIncrement = -::intensityIncrement; - } - - detail.red = 255 * ::intensity; - detail.green = 0 * ::intensity; - detail.blue = 0 * ::intensity; - - PacketType message = PacketTypeVoxelSetDestructive; - - ::voxelEditPacketSender->sendVoxelEditMessage(message, detail); -} - -bool stringOfLightsInitialized = false; -int currentLight = 0; -int lightMovementDirection = 1; -const int SEGMENT_COUNT = 4; -const int LIGHTS_PER_SEGMENT = 80; -const int LIGHT_COUNT = LIGHTS_PER_SEGMENT * SEGMENT_COUNT; -glm::vec3 stringOfLights[LIGHT_COUNT]; -unsigned char offColor[3] = { 240, 240, 240 }; -unsigned char onColor[3] = { 0, 255, 255 }; -const float STRING_OF_LIGHTS_SIZE = 0.125f / TREE_SCALE; // approximately 1/8th meter - -static void sendBlinkingStringOfLights() { - PacketType message = PacketTypeVoxelSetDestructive; // we're a bully! - float lightScale = STRING_OF_LIGHTS_SIZE; - static VoxelDetail details[LIGHTS_PER_SEGMENT]; - - // first initialized the string of lights if needed... - if (!stringOfLightsInitialized) { - for (int segment = 0; segment < SEGMENT_COUNT; segment++) { - for (int indexInSegment = 0; indexInSegment < LIGHTS_PER_SEGMENT; indexInSegment++) { - - int i = (segment * LIGHTS_PER_SEGMENT) + indexInSegment; - - // four different segments on sides of initial platform - switch (segment) { - case 0: - // along x axis - stringOfLights[i] = glm::vec3(indexInSegment * lightScale, 0, 0); - break; - case 1: - // parallel to Z axis at outer X edge - stringOfLights[i] = glm::vec3(LIGHTS_PER_SEGMENT * lightScale, 0, indexInSegment * lightScale); - break; - case 2: - // parallel to X axis at outer Z edge - stringOfLights[i] = glm::vec3((LIGHTS_PER_SEGMENT-indexInSegment) * lightScale, 0, - LIGHTS_PER_SEGMENT * lightScale); - break; - case 3: - // on Z axis - stringOfLights[i] = glm::vec3(0, 0, (LIGHTS_PER_SEGMENT-indexInSegment) * lightScale); - break; - } - - details[indexInSegment].s = STRING_OF_LIGHTS_SIZE; - details[indexInSegment].x = stringOfLights[i].x; - details[indexInSegment].y = stringOfLights[i].y; - details[indexInSegment].z = stringOfLights[i].z; - - details[indexInSegment].red = offColor[0]; - details[indexInSegment].green = offColor[1]; - details[indexInSegment].blue = offColor[2]; - } - - ::voxelEditPacketSender->queueVoxelEditMessages(message, LIGHTS_PER_SEGMENT, (VoxelDetail*)&details); - } - stringOfLightsInitialized = true; - } else { - // turn off current light - details[0].x = stringOfLights[currentLight].x; - details[0].y = stringOfLights[currentLight].y; - details[0].z = stringOfLights[currentLight].z; - details[0].red = offColor[0]; - details[0].green = offColor[1]; - details[0].blue = offColor[2]; - - // move current light... - // if we're at the end of our string, then change direction - if (currentLight == LIGHT_COUNT-1) { - lightMovementDirection = -1; - } - if (currentLight == 0) { - lightMovementDirection = 1; - } - currentLight += lightMovementDirection; - - // turn on new current light - details[1].x = stringOfLights[currentLight].x; - details[1].y = stringOfLights[currentLight].y; - details[1].z = stringOfLights[currentLight].z; - details[1].red = onColor[0]; - details[1].green = onColor[1]; - details[1].blue = onColor[2]; - - // send both changes in same message - ::voxelEditPacketSender->queueVoxelEditMessages(message, 2, (VoxelDetail*)&details); - } -} - -bool danceFloorInitialized = false; -const float DANCE_FLOOR_LIGHT_SIZE = 1.0f / TREE_SCALE; // approximately 1 meter -const int DANCE_FLOOR_LENGTH = 10; -const int DANCE_FLOOR_WIDTH = 10; -glm::vec3 danceFloorPosition(100.0f / TREE_SCALE, 30.0f / TREE_SCALE, 10.0f / TREE_SCALE); -glm::vec3 danceFloorLights[DANCE_FLOOR_LENGTH][DANCE_FLOOR_WIDTH]; -unsigned char danceFloorOffColor[3] = { 240, 240, 240 }; -const int DANCE_FLOOR_COLORS = 6; - -unsigned char danceFloorOnColorA[DANCE_FLOOR_COLORS][3] = { - { 255, 0, 0 }, { 0, 255, 0 }, { 0, 0, 255 }, - { 0, 191, 255 }, { 0, 250, 154 }, { 255, 69, 0 }, -}; -unsigned char danceFloorOnColorB[DANCE_FLOOR_COLORS][3] = { - { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } , - { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } -}; -float danceFloorGradient = 0.5f; -const float BEATS_PER_MINUTE = 118.0f; -const float SECONDS_PER_MINUTE = 60.0f; -const float FRAMES_PER_BEAT = (SECONDS_PER_MINUTE * ANIMATE_FPS) / BEATS_PER_MINUTE; -float danceFloorGradientIncrement = 1.0f / FRAMES_PER_BEAT; -const float DANCE_FLOOR_MAX_GRADIENT = 1.0f; -const float DANCE_FLOOR_MIN_GRADIENT = 0.0f; -const int DANCE_FLOOR_VOXELS_PER_PACKET = 100; -int danceFloorColors[DANCE_FLOOR_WIDTH][DANCE_FLOOR_LENGTH]; - -void sendDanceFloor() { - PacketType message = PacketTypeVoxelSetDestructive; // we're a bully! - float lightScale = DANCE_FLOOR_LIGHT_SIZE; - static VoxelDetail details[DANCE_FLOOR_VOXELS_PER_PACKET]; - - // first initialized the billboard of lights if needed... - if (!::danceFloorInitialized) { - for (int i = 0; i < DANCE_FLOOR_WIDTH; i++) { - for (int j = 0; j < DANCE_FLOOR_LENGTH; j++) { - - int randomColorIndex = randIntInRange(-DANCE_FLOOR_COLORS, DANCE_FLOOR_COLORS); - ::danceFloorColors[i][j] = randomColorIndex; - ::danceFloorLights[i][j] = ::danceFloorPosition + - glm::vec3(i * DANCE_FLOOR_LIGHT_SIZE, 0, j * DANCE_FLOOR_LIGHT_SIZE); - } - } - ::danceFloorInitialized = true; - } - - ::danceFloorGradient += ::danceFloorGradientIncrement; - - if (::danceFloorGradient >= DANCE_FLOOR_MAX_GRADIENT) { - ::danceFloorGradient = DANCE_FLOOR_MAX_GRADIENT; - ::danceFloorGradientIncrement = -::danceFloorGradientIncrement; - } - if (::danceFloorGradient <= DANCE_FLOOR_MIN_GRADIENT) { - ::danceFloorGradient = DANCE_FLOOR_MIN_GRADIENT; - ::danceFloorGradientIncrement = -::danceFloorGradientIncrement; - } - - for (int i = 0; i < DANCE_FLOOR_LENGTH; i++) { - for (int j = 0; j < DANCE_FLOOR_WIDTH; j++) { - - int nthVoxel = ((i * DANCE_FLOOR_WIDTH) + j); - int item = nthVoxel % DANCE_FLOOR_VOXELS_PER_PACKET; - - ::danceFloorLights[i][j] = ::danceFloorPosition + - glm::vec3(i * DANCE_FLOOR_LIGHT_SIZE, 0, j * DANCE_FLOOR_LIGHT_SIZE); - - details[item].s = lightScale; - details[item].x = ::danceFloorLights[i][j].x; - details[item].y = ::danceFloorLights[i][j].y; - details[item].z = ::danceFloorLights[i][j].z; - - if (danceFloorColors[i][j] > 0) { - int color = danceFloorColors[i][j] - 1; - details[item].red = (::danceFloorOnColorA[color][0] + - ((::danceFloorOnColorB[color][0] - ::danceFloorOnColorA[color][0]) - * ::danceFloorGradient)); - details[item].green = (::danceFloorOnColorA[color][1] + - ((::danceFloorOnColorB[color][1] - ::danceFloorOnColorA[color][1]) - * ::danceFloorGradient)); - details[item].blue = (::danceFloorOnColorA[color][2] + - ((::danceFloorOnColorB[color][2] - ::danceFloorOnColorA[color][2]) - * ::danceFloorGradient)); - } else if (::danceFloorColors[i][j] < 0) { - int color = -(::danceFloorColors[i][j] + 1); - details[item].red = (::danceFloorOnColorB[color][0] + - ((::danceFloorOnColorA[color][0] - ::danceFloorOnColorB[color][0]) - * ::danceFloorGradient)); - details[item].green = (::danceFloorOnColorB[color][1] + - ((::danceFloorOnColorA[color][1] - ::danceFloorOnColorB[color][1]) - * ::danceFloorGradient)); - details[item].blue = (::danceFloorOnColorB[color][2] + - ((::danceFloorOnColorA[color][2] - ::danceFloorOnColorB[color][2]) - * ::danceFloorGradient)); - } else { - int color = 0; - details[item].red = (::danceFloorOnColorB[color][0] + - ((::danceFloorOnColorA[color][0] - ::danceFloorOnColorB[color][0]) - * ::danceFloorGradient)); - details[item].green = (::danceFloorOnColorB[color][1] + - ((::danceFloorOnColorA[color][1] - ::danceFloorOnColorB[color][1]) - * ::danceFloorGradient)); - details[item].blue = (::danceFloorOnColorB[color][2] + - ((::danceFloorOnColorA[color][2] - ::danceFloorOnColorB[color][2]) - * ::danceFloorGradient)); - } - - if (item == DANCE_FLOOR_VOXELS_PER_PACKET - 1) { - ::voxelEditPacketSender->queueVoxelEditMessages(message, DANCE_FLOOR_VOXELS_PER_PACKET, (VoxelDetail*)&details); - } - } - } -} - -bool billboardInitialized = false; -const int BILLBOARD_HEIGHT = 9; -const int BILLBOARD_WIDTH = 45; -glm::vec3 billboardPosition((0.125f / TREE_SCALE),(0.125f / TREE_SCALE),0); -glm::vec3 billboardLights[BILLBOARD_HEIGHT][BILLBOARD_WIDTH]; -unsigned char billboardOffColor[3] = { 240, 240, 240 }; -unsigned char billboardOnColorA[3] = { 0, 0, 255 }; -unsigned char billboardOnColorB[3] = { 0, 255, 0 }; -float billboardGradient = 0.5f; -float billboardGradientIncrement = 0.01f; -const float BILLBOARD_MAX_GRADIENT = 1.0f; -const float BILLBOARD_MIN_GRADIENT = 0.0f; -const float BILLBOARD_LIGHT_SIZE = 0.125f / TREE_SCALE; // approximately 1/8 meter per light -const int VOXELS_PER_PACKET = 81; - -// top to bottom... -bool billboardMessage[BILLBOARD_HEIGHT][BILLBOARD_WIDTH] = { - { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, - { 0,0,1,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,1,1,1,1,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0,0,0,0 }, - { 0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,1,1,0,0,0,0,0 }, - { 0,0,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,0,1,1,1,0,0,0,0,1,1,1,0,1,1,1,0,1,0,1,0,0,1,0,0,1,0,1,0 }, - { 0,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,1,0 }, - { 0,0,1,0,0,1,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,0,1,0,0,1,1,1,0 }, - { 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0 }, - { 0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0 }, - { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } -}; - -static void sendBillboard() { - PacketType message = PacketTypeVoxelSetDestructive; // we're a bully! - float lightScale = BILLBOARD_LIGHT_SIZE; - static VoxelDetail details[VOXELS_PER_PACKET]; - - // first initialized the billboard of lights if needed... - if (!billboardInitialized) { - for (int i = 0; i < BILLBOARD_HEIGHT; i++) { - for (int j = 0; j < BILLBOARD_WIDTH; j++) { - - billboardLights[i][j] = billboardPosition + glm::vec3(j * lightScale, (float)((BILLBOARD_HEIGHT - i) * lightScale), 0); - } - } - billboardInitialized = true; - } - - ::billboardGradient += ::billboardGradientIncrement; - - if (::billboardGradient >= BILLBOARD_MAX_GRADIENT) { - ::billboardGradient = BILLBOARD_MAX_GRADIENT; - ::billboardGradientIncrement = -::billboardGradientIncrement; - } - if (::billboardGradient <= BILLBOARD_MIN_GRADIENT) { - ::billboardGradient = BILLBOARD_MIN_GRADIENT; - ::billboardGradientIncrement = -::billboardGradientIncrement; - } - - for (int i = 0; i < BILLBOARD_HEIGHT; i++) { - for (int j = 0; j < BILLBOARD_WIDTH; j++) { - - int nthVoxel = ((i * BILLBOARD_WIDTH) + j); - int item = nthVoxel % VOXELS_PER_PACKET; - - billboardLights[i][j] = billboardPosition + glm::vec3(j * lightScale, (float)((BILLBOARD_HEIGHT - i) * lightScale), 0); - - details[item].s = lightScale; - details[item].x = billboardLights[i][j].x; - details[item].y = billboardLights[i][j].y; - details[item].z = billboardLights[i][j].z; - - if (billboardMessage[i][j]) { - details[item].red = (billboardOnColorA[0] + ((billboardOnColorB[0] - billboardOnColorA[0]) * ::billboardGradient)); - details[item].green = (billboardOnColorA[1] + ((billboardOnColorB[1] - billboardOnColorA[1]) * ::billboardGradient)); - details[item].blue = (billboardOnColorA[2] + ((billboardOnColorB[2] - billboardOnColorA[2]) * ::billboardGradient)); - } else { - details[item].red = billboardOffColor[0]; - details[item].green = billboardOffColor[1]; - details[item].blue = billboardOffColor[2]; - } - - if (item == VOXELS_PER_PACKET - 1) { - ::voxelEditPacketSender->queueVoxelEditMessages(message, VOXELS_PER_PACKET, (VoxelDetail*)&details); - } - } - } -} - -bool roadInitialized = false; -const int BRICKS_ACROSS_ROAD = 32; -const float ROAD_BRICK_SIZE = 0.125f/TREE_SCALE; //(ROAD_WIDTH_METERS / TREE_SCALE) / BRICKS_ACROSS_ROAD; // in voxel units -const int ROAD_LENGTH = 1.0f / ROAD_BRICK_SIZE; // in bricks -const int ROAD_WIDTH = BRICKS_ACROSS_ROAD; // in bricks -glm::vec3 roadPosition(0.5f - (ROAD_BRICK_SIZE * BRICKS_ACROSS_ROAD), 0.0f, 0.0f); -const int BRICKS_PER_PACKET = 32; // guessing - -void doBuildStreet() { - if (roadInitialized) { - return; - } - - PacketType message = PacketTypeVoxelSetDestructive; // we're a bully! - static VoxelDetail details[BRICKS_PER_PACKET]; - - for (int z = 0; z < ROAD_LENGTH; z++) { - for (int x = 0; x < ROAD_WIDTH; x++) { - - int nthVoxel = ((z * ROAD_WIDTH) + x); - int item = nthVoxel % BRICKS_PER_PACKET; - - glm::vec3 brick = roadPosition + glm::vec3(x * ROAD_BRICK_SIZE, 0, z * ROAD_BRICK_SIZE); - - details[item].s = ROAD_BRICK_SIZE; - details[item].x = brick.x; - details[item].y = brick.y; - details[item].z = brick.z; - - unsigned char randomTone = randIntInRange(118,138); - details[item].red = randomTone; - details[item].green = randomTone; - details[item].blue = randomTone; - - if (item == BRICKS_PER_PACKET - 1) { - ::voxelEditPacketSender->queueVoxelEditMessages(message, BRICKS_PER_PACKET, (VoxelDetail*)&details); - } - } - } - roadInitialized = true; -} - - -double start = 0; - - -void* animateVoxels(void* args) { - - quint64 lastAnimateTime = 0; - quint64 lastProcessTime = 0; - int processesPerAnimate = 0; - - bool firstTime = true; - - qDebug() << "Setting PPS to " << ::packetsPerSecond; - ::voxelEditPacketSender->setPacketsPerSecond(::packetsPerSecond); - - qDebug() << "PPS set to " << ::voxelEditPacketSender->getPacketsPerSecond(); - - while (true) { - - // If we're asked to wait for voxel servers, and there isn't one available yet, then - // let the voxelEditPacketSender process and move on. - if (::waitForVoxelServer && !::voxelEditPacketSender->voxelServersExist()) { - if (::nonThreadedPacketSender) { - ::voxelEditPacketSender->process(); - } - } else { - if (firstTime) { - lastAnimateTime = usecTimestampNow(); - firstTime = false; - } - lastProcessTime = usecTimestampNow(); - - // The while loop will be running at PROCESSING_FPS, but we only want to call these animation functions at - // ANIMATE_FPS. So we check out last animate time and only call these if we've elapsed that time. - quint64 now = usecTimestampNow(); - quint64 animationElapsed = now - lastAnimateTime; - int withinAnimationTarget = ANIMATE_VOXELS_INTERVAL_USECS - animationElapsed; - const int CLOSE_ENOUGH_TO_ANIMATE = 2000; // approximately 2 ms - - int animateLoopsPerAnimate = 0; - while (withinAnimationTarget < CLOSE_ENOUGH_TO_ANIMATE) { - processesPerAnimate = 0; - animateLoopsPerAnimate++; - - lastAnimateTime = now; - // some animations - //sendVoxelBlinkMessage(); - - if (::includeBillboard) { - sendBillboard(); - } - if (::includeBorderTracer) { - sendBlinkingStringOfLights(); - } - if (::includeMovingBug) { - renderMovingBug(); - } - if (::includeBlinkingVoxel) { - sendVoxelBlinkMessage(); - } - if (::includeDanceFloor) { - sendDanceFloor(); - } - - if (::buildStreet) { - doBuildStreet(); - } - - if (animationElapsed > ANIMATE_VOXELS_INTERVAL_USECS) { - animationElapsed -= ANIMATE_VOXELS_INTERVAL_USECS; // credit ourselves one animation frame - } else { - animationElapsed = 0; - } - withinAnimationTarget = ANIMATE_VOXELS_INTERVAL_USECS - animationElapsed; - - ::voxelEditPacketSender->releaseQueuedMessages(); - } - - if (::nonThreadedPacketSender) { - ::voxelEditPacketSender->process(); - } - processesPerAnimate++; - } - // dynamically sleep until we need to fire off the next set of voxels - quint64 usecToSleep = ::PROCESSING_INTERVAL_USECS - (usecTimestampNow() - lastProcessTime); - if (usecToSleep > ::PROCESSING_INTERVAL_USECS) { - usecToSleep = ::PROCESSING_INTERVAL_USECS; - } - - if (usecToSleep > 0) { - usleep(usecToSleep); - } - } - - pthread_exit(0); -} - -AnimationServer::AnimationServer(int &argc, char **argv) : - QCoreApplication(argc, argv) -{ - ::start = usecTimestampNow(); - - NodeList* nodeList = NodeList::createInstance(NodeType::AnimationServer, ANIMATION_LISTEN_PORT); - setvbuf(stdout, NULL, _IOLBF, 0); - - // Handle Local Domain testing with the --local command line - const char* NON_THREADED_PACKETSENDER = "--NonThreadedPacketSender"; - ::nonThreadedPacketSender = cmdOptionExists(argc, (const char**) argv, NON_THREADED_PACKETSENDER); - qDebug("nonThreadedPacketSender=%s", debug::valueOf(::nonThreadedPacketSender)); - - // Handle Local Domain testing with the --local command line - const char* NO_BILLBOARD = "--NoBillboard"; - ::includeBillboard = !cmdOptionExists(argc, (const char**) argv, NO_BILLBOARD); - qDebug("includeBillboard=%s", debug::valueOf(::includeBillboard)); - - const char* NO_BORDER_TRACER = "--NoBorderTracer"; - ::includeBorderTracer = !cmdOptionExists(argc, (const char**) argv, NO_BORDER_TRACER); - qDebug("includeBorderTracer=%s", debug::valueOf(::includeBorderTracer)); - - const char* NO_MOVING_BUG = "--NoMovingBug"; - ::includeMovingBug = !cmdOptionExists(argc, (const char**) argv, NO_MOVING_BUG); - qDebug("includeMovingBug=%s", debug::valueOf(::includeMovingBug)); - - const char* INCLUDE_BLINKING_VOXEL = "--includeBlinkingVoxel"; - ::includeBlinkingVoxel = cmdOptionExists(argc, (const char**) argv, INCLUDE_BLINKING_VOXEL); - qDebug("includeBlinkingVoxel=%s", debug::valueOf(::includeBlinkingVoxel)); - - const char* NO_DANCE_FLOOR = "--NoDanceFloor"; - ::includeDanceFloor = !cmdOptionExists(argc, (const char**) argv, NO_DANCE_FLOOR); - qDebug("includeDanceFloor=%s", debug::valueOf(::includeDanceFloor)); - - const char* BUILD_STREET = "--BuildStreet"; - ::buildStreet = cmdOptionExists(argc, (const char**) argv, BUILD_STREET); - qDebug("buildStreet=%s", debug::valueOf(::buildStreet)); - - // Handle Local Domain testing with the --local command line - const char* showPPS = "--showPPS"; - ::shouldShowPacketsPerSecond = cmdOptionExists(argc, (const char**) argv, showPPS); - - // Handle Local Domain testing with the --local command line - const char* local = "--local"; - ::wantLocalDomain = cmdOptionExists(argc, (const char**) argv,local); - if (::wantLocalDomain) { - qDebug("Local Domain MODE!"); - nodeList->getDomainHandler().setIPToLocalhost(); - } - - const char* domainHostname = getCmdOption(argc, (const char**) argv, "--domain"); - if (domainHostname) { - NodeList::getInstance()->getDomainHandler().setHostname(domainHostname); - } - - const char* packetsPerSecondCommand = getCmdOption(argc, (const char**) argv, "--pps"); - if (packetsPerSecondCommand) { - ::packetsPerSecond = atoi(packetsPerSecondCommand); - } - qDebug("packetsPerSecond=%d",packetsPerSecond); - - const char* animateFPSCommand = getCmdOption(argc, (const char**) argv, "--AnimateFPS"); - const char* animateIntervalCommand = getCmdOption(argc, (const char**) argv, "--AnimateInterval"); - if (animateFPSCommand || animateIntervalCommand) { - if (animateIntervalCommand) { - ::ANIMATE_FPS_IN_MILLISECONDS = atoi(animateIntervalCommand); - ::ANIMATE_VOXELS_INTERVAL_USECS = (ANIMATE_FPS_IN_MILLISECONDS * 1000.0); // converts from milliseconds to usecs - ::ANIMATE_FPS = PacketSender::USECS_PER_SECOND / ::ANIMATE_VOXELS_INTERVAL_USECS; - } else { - ::ANIMATE_FPS = atoi(animateFPSCommand); - ::ANIMATE_FPS_IN_MILLISECONDS = 1000.0/ANIMATE_FPS; // determines FPS from our desired FPS - ::ANIMATE_VOXELS_INTERVAL_USECS = (ANIMATE_FPS_IN_MILLISECONDS * 1000.0); // converts from milliseconds to usecs - } - } - qDebug("ANIMATE_FPS=%d",ANIMATE_FPS); - qDebug("ANIMATE_VOXELS_INTERVAL_USECS=%llu",ANIMATE_VOXELS_INTERVAL_USECS); - - const char* processingFPSCommand = getCmdOption(argc, (const char**) argv, "--ProcessingFPS"); - const char* processingIntervalCommand = getCmdOption(argc, (const char**) argv, "--ProcessingInterval"); - if (processingFPSCommand || processingIntervalCommand) { - if (processingIntervalCommand) { - ::PROCESSING_FPS_IN_MILLISECONDS = atoi(processingIntervalCommand); - ::PROCESSING_INTERVAL_USECS = ::PROCESSING_FPS_IN_MILLISECONDS * 1000.0; - ::PROCESSING_FPS = PacketSender::USECS_PER_SECOND / ::PROCESSING_INTERVAL_USECS; - } else { - ::PROCESSING_FPS = atoi(processingFPSCommand); - ::PROCESSING_FPS_IN_MILLISECONDS = 1000.0/PROCESSING_FPS; // determines FPS from our desired FPS - ::PROCESSING_INTERVAL_USECS = (PROCESSING_FPS_IN_MILLISECONDS * 1000.0) - FUDGE_USECS; // converts from milliseconds to usecs - } - } - qDebug("PROCESSING_FPS=%d",PROCESSING_FPS); - qDebug("PROCESSING_INTERVAL_USECS=%llu",PROCESSING_INTERVAL_USECS); - - nodeList->linkedDataCreateCallback = NULL; // do we need a callback? - - // Create our JurisdictionListener so we'll know where to send edit packets - ::jurisdictionListener = new JurisdictionListener(); - if (::jurisdictionListener) { - ::jurisdictionListener->initialize(true); - } - - // Create out VoxelEditPacketSender - ::voxelEditPacketSender = new VoxelEditPacketSender; - ::voxelEditPacketSender->initialize(!::nonThreadedPacketSender); - - if (::jurisdictionListener) { - ::voxelEditPacketSender->setVoxelServerJurisdictions(::jurisdictionListener->getJurisdictions()); - } - if (::nonThreadedPacketSender) { - ::voxelEditPacketSender->setProcessCallIntervalHint(PROCESSING_INTERVAL_USECS); - } - - srand((unsigned)time(0)); - - - pthread_create(&::animateVoxelThread, NULL, animateVoxels, NULL); - - NodeList::getInstance()->addNodeTypeToInterestSet(NodeType::VoxelServer); - - QTimer* domainServerTimer = new QTimer(this); - connect(domainServerTimer, SIGNAL(timeout()), nodeList, SLOT(sendDomainServerCheckIn())); - domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); - - QTimer* silentNodeTimer = new QTimer(this); - connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); - silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS); - - connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), SLOT(readPendingDatagrams())); -} - -void AnimationServer::readPendingDatagrams() { - NodeList* nodeList = NodeList::getInstance(); - - static QByteArray receivedPacket; - static HifiSockAddr nodeSockAddr; - - // Nodes sending messages to us... - while (nodeList->getNodeSocket().hasPendingDatagrams()) { - receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize()); - nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(), - nodeSockAddr.getAddressPointer(), nodeSockAddr.getPortPointer()); - if (nodeList->packetVersionAndHashMatch(receivedPacket)) { - if (packetTypeForPacket(receivedPacket) == PacketTypeJurisdiction) { - int headerBytes = numBytesForPacketHeader(receivedPacket); - // PacketType_JURISDICTION, first byte is the node type... - if (receivedPacket.data()[headerBytes] == NodeType::VoxelServer && ::jurisdictionListener) { - - SharedNodePointer matchedNode = NodeList::getInstance()->sendingNodeForPacket(receivedPacket); - if (matchedNode) { - ::jurisdictionListener->queueReceivedPacket(matchedNode, receivedPacket); - } - } - } - NodeList::getInstance()->processNodeData(nodeSockAddr, receivedPacket); - } - } -} - -AnimationServer::~AnimationServer() { - pthread_join(animateVoxelThread, NULL); - - if (::jurisdictionListener) { - ::jurisdictionListener->terminate(); - delete ::jurisdictionListener; - } - - if (::voxelEditPacketSender) { - ::voxelEditPacketSender->terminate(); - delete ::voxelEditPacketSender; - } -} diff --git a/animation-server/src/AnimationServer.h b/animation-server/src/AnimationServer.h deleted file mode 100644 index 58f05c32c5..0000000000 --- a/animation-server/src/AnimationServer.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// AnimationServer.h -// animation-server/src -// -// Created by Stephen Birarda on 12/5/2013. -// Copyright 2013 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 -// - -#ifndef hifi_AnimationServer_h -#define hifi_AnimationServer_h - -#include - -class AnimationServer : public QCoreApplication { - Q_OBJECT -public: - AnimationServer(int &argc, char **argv); - ~AnimationServer(); -private slots: - void readPendingDatagrams(); -}; - - -#endif // hifi_AnimationServer_h diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp deleted file mode 100644 index 8acf3b8db2..0000000000 --- a/animation-server/src/main.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// -// main.cpp -// animation-server/src -// -// Created by Brad Hefta-Gaub on 05/16/2013. -// Copyright 2012 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 -// - -#include "AnimationServer.h" - -int main(int argc, char * argv[]) { - AnimationServer animationServer(argc, argv); - return animationServer.exec(); -} From 64699a213a7088274f78b452718f6a42947e7859 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 7 Aug 2014 14:48:51 -0700 Subject: [PATCH 247/407] remove animation server --- CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2dbc89b75f..578c36841d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,11 +44,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed. set(CMAKE_AUTOMOC ON) -# targets not supported on windows -if (NOT WIN32) - add_subdirectory(animation-server) -endif () - # targets on all platforms add_subdirectory(assignment-client) add_subdirectory(domain-server) From 4e1886dfcbbcfc28d06a190f83c7a03c962f27eb Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 7 Aug 2014 15:04:55 -0700 Subject: [PATCH 248/407] Divided when I should have multiplied. --- interface/src/ui/MetavoxelEditor.cpp | 3 +-- libraries/metavoxels/src/MetavoxelClientManager.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index a5186567bd..01b5ad0718 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -1104,7 +1104,6 @@ void HeightfieldBrushTool::render() { if (!Application::getInstance()->getMetavoxels()->findFirstRayHeightfieldIntersection(origin, direction, distance)) { return; } - qDebug() << distance; glm::vec3 point = origin + distance * direction; glPushMatrix(); @@ -1112,7 +1111,7 @@ void HeightfieldBrushTool::render() { glColor4f(1.0f, 0.0f, 0.0f, 1.0f); - glutSolidSphere(0.1f, 8, 8); + glutSolidSphere(1.0f, 8, 8); glPopMatrix(); } diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index a9eff58f33..0ffdefd134 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -92,7 +92,7 @@ int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance const uchar* src = (const uchar*)contents.constData(); int size = glm::sqrt((float)contents.size()); int highest = size - 1; - float heightScale = highest / EIGHT_BIT_MAXIMUM_RECIPROCAL; + float heightScale = highest * EIGHT_BIT_MAXIMUM_RECIPROCAL; // find the initial location in heightfield coordinates glm::vec3 entry = (_origin + distance * _direction - info.minimum) * (float)highest / info.size; From 84f3ede32f04acdba5ed09feeb9544c256844e56 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 7 Aug 2014 15:09:24 -0700 Subject: [PATCH 249/407] small change to force rebuild --- libraries/shared/src/SharedUtil.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 18494d48e4..4a9de2cc18 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -191,4 +191,5 @@ QByteArray createByteArray(const glm::vec3& vector); QString formatUsecTime(float usecs, int prec = 3); + #endif // hifi_SharedUtil_h From 83a868d7418534bd0ee6a51cb78fe298b98b5470 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 7 Aug 2014 15:20:30 -0700 Subject: [PATCH 250/407] Make XMLHttpRequest automatically authorize API calls --- libraries/script-engine/src/XMLHttpRequestClass.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index 9d8988c43d..cb891c2ab1 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -17,6 +17,7 @@ #include +#include #include "XMLHttpRequestClass.h" #include "ScriptEngine.h" @@ -201,6 +202,9 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a notImplemented(); } } else { + if (url.toLower().left(33) == "https://data.highfidelity.io/api/") { + _url.setQuery("access_token=" + AccountManager::getInstance().getAccountInfo().getAccessToken().token); + } if (!username.isEmpty()) { _url.setUserName(username); } From 70548976dbec7f11f3d4e2c8f71a8fd2b6be29b0 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 7 Aug 2014 15:27:30 -0700 Subject: [PATCH 251/407] Fix boundary string format to not include curly braces --- examples/editModels.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/editModels.js b/examples/editModels.js index b6d783700d..1f1c349738 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -169,7 +169,7 @@ var httpMultiPart = (function () { crlf; function clear() { - boundaryString = "--boundary_" + Uuid.generate() + "="; + boundaryString = "--boundary_" + String(Uuid.generate()).slice(1, 36) + "="; parts = []; byteLength = 0; crlf = ""; From eaf0b366d009807314de697d934846f3c1ebcbdc Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 7 Aug 2014 15:30:27 -0700 Subject: [PATCH 252/407] Update model reading in preparation for API upload --- examples/editModels.js | 96 +++++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 34 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 1f1c349738..0042fe29ab 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -64,6 +64,13 @@ if (typeof String.prototype.fileName !== "function") { }; } +if (typeof String.prototype.fileBase !== "function") { + String.prototype.fileBase = function () { + var filename = this.fileName(); + return filename.slice(0, filename.indexOf(".")); + }; +} + if (typeof String.prototype.fileType !== "function") { String.prototype.fileType = function () { return this.slice(this.lastIndexOf(".") + 1); @@ -272,13 +279,14 @@ var httpMultiPart = (function () { var modelUploader = (function () { var that = {}, - urlBase = "http://public.highfidelity.io/meshes/", modelFile, fstBuffer, fbxBuffer, svoBuffer, mapping, geometry, + API_URL = "https://data.highfidelity.io/api/v1/models", + MODEL_URL = "http://public.highfidelity.io/models/content", NAME_FIELD = "name", SCALE_FIELD = "scale", FILENAME_FIELD = "filename", @@ -290,8 +298,8 @@ var modelUploader = (function () { MAX_TEXTURE_SIZE = 1024; function error(message) { - Window.alert(message); print(message); + Window.alert(message); } function resetDataObjects() { @@ -460,57 +468,71 @@ var modelUploader = (function () { } function readModel() { - var fbxFilename; + var fbxFilename, + svoFilename, + fileType; print("Reading model file: " + modelFile); - if (modelFile.toLowerCase().slice(-4) === ".svo") { - svoBuffer = readFile(modelFile); - if (svoBuffer === null) { + if (modelFile.toLowerCase().slice(-4) === ".fst") { + fstBuffer = readFile(modelFile); + if (fstBuffer === null) { return false; } + readMapping(fstBuffer); + fileType = mapping[FILENAME_FIELD].toLowerCase().fileType(); + if (mapping.hasOwnProperty(FILENAME_FIELD)) { + if (fileType === "fbx") { + fbxFilename = modelFile.path() + "\\" + mapping[FILENAME_FIELD]; + } else if (fileType === "svo") { + svoFilename = modelFile.path() + "\\" + mapping[FILENAME_FIELD]; + } else { + error("Unrecognized model type in FST file!"); + return false; + } + } else { + error("Model file name not found in FST file!"); + return false; + } + + } else if (modelFile.toLowerCase().slice(-4) === ".fbx") { + fbxFilename = modelFile; + mapping[FILENAME_FIELD] = modelFile.fileName(); + + } else if (modelFile.toLowerCase().slice(-4) === ".svo") { + svoFilename = modelFile; + mapping[FILENAME_FIELD] = modelFile.fileName(); } else { + error("Unrecognized file type: " + modelFile); + return false; + } - if (modelFile.toLowerCase().slice(-4) === ".fst") { - fstBuffer = readFile(modelFile); - if (fstBuffer === null) { - return false; - } - readMapping(fstBuffer); - if (mapping.hasOwnProperty(FILENAME_FIELD)) { - fbxFilename = modelFile.path() + "\\" + mapping[FILENAME_FIELD]; - } else { - error("FBX file name not found in FST file!"); - return false; - } - - } else if (modelFile.toLowerCase().slice(-4) === ".fbx") { - fbxFilename = modelFile; - mapping[FILENAME_FIELD] = modelFile.fileName(); - - } else { - error("Unrecognized file type: " + modelFile); - return false; - } - + if (fbxFilename) { fbxBuffer = readFile(fbxFilename); if (fbxBuffer === null) { return false; } readGeometry(fbxBuffer); + } - if (mapping.hasOwnProperty(SCALE_FIELD)) { - mapping[SCALE_FIELD] = parseFloat(mapping[SCALE_FIELD]); - } else { - mapping[SCALE_FIELD] = (geometry.author === "www.makehuman.org" ? 150.0 : 15.0); + if (svoFilename) { + svoBuffer = readFile(svoFilename); + if (svoBuffer === null) { + return false; } } + if (mapping.hasOwnProperty(SCALE_FIELD)) { + mapping[SCALE_FIELD] = parseFloat(mapping[SCALE_FIELD]); + } else { + mapping[SCALE_FIELD] = (geometry.author === "www.makehuman.org" ? 150.0 : 15.0); + } + // Add any missing basic mappings if (!mapping.hasOwnProperty(NAME_FIELD)) { - mapping[NAME_FIELD] = modelFile.fileName().slice(0, -4); + mapping[NAME_FIELD] = modelFile.fileName().fileBase(); } if (!mapping.hasOwnProperty(TEXDIR_FIELD)) { mapping[TEXDIR_FIELD] = "."; @@ -626,6 +648,9 @@ var modelUploader = (function () { for (lodFile in mapping.lod) { if (mapping.lod.hasOwnProperty(lodFile)) { lodBuffer = readFile(modelFile.path() + "\/" + lodFile); + if (lodBuffer === null) { + return false; + } httpMultiPart.add({ name: "lod" + lodCount, buffer: lodBuffer @@ -639,6 +664,9 @@ var modelUploader = (function () { textureBuffer = readFile(modelFile.path() + "\/" + (mapping[TEXDIR_FIELD] !== "." ? mapping[TEXDIR_FIELD] + "\/" : "") + geometry.textures[i]); + if (textureBuffer === null) { + return false; + } textureSourceFormat = geometry.textures[i].fileType().toLowerCase(); textureTargetFormat = (textureSourceFormat === "jpg" ? "jpg" : "png"); @@ -654,7 +682,7 @@ var modelUploader = (function () { // Model category httpMultiPart.add({ name : "model_category", - string : "item" // DJRTODO: What model category to use? + string : "content" }); return true; From 7f2d33c4e43f7ad1e37e2b122e5d3f49eeaca1d9 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 7 Aug 2014 15:31:44 -0700 Subject: [PATCH 253/407] Add in model uploading via API --- examples/editModels.js | 147 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 132 insertions(+), 15 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 0042fe29ab..67760acdb0 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -688,32 +688,148 @@ var modelUploader = (function () { return true; } - function sendToHighFidelity(url, callback) { - var req; + function sendToHighFidelity(addModelCallback) { + var req, + modelName, + modelURL, + uploadedChecks, + HTTP_GET_TIMEOUT = 60, // 1 minute + HTTP_SEND_TIMEOUT = 900, // 15 minutes + UPLOADED_CHECKS = 30, + CHECK_UPLOADED_TIMEOUT = 1, // 1 second + handleCheckUploadedResponses, + handleUploadModelResponses, + handleRequestUploadResponses; - print("Sending model to High Fidelity"); + function uploadTimedOut() { + error("Model upload failed: Internet request timed out!"); + } - req = new XMLHttpRequest(); - req.open("POST", url, true); - req.setRequestHeader("Content-Type", "multipart/form-data; boundary=\"" + httpMultiPart.boundary() + "\""); + function debugResponse() { + print("req.errorCode = " + req.errorCode); + print("req.readyState = " + req.readyState); + print("req.status = " + req.status); + print("req.statusText = " + req.statusText); + print("req.responseType = " + req.responseType); + print("req.responseText = " + req.responseText); + print("req.response = " + req.response); + print("req.getAllResponseHeaders() = " + req.getAllResponseHeaders()); + } - req.onreadystatechange = function () { + function checkUploaded() { + print("Checking uploaded model"); + + req = new XMLHttpRequest(); + req.open("HEAD", modelURL, true); + req.timeout = HTTP_GET_TIMEOUT * 1000; + req.onreadystatechange = handleCheckUploadedResponses; + req.ontimeout = uploadTimedOut; + req.send(); + } + + handleCheckUploadedResponses = function () { + //debugResponse(); if (req.readyState === req.DONE) { if (req.status === 200) { - print("Uploaded model: " + url); - callback(url); + // Note: Unlike avatar models, for content models we don't need to refresh texture cache. + addModelCallback(modelURL); // Add model to the world + print("Model uploaded: " + modelURL); + Window.alert("Your model has been uploaded as: " + modelURL); + } else if (req.status === 404) { + if (uploadedChecks > 0) { + uploadedChecks -= 1; + Script.setTimeout(checkUploaded, CHECK_UPLOADED_TIMEOUT * 1000); + } else { + print("Error: " + req.status + " " + req.statusText); + error("We could not verify that your model was successfully uploaded but it may have been at: " + + modelURL); + } } else { - print("Error uploading file: " + req.status + " " + req.statusText); - Window.alert("Could not upload file: " + req.status + " " + req.statusText); + print("Error: " + req.status + " " + req.statusText); + error("There was a problem with your upload, please try again later."); } } }; - req.send(httpMultiPart.response().buffer); + function uploadModel(method) { + var url; + + req = new XMLHttpRequest(); + if (method === "PUT") { + url = API_URL + "\/" + modelName; + req.open("PUT", url, true); //print("PUT " + url); + } else { + url = API_URL; + req.open("POST", url, true); //print("POST " + url); + } + req.setRequestHeader("Content-Type", "multipart/form-data; boundary=\"" + httpMultiPart.boundary() + "\""); + req.timeout = HTTP_SEND_TIMEOUT * 1000; + req.onreadystatechange = handleUploadModelResponses; + req.ontimeout = uploadTimedOut; + req.send(httpMultiPart.response().buffer); + } + + handleUploadModelResponses = function () { + //debugResponse(); + if (req.readyState === req.DONE) { + if (req.status === 200) { + uploadedChecks = 30; + checkUploaded(); + } else { + print("Error: " + req.status + " " + req.statusText); + error("There was a problem with your upload, please try again later."); + } + } + }; + + function requestUpload() { + var url; + + url = API_URL + "\/" + modelName; // XMLHttpRequest automatically handles authorization of API requests. + req = new XMLHttpRequest(); + req.open("GET", url, true); //print("GET " + url); + req.responseType = "json"; + req.timeout = HTTP_GET_TIMEOUT * 1000; + req.onreadystatechange = handleRequestUploadResponses; + req.ontimeout = uploadTimedOut; + req.send(); + } + + handleRequestUploadResponses = function () { + var response; + + //debugResponse(); + if (req.readyState === req.DONE) { + if (req.status === 200) { + if (req.responseType === "json") { + response = JSON.parse(req.responseText); + if (response.status === "success") { + if (response.exists === false) { + uploadModel("POST"); + } else if (response.can_update === true) { + uploadModel("PUT"); + } else { + error("This model file already exists and is owned by someone else!"); + } + return; + } + } + } else { + print("Error: " + req.status + " " + req.statusText); + } + error("Model upload failed! Something went wrong at the data server."); + } + }; + + print("Sending model to High Fidelity"); + + modelName = mapping[NAME_FIELD]; + modelURL = MODEL_URL + "\/" + mapping[NAME_FIELD] + ".fst"; // DJRTODO: Do all models get a FST? + + requestUpload(); } - that.upload = function (file, callback) { - var url = urlBase + file.fileName(); + that.upload = function (file, addModelCallback) { modelFile = file; @@ -738,7 +854,8 @@ var modelUploader = (function () { } // Send model to High Fidelity ... - sendToHighFidelity(url, callback); + sendToHighFidelity(addModelCallback); + resetDataObjects(); }; From 9a55252587f1c02fe5fa88ce8e88c55e8aabf46f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Aug 2014 17:02:28 -0700 Subject: [PATCH 254/407] remove extraneous roots from Model::_jointStates --- interface/src/avatar/SkeletonModel.cpp | 24 +++++++--------- interface/src/renderer/Model.cpp | 40 ++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 6b77e1c2f1..f759dc99a3 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -515,9 +515,9 @@ void SkeletonModel::initRagdollPoints() { initRagdollTransform(); // one point for each joint - int numJoints = _jointStates.size(); - _ragdollPoints.fill(VerletPoint(), numJoints); - for (int i = 0; i < numJoints; ++i) { + int numStates = _jointStates.size(); + _ragdollPoints.fill(VerletPoint(), numStates); + for (int i = 0; i < numStates; ++i) { const JointState& state = _jointStates.at(i); // _ragdollPoints start in model-frame _ragdollPoints[i].initPosition(state.getPosition()); @@ -719,8 +719,8 @@ void SkeletonModel::buildShapes() { // ... then move shapes back to current joint positions if (_ragdollPoints.size() == numStates) { - int numJoints = _jointStates.size(); - for (int i = 0; i < numJoints; ++i) { + int numStates = _jointStates.size(); + for (int i = 0; i < numStates; ++i) { // ragdollPoints start in model-frame _ragdollPoints[i].initPosition(_jointStates.at(i).getPosition()); } @@ -765,17 +765,15 @@ void SkeletonModel::updateMuscles() { void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { // compute default joint transforms - int numJoints = geometry.joints.size(); - if (numJoints != _ragdollPoints.size()) { - return; - } + int numStates = _jointStates.size(); QVector transforms; - transforms.fill(glm::mat4(), numJoints); + transforms.fill(glm::mat4(), numStates); // compute the default transforms and slam the ragdoll positions accordingly // (which puts the shapes where we want them) - for (int i = 0; i < numJoints; i++) { - const FBXJoint& joint = geometry.joints.at(i); + for (int i = 0; i < numStates; i++) { + JointState& state = _jointStates[i]; + const FBXJoint& joint = state.getFBXJoint(); int parentIndex = joint.parentIndex; if (parentIndex == -1) { transforms[i] = _jointStates[i].getTransform(); @@ -847,7 +845,7 @@ void SkeletonModel::resetShapePositionsToDefaultPose() { } const FBXGeometry& geometry = _geometry->getFBXGeometry(); - if (geometry.joints.isEmpty() || _shapes.size() != geometry.joints.size()) { + if (geometry.joints.isEmpty()) { return; } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 025971db4b..73b65b6d41 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -188,10 +188,38 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati QVector Model::createJointStates(const FBXGeometry& geometry) { QVector jointStates; - foreach (const FBXJoint& joint, geometry.joints) { - // NOTE: the state keeps a pointer to an FBXJoint + QVector roots; + roots.fill(-1, geometry.joints.size()); + for (int i = 0; i < geometry.joints.size(); ++i) { + const FBXJoint& joint = geometry.joints[i]; + int parentIndex = joint.parentIndex; + + // Some models may have multiple roots (?!), but these are causing problems in + // the Avatar Ragdoll simulation, so we prune them out of the JointState tree. + int rootIndex = 0; + if (parentIndex == -1) { + if (i != 0) { + // skip other root + continue; + } + } else { + rootIndex = roots[parentIndex]; + if (rootIndex == -1) { + roots[i] = parentIndex; + rootIndex = parentIndex; + } else { + roots[i] = rootIndex; + } + if (rootIndex != 0) { + // skip child of other root + continue; + } + } + + // store a pointer to the FBXJoint in the JointState JointState state; state.setFBXJoint(&joint); + jointStates.append(state); } return jointStates; @@ -199,8 +227,8 @@ QVector Model::createJointStates(const FBXGeometry& geometry) { void Model::initJointTransforms() { // compute model transforms - int numJoints = _jointStates.size(); - for (int i = 0; i < numJoints; ++i) { + int numStates = _jointStates.size(); + for (int i = 0; i < numStates; ++i) { JointState& state = _jointStates[i]; const FBXJoint& joint = state.getFBXJoint(); int parentIndex = joint.parentIndex; @@ -538,9 +566,9 @@ void Model::setJointStates(QVector states) { _jointStates = states; initJointTransforms(); - int numJoints = _jointStates.size(); + int numStates = _jointStates.size(); float radius = 0.0f; - for (int i = 0; i < numJoints; ++i) { + for (int i = 0; i < numStates; ++i) { float distance = glm::length(_jointStates[i].getPosition()); if (distance > radius) { radius = distance; From 0fc34a47aacdfcec1480dd8c91fc9d30e20adcb8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 7 Aug 2014 18:19:58 -0700 Subject: [PATCH 255/407] Show heightfield cursor. --- .../shaders/metavoxel_heightfield_cursor.frag | 20 +++ .../shaders/metavoxel_heightfield_cursor.vert | 31 ++++ interface/src/MetavoxelSystem.cpp | 140 +++++++++++++++++- interface/src/MetavoxelSystem.h | 19 ++- interface/src/ui/MetavoxelEditor.cpp | 10 +- .../metavoxels/src/MetavoxelClientManager.cpp | 6 +- 6 files changed, 204 insertions(+), 22 deletions(-) create mode 100644 interface/resources/shaders/metavoxel_heightfield_cursor.frag create mode 100644 interface/resources/shaders/metavoxel_heightfield_cursor.vert diff --git a/interface/resources/shaders/metavoxel_heightfield_cursor.frag b/interface/resources/shaders/metavoxel_heightfield_cursor.frag new file mode 100644 index 0000000000..20efc51e08 --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield_cursor.frag @@ -0,0 +1,20 @@ +#version 120 + +// +// metavoxel_heightfield_cursor.frag +// fragment shader +// +// Created by Andrzej Kapolka on 8/7/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 cursor texture +uniform sampler2D cursorMap; + +void main(void) { + // just multiply the color by the cursor texture + gl_FragColor = gl_Color * texture2D(cursorMap, gl_TexCoord[0].st); +} diff --git a/interface/resources/shaders/metavoxel_heightfield_cursor.vert b/interface/resources/shaders/metavoxel_heightfield_cursor.vert new file mode 100644 index 0000000000..20502fbdce --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield_cursor.vert @@ -0,0 +1,31 @@ +#version 120 + +// +// metavoxel_heighfield_cursor.vert +// vertex shader +// +// Created by Andrzej Kapolka on 8/7/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 height texture +uniform sampler2D heightMap; + +// the distance between height points in texture space +uniform float heightScale; + +void main(void) { + // compute the view space coordinates + float height = texture2D(heightMap, gl_MultiTexCoord0.st).r; + vec4 viewPosition = gl_ModelViewMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0)); + gl_Position = gl_ProjectionMatrix * viewPosition; + + // generate the texture coordinates from the view position + gl_TexCoord[0] = vec4(dot(viewPosition, gl_EyePlaneS[4]), dot(viewPosition, gl_EyePlaneT[4]), 0.0, 1.0); + + // the zero height should be invisible + gl_FrontColor = vec4(1.0, 1.0, 1.0, 1.0 - step(height, 0.0)); +} diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index f66d71070a..85a1f5a1fc 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -31,6 +31,10 @@ REGISTER_META_OBJECT(StaticModelRenderer) static int bufferPointVectorMetaTypeId = qRegisterMetaType(); +MetavoxelSystem::MetavoxelSystem() : + _cursorTexture(QOpenGLTexture::Target2D) { +} + void MetavoxelSystem::init() { MetavoxelClientManager::init(); DefaultMetavoxelRendererImplementation::init(); @@ -118,6 +122,105 @@ void MetavoxelSystem::render() { guideToAugmented(renderVisitor); } +class HeightfieldCursorRenderVisitor : public MetavoxelVisitor { +public: + + HeightfieldCursorRenderVisitor(const MetavoxelLOD& lod, const Box& bounds); + + virtual int visit(MetavoxelInfo& info); + +private: + + Box _bounds; +}; + +HeightfieldCursorRenderVisitor::HeightfieldCursorRenderVisitor(const MetavoxelLOD& lod, const Box& bounds) : + MetavoxelVisitor(QVector() << + Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector(), lod), + _bounds(bounds) { +} + +int HeightfieldCursorRenderVisitor::visit(MetavoxelInfo& info) { + if (!info.getBounds().intersects(_bounds)) { + return STOP_RECURSION; + } + if (!info.isLeaf) { + return DEFAULT_ORDER; + } + BufferDataPointer buffer = info.inputValues.at(0).getInlineValue(); + if (buffer) { + buffer->render(true); + } + return STOP_RECURSION; +} + +void MetavoxelSystem::renderHeightfieldCursor(const glm::vec3& position, float radius) { + // create the cursor texture lazily + if (!_cursorTexture.isCreated()) { + const int CURSOR_TEXTURE_SIZE = 512; + QImage cursorImage(CURSOR_TEXTURE_SIZE, CURSOR_TEXTURE_SIZE, QImage::Format_ARGB32_Premultiplied); + cursorImage.fill(0x0); + { + QPainter painter(&cursorImage); + const int ELLIPSE_EDGE = 10; + const int OUTER_WIDTH = 10; + QPen outerPen; + outerPen.setWidth(OUTER_WIDTH); + painter.setPen(outerPen); + const int HALF_TEXTURE_SIZE = CURSOR_TEXTURE_SIZE / 2; + painter.drawEllipse(QPoint(HALF_TEXTURE_SIZE, HALF_TEXTURE_SIZE), HALF_TEXTURE_SIZE - ELLIPSE_EDGE, + HALF_TEXTURE_SIZE - ELLIPSE_EDGE); + QPen innerPen(Qt::white); + const int INNER_WIDTH = 6; + innerPen.setWidth(INNER_WIDTH); + painter.setPen(innerPen); + painter.drawEllipse(QPoint(HALF_TEXTURE_SIZE, HALF_TEXTURE_SIZE), HALF_TEXTURE_SIZE - ELLIPSE_EDGE, + HALF_TEXTURE_SIZE - ELLIPSE_EDGE); + } + _cursorTexture.setData(cursorImage, QOpenGLTexture::DontGenerateMipMaps); + _cursorTexture.setWrapMode(QOpenGLTexture::ClampToEdge); + _cursorTexture.setMinificationFilter(QOpenGLTexture::Linear); + } + + glDepthFunc(GL_LEQUAL); + glEnable(GL_CULL_FACE); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(-1.0f, -1.0f); + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().bind(); + + glActiveTexture(GL_TEXTURE4); + float scale = 1.0f / radius; + glm::vec4 sCoefficients(scale, 0.0f, 0.0f, 0.5f - scale * position.x); + glm::vec4 tCoefficients(0.0f, 0.0f, scale, 0.5f - scale * position.z); + glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&sCoefficients); + glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&tCoefficients); + + _cursorTexture.bind(1); + glActiveTexture(GL_TEXTURE0); + + glm::vec3 extents(radius, radius, radius); + HeightfieldCursorRenderVisitor visitor(getLOD(), Box(position - extents, position + extents)); + guideToAugmented(visitor); + + _cursorTexture.release(1); + glActiveTexture(GL_TEXTURE0); + + DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().release(); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + + glDisable(GL_POLYGON_OFFSET_FILL); + glDisable(GL_CULL_FACE); + glDepthFunc(GL_LESS); +} + void MetavoxelSystem::deleteTextures(int heightID, int colorID) { glDeleteTextures(1, (GLuint*)&heightID); glDeleteTextures(1, (GLuint*)&colorID); @@ -239,7 +342,7 @@ PointBuffer::PointBuffer(const BufferPointVector& points) : _points(points) { } -void PointBuffer::render() { +void PointBuffer::render(bool cursor) { // initialize buffer, etc. on first render if (!_buffer.isCreated()) { _buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); @@ -294,7 +397,7 @@ public: glm::vec3 vertex; }; -void HeightfieldBuffer::render() { +void HeightfieldBuffer::render(bool cursor) { // initialize textures, etc. on first render if (_heightTextureID == 0) { glGenTextures(1, &_heightTextureID); @@ -385,17 +488,24 @@ void HeightfieldBuffer::render() { glBindTexture(GL_TEXTURE_2D, _heightTextureID); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, _colorTextureID); + int heightScaleLocation; + if (cursor) { + heightScaleLocation = DefaultMetavoxelRendererImplementation::getCursorHeightScaleLocation(); + } else { + heightScaleLocation = DefaultMetavoxelRendererImplementation::getHeightScaleLocation(); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, _colorTextureID); + } - DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue( - DefaultMetavoxelRendererImplementation::getHeightScaleLocation(), 1.0f / _heightSize); + DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue(heightScaleLocation, 1.0f / _heightSize); glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); - glBindTexture(GL_TEXTURE_2D, 0); + if (!cursor) { + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + } - glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); glPopMatrix(); @@ -475,6 +585,18 @@ void DefaultMetavoxelRendererImplementation::init() { _heightfieldProgram.setUniformValue("diffuseMap", 1); _heightScaleLocation = _heightfieldProgram.uniformLocation("heightScale"); _heightfieldProgram.release(); + + _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/metavoxel_heightfield_cursor.vert"); + _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/metavoxel_heightfield_cursor.frag"); + _heightfieldCursorProgram.link(); + + _heightfieldCursorProgram.bind(); + _heightfieldCursorProgram.setUniformValue("heightMap", 0); + _heightfieldCursorProgram.setUniformValue("cursorMap", 1); + _cursorHeightScaleLocation = _heightfieldCursorProgram.uniformLocation("heightScale"); + _heightfieldCursorProgram.release(); } } @@ -771,6 +893,8 @@ ProgramObject DefaultMetavoxelRendererImplementation::_pointProgram; int DefaultMetavoxelRendererImplementation::_pointScaleLocation; ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldProgram; int DefaultMetavoxelRendererImplementation::_heightScaleLocation; +ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldCursorProgram; +int DefaultMetavoxelRendererImplementation::_cursorHeightScaleLocation; static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { GLdouble coefficients[] = { x, y, z, w }; diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index e7ee0d2c18..a2d3128cb7 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -31,6 +32,8 @@ class MetavoxelSystem : public MetavoxelClientManager { public: + MetavoxelSystem(); + virtual void init(); virtual MetavoxelLOD getLOD(); @@ -43,6 +46,8 @@ public: void simulate(float deltaTime); void render(); + void renderHeightfieldCursor(const glm::vec3& position, float radius); + Q_INVOKABLE void deleteTextures(int heightID, int colorID); protected: @@ -59,6 +64,8 @@ private: MetavoxelLOD _lod; QReadWriteLock _lodLock; Frustum _frustum; + + QOpenGLTexture _cursorTexture; }; /// Describes contents of a point in a point buffer. @@ -105,7 +112,7 @@ public: virtual ~BufferData(); - virtual void render() = 0; + virtual void render(bool cursor = false) = 0; }; typedef QExplicitlySharedDataPointer BufferDataPointer; @@ -116,7 +123,7 @@ public: PointBuffer(const BufferPointVector& points); - virtual void render(); + virtual void render(bool cursor = false); private: @@ -140,7 +147,7 @@ public: const QByteArray& getHeight() const { return _height; } const QByteArray& getColor() const { return _color; } - virtual void render(); + virtual void render(bool cursor = false); private: @@ -193,6 +200,9 @@ public: static ProgramObject& getHeightfieldProgram() { return _heightfieldProgram; } static int getHeightScaleLocation() { return _heightScaleLocation; } + static ProgramObject& getHeightfieldCursorProgram() { return _heightfieldCursorProgram; } + static int getCursorHeightScaleLocation() { return _cursorHeightScaleLocation; } + Q_INVOKABLE DefaultMetavoxelRendererImplementation(); virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod); @@ -206,6 +216,9 @@ private: static ProgramObject _heightfieldProgram; static int _heightScaleLocation; + + static ProgramObject _heightfieldCursorProgram; + static int _cursorHeightScaleLocation; }; /// Base class for spanner renderers; provides clipping. diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 01b5ad0718..28a4d6da27 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -1105,15 +1105,7 @@ void HeightfieldBrushTool::render() { return; } glm::vec3 point = origin + distance * direction; - - glPushMatrix(); - glTranslatef(point.x, point.y, point.z); - - glColor4f(1.0f, 0.0f, 0.0f, 1.0f); - - glutSolidSphere(1.0f, 8, 8); - - glPopMatrix(); + Application::getInstance()->getMetavoxels()->renderHeightfieldCursor(point, _radius->value()); } HeightBrushTool::HeightBrushTool(MetavoxelEditor* editor) : diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index 0ffdefd134..70b574d2a2 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -194,7 +194,8 @@ int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance glm::vec3 intersection = relativeEntry + planeDistance * _direction; if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && intersection.z >= intersection.x) { - intersectionDistance = distance + (accumulatedDistance + planeDistance) * (info.size / highest); + intersectionDistance = qMin(intersectionDistance, distance + + (accumulatedDistance + planeDistance) * (info.size / highest)); return SHORT_CIRCUIT; } } @@ -207,7 +208,8 @@ int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance glm::vec3 intersection = relativeEntry + planeDistance * _direction; if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && intersection.x >= intersection.z) { - intersectionDistance = distance + (accumulatedDistance + planeDistance) * (info.size / highest); + intersectionDistance = qMin(intersectionDistance, distance + + (accumulatedDistance + planeDistance) * (info.size / highest)); return SHORT_CIRCUIT; } } From 6930174a9ecc9b4adf0846d13c38cfe2160deb47 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 7 Aug 2014 18:30:33 -0700 Subject: [PATCH 256/407] Hide the cursor when the mouse pointer is hidden. --- interface/src/ui/MetavoxelEditor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 28a4d6da27..48fa2ed070 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -1096,6 +1096,10 @@ HeightfieldBrushTool::HeightfieldBrushTool(MetavoxelEditor* editor, const QStrin } void HeightfieldBrushTool::render() { + if (Application::getInstance()->isMouseHidden()) { + return; + } + // find the intersection with the heightfield glm::vec3 origin = Application::getInstance()->getMouseRayOrigin(); glm::vec3 direction = Application::getInstance()->getMouseRayDirection(); From 5de762361a70f12e560eb12ae6c1f12c22abc447 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 Aug 2014 08:20:42 -0700 Subject: [PATCH 257/407] remove cleanup of Model::_jointStates tree the cleanup causes crashes and broken models --- interface/src/renderer/Model.cpp | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 73b65b6d41..a915406f8e 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -188,34 +188,8 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati QVector Model::createJointStates(const FBXGeometry& geometry) { QVector jointStates; - QVector roots; - roots.fill(-1, geometry.joints.size()); for (int i = 0; i < geometry.joints.size(); ++i) { const FBXJoint& joint = geometry.joints[i]; - int parentIndex = joint.parentIndex; - - // Some models may have multiple roots (?!), but these are causing problems in - // the Avatar Ragdoll simulation, so we prune them out of the JointState tree. - int rootIndex = 0; - if (parentIndex == -1) { - if (i != 0) { - // skip other root - continue; - } - } else { - rootIndex = roots[parentIndex]; - if (rootIndex == -1) { - roots[i] = parentIndex; - rootIndex = parentIndex; - } else { - roots[i] = rootIndex; - } - if (rootIndex != 0) { - // skip child of other root - continue; - } - } - // store a pointer to the FBXJoint in the JointState JointState state; state.setFBXJoint(&joint); From bcb0cb2c3c09ea77d0c3f85d7f0c6bc959c2afb6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 Aug 2014 08:26:25 -0700 Subject: [PATCH 258/407] fix bug: variable should be float rather than int --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0b940dc3df..f59064732c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -206,7 +206,7 @@ void MyAvatar::simulate(float deltaTime) { { PerformanceTimer perfTimer("ragdoll"); if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { - const int minError = 0.01f; + const float minError = 0.01f; const float maxIterations = 10; const quint64 maxUsec = 2000; _physicsSimulation.setTranslation(_position); From 05318acc7f4472d6e8e40449586c596b3b82ddf6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 Aug 2014 08:37:28 -0700 Subject: [PATCH 259/407] don't make shapes for joints with zero radius --- interface/src/avatar/SkeletonModel.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index f759dc99a3..5e593526be 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -685,6 +685,9 @@ void SkeletonModel::buildShapes() { // this shape is forced to be a sphere type = Shape::SPHERE_SHAPE; } + if (radius < EPSILON) { + type = Shape::UNKNOWN_SHAPE; + } Shape* shape = NULL; int parentIndex = joint.parentIndex; if (type == Shape::SPHERE_SHAPE) { @@ -699,7 +702,9 @@ void SkeletonModel::buildShapes() { } if (parentIndex != -1) { // always disable collisions between joint and its parent - disableCollisions(i, parentIndex); + if (shape) { + disableCollisions(i, parentIndex); + } } else { // give the base joint a very large mass since it doesn't actually move // in the local-frame simulation (it defines the origin) From 2286eae64accf245382c2613199321b82bd66a69 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 Aug 2014 10:53:38 -0700 Subject: [PATCH 260/407] head connects to neck during ragdoll simulation --- interface/src/avatar/SkeletonModel.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 5e593526be..24acd8d2e3 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -432,6 +432,9 @@ bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const { } bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const { + if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { + return isActive() && getVisibleJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition); + } return isActive() && getJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition); } @@ -445,11 +448,16 @@ bool SkeletonModel::getNeckParentRotationFromDefaultOrientation(glm::quat& neckP } int parentIndex = geometry.joints.at(geometry.neckJointIndex).parentIndex; glm::quat worldFrameRotation; - if (getJointRotationInWorldFrame(parentIndex, worldFrameRotation)) { - neckParentRotation = worldFrameRotation * _jointStates[parentIndex].getFBXJoint().inverseDefaultRotation; - return true; + bool success = false; + if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { + success = getVisibleJointRotationInWorldFrame(parentIndex, worldFrameRotation); + } else { + success = getJointRotationInWorldFrame(parentIndex, worldFrameRotation); } - return false; + if (success) { + neckParentRotation = worldFrameRotation * _jointStates[parentIndex].getFBXJoint().inverseDefaultRotation; + } + return success; } bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { From c82a2003a21d63b38ba66bf65b1f28d351892660 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 8 Aug 2014 11:14:36 -0700 Subject: [PATCH 261/407] Add prompt asking user whether they want to rez their uploaded model A user updating an existing model may not want to rez a new copy. --- examples/editModels.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 67760acdb0..39dcea7cad 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -732,9 +732,10 @@ var modelUploader = (function () { if (req.readyState === req.DONE) { if (req.status === 200) { // Note: Unlike avatar models, for content models we don't need to refresh texture cache. - addModelCallback(modelURL); // Add model to the world print("Model uploaded: " + modelURL); - Window.alert("Your model has been uploaded as: " + modelURL); + if (Window.confirm("Your model has been uploaded as: " + modelURL + "\nDo you want to rez it?")) { + addModelCallback(modelURL); + } } else if (req.status === 404) { if (uploadedChecks > 0) { uploadedChecks -= 1; @@ -943,8 +944,9 @@ var toolBar = (function () { radius: DEFAULT_RADIUS, modelURL: url }); + print("Model added: " + url); } else { - print("Can't create model: Model would be out of bounds."); + print("Can't add model: Model would be out of bounds."); } } From b7b1b018eedc7e79b21d7d9b27bedbf907ec28b4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 8 Aug 2014 11:24:57 -0700 Subject: [PATCH 262/407] No need to use a texture for the cursor; we can just use a fragment shader. --- .../shaders/metavoxel_heightfield_cursor.frag | 20 ++++++++-- interface/src/MetavoxelSystem.cpp | 40 +------------------ interface/src/MetavoxelSystem.h | 5 --- 3 files changed, 18 insertions(+), 47 deletions(-) diff --git a/interface/resources/shaders/metavoxel_heightfield_cursor.frag b/interface/resources/shaders/metavoxel_heightfield_cursor.frag index 20efc51e08..0bb5e21e7d 100644 --- a/interface/resources/shaders/metavoxel_heightfield_cursor.frag +++ b/interface/resources/shaders/metavoxel_heightfield_cursor.frag @@ -11,10 +11,22 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// the cursor texture -uniform sampler2D cursorMap; +// the inner radius of the outline, squared +const float SQUARED_OUTLINE_INNER_RADIUS = 0.81; + +// the outer radius of the outline, squared +const float SQUARED_OUTLINE_OUTER_RADIUS = 1.0; + +// the inner radius of the inset, squared +const float SQUARED_INSET_INNER_RADIUS = 0.855625; + +// the outer radius of the inset, squared +const float SQUARED_INSET_OUTER_RADIUS = 0.950625; void main(void) { - // just multiply the color by the cursor texture - gl_FragColor = gl_Color * texture2D(cursorMap, gl_TexCoord[0].st); + // use the distance to compute the ring color, then multiply it by the varying color + float squaredDistance = dot(gl_TexCoord[0].st, gl_TexCoord[0].st); + float alpha = step(SQUARED_OUTLINE_INNER_RADIUS, squaredDistance) * step(squaredDistance, SQUARED_OUTLINE_OUTER_RADIUS); + float white = step(SQUARED_INSET_INNER_RADIUS, squaredDistance) * step(squaredDistance, SQUARED_INSET_OUTER_RADIUS); + gl_FragColor = gl_Color * vec4(white, white, white, alpha); } diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 85a1f5a1fc..f62a85025b 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -31,10 +31,6 @@ REGISTER_META_OBJECT(StaticModelRenderer) static int bufferPointVectorMetaTypeId = qRegisterMetaType(); -MetavoxelSystem::MetavoxelSystem() : - _cursorTexture(QOpenGLTexture::Target2D) { -} - void MetavoxelSystem::init() { MetavoxelClientManager::init(); DefaultMetavoxelRendererImplementation::init(); @@ -155,33 +151,6 @@ int HeightfieldCursorRenderVisitor::visit(MetavoxelInfo& info) { } void MetavoxelSystem::renderHeightfieldCursor(const glm::vec3& position, float radius) { - // create the cursor texture lazily - if (!_cursorTexture.isCreated()) { - const int CURSOR_TEXTURE_SIZE = 512; - QImage cursorImage(CURSOR_TEXTURE_SIZE, CURSOR_TEXTURE_SIZE, QImage::Format_ARGB32_Premultiplied); - cursorImage.fill(0x0); - { - QPainter painter(&cursorImage); - const int ELLIPSE_EDGE = 10; - const int OUTER_WIDTH = 10; - QPen outerPen; - outerPen.setWidth(OUTER_WIDTH); - painter.setPen(outerPen); - const int HALF_TEXTURE_SIZE = CURSOR_TEXTURE_SIZE / 2; - painter.drawEllipse(QPoint(HALF_TEXTURE_SIZE, HALF_TEXTURE_SIZE), HALF_TEXTURE_SIZE - ELLIPSE_EDGE, - HALF_TEXTURE_SIZE - ELLIPSE_EDGE); - QPen innerPen(Qt::white); - const int INNER_WIDTH = 6; - innerPen.setWidth(INNER_WIDTH); - painter.setPen(innerPen); - painter.drawEllipse(QPoint(HALF_TEXTURE_SIZE, HALF_TEXTURE_SIZE), HALF_TEXTURE_SIZE - ELLIPSE_EDGE, - HALF_TEXTURE_SIZE - ELLIPSE_EDGE); - } - _cursorTexture.setData(cursorImage, QOpenGLTexture::DontGenerateMipMaps); - _cursorTexture.setWrapMode(QOpenGLTexture::ClampToEdge); - _cursorTexture.setMinificationFilter(QOpenGLTexture::Linear); - } - glDepthFunc(GL_LEQUAL); glEnable(GL_CULL_FACE); glEnable(GL_POLYGON_OFFSET_FILL); @@ -196,21 +165,16 @@ void MetavoxelSystem::renderHeightfieldCursor(const glm::vec3& position, float r glActiveTexture(GL_TEXTURE4); float scale = 1.0f / radius; - glm::vec4 sCoefficients(scale, 0.0f, 0.0f, 0.5f - scale * position.x); - glm::vec4 tCoefficients(0.0f, 0.0f, scale, 0.5f - scale * position.z); + glm::vec4 sCoefficients(scale, 0.0f, 0.0f, -scale * position.x); + glm::vec4 tCoefficients(0.0f, 0.0f, scale, -scale * position.z); glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&sCoefficients); glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&tCoefficients); - - _cursorTexture.bind(1); glActiveTexture(GL_TEXTURE0); glm::vec3 extents(radius, radius, radius); HeightfieldCursorRenderVisitor visitor(getLOD(), Box(position - extents, position + extents)); guideToAugmented(visitor); - _cursorTexture.release(1); - glActiveTexture(GL_TEXTURE0); - DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().release(); glDisableClientState(GL_TEXTURE_COORD_ARRAY); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index a2d3128cb7..7b681ff3a9 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -14,7 +14,6 @@ #include #include -#include #include #include @@ -32,8 +31,6 @@ class MetavoxelSystem : public MetavoxelClientManager { public: - MetavoxelSystem(); - virtual void init(); virtual MetavoxelLOD getLOD(); @@ -64,8 +61,6 @@ private: MetavoxelLOD _lod; QReadWriteLock _lodLock; Frustum _frustum; - - QOpenGLTexture _cursorTexture; }; /// Describes contents of a point in a point buffer. From 45afce48f748ccfdd80088b98befc88213d91b72 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Aug 2014 11:29:13 -0700 Subject: [PATCH 263/407] remember old session UUID in AvatarHashMap to work around ghosting --- interface/src/Application.cpp | 3 +- libraries/avatars/src/AvatarData.h | 2 +- libraries/avatars/src/AvatarHashMap.cpp | 30 ++++++++++++++------ libraries/avatars/src/AvatarHashMap.h | 8 ++++-- libraries/networking/src/LimitedNodeList.cpp | 2 +- libraries/networking/src/LimitedNodeList.h | 2 +- 6 files changed, 31 insertions(+), 16 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7eb087c531..6f7212e68f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -261,8 +261,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer))); connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), &_voxels, SLOT(nodeAdded(SharedNodePointer))); connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), &_voxels, SLOT(nodeKilled(SharedNodePointer))); - connect(nodeList, &NodeList::uuidChanged, this, &Application::updateWindowTitle); - connect(nodeList, SIGNAL(uuidChanged(const QUuid&)), _myAvatar, SLOT(setSessionUUID(const QUuid&))); + connect(nodeList, &NodeList::uuidChanged, _myAvatar, &MyAvatar::setSessionUUID); connect(nodeList, &NodeList::limitOfSilentDomainCheckInsReached, nodeList, &NodeList::reset); // connect to appropriate slots on AccountManager diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 2971598c1d..a4bb0d48bb 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -290,7 +290,7 @@ public slots: void sendBillboardPacket(); void setBillboardFromNetworkReply(); void setJointMappingsFromNetworkReply(); - void setSessionUUID(const QUuid& id) { _sessionUUID = id; } + void setSessionUUID(const QUuid& sessionUUID) { _sessionUUID = sessionUUID; } bool hasReferential(); protected: diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 8e3797cbc0..202121bad3 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -9,19 +9,21 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include "AvatarHashMap.h" AvatarHashMap::AvatarHashMap() : - _avatarHash() + _avatarHash(), + _lastOwnerSessionUUID() { - + connect(NodeList::getInstance(), &NodeList::uuidChanged, this, &AvatarHashMap::sessionUUIDChanged); } -void AvatarHashMap::insert(const QUuid& id, AvatarSharedPointer avatar) { - _avatarHash.insert(id, avatar); - avatar->setSessionUUID(id); +void AvatarHashMap::insert(const QUuid& sessionUUID, AvatarSharedPointer avatar) { + _avatarHash.insert(sessionUUID, avatar); + avatar->setSessionUUID(sessionUUID); } AvatarHash::iterator AvatarHashMap::erase(const AvatarHash::iterator& iterator) { @@ -110,10 +112,16 @@ void AvatarHashMap::processAvatarDataPacket(const QByteArray &datagram, const QW QUuid sessionUUID = QUuid::fromRfc4122(datagram.mid(bytesRead, NUM_BYTES_RFC4122_UUID)); bytesRead += NUM_BYTES_RFC4122_UUID; - AvatarSharedPointer matchingAvatarData = matchingOrNewAvatar(sessionUUID, mixerWeakPointer); - - // have the matching (or new) avatar parse the data from the packet - bytesRead += matchingAvatarData->parseDataAtOffset(datagram, bytesRead); + if (sessionUUID != _lastOwnerSessionUUID) { + AvatarSharedPointer matchingAvatarData = matchingOrNewAvatar(sessionUUID, mixerWeakPointer); + + // have the matching (or new) avatar parse the data from the packet + bytesRead += matchingAvatarData->parseDataAtOffset(datagram, bytesRead); + } else { + // create a dummy AvatarData class to throw this data on the ground + AvatarData dummyData; + bytesRead += dummyData.parseDataAtOffset(datagram, bytesRead); + } } } @@ -177,3 +185,7 @@ void AvatarHashMap::processKillAvatar(const QByteArray& datagram) { erase(matchedAvatar); } } + +void AvatarHashMap::sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& oldUUID) { + _lastOwnerSessionUUID = oldUUID; +} \ No newline at end of file diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index 542a2d62ab..fe9ab3d634 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -31,12 +31,15 @@ public: const AvatarHash& getAvatarHash() { return _avatarHash; } int size() const { return _avatarHash.size(); } - virtual void insert(const QUuid& id, AvatarSharedPointer avatar); + virtual void insert(const QUuid& sessionUUID, AvatarSharedPointer avatar); public slots: void processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer& mixerWeakPointer); bool containsAvatarWithDisplayName(const QString& displayName); - + +private slots: + void sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& oldUUID); + protected: virtual AvatarHash::iterator erase(const AvatarHash::iterator& iterator); @@ -51,6 +54,7 @@ protected: void processKillAvatar(const QByteArray& datagram); AvatarHash _avatarHash; + QUuid _lastOwnerSessionUUID; }; #endif // hifi_AvatarHashMap_h diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index c0d7941edf..13dc558687 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -95,7 +95,7 @@ void LimitedNodeList::setSessionUUID(const QUuid& sessionUUID) { if (sessionUUID != oldUUID) { qDebug() << "NodeList UUID changed from" << uuidStringWithoutCurlyBraces(oldUUID) << "to" << uuidStringWithoutCurlyBraces(_sessionUUID); - emit uuidChanged(sessionUUID); + emit uuidChanged(sessionUUID, oldUUID); } } diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index a4bc8022bf..3e62d4aaab 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -107,7 +107,7 @@ public slots: void killNodeWithUUID(const QUuid& nodeUUID); signals: - void uuidChanged(const QUuid& ownerUUID); + void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID); void nodeAdded(SharedNodePointer); void nodeKilled(SharedNodePointer); protected: From 9a50532b1f1fa55b4f0b668abfc5947b88f8f87b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Aug 2014 14:22:42 -0700 Subject: [PATCH 264/407] bubble up sub dependencies to link_hifi_library --- cmake/macros/LinkHifiLibrary.cmake | 2 +- interface/CMakeLists.txt | 6 ------ libraries/octree/CMakeLists.txt | 10 ++++++++-- libraries/shared/CMakeLists.txt | 5 ++++- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/cmake/macros/LinkHifiLibrary.cmake b/cmake/macros/LinkHifiLibrary.cmake index 6300e50c34..577f0c9f37 100644 --- a/cmake/macros/LinkHifiLibrary.cmake +++ b/cmake/macros/LinkHifiLibrary.cmake @@ -16,7 +16,7 @@ macro(LINK_HIFI_LIBRARY LIBRARY TARGET ROOT_DIR) include_directories("${ROOT_DIR}/libraries/${LIBRARY}/src") add_dependencies(${TARGET} ${LIBRARY}) - target_link_libraries(${TARGET} ${LIBRARY}) + target_link_libraries(${TARGET} ${LIBRARY} ${REQUIRED_DEPENDENCY_LIBRARIES}) if (APPLE) # currently the "shared" library requires CoreServices diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 7336b55852..5c1bec0321 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -126,7 +126,6 @@ find_package(LeapMotion) find_package(ZLIB) find_package(Qxmpp) find_package(RtMidi) -find_package(OpenSSL REQUIRED) # perform standard include and linking for found externals foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) @@ -180,14 +179,9 @@ endif () # include headers for interface and InterfaceConfig. include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes") -# include external library headers -# use system flag so warnings are supressed -include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}") - target_link_libraries( ${TARGET_NAME} "${ZLIB_LIBRARIES}" - ${OPENSSL_LIBRARIES} Qt5::Core Qt5::Gui Qt5::Multimedia Qt5::Network Qt5::OpenGL Qt5::Script Qt5::Svg Qt5::WebKit Qt5::WebKitWidgets Qt5::Xml Qt5::UiTools ) diff --git a/libraries/octree/CMakeLists.txt b/libraries/octree/CMakeLists.txt index 031f7ef69a..398bf80157 100644 --- a/libraries/octree/CMakeLists.txt +++ b/libraries/octree/CMakeLists.txt @@ -20,9 +20,15 @@ link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") # link ZLIB find_package(ZLIB) +find_package(OpenSSL REQUIRED) -include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") -target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets) +include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}" "${OPENSSL_INCLUDE_DIR}") + +# bubble up the libraries we are dependent on +set(REQUIRED_DEPENDENCY_LIBRARIES ${REQUIRED_DEPENDENCY_LIBRARIES} + "${ZLIB_LIBRARIES}" "${OPENSSL_LIBRARIES}" Qt5::Widgets PARENT_SCOPE) + +target_link_libraries(${TARGET_NAME} ${REQUIRED_DEPENDENCY_LIBRARIES}) # add a definition for ssize_t so that windows doesn't bail if (WIN32) diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index f099f424e9..c0d59c8b75 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -30,4 +30,7 @@ endif (UNIX AND NOT APPLE) # directory when Qt5 (5.2.1) is compiled from source and is not in a standard place. include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}") -target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets) +# bubble up the libraries we are dependent on and link them to ourselves +set(REQUIRED_DEPENDENCY_LIBRARIES Qt5::Network Qt5::Widgets) +set(SUB_DEPENDENCY_LIBRARIES ${REQUIRED_DEPENDENCY_LIBRARIES} PARENT_SCOPE) +target_link_libraries(${TARGET_NAME} ${REQUIRED_DEPENDENCY_LIBRARIES}) \ No newline at end of file From 33e58268423babe05d0f36c21b33fc9509a999b5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Aug 2014 14:57:09 -0700 Subject: [PATCH 265/407] remove animation server, bubble up qt modules --- CMakeLists.txt | 5 - animation-server/CMakeLists.txt | 39 -- animation-server/src/AnimationServer.cpp | 852 ----------------------- animation-server/src/AnimationServer.h | 27 - animation-server/src/main.cpp | 17 - assignment-client/CMakeLists.txt | 4 - cmake/macros/LinkHifiLibrary.cmake | 8 +- libraries/networking/CMakeLists.txt | 7 +- libraries/octree/CMakeLists.txt | 4 +- libraries/shared/CMakeLists.txt | 20 +- 10 files changed, 18 insertions(+), 965 deletions(-) delete mode 100644 animation-server/CMakeLists.txt delete mode 100644 animation-server/src/AnimationServer.cpp delete mode 100644 animation-server/src/AnimationServer.h delete mode 100644 animation-server/src/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2dbc89b75f..578c36841d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,11 +44,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed. set(CMAKE_AUTOMOC ON) -# targets not supported on windows -if (NOT WIN32) - add_subdirectory(animation-server) -endif () - # targets on all platforms add_subdirectory(assignment-client) add_subdirectory(domain-server) diff --git a/animation-server/CMakeLists.txt b/animation-server/CMakeLists.txt deleted file mode 100644 index 116ee0e942..0000000000 --- a/animation-server/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ -if (WIN32) - cmake_policy (SET CMP0020 NEW) -endif (WIN32) - -set(TARGET_NAME animation-server) - -set(ROOT_DIR ..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") - -find_package(Qt5 COMPONENTS Script) -include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}") - -# set up the external glm library -include("${MACRO_DIR}/IncludeGLM.cmake") -include_glm(${TARGET_NAME} "${ROOT_DIR}") - -include("${MACRO_DIR}/SetupHifiProject.cmake") -setup_hifi_project(${TARGET_NAME} TRUE) - -# link in the shared library -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") - -# link in the hifi octree library -link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") - -# link in the hifi voxels library -link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") - -# link the hifi networking library -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") - -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () diff --git a/animation-server/src/AnimationServer.cpp b/animation-server/src/AnimationServer.cpp deleted file mode 100644 index 32a95b48ea..0000000000 --- a/animation-server/src/AnimationServer.cpp +++ /dev/null @@ -1,852 +0,0 @@ -// -// AnimationServer.cpp -// animation-server/src -// -// Created by Stephen Birarda on 12/5/2013. -// Copyright 2013 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 -// - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AnimationServer.h" - -bool shouldShowPacketsPerSecond = false; // do we want to debug packets per second -bool includeBillboard = true; -bool includeBorderTracer = true; -bool includeMovingBug = true; -bool includeBlinkingVoxel = false; -bool includeDanceFloor = true; -bool buildStreet = false; -bool nonThreadedPacketSender = false; -int packetsPerSecond = PacketSender::DEFAULT_PACKETS_PER_SECOND; -bool waitForVoxelServer = true; - - -const int ANIMATION_LISTEN_PORT = 40107; -int ANIMATE_FPS = 60; -double ANIMATE_FPS_IN_MILLISECONDS = 1000.0/ANIMATE_FPS; // determines FPS from our desired FPS -quint64 ANIMATE_VOXELS_INTERVAL_USECS = (ANIMATE_FPS_IN_MILLISECONDS * 1000); // converts from milliseconds to usecs - - -int PROCESSING_FPS = 60; -double PROCESSING_FPS_IN_MILLISECONDS = 1000.0/PROCESSING_FPS; // determines FPS from our desired FPS -int FUDGE_USECS = 650; // a little bit of fudge to actually do some processing -quint64 PROCESSING_INTERVAL_USECS = (PROCESSING_FPS_IN_MILLISECONDS * 1000) - FUDGE_USECS; // converts from milliseconds to usecs - -bool wantLocalDomain = false; - -unsigned long packetsSent = 0; -unsigned long bytesSent = 0; - -JurisdictionListener* jurisdictionListener = NULL; -VoxelEditPacketSender* voxelEditPacketSender = NULL; -pthread_t animateVoxelThread; - -glm::vec3 rotatePoint(glm::vec3 point, float angle) { - // First, create the quaternion based on this angle of rotation - glm::quat q(glm::vec3(0, -angle, 0)); - - // Next, create a rotation matrix from that quaternion - glm::mat4 rotation = glm::mat4_cast(q); - - // Transform the original vectors by the rotation matrix to get the new vectors - glm::vec4 quatPoint(point.x, point.y, point.z, 0); - glm::vec4 newPoint = quatPoint * rotation; - - return glm::vec3(newPoint.x, newPoint.y, newPoint.z); -} - - -const float BUG_VOXEL_SIZE = 0.0625f / TREE_SCALE; -glm::vec3 bugPosition = glm::vec3(BUG_VOXEL_SIZE * 20.0, BUG_VOXEL_SIZE * 30.0, BUG_VOXEL_SIZE * 20.0); -glm::vec3 bugDirection = glm::vec3(0, 0, 1); -const int VOXELS_PER_BUG = 18; -glm::vec3 bugPathCenter = glm::vec3(0.25f,0.15f,0.25f); // glm::vec3(BUG_VOXEL_SIZE * 150.0, BUG_VOXEL_SIZE * 30.0, BUG_VOXEL_SIZE * 150.0); -float bugPathRadius = 0.2f; //BUG_VOXEL_SIZE * 140.0; -float bugPathTheta = 0.0f * RADIANS_PER_DEGREE; -float bugRotation = 0.0f * RADIANS_PER_DEGREE; -float bugAngleDelta = 0.2f * RADIANS_PER_DEGREE; -bool moveBugInLine = false; - -class BugPart { -public: - glm::vec3 partLocation; - unsigned char partColor[3]; - - BugPart(const glm::vec3& location, unsigned char red, unsigned char green, unsigned char blue ) { - partLocation = location; - partColor[0] = red; - partColor[1] = green; - partColor[2] = blue; - } -}; - -const BugPart bugParts[VOXELS_PER_BUG] = { - - // tail - BugPart(glm::vec3( 0, 0, -3), 51, 51, 153) , - BugPart(glm::vec3( 0, 0, -2), 51, 51, 153) , - BugPart(glm::vec3( 0, 0, -1), 51, 51, 153) , - - // body - BugPart(glm::vec3( 0, 0, 0), 255, 200, 0) , - BugPart(glm::vec3( 0, 0, 1), 255, 200, 0) , - - // head - BugPart(glm::vec3( 0, 0, 2), 200, 0, 0) , - - // eyes - BugPart(glm::vec3( 1, 0, 3), 64, 64, 64) , - BugPart(glm::vec3(-1, 0, 3), 64, 64, 64) , - - // wings - BugPart(glm::vec3( 3, 1, 1), 0, 153, 0) , - BugPart(glm::vec3( 2, 1, 1), 0, 153, 0) , - BugPart(glm::vec3( 1, 0, 1), 0, 153, 0) , - BugPart(glm::vec3(-1, 0, 1), 0, 153, 0) , - BugPart(glm::vec3(-2, 1, 1), 0, 153, 0) , - BugPart(glm::vec3(-3, 1, 1), 0, 153, 0) , - - - BugPart(glm::vec3( 2, -1, 0), 153, 200, 0) , - BugPart(glm::vec3( 1, -1, 0), 153, 200, 0) , - BugPart(glm::vec3(-1, -1, 0), 153, 200, 0) , - BugPart(glm::vec3(-2, -1, 0), 153, 200, 0) , -}; - -static void renderMovingBug() { - VoxelDetail details[VOXELS_PER_BUG]; - - // Generate voxels for where bug used to be - for (int i = 0; i < VOXELS_PER_BUG; i++) { - details[i].s = BUG_VOXEL_SIZE; - - glm::vec3 partAt = bugParts[i].partLocation * BUG_VOXEL_SIZE * (bugDirection.x < 0 ? -1.0f : 1.0f); - glm::vec3 rotatedPartAt = rotatePoint(partAt, bugRotation); - glm::vec3 offsetPartAt = rotatedPartAt + bugPosition; - - details[i].x = offsetPartAt.x; - details[i].y = offsetPartAt.y; - details[i].z = offsetPartAt.z; - - details[i].red = bugParts[i].partColor[0]; - details[i].green = bugParts[i].partColor[1]; - details[i].blue = bugParts[i].partColor[2]; - } - - // send the "erase message" first... - PacketType message = PacketTypeVoxelErase; - ::voxelEditPacketSender->queueVoxelEditMessages(message, VOXELS_PER_BUG, (VoxelDetail*)&details); - - // Move the bug... - if (moveBugInLine) { - bugPosition.x += (bugDirection.x * BUG_VOXEL_SIZE); - bugPosition.y += (bugDirection.y * BUG_VOXEL_SIZE); - bugPosition.z += (bugDirection.z * BUG_VOXEL_SIZE); - - // Check boundaries - if (bugPosition.z > 1.0f) { - bugDirection.z = -1.f; - } - if (bugPosition.z < BUG_VOXEL_SIZE) { - bugDirection.z = 1.f; - } - } else { - - //qDebug("bugPathCenter=(%f,%f,%f)", bugPathCenter.x, bugPathCenter.y, bugPathCenter.z); - - bugPathTheta += bugAngleDelta; // move slightly - bugRotation -= bugAngleDelta; // rotate slightly - - // If we loop past end of circle, just reset back into normal range - if (bugPathTheta > TWO_PI) { - bugPathTheta = 0.f; - bugRotation = 0.f; - } - - float x = bugPathCenter.x + bugPathRadius * cos(bugPathTheta); - float z = bugPathCenter.z + bugPathRadius * sin(bugPathTheta); - float y = bugPathCenter.y; - - bugPosition = glm::vec3(x, y, z); - //qDebug("bugPathTheta=%f", bugPathTheta); - //qDebug("bugRotation=%f", bugRotation); - } - - //qDebug("bugPosition=(%f,%f,%f)", bugPosition.x, bugPosition.y, bugPosition.z); - //qDebug("bugDirection=(%f,%f,%f)", bugDirection.x, bugDirection.y, bugDirection.z); - // would be nice to add some randomness here... - - // Generate voxels for where bug is going to - for (int i = 0; i < VOXELS_PER_BUG; i++) { - details[i].s = BUG_VOXEL_SIZE; - - glm::vec3 partAt = bugParts[i].partLocation * BUG_VOXEL_SIZE * (bugDirection.x < 0 ? -1.0f : 1.0f); - glm::vec3 rotatedPartAt = rotatePoint(partAt, bugRotation); - glm::vec3 offsetPartAt = rotatedPartAt + bugPosition; - - details[i].x = offsetPartAt.x; - details[i].y = offsetPartAt.y; - details[i].z = offsetPartAt.z; - - details[i].red = bugParts[i].partColor[0]; - details[i].green = bugParts[i].partColor[1]; - details[i].blue = bugParts[i].partColor[2]; - } - - // send the "create message" ... - message = PacketTypeVoxelSetDestructive; - ::voxelEditPacketSender->queueVoxelEditMessages(message, VOXELS_PER_BUG, (VoxelDetail*)&details); -} - - -float intensity = 0.5f; -float intensityIncrement = 0.1f; -const float MAX_INTENSITY = 1.0f; -const float MIN_INTENSITY = 0.5f; -const float BEACON_SIZE = 0.25f / TREE_SCALE; // approximately 1/4th meter - -static void sendVoxelBlinkMessage() { - VoxelDetail detail; - detail.s = BEACON_SIZE; - - glm::vec3 position = glm::vec3(0.f, 0.f, detail.s); - - detail.x = detail.s * floor(position.x / detail.s); - detail.y = detail.s * floor(position.y / detail.s); - detail.z = detail.s * floor(position.z / detail.s); - - ::intensity += ::intensityIncrement; - if (::intensity >= MAX_INTENSITY) { - ::intensity = MAX_INTENSITY; - ::intensityIncrement = -::intensityIncrement; - } - if (::intensity <= MIN_INTENSITY) { - ::intensity = MIN_INTENSITY; - ::intensityIncrement = -::intensityIncrement; - } - - detail.red = 255 * ::intensity; - detail.green = 0 * ::intensity; - detail.blue = 0 * ::intensity; - - PacketType message = PacketTypeVoxelSetDestructive; - - ::voxelEditPacketSender->sendVoxelEditMessage(message, detail); -} - -bool stringOfLightsInitialized = false; -int currentLight = 0; -int lightMovementDirection = 1; -const int SEGMENT_COUNT = 4; -const int LIGHTS_PER_SEGMENT = 80; -const int LIGHT_COUNT = LIGHTS_PER_SEGMENT * SEGMENT_COUNT; -glm::vec3 stringOfLights[LIGHT_COUNT]; -unsigned char offColor[3] = { 240, 240, 240 }; -unsigned char onColor[3] = { 0, 255, 255 }; -const float STRING_OF_LIGHTS_SIZE = 0.125f / TREE_SCALE; // approximately 1/8th meter - -static void sendBlinkingStringOfLights() { - PacketType message = PacketTypeVoxelSetDestructive; // we're a bully! - float lightScale = STRING_OF_LIGHTS_SIZE; - static VoxelDetail details[LIGHTS_PER_SEGMENT]; - - // first initialized the string of lights if needed... - if (!stringOfLightsInitialized) { - for (int segment = 0; segment < SEGMENT_COUNT; segment++) { - for (int indexInSegment = 0; indexInSegment < LIGHTS_PER_SEGMENT; indexInSegment++) { - - int i = (segment * LIGHTS_PER_SEGMENT) + indexInSegment; - - // four different segments on sides of initial platform - switch (segment) { - case 0: - // along x axis - stringOfLights[i] = glm::vec3(indexInSegment * lightScale, 0, 0); - break; - case 1: - // parallel to Z axis at outer X edge - stringOfLights[i] = glm::vec3(LIGHTS_PER_SEGMENT * lightScale, 0, indexInSegment * lightScale); - break; - case 2: - // parallel to X axis at outer Z edge - stringOfLights[i] = glm::vec3((LIGHTS_PER_SEGMENT-indexInSegment) * lightScale, 0, - LIGHTS_PER_SEGMENT * lightScale); - break; - case 3: - // on Z axis - stringOfLights[i] = glm::vec3(0, 0, (LIGHTS_PER_SEGMENT-indexInSegment) * lightScale); - break; - } - - details[indexInSegment].s = STRING_OF_LIGHTS_SIZE; - details[indexInSegment].x = stringOfLights[i].x; - details[indexInSegment].y = stringOfLights[i].y; - details[indexInSegment].z = stringOfLights[i].z; - - details[indexInSegment].red = offColor[0]; - details[indexInSegment].green = offColor[1]; - details[indexInSegment].blue = offColor[2]; - } - - ::voxelEditPacketSender->queueVoxelEditMessages(message, LIGHTS_PER_SEGMENT, (VoxelDetail*)&details); - } - stringOfLightsInitialized = true; - } else { - // turn off current light - details[0].x = stringOfLights[currentLight].x; - details[0].y = stringOfLights[currentLight].y; - details[0].z = stringOfLights[currentLight].z; - details[0].red = offColor[0]; - details[0].green = offColor[1]; - details[0].blue = offColor[2]; - - // move current light... - // if we're at the end of our string, then change direction - if (currentLight == LIGHT_COUNT-1) { - lightMovementDirection = -1; - } - if (currentLight == 0) { - lightMovementDirection = 1; - } - currentLight += lightMovementDirection; - - // turn on new current light - details[1].x = stringOfLights[currentLight].x; - details[1].y = stringOfLights[currentLight].y; - details[1].z = stringOfLights[currentLight].z; - details[1].red = onColor[0]; - details[1].green = onColor[1]; - details[1].blue = onColor[2]; - - // send both changes in same message - ::voxelEditPacketSender->queueVoxelEditMessages(message, 2, (VoxelDetail*)&details); - } -} - -bool danceFloorInitialized = false; -const float DANCE_FLOOR_LIGHT_SIZE = 1.0f / TREE_SCALE; // approximately 1 meter -const int DANCE_FLOOR_LENGTH = 10; -const int DANCE_FLOOR_WIDTH = 10; -glm::vec3 danceFloorPosition(100.0f / TREE_SCALE, 30.0f / TREE_SCALE, 10.0f / TREE_SCALE); -glm::vec3 danceFloorLights[DANCE_FLOOR_LENGTH][DANCE_FLOOR_WIDTH]; -unsigned char danceFloorOffColor[3] = { 240, 240, 240 }; -const int DANCE_FLOOR_COLORS = 6; - -unsigned char danceFloorOnColorA[DANCE_FLOOR_COLORS][3] = { - { 255, 0, 0 }, { 0, 255, 0 }, { 0, 0, 255 }, - { 0, 191, 255 }, { 0, 250, 154 }, { 255, 69, 0 }, -}; -unsigned char danceFloorOnColorB[DANCE_FLOOR_COLORS][3] = { - { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } , - { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } -}; -float danceFloorGradient = 0.5f; -const float BEATS_PER_MINUTE = 118.0f; -const float SECONDS_PER_MINUTE = 60.0f; -const float FRAMES_PER_BEAT = (SECONDS_PER_MINUTE * ANIMATE_FPS) / BEATS_PER_MINUTE; -float danceFloorGradientIncrement = 1.0f / FRAMES_PER_BEAT; -const float DANCE_FLOOR_MAX_GRADIENT = 1.0f; -const float DANCE_FLOOR_MIN_GRADIENT = 0.0f; -const int DANCE_FLOOR_VOXELS_PER_PACKET = 100; -int danceFloorColors[DANCE_FLOOR_WIDTH][DANCE_FLOOR_LENGTH]; - -void sendDanceFloor() { - PacketType message = PacketTypeVoxelSetDestructive; // we're a bully! - float lightScale = DANCE_FLOOR_LIGHT_SIZE; - static VoxelDetail details[DANCE_FLOOR_VOXELS_PER_PACKET]; - - // first initialized the billboard of lights if needed... - if (!::danceFloorInitialized) { - for (int i = 0; i < DANCE_FLOOR_WIDTH; i++) { - for (int j = 0; j < DANCE_FLOOR_LENGTH; j++) { - - int randomColorIndex = randIntInRange(-DANCE_FLOOR_COLORS, DANCE_FLOOR_COLORS); - ::danceFloorColors[i][j] = randomColorIndex; - ::danceFloorLights[i][j] = ::danceFloorPosition + - glm::vec3(i * DANCE_FLOOR_LIGHT_SIZE, 0, j * DANCE_FLOOR_LIGHT_SIZE); - } - } - ::danceFloorInitialized = true; - } - - ::danceFloorGradient += ::danceFloorGradientIncrement; - - if (::danceFloorGradient >= DANCE_FLOOR_MAX_GRADIENT) { - ::danceFloorGradient = DANCE_FLOOR_MAX_GRADIENT; - ::danceFloorGradientIncrement = -::danceFloorGradientIncrement; - } - if (::danceFloorGradient <= DANCE_FLOOR_MIN_GRADIENT) { - ::danceFloorGradient = DANCE_FLOOR_MIN_GRADIENT; - ::danceFloorGradientIncrement = -::danceFloorGradientIncrement; - } - - for (int i = 0; i < DANCE_FLOOR_LENGTH; i++) { - for (int j = 0; j < DANCE_FLOOR_WIDTH; j++) { - - int nthVoxel = ((i * DANCE_FLOOR_WIDTH) + j); - int item = nthVoxel % DANCE_FLOOR_VOXELS_PER_PACKET; - - ::danceFloorLights[i][j] = ::danceFloorPosition + - glm::vec3(i * DANCE_FLOOR_LIGHT_SIZE, 0, j * DANCE_FLOOR_LIGHT_SIZE); - - details[item].s = lightScale; - details[item].x = ::danceFloorLights[i][j].x; - details[item].y = ::danceFloorLights[i][j].y; - details[item].z = ::danceFloorLights[i][j].z; - - if (danceFloorColors[i][j] > 0) { - int color = danceFloorColors[i][j] - 1; - details[item].red = (::danceFloorOnColorA[color][0] + - ((::danceFloorOnColorB[color][0] - ::danceFloorOnColorA[color][0]) - * ::danceFloorGradient)); - details[item].green = (::danceFloorOnColorA[color][1] + - ((::danceFloorOnColorB[color][1] - ::danceFloorOnColorA[color][1]) - * ::danceFloorGradient)); - details[item].blue = (::danceFloorOnColorA[color][2] + - ((::danceFloorOnColorB[color][2] - ::danceFloorOnColorA[color][2]) - * ::danceFloorGradient)); - } else if (::danceFloorColors[i][j] < 0) { - int color = -(::danceFloorColors[i][j] + 1); - details[item].red = (::danceFloorOnColorB[color][0] + - ((::danceFloorOnColorA[color][0] - ::danceFloorOnColorB[color][0]) - * ::danceFloorGradient)); - details[item].green = (::danceFloorOnColorB[color][1] + - ((::danceFloorOnColorA[color][1] - ::danceFloorOnColorB[color][1]) - * ::danceFloorGradient)); - details[item].blue = (::danceFloorOnColorB[color][2] + - ((::danceFloorOnColorA[color][2] - ::danceFloorOnColorB[color][2]) - * ::danceFloorGradient)); - } else { - int color = 0; - details[item].red = (::danceFloorOnColorB[color][0] + - ((::danceFloorOnColorA[color][0] - ::danceFloorOnColorB[color][0]) - * ::danceFloorGradient)); - details[item].green = (::danceFloorOnColorB[color][1] + - ((::danceFloorOnColorA[color][1] - ::danceFloorOnColorB[color][1]) - * ::danceFloorGradient)); - details[item].blue = (::danceFloorOnColorB[color][2] + - ((::danceFloorOnColorA[color][2] - ::danceFloorOnColorB[color][2]) - * ::danceFloorGradient)); - } - - if (item == DANCE_FLOOR_VOXELS_PER_PACKET - 1) { - ::voxelEditPacketSender->queueVoxelEditMessages(message, DANCE_FLOOR_VOXELS_PER_PACKET, (VoxelDetail*)&details); - } - } - } -} - -bool billboardInitialized = false; -const int BILLBOARD_HEIGHT = 9; -const int BILLBOARD_WIDTH = 45; -glm::vec3 billboardPosition((0.125f / TREE_SCALE),(0.125f / TREE_SCALE),0); -glm::vec3 billboardLights[BILLBOARD_HEIGHT][BILLBOARD_WIDTH]; -unsigned char billboardOffColor[3] = { 240, 240, 240 }; -unsigned char billboardOnColorA[3] = { 0, 0, 255 }; -unsigned char billboardOnColorB[3] = { 0, 255, 0 }; -float billboardGradient = 0.5f; -float billboardGradientIncrement = 0.01f; -const float BILLBOARD_MAX_GRADIENT = 1.0f; -const float BILLBOARD_MIN_GRADIENT = 0.0f; -const float BILLBOARD_LIGHT_SIZE = 0.125f / TREE_SCALE; // approximately 1/8 meter per light -const int VOXELS_PER_PACKET = 81; - -// top to bottom... -bool billboardMessage[BILLBOARD_HEIGHT][BILLBOARD_WIDTH] = { - { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, - { 0,0,1,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,1,1,1,1,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0,0,0,0 }, - { 0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,1,1,0,0,0,0,0 }, - { 0,0,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,0,1,1,1,0,0,0,0,1,1,1,0,1,1,1,0,1,0,1,0,0,1,0,0,1,0,1,0 }, - { 0,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,1,0 }, - { 0,0,1,0,0,1,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,0,1,0,0,1,1,1,0 }, - { 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0 }, - { 0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0 }, - { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } -}; - -static void sendBillboard() { - PacketType message = PacketTypeVoxelSetDestructive; // we're a bully! - float lightScale = BILLBOARD_LIGHT_SIZE; - static VoxelDetail details[VOXELS_PER_PACKET]; - - // first initialized the billboard of lights if needed... - if (!billboardInitialized) { - for (int i = 0; i < BILLBOARD_HEIGHT; i++) { - for (int j = 0; j < BILLBOARD_WIDTH; j++) { - - billboardLights[i][j] = billboardPosition + glm::vec3(j * lightScale, (float)((BILLBOARD_HEIGHT - i) * lightScale), 0); - } - } - billboardInitialized = true; - } - - ::billboardGradient += ::billboardGradientIncrement; - - if (::billboardGradient >= BILLBOARD_MAX_GRADIENT) { - ::billboardGradient = BILLBOARD_MAX_GRADIENT; - ::billboardGradientIncrement = -::billboardGradientIncrement; - } - if (::billboardGradient <= BILLBOARD_MIN_GRADIENT) { - ::billboardGradient = BILLBOARD_MIN_GRADIENT; - ::billboardGradientIncrement = -::billboardGradientIncrement; - } - - for (int i = 0; i < BILLBOARD_HEIGHT; i++) { - for (int j = 0; j < BILLBOARD_WIDTH; j++) { - - int nthVoxel = ((i * BILLBOARD_WIDTH) + j); - int item = nthVoxel % VOXELS_PER_PACKET; - - billboardLights[i][j] = billboardPosition + glm::vec3(j * lightScale, (float)((BILLBOARD_HEIGHT - i) * lightScale), 0); - - details[item].s = lightScale; - details[item].x = billboardLights[i][j].x; - details[item].y = billboardLights[i][j].y; - details[item].z = billboardLights[i][j].z; - - if (billboardMessage[i][j]) { - details[item].red = (billboardOnColorA[0] + ((billboardOnColorB[0] - billboardOnColorA[0]) * ::billboardGradient)); - details[item].green = (billboardOnColorA[1] + ((billboardOnColorB[1] - billboardOnColorA[1]) * ::billboardGradient)); - details[item].blue = (billboardOnColorA[2] + ((billboardOnColorB[2] - billboardOnColorA[2]) * ::billboardGradient)); - } else { - details[item].red = billboardOffColor[0]; - details[item].green = billboardOffColor[1]; - details[item].blue = billboardOffColor[2]; - } - - if (item == VOXELS_PER_PACKET - 1) { - ::voxelEditPacketSender->queueVoxelEditMessages(message, VOXELS_PER_PACKET, (VoxelDetail*)&details); - } - } - } -} - -bool roadInitialized = false; -const int BRICKS_ACROSS_ROAD = 32; -const float ROAD_BRICK_SIZE = 0.125f/TREE_SCALE; //(ROAD_WIDTH_METERS / TREE_SCALE) / BRICKS_ACROSS_ROAD; // in voxel units -const int ROAD_LENGTH = 1.0f / ROAD_BRICK_SIZE; // in bricks -const int ROAD_WIDTH = BRICKS_ACROSS_ROAD; // in bricks -glm::vec3 roadPosition(0.5f - (ROAD_BRICK_SIZE * BRICKS_ACROSS_ROAD), 0.0f, 0.0f); -const int BRICKS_PER_PACKET = 32; // guessing - -void doBuildStreet() { - if (roadInitialized) { - return; - } - - PacketType message = PacketTypeVoxelSetDestructive; // we're a bully! - static VoxelDetail details[BRICKS_PER_PACKET]; - - for (int z = 0; z < ROAD_LENGTH; z++) { - for (int x = 0; x < ROAD_WIDTH; x++) { - - int nthVoxel = ((z * ROAD_WIDTH) + x); - int item = nthVoxel % BRICKS_PER_PACKET; - - glm::vec3 brick = roadPosition + glm::vec3(x * ROAD_BRICK_SIZE, 0, z * ROAD_BRICK_SIZE); - - details[item].s = ROAD_BRICK_SIZE; - details[item].x = brick.x; - details[item].y = brick.y; - details[item].z = brick.z; - - unsigned char randomTone = randIntInRange(118,138); - details[item].red = randomTone; - details[item].green = randomTone; - details[item].blue = randomTone; - - if (item == BRICKS_PER_PACKET - 1) { - ::voxelEditPacketSender->queueVoxelEditMessages(message, BRICKS_PER_PACKET, (VoxelDetail*)&details); - } - } - } - roadInitialized = true; -} - - -double start = 0; - - -void* animateVoxels(void* args) { - - quint64 lastAnimateTime = 0; - quint64 lastProcessTime = 0; - int processesPerAnimate = 0; - - bool firstTime = true; - - qDebug() << "Setting PPS to " << ::packetsPerSecond; - ::voxelEditPacketSender->setPacketsPerSecond(::packetsPerSecond); - - qDebug() << "PPS set to " << ::voxelEditPacketSender->getPacketsPerSecond(); - - while (true) { - - // If we're asked to wait for voxel servers, and there isn't one available yet, then - // let the voxelEditPacketSender process and move on. - if (::waitForVoxelServer && !::voxelEditPacketSender->voxelServersExist()) { - if (::nonThreadedPacketSender) { - ::voxelEditPacketSender->process(); - } - } else { - if (firstTime) { - lastAnimateTime = usecTimestampNow(); - firstTime = false; - } - lastProcessTime = usecTimestampNow(); - - // The while loop will be running at PROCESSING_FPS, but we only want to call these animation functions at - // ANIMATE_FPS. So we check out last animate time and only call these if we've elapsed that time. - quint64 now = usecTimestampNow(); - quint64 animationElapsed = now - lastAnimateTime; - int withinAnimationTarget = ANIMATE_VOXELS_INTERVAL_USECS - animationElapsed; - const int CLOSE_ENOUGH_TO_ANIMATE = 2000; // approximately 2 ms - - int animateLoopsPerAnimate = 0; - while (withinAnimationTarget < CLOSE_ENOUGH_TO_ANIMATE) { - processesPerAnimate = 0; - animateLoopsPerAnimate++; - - lastAnimateTime = now; - // some animations - //sendVoxelBlinkMessage(); - - if (::includeBillboard) { - sendBillboard(); - } - if (::includeBorderTracer) { - sendBlinkingStringOfLights(); - } - if (::includeMovingBug) { - renderMovingBug(); - } - if (::includeBlinkingVoxel) { - sendVoxelBlinkMessage(); - } - if (::includeDanceFloor) { - sendDanceFloor(); - } - - if (::buildStreet) { - doBuildStreet(); - } - - if (animationElapsed > ANIMATE_VOXELS_INTERVAL_USECS) { - animationElapsed -= ANIMATE_VOXELS_INTERVAL_USECS; // credit ourselves one animation frame - } else { - animationElapsed = 0; - } - withinAnimationTarget = ANIMATE_VOXELS_INTERVAL_USECS - animationElapsed; - - ::voxelEditPacketSender->releaseQueuedMessages(); - } - - if (::nonThreadedPacketSender) { - ::voxelEditPacketSender->process(); - } - processesPerAnimate++; - } - // dynamically sleep until we need to fire off the next set of voxels - quint64 usecToSleep = ::PROCESSING_INTERVAL_USECS - (usecTimestampNow() - lastProcessTime); - if (usecToSleep > ::PROCESSING_INTERVAL_USECS) { - usecToSleep = ::PROCESSING_INTERVAL_USECS; - } - - if (usecToSleep > 0) { - usleep(usecToSleep); - } - } - - pthread_exit(0); -} - -AnimationServer::AnimationServer(int &argc, char **argv) : - QCoreApplication(argc, argv) -{ - ::start = usecTimestampNow(); - - NodeList* nodeList = NodeList::createInstance(NodeType::AnimationServer, ANIMATION_LISTEN_PORT); - setvbuf(stdout, NULL, _IOLBF, 0); - - // Handle Local Domain testing with the --local command line - const char* NON_THREADED_PACKETSENDER = "--NonThreadedPacketSender"; - ::nonThreadedPacketSender = cmdOptionExists(argc, (const char**) argv, NON_THREADED_PACKETSENDER); - qDebug("nonThreadedPacketSender=%s", debug::valueOf(::nonThreadedPacketSender)); - - // Handle Local Domain testing with the --local command line - const char* NO_BILLBOARD = "--NoBillboard"; - ::includeBillboard = !cmdOptionExists(argc, (const char**) argv, NO_BILLBOARD); - qDebug("includeBillboard=%s", debug::valueOf(::includeBillboard)); - - const char* NO_BORDER_TRACER = "--NoBorderTracer"; - ::includeBorderTracer = !cmdOptionExists(argc, (const char**) argv, NO_BORDER_TRACER); - qDebug("includeBorderTracer=%s", debug::valueOf(::includeBorderTracer)); - - const char* NO_MOVING_BUG = "--NoMovingBug"; - ::includeMovingBug = !cmdOptionExists(argc, (const char**) argv, NO_MOVING_BUG); - qDebug("includeMovingBug=%s", debug::valueOf(::includeMovingBug)); - - const char* INCLUDE_BLINKING_VOXEL = "--includeBlinkingVoxel"; - ::includeBlinkingVoxel = cmdOptionExists(argc, (const char**) argv, INCLUDE_BLINKING_VOXEL); - qDebug("includeBlinkingVoxel=%s", debug::valueOf(::includeBlinkingVoxel)); - - const char* NO_DANCE_FLOOR = "--NoDanceFloor"; - ::includeDanceFloor = !cmdOptionExists(argc, (const char**) argv, NO_DANCE_FLOOR); - qDebug("includeDanceFloor=%s", debug::valueOf(::includeDanceFloor)); - - const char* BUILD_STREET = "--BuildStreet"; - ::buildStreet = cmdOptionExists(argc, (const char**) argv, BUILD_STREET); - qDebug("buildStreet=%s", debug::valueOf(::buildStreet)); - - // Handle Local Domain testing with the --local command line - const char* showPPS = "--showPPS"; - ::shouldShowPacketsPerSecond = cmdOptionExists(argc, (const char**) argv, showPPS); - - // Handle Local Domain testing with the --local command line - const char* local = "--local"; - ::wantLocalDomain = cmdOptionExists(argc, (const char**) argv,local); - if (::wantLocalDomain) { - qDebug("Local Domain MODE!"); - nodeList->getDomainHandler().setIPToLocalhost(); - } - - const char* domainHostname = getCmdOption(argc, (const char**) argv, "--domain"); - if (domainHostname) { - NodeList::getInstance()->getDomainHandler().setHostname(domainHostname); - } - - const char* packetsPerSecondCommand = getCmdOption(argc, (const char**) argv, "--pps"); - if (packetsPerSecondCommand) { - ::packetsPerSecond = atoi(packetsPerSecondCommand); - } - qDebug("packetsPerSecond=%d",packetsPerSecond); - - const char* animateFPSCommand = getCmdOption(argc, (const char**) argv, "--AnimateFPS"); - const char* animateIntervalCommand = getCmdOption(argc, (const char**) argv, "--AnimateInterval"); - if (animateFPSCommand || animateIntervalCommand) { - if (animateIntervalCommand) { - ::ANIMATE_FPS_IN_MILLISECONDS = atoi(animateIntervalCommand); - ::ANIMATE_VOXELS_INTERVAL_USECS = (ANIMATE_FPS_IN_MILLISECONDS * 1000.0); // converts from milliseconds to usecs - ::ANIMATE_FPS = PacketSender::USECS_PER_SECOND / ::ANIMATE_VOXELS_INTERVAL_USECS; - } else { - ::ANIMATE_FPS = atoi(animateFPSCommand); - ::ANIMATE_FPS_IN_MILLISECONDS = 1000.0/ANIMATE_FPS; // determines FPS from our desired FPS - ::ANIMATE_VOXELS_INTERVAL_USECS = (ANIMATE_FPS_IN_MILLISECONDS * 1000.0); // converts from milliseconds to usecs - } - } - qDebug("ANIMATE_FPS=%d",ANIMATE_FPS); - qDebug("ANIMATE_VOXELS_INTERVAL_USECS=%llu",ANIMATE_VOXELS_INTERVAL_USECS); - - const char* processingFPSCommand = getCmdOption(argc, (const char**) argv, "--ProcessingFPS"); - const char* processingIntervalCommand = getCmdOption(argc, (const char**) argv, "--ProcessingInterval"); - if (processingFPSCommand || processingIntervalCommand) { - if (processingIntervalCommand) { - ::PROCESSING_FPS_IN_MILLISECONDS = atoi(processingIntervalCommand); - ::PROCESSING_INTERVAL_USECS = ::PROCESSING_FPS_IN_MILLISECONDS * 1000.0; - ::PROCESSING_FPS = PacketSender::USECS_PER_SECOND / ::PROCESSING_INTERVAL_USECS; - } else { - ::PROCESSING_FPS = atoi(processingFPSCommand); - ::PROCESSING_FPS_IN_MILLISECONDS = 1000.0/PROCESSING_FPS; // determines FPS from our desired FPS - ::PROCESSING_INTERVAL_USECS = (PROCESSING_FPS_IN_MILLISECONDS * 1000.0) - FUDGE_USECS; // converts from milliseconds to usecs - } - } - qDebug("PROCESSING_FPS=%d",PROCESSING_FPS); - qDebug("PROCESSING_INTERVAL_USECS=%llu",PROCESSING_INTERVAL_USECS); - - nodeList->linkedDataCreateCallback = NULL; // do we need a callback? - - // Create our JurisdictionListener so we'll know where to send edit packets - ::jurisdictionListener = new JurisdictionListener(); - if (::jurisdictionListener) { - ::jurisdictionListener->initialize(true); - } - - // Create out VoxelEditPacketSender - ::voxelEditPacketSender = new VoxelEditPacketSender; - ::voxelEditPacketSender->initialize(!::nonThreadedPacketSender); - - if (::jurisdictionListener) { - ::voxelEditPacketSender->setVoxelServerJurisdictions(::jurisdictionListener->getJurisdictions()); - } - if (::nonThreadedPacketSender) { - ::voxelEditPacketSender->setProcessCallIntervalHint(PROCESSING_INTERVAL_USECS); - } - - srand((unsigned)time(0)); - - - pthread_create(&::animateVoxelThread, NULL, animateVoxels, NULL); - - NodeList::getInstance()->addNodeTypeToInterestSet(NodeType::VoxelServer); - - QTimer* domainServerTimer = new QTimer(this); - connect(domainServerTimer, SIGNAL(timeout()), nodeList, SLOT(sendDomainServerCheckIn())); - domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); - - QTimer* silentNodeTimer = new QTimer(this); - connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); - silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS); - - connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), SLOT(readPendingDatagrams())); -} - -void AnimationServer::readPendingDatagrams() { - NodeList* nodeList = NodeList::getInstance(); - - static QByteArray receivedPacket; - static HifiSockAddr nodeSockAddr; - - // Nodes sending messages to us... - while (nodeList->getNodeSocket().hasPendingDatagrams()) { - receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize()); - nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(), - nodeSockAddr.getAddressPointer(), nodeSockAddr.getPortPointer()); - if (nodeList->packetVersionAndHashMatch(receivedPacket)) { - if (packetTypeForPacket(receivedPacket) == PacketTypeJurisdiction) { - int headerBytes = numBytesForPacketHeader(receivedPacket); - // PacketType_JURISDICTION, first byte is the node type... - if (receivedPacket.data()[headerBytes] == NodeType::VoxelServer && ::jurisdictionListener) { - - SharedNodePointer matchedNode = NodeList::getInstance()->sendingNodeForPacket(receivedPacket); - if (matchedNode) { - ::jurisdictionListener->queueReceivedPacket(matchedNode, receivedPacket); - } - } - } - NodeList::getInstance()->processNodeData(nodeSockAddr, receivedPacket); - } - } -} - -AnimationServer::~AnimationServer() { - pthread_join(animateVoxelThread, NULL); - - if (::jurisdictionListener) { - ::jurisdictionListener->terminate(); - delete ::jurisdictionListener; - } - - if (::voxelEditPacketSender) { - ::voxelEditPacketSender->terminate(); - delete ::voxelEditPacketSender; - } -} diff --git a/animation-server/src/AnimationServer.h b/animation-server/src/AnimationServer.h deleted file mode 100644 index 58f05c32c5..0000000000 --- a/animation-server/src/AnimationServer.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// AnimationServer.h -// animation-server/src -// -// Created by Stephen Birarda on 12/5/2013. -// Copyright 2013 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 -// - -#ifndef hifi_AnimationServer_h -#define hifi_AnimationServer_h - -#include - -class AnimationServer : public QCoreApplication { - Q_OBJECT -public: - AnimationServer(int &argc, char **argv); - ~AnimationServer(); -private slots: - void readPendingDatagrams(); -}; - - -#endif // hifi_AnimationServer_h diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp deleted file mode 100644 index 8acf3b8db2..0000000000 --- a/animation-server/src/main.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// -// main.cpp -// animation-server/src -// -// Created by Brad Hefta-Gaub on 05/16/2013. -// Copyright 2012 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 -// - -#include "AnimationServer.h" - -int main(int argc, char * argv[]) { - AnimationServer animationServer(argc, argv); - return animationServer.exec(); -} diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 5ca021b175..fec0aedfdd 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -6,8 +6,6 @@ set(MACRO_DIR "${ROOT_DIR}/cmake/macros") # setup for find modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") -find_package(Qt5 COMPONENTS Network Script Widgets) - include("${MACRO_DIR}/SetupHifiProject.cmake") setup_hifi_project(${TARGET_NAME} TRUE) @@ -39,8 +37,6 @@ IF (WIN32) target_link_libraries(${TARGET_NAME} Winmm Ws2_32) ENDIF(WIN32) -target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script) - # add a definition for ssize_t so that windows doesn't bail if (WIN32) add_definitions(-Dssize_t=long) diff --git a/cmake/macros/LinkHifiLibrary.cmake b/cmake/macros/LinkHifiLibrary.cmake index 577f0c9f37..0728abf8c9 100644 --- a/cmake/macros/LinkHifiLibrary.cmake +++ b/cmake/macros/LinkHifiLibrary.cmake @@ -16,12 +16,10 @@ macro(LINK_HIFI_LIBRARY LIBRARY TARGET ROOT_DIR) include_directories("${ROOT_DIR}/libraries/${LIBRARY}/src") add_dependencies(${TARGET} ${LIBRARY}) + target_link_libraries(${TARGET} ${LIBRARY} ${REQUIRED_DEPENDENCY_LIBRARIES}) - if (APPLE) - # currently the "shared" library requires CoreServices - # link in required OS X framework - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework CoreServices") + if (REQUIRED_DEPENDENCY_QT_MODULES) + qt5_use_modules(${TARGET_NAME} ${REQUIRED_DEPENDENCY_QT_MODULES}) endif () - endmacro(LINK_HIFI_LIBRARY _library _target _root_dir) \ No newline at end of file diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index 9a13374a4f..8f8366d4d3 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -4,8 +4,6 @@ set(MACRO_DIR "${ROOT_DIR}/cmake/macros") set(TARGET_NAME networking) project(${TARGET_NAME}) -find_package(Qt5 COMPONENTS Network) - include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) @@ -13,7 +11,10 @@ setup_hifi_library(${TARGET_NAME}) include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} "${ROOT_DIR}") -target_link_libraries(${TARGET_NAME} Qt5::Network) +find_package(Qt5Network REQUIRED) +set(DEPENDENCY_QT_MODULES Network) +set(REQUIRED_DEPENDENCY_QT_MODULES ${DEPENDENCY_QT_MODULES} PARENT_SCOPE) +qt5_use_modules(${TARGET_NAME} ${DEPENDENCY_QT_MODULES}) # add a definition for ssize_t so that windows doesn't bail if (WIN32) diff --git a/libraries/octree/CMakeLists.txt b/libraries/octree/CMakeLists.txt index 398bf80157..99da8d1bf2 100644 --- a/libraries/octree/CMakeLists.txt +++ b/libraries/octree/CMakeLists.txt @@ -6,8 +6,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cm set(TARGET_NAME octree) -find_package(Qt5Widgets REQUIRED) - include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) @@ -26,7 +24,7 @@ include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}" "${OPENSSL_INCLUDE_DIR}") # bubble up the libraries we are dependent on set(REQUIRED_DEPENDENCY_LIBRARIES ${REQUIRED_DEPENDENCY_LIBRARIES} - "${ZLIB_LIBRARIES}" "${OPENSSL_LIBRARIES}" Qt5::Widgets PARENT_SCOPE) + "${ZLIB_LIBRARIES}" "${OPENSSL_LIBRARIES}" PARENT_SCOPE) target_link_libraries(${TARGET_NAME} ${REQUIRED_DEPENDENCY_LIBRARIES}) diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index c0d59c8b75..f7f05c88a7 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -4,7 +4,8 @@ set(MACRO_DIR "${ROOT_DIR}/cmake/macros") set(TARGET_NAME shared) project(${TARGET_NAME}) -find_package(Qt5 COMPONENTS Network Widgets Xml Script) +find_package(Qt5 COMPONENTS Network) +find_package(Qt5Widgets REQUIRED) include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) @@ -21,16 +22,15 @@ if (WIN32) endif (WIN32) # link required libraries on UNIX -if (UNIX AND NOT APPLE) - find_package(Threads REQUIRED) - target_link_libraries(${TARGET_NAME} "${CMAKE_THREAD_LIBS_INIT}") -endif (UNIX AND NOT APPLE) - -# There is something special (bug) about Qt5Scripts, that we have to explicitly add its include -# directory when Qt5 (5.2.1) is compiled from source and is not in a standard place. -include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}") +if (APPLE) + find_library(CoreServices CoreServices) + list(APPEND REQUIRED_DEPENDENCY_LIBRARIES ${CoreServices}) +elseif (UNIX) + find_package(Threads REQUIRED) + LIST(APPEND REQUIRED_DEPENDENCY_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}") +endif () # bubble up the libraries we are dependent on and link them to ourselves -set(REQUIRED_DEPENDENCY_LIBRARIES Qt5::Network Qt5::Widgets) +list(APPEND REQUIRED_DEPENDENCY_LIBRARIES Qt5::Network Qt5::Widgets) set(SUB_DEPENDENCY_LIBRARIES ${REQUIRED_DEPENDENCY_LIBRARIES} PARENT_SCOPE) target_link_libraries(${TARGET_NAME} ${REQUIRED_DEPENDENCY_LIBRARIES}) \ No newline at end of file From fa26957b230051b8af7c447d861f7c0900191ea2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Aug 2014 15:20:26 -0700 Subject: [PATCH 266/407] more CMakeLists cleanup for sub-dependencies --- assignment-client/CMakeLists.txt | 4 - cmake/macros/LinkHifiLibrary.cmake | 6 +- domain-server/CMakeLists.txt | 13 - libraries/animation/CMakeLists.txt | 10 +- libraries/avatars/CMakeLists.txt | 5 - libraries/embedded-webserver/CMakeLists.txt | 9 +- libraries/networking/CMakeLists.txt | 10 +- libraries/particles/CMakeLists.txt | 8 - libraries/shared/CMakeLists.txt | 13 +- libraries/shared/external/pthread.h | 1403 ------------------- libraries/shared/external/sched.h | 189 --- 11 files changed, 18 insertions(+), 1652 deletions(-) delete mode 100644 libraries/shared/external/pthread.h delete mode 100644 libraries/shared/external/sched.h diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index fec0aedfdd..a4e26899fb 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -9,10 +9,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake include("${MACRO_DIR}/SetupHifiProject.cmake") setup_hifi_project(${TARGET_NAME} TRUE) -# include glm -include("${MACRO_DIR}/IncludeGLM.cmake") -include_glm(${TARGET_NAME} "${ROOT_DIR}") - # link in the shared libraries include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") diff --git a/cmake/macros/LinkHifiLibrary.cmake b/cmake/macros/LinkHifiLibrary.cmake index 0728abf8c9..afb1f1febd 100644 --- a/cmake/macros/LinkHifiLibrary.cmake +++ b/cmake/macros/LinkHifiLibrary.cmake @@ -17,9 +17,5 @@ macro(LINK_HIFI_LIBRARY LIBRARY TARGET ROOT_DIR) add_dependencies(${TARGET} ${LIBRARY}) - target_link_libraries(${TARGET} ${LIBRARY} ${REQUIRED_DEPENDENCY_LIBRARIES}) - - if (REQUIRED_DEPENDENCY_QT_MODULES) - qt5_use_modules(${TARGET_NAME} ${REQUIRED_DEPENDENCY_QT_MODULES}) - endif () + target_link_libraries(${TARGET} ${LIBRARY} ${SUB_DEPENDENCY_LIBRARIES}) endmacro(LINK_HIFI_LIBRARY _library _target _root_dir) \ No newline at end of file diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index 6ee794f7c6..26f07cf776 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -1,7 +1,3 @@ -if (WIN32) - cmake_policy (SET CMP0020 NEW) -endif (WIN32) - set(TARGET_NAME domain-server) set(ROOT_DIR ..) @@ -10,12 +6,6 @@ set(MACRO_DIR "${ROOT_DIR}/cmake/macros") # setup for find modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") -# set up the external glm library -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} "${ROOT_DIR}") - -find_package(Qt5Network REQUIRED) - include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME} TRUE) @@ -39,9 +29,6 @@ IF (WIN32) target_link_libraries(${TARGET_NAME} Winmm Ws2_32) ENDIF(WIN32) -# link QtNetwork -target_link_libraries(${TARGET_NAME} Qt5::Network) - # add a definition for ssize_t so that windows doesn't bail if (WIN32) add_definitions(-Dssize_t=long) diff --git a/libraries/animation/CMakeLists.txt b/libraries/animation/CMakeLists.txt index b1dc59fff8..be6ed47898 100644 --- a/libraries/animation/CMakeLists.txt +++ b/libraries/animation/CMakeLists.txt @@ -6,22 +6,16 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cm set(TARGET_NAME animation) -find_package(Qt5Widgets REQUIRED) +find_package(Qt5 COMPONENTS Script) include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} "${ROOT_DIR}") - include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") -# link ZLIB -find_package(ZLIB) - -target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets) +target_link_libraries(${TARGET_NAME} Qt5::Script) # add a definition for ssize_t so that windows doesn't bail if (WIN32) diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index ca4a2630b4..feb1e68557 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -6,8 +6,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cm set(TARGET_NAME avatars) -find_package(Qt5Script REQUIRED) - include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) @@ -17,13 +15,10 @@ include_glm(${TARGET_NAME} "${ROOT_DIR}") include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") -# link in the hifi voxels library link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") -target_link_libraries(${TARGET_NAME} Qt5::Script) - # add a definition for ssize_t so that windows doesn't bail if (WIN32) add_definitions(-Dssize_t=long) diff --git a/libraries/embedded-webserver/CMakeLists.txt b/libraries/embedded-webserver/CMakeLists.txt index 1386bcc392..f1681cdd12 100644 --- a/libraries/embedded-webserver/CMakeLists.txt +++ b/libraries/embedded-webserver/CMakeLists.txt @@ -6,9 +6,12 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cm set(TARGET_NAME embedded-webserver) -find_package(Qt5Network REQUIRED) - include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -target_link_libraries(${TARGET_NAME} Qt5::Network) \ No newline at end of file +find_package(Qt5Network REQUIRED) + +# bubble up the libraries we are dependent on and link them to ourselves +set(REQUIRED_DEPENDENCY_LIBRARIES Qt5::Network) +set(SUB_DEPENDENCY_LIBRARIES ${REQUIRED_DEPENDENCY_LIBRARIES} PARENT_SCOPE) +target_link_libraries(${TARGET_NAME} ${REQUIRED_DEPENDENCY_LIBRARIES}) \ No newline at end of file diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index 8f8366d4d3..215d406133 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -11,10 +11,12 @@ setup_hifi_library(${TARGET_NAME}) include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} "${ROOT_DIR}") -find_package(Qt5Network REQUIRED) -set(DEPENDENCY_QT_MODULES Network) -set(REQUIRED_DEPENDENCY_QT_MODULES ${DEPENDENCY_QT_MODULES} PARENT_SCOPE) -qt5_use_modules(${TARGET_NAME} ${DEPENDENCY_QT_MODULES}) +find_package(Qt5Network) + +# bubble up the libraries we are dependent on and link them to ourselves +set(REQUIRED_DEPENDENCY_LIBRARIES Qt5::Network) +set(SUB_DEPENDENCY_LIBRARIES ${REQUIRED_DEPENDENCY_LIBRARIES} PARENT_SCOPE) +target_link_libraries(${TARGET_NAME} ${REQUIRED_DEPENDENCY_LIBRARIES}) # add a definition for ssize_t so that windows doesn't bail if (WIN32) diff --git a/libraries/particles/CMakeLists.txt b/libraries/particles/CMakeLists.txt index 76b3373466..cecbdaaa21 100644 --- a/libraries/particles/CMakeLists.txt +++ b/libraries/particles/CMakeLists.txt @@ -6,8 +6,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cm set(TARGET_NAME particles) -find_package(Qt5Widgets REQUIRED) - include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) @@ -21,12 +19,6 @@ link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") -# link ZLIB -find_package(ZLIB) - -include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") -target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets) - # add a definition for ssize_t so that windows doesn't bail if (WIN32) add_definitions(-Dssize_t=long) diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index f7f05c88a7..067551ba31 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -4,9 +4,6 @@ set(MACRO_DIR "${ROOT_DIR}/cmake/macros") set(TARGET_NAME shared) project(${TARGET_NAME}) -find_package(Qt5 COMPONENTS Network) -find_package(Qt5Widgets REQUIRED) - include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) @@ -14,13 +11,6 @@ setup_hifi_library(${TARGET_NAME}) include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} "${ROOT_DIR}") -set(EXTERNAL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external") - -if (WIN32) - # include headers for external libraries and InterfaceConfig. - include_directories("${EXTERNAL_ROOT_DIR}") -endif (WIN32) - # link required libraries on UNIX if (APPLE) find_library(CoreServices CoreServices) @@ -30,6 +20,9 @@ elseif (UNIX) LIST(APPEND REQUIRED_DEPENDENCY_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}") endif () +find_package(Qt5Network) +find_package(Qt5Widgets) + # bubble up the libraries we are dependent on and link them to ourselves list(APPEND REQUIRED_DEPENDENCY_LIBRARIES Qt5::Network Qt5::Widgets) set(SUB_DEPENDENCY_LIBRARIES ${REQUIRED_DEPENDENCY_LIBRARIES} PARENT_SCOPE) diff --git a/libraries/shared/external/pthread.h b/libraries/shared/external/pthread.h deleted file mode 100644 index f910eb4b0e..0000000000 --- a/libraries/shared/external/pthread.h +++ /dev/null @@ -1,1403 +0,0 @@ -/* This is an implementation of the threads API of POSIX 1003.1-2001. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#if !defined( PTHREAD_H ) -#define PTHREAD_H - -#define PTW32_STATIC_LIB - -/* - * See the README file for an explanation of the pthreads-win32 version - * numbering scheme and how the DLL is named etc. - */ -#define PTW32_VERSION 2,10,0,0 -#define PTW32_VERSION_STRING "2, 10, 0, 0\0" - -/* There are three implementations of cancel cleanup. - * Note that pthread.h is included in both application - * compilation units and also internally for the library. - * The code here and within the library aims to work - * for all reasonable combinations of environments. - * - * The three implementations are: - * - * WIN32 SEH - * C - * C++ - * - * Please note that exiting a push/pop block via - * "return", "exit", "break", or "continue" will - * lead to different behaviour amongst applications - * depending upon whether the library was built - * using SEH, C++, or C. For example, a library built - * with SEH will call the cleanup routine, while both - * C++ and C built versions will not. - */ - -/* - * Define defaults for cleanup code. - * Note: Unless the build explicitly defines one of the following, then - * we default to standard C style cleanup. This style uses setjmp/longjmp - * in the cancellation and thread exit implementations and therefore won't - * do stack unwinding if linked to applications that have it (e.g. - * C++ apps). This is currently consistent with most/all commercial Unix - * POSIX threads implementations. - */ -#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C ) -/* - [i_a] fix for apps using pthreads-Win32: when they do not define __CLEANUP_SEH themselves, - they're screwed as they'll receive the '__CLEANUP_C' macros which do NOT work when - the pthreads library code itself has actually been build with __CLEANUP_SEH, - which is the case when building this stuff in MSVC. - - Hence this section is made to 'sensibly autodetect' the cleanup mode, when it hasn't - been hardwired in the makefiles / project files. - - After all, who expects he MUST define one of these __CLEANUP_XXX defines in his own - code when using pthreads-Win32, for whatever reason. - */ -#if (defined(_MSC_VER) || defined(PTW32_RC_MSC)) -#define __CLEANUP_SEH -#elif defined(__cplusplus) -#define __CLEANUP_CXX -#else -#define __CLEANUP_C -#endif -#endif - -#if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC)) -#error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler. -#endif - -/* - * Stop here if we are being included by the resource compiler. - */ -#if !defined(RC_INVOKED) - -#undef PTW32_LEVEL - -#if defined(_POSIX_SOURCE) -#define PTW32_LEVEL 0 -/* Early POSIX */ -#endif - -#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 -#undef PTW32_LEVEL -#define PTW32_LEVEL 1 -/* Include 1b, 1c and 1d */ -#endif - -#if defined(INCLUDE_NP) -#undef PTW32_LEVEL -#define PTW32_LEVEL 2 -/* Include Non-Portable extensions */ -#endif - -#define PTW32_LEVEL_MAX 3 - -#if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_LEVEL) -#define PTW32_LEVEL PTW32_LEVEL_MAX -/* Include everything */ -#endif - -#if defined(_UWIN) -# define HAVE_STRUCT_TIMESPEC 1 -# define HAVE_SIGNAL_H 1 -# undef HAVE_PTW32_CONFIG_H -# pragma comment(lib, "pthread") -#endif - -#if defined(__MINGW32__) || defined(__MINGW64__) -# define PTW32_CONFIG_MINGW -#endif -#if defined(_MSC_VER) -# if _MSC_VER < 1300 -# define PTW32_CONFIG_MSVC6 -# endif -# if _MSC_VER < 1400 -# define PTW32_CONFIG_MSVC7 -# endif -#endif - -/* - * ------------------------------------------------------------- - * - * - * Module: pthread.h - * - * Purpose: - * Provides an implementation of PThreads based upon the - * standard: - * - * POSIX 1003.1-2001 - * and - * The Single Unix Specification version 3 - * - * (these two are equivalent) - * - * in order to enhance code portability between Windows, - * various commercial Unix implementations, and Linux. - * - * See the ANNOUNCE file for a full list of conforming - * routines and defined constants, and a list of missing - * routines and constants not defined in this implementation. - * - * Authors: - * There have been many contributors to this library. - * The initial implementation was contributed by - * John Bossom, and several others have provided major - * sections or revisions of parts of the implementation. - * Often significant effort has been contributed to - * find and fix important bugs and other problems to - * improve the reliability of the library, which sometimes - * is not reflected in the amount of code which changed as - * result. - * As much as possible, the contributors are acknowledged - * in the ChangeLog file in the source code distribution - * where their changes are noted in detail. - * - * Contributors are listed in the CONTRIBUTORS file. - * - * As usual, all bouquets go to the contributors, and all - * brickbats go to the project maintainer. - * - * Maintainer: - * The code base for this project is coordinated and - * eventually pre-tested, packaged, and made available by - * - * Ross Johnson - * - * QA Testers: - * Ultimately, the library is tested in the real world by - * a host of competent and demanding scientists and - * engineers who report bugs and/or provide solutions - * which are then fixed or incorporated into subsequent - * versions of the library. Each time a bug is fixed, a - * test case is written to prove the fix and ensure - * that later changes to the code don't reintroduce the - * same error. The number of test cases is slowly growing - * and therefore so is the code reliability. - * - * Compliance: - * See the file ANNOUNCE for the list of implemented - * and not-implemented routines and defined options. - * Of course, these are all defined is this file as well. - * - * Web site: - * The source code and other information about this library - * are available from - * - * http://sources.redhat.com/pthreads-win32/ - * - * ------------------------------------------------------------- - */ - -/* Try to avoid including windows.h */ -#if defined(PTW32_CONFIG_MINGW) && defined(__cplusplus) -#define PTW32_INCLUDE_WINDOWS_H -#endif - -#if defined(PTW32_INCLUDE_WINDOWS_H) -#include -#endif - -#if defined(PTW32_CONFIG_MSVC6) || defined(__DMC__) -/* - * VC++6.0 or early compiler's header has no DWORD_PTR type. - */ -typedef unsigned long DWORD_PTR; -typedef unsigned long ULONG_PTR; -#endif -/* - * ----------------- - * autoconf switches - * ----------------- - */ - -#if defined(HAVE_PTW32_CONFIG_H) -#include "config.h" -#endif /* HAVE_PTW32_CONFIG_H */ - -#if !defined(NEED_FTIME) -#include -#else /* NEED_FTIME */ -/* use native WIN32 time API */ -#endif /* NEED_FTIME */ - -#if defined(HAVE_SIGNAL_H) -#include -#endif /* HAVE_SIGNAL_H */ - -#include - -/* - * Boolean values to make us independent of system includes. - */ -enum { - PTW32_FALSE = 0, - PTW32_TRUE = (! PTW32_FALSE) -}; - -/* - * This is a duplicate of what is in the autoconf config.h, - * which is only used when building the pthread-win32 libraries. - */ - -#if !defined(PTW32_CONFIG_H) -# if defined(WINCE) -# define NEED_ERRNO -# define NEED_SEM -# endif -# if defined(__MINGW64__) -# define HAVE_STRUCT_TIMESPEC -# define HAVE_MODE_T -# elif defined(_UWIN) || defined(__MINGW32__) -# define HAVE_MODE_T -# endif -#endif - -/* - * - */ - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX -#if defined(NEED_ERRNO) -#include "need_errno.h" -#else -#include -#endif -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -/* - * Several systems don't define some error numbers. - */ -#if !defined(ENOTSUP) -# define ENOTSUP 48 /* This is the value in Solaris. */ -#endif - -#if !defined(ETIMEDOUT) -# define ETIMEDOUT 10060 /* Same as WSAETIMEDOUT */ -#endif - -#if !defined(ENOSYS) -# define ENOSYS 140 /* Semi-arbitrary value */ -#endif - -#if !defined(EDEADLK) -# if defined(EDEADLOCK) -# define EDEADLK EDEADLOCK -# else -# define EDEADLK 36 /* This is the value in MSVC. */ -# endif -#endif - -/* POSIX 2008 - related to robust mutexes */ -#if !defined(EOWNERDEAD) -# define EOWNERDEAD 43 -#endif -#if !defined(ENOTRECOVERABLE) -# define ENOTRECOVERABLE 44 -#endif - -#include - -/* - * To avoid including windows.h we define only those things that we - * actually need from it. - */ -#if !defined(PTW32_INCLUDE_WINDOWS_H) -#if !defined(HANDLE) -# define PTW32__HANDLE_DEF -# define HANDLE void * -#endif -#if !defined(DWORD) -# define PTW32__DWORD_DEF -# define DWORD unsigned long -#endif -#endif - -#if !defined(HAVE_STRUCT_TIMESPEC) -#define HAVE_STRUCT_TIMESPEC -#if !defined(_TIMESPEC_DEFINED) -#define _TIMESPEC_DEFINED -struct timespec { - time_t tv_sec; - long tv_nsec; -}; -#endif /* _TIMESPEC_DEFINED */ -#endif /* HAVE_STRUCT_TIMESPEC */ - -#if !defined(SIG_BLOCK) -#define SIG_BLOCK 0 -#endif /* SIG_BLOCK */ - -#if !defined(SIG_UNBLOCK) -#define SIG_UNBLOCK 1 -#endif /* SIG_UNBLOCK */ - -#if !defined(SIG_SETMASK) -#define SIG_SETMASK 2 -#endif /* SIG_SETMASK */ - -#if defined(__cplusplus) -extern "C" -{ -#endif /* __cplusplus */ - -/* - * ------------------------------------------------------------- - * - * POSIX 1003.1-2001 Options - * ========================= - * - * Options are normally set in , which is not provided - * with pthreads-win32. - * - * For conformance with the Single Unix Specification (version 3), all of the - * options below are defined, and have a value of either -1 (not supported) - * or 200112L (supported). - * - * These options can neither be left undefined nor have a value of 0, because - * either indicates that sysconf(), which is not implemented, may be used at - * runtime to check the status of the option. - * - * _POSIX_THREADS (== 200112L) - * If == 200112L, you can use threads - * - * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L) - * If == 200112L, you can control the size of a thread's - * stack - * pthread_attr_getstacksize - * pthread_attr_setstacksize - * - * _POSIX_THREAD_ATTR_STACKADDR (== -1) - * If == 200112L, you can allocate and control a thread's - * stack. If not supported, the following functions - * will return ENOSYS, indicating they are not - * supported: - * pthread_attr_getstackaddr - * pthread_attr_setstackaddr - * - * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1) - * If == 200112L, you can use realtime scheduling. - * This option indicates that the behaviour of some - * implemented functions conforms to the additional TPS - * requirements in the standard. E.g. rwlocks favour - * writers over readers when threads have equal priority. - * - * _POSIX_THREAD_PRIO_INHERIT (== -1) - * If == 200112L, you can create priority inheritance - * mutexes. - * pthread_mutexattr_getprotocol + - * pthread_mutexattr_setprotocol + - * - * _POSIX_THREAD_PRIO_PROTECT (== -1) - * If == 200112L, you can create priority ceiling mutexes - * Indicates the availability of: - * pthread_mutex_getprioceiling - * pthread_mutex_setprioceiling - * pthread_mutexattr_getprioceiling - * pthread_mutexattr_getprotocol + - * pthread_mutexattr_setprioceiling - * pthread_mutexattr_setprotocol + - * - * _POSIX_THREAD_PROCESS_SHARED (== -1) - * If set, you can create mutexes and condition - * variables that can be shared with another - * process.If set, indicates the availability - * of: - * pthread_mutexattr_getpshared - * pthread_mutexattr_setpshared - * pthread_condattr_getpshared - * pthread_condattr_setpshared - * - * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L) - * If == 200112L you can use the special *_r library - * functions that provide thread-safe behaviour - * - * _POSIX_READER_WRITER_LOCKS (== 200112L) - * If == 200112L, you can use read/write locks - * - * _POSIX_SPIN_LOCKS (== 200112L) - * If == 200112L, you can use spin locks - * - * _POSIX_BARRIERS (== 200112L) - * If == 200112L, you can use barriers - * - * + These functions provide both 'inherit' and/or - * 'protect' protocol, based upon these macro - * settings. - * - * ------------------------------------------------------------- - */ - -/* - * POSIX Options - */ -#undef _POSIX_THREADS -#define _POSIX_THREADS 200809L - -#undef _POSIX_READER_WRITER_LOCKS -#define _POSIX_READER_WRITER_LOCKS 200809L - -#undef _POSIX_SPIN_LOCKS -#define _POSIX_SPIN_LOCKS 200809L - -#undef _POSIX_BARRIERS -#define _POSIX_BARRIERS 200809L - -#undef _POSIX_THREAD_SAFE_FUNCTIONS -#define _POSIX_THREAD_SAFE_FUNCTIONS 200809L - -#undef _POSIX_THREAD_ATTR_STACKSIZE -#define _POSIX_THREAD_ATTR_STACKSIZE 200809L - -/* - * The following options are not supported - */ -#undef _POSIX_THREAD_ATTR_STACKADDR -#define _POSIX_THREAD_ATTR_STACKADDR -1 - -#undef _POSIX_THREAD_PRIO_INHERIT -#define _POSIX_THREAD_PRIO_INHERIT -1 - -#undef _POSIX_THREAD_PRIO_PROTECT -#define _POSIX_THREAD_PRIO_PROTECT -1 - -/* TPS is not fully supported. */ -#undef _POSIX_THREAD_PRIORITY_SCHEDULING -#define _POSIX_THREAD_PRIORITY_SCHEDULING -1 - -#undef _POSIX_THREAD_PROCESS_SHARED -#define _POSIX_THREAD_PROCESS_SHARED -1 - - -/* - * POSIX 1003.1-2001 Limits - * =========================== - * - * These limits are normally set in , which is not provided with - * pthreads-win32. - * - * PTHREAD_DESTRUCTOR_ITERATIONS - * Maximum number of attempts to destroy - * a thread's thread-specific data on - * termination (must be at least 4) - * - * PTHREAD_KEYS_MAX - * Maximum number of thread-specific data keys - * available per process (must be at least 128) - * - * PTHREAD_STACK_MIN - * Minimum supported stack size for a thread - * - * PTHREAD_THREADS_MAX - * Maximum number of threads supported per - * process (must be at least 64). - * - * SEM_NSEMS_MAX - * The maximum number of semaphores a process can have. - * (must be at least 256) - * - * SEM_VALUE_MAX - * The maximum value a semaphore can have. - * (must be at least 32767) - * - */ -#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS -#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 - -#undef PTHREAD_DESTRUCTOR_ITERATIONS -#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS - -#undef _POSIX_THREAD_KEYS_MAX -#define _POSIX_THREAD_KEYS_MAX 128 - -#undef PTHREAD_KEYS_MAX -#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX - -#undef PTHREAD_STACK_MIN -#define PTHREAD_STACK_MIN 0 - -#undef _POSIX_THREAD_THREADS_MAX -#define _POSIX_THREAD_THREADS_MAX 64 - - /* Arbitrary value */ -#undef PTHREAD_THREADS_MAX -#define PTHREAD_THREADS_MAX 2019 - -#undef _POSIX_SEM_NSEMS_MAX -#define _POSIX_SEM_NSEMS_MAX 256 - - /* Arbitrary value */ -#undef SEM_NSEMS_MAX -#define SEM_NSEMS_MAX 1024 - -#undef _POSIX_SEM_VALUE_MAX -#define _POSIX_SEM_VALUE_MAX 32767 - -#undef SEM_VALUE_MAX -#define SEM_VALUE_MAX INT_MAX - - -#if defined(__GNUC__) && !defined(__declspec) -# error Please upgrade your GNU compiler to one that supports __declspec. -#endif - -/* - * When building the library, you should define PTW32_BUILD so that - * the variables/functions are exported correctly. When using the library, - * do NOT define PTW32_BUILD, and then the variables/functions will - * be imported correctly. - */ -#if !defined(PTW32_STATIC_LIB) -# if defined(PTW32_BUILD) -# define PTW32_DLLPORT __declspec (dllexport) -# else -# define PTW32_DLLPORT __declspec (dllimport) -# endif -#else -# define PTW32_DLLPORT -#endif - -/* - * The Open Watcom C/C++ compiler uses a non-standard calling convention - * that passes function args in registers unless __cdecl is explicitly specified - * in exposed function prototypes. - * - * We force all calls to cdecl even though this could slow Watcom code down - * slightly. If you know that the Watcom compiler will be used to build both - * the DLL and application, then you can probably define this as a null string. - * Remember that pthread.h (this file) is used for both the DLL and application builds. - */ -#define PTW32_CDECL __cdecl - -#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX -# include -#else -/* - * Generic handle type - intended to extend uniqueness beyond - * that available with a simple pointer. It should scale for either - * IA-32 or IA-64. - */ -typedef struct { - void * p; /* Pointer to actual object */ - unsigned int x; /* Extra information - reuse count etc */ -} ptw32_handle_t; - -typedef ptw32_handle_t pthread_t; -typedef struct pthread_attr_t_ * pthread_attr_t; -typedef struct pthread_once_t_ pthread_once_t; -typedef struct pthread_key_t_ * pthread_key_t; -typedef struct pthread_mutex_t_ * pthread_mutex_t; -typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t; -typedef struct pthread_cond_t_ * pthread_cond_t; -typedef struct pthread_condattr_t_ * pthread_condattr_t; -#endif -typedef struct pthread_rwlock_t_ * pthread_rwlock_t; -typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t; -typedef struct pthread_spinlock_t_ * pthread_spinlock_t; -typedef struct pthread_barrier_t_ * pthread_barrier_t; -typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t; - -/* - * ==================== - * ==================== - * POSIX Threads - * ==================== - * ==================== - */ - -enum { -/* - * pthread_attr_{get,set}detachstate - */ - PTHREAD_CREATE_JOINABLE = 0, /* Default */ - PTHREAD_CREATE_DETACHED = 1, - -/* - * pthread_attr_{get,set}inheritsched - */ - PTHREAD_INHERIT_SCHED = 0, - PTHREAD_EXPLICIT_SCHED = 1, /* Default */ - -/* - * pthread_{get,set}scope - */ - PTHREAD_SCOPE_PROCESS = 0, - PTHREAD_SCOPE_SYSTEM = 1, /* Default */ - -/* - * pthread_setcancelstate paramters - */ - PTHREAD_CANCEL_ENABLE = 0, /* Default */ - PTHREAD_CANCEL_DISABLE = 1, - -/* - * pthread_setcanceltype parameters - */ - PTHREAD_CANCEL_ASYNCHRONOUS = 0, - PTHREAD_CANCEL_DEFERRED = 1, /* Default */ - -/* - * pthread_mutexattr_{get,set}pshared - * pthread_condattr_{get,set}pshared - */ - PTHREAD_PROCESS_PRIVATE = 0, - PTHREAD_PROCESS_SHARED = 1, - -/* - * pthread_mutexattr_{get,set}robust - */ - PTHREAD_MUTEX_STALLED = 0, /* Default */ - PTHREAD_MUTEX_ROBUST = 1, - -/* - * pthread_barrier_wait - */ - PTHREAD_BARRIER_SERIAL_THREAD = -1 -}; - -/* - * ==================== - * ==================== - * cancellation - * ==================== - * ==================== - */ -#define PTHREAD_CANCELED ((void *)(size_t) -1) - - -/* - * ==================== - * ==================== - * Once Key - * ==================== - * ==================== - */ -#define PTHREAD_ONCE_INIT { PTW32_FALSE, 0, 0, 0} - -struct pthread_once_t_ -{ - int done; /* indicates if user function has been executed */ - void * lock; - int reserved1; - int reserved2; -}; - - -/* - * ==================== - * ==================== - * Object initialisers - * ==================== - * ==================== - */ -#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -1) -#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -2) -#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -3) - -/* - * Compatibility with LinuxThreads - */ -#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER -#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER - -#define PTHREAD_COND_INITIALIZER ((pthread_cond_t)(size_t) -1) - -#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t)(size_t) -1) - -#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t)(size_t) -1) - - -/* - * Mutex types. - */ -enum -{ - /* Compatibility with LinuxThreads */ - PTHREAD_MUTEX_FAST_NP, - PTHREAD_MUTEX_RECURSIVE_NP, - PTHREAD_MUTEX_ERRORCHECK_NP, - PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP, - PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP, - /* For compatibility with POSIX */ - PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP, - PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, - PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, - PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL -}; - - -typedef struct ptw32_cleanup_t ptw32_cleanup_t; - -#if defined(_MSC_VER) -/* Disable MSVC 'anachronism used' warning */ -#pragma warning( disable : 4229 ) -#endif - -typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); - -#if defined(_MSC_VER) -#pragma warning( default : 4229 ) -#endif - -struct ptw32_cleanup_t -{ - ptw32_cleanup_callback_t routine; - void *arg; - struct ptw32_cleanup_t *prev; -}; - -#if defined(__CLEANUP_SEH) - /* - * WIN32 SEH version of cancel cleanup. - */ - -#define pthread_cleanup_push( _rout, _arg ) \ - { \ - ptw32_cleanup_t _cleanup; \ - \ - _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \ - _cleanup.arg = (_arg); \ - __try \ - { \ - -#define pthread_cleanup_pop( _execute ) \ - } \ - __finally \ - { \ - if( _execute || AbnormalTermination()) \ - { \ - (*(_cleanup.routine))( _cleanup.arg ); \ - } \ - } \ - } - -#else /* __CLEANUP_SEH */ - -#if defined(__CLEANUP_C) - - /* - * C implementation of PThreads cancel cleanup - */ - -#define pthread_cleanup_push( _rout, _arg ) \ - { \ - ptw32_cleanup_t _cleanup; \ - \ - ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \ - -#define pthread_cleanup_pop( _execute ) \ - (void) ptw32_pop_cleanup( _execute ); \ - } - -#else /* __CLEANUP_C */ - -#if defined(__CLEANUP_CXX) - - /* - * C++ version of cancel cleanup. - * - John E. Bossom. - */ - - class PThreadCleanup { - /* - * PThreadCleanup - * - * Purpose - * This class is a C++ helper class that is - * used to implement pthread_cleanup_push/ - * pthread_cleanup_pop. - * The destructor of this class automatically - * pops the pushed cleanup routine regardless - * of how the code exits the scope - * (i.e. such as by an exception) - */ - ptw32_cleanup_callback_t cleanUpRout; - void * obj; - int executeIt; - - public: - PThreadCleanup() : - cleanUpRout( 0 ), - obj( 0 ), - executeIt( 0 ) - /* - * No cleanup performed - */ - { - } - - PThreadCleanup( - ptw32_cleanup_callback_t routine, - void * arg ) : - cleanUpRout( routine ), - obj( arg ), - executeIt( 1 ) - /* - * Registers a cleanup routine for 'arg' - */ - { - } - - ~PThreadCleanup() - { - if ( executeIt && ((void *) cleanUpRout != (void *) 0) ) - { - (void) (*cleanUpRout)( obj ); - } - } - - void execute( int exec ) - { - executeIt = exec; - } - }; - - /* - * C++ implementation of PThreads cancel cleanup; - * This implementation takes advantage of a helper - * class who's destructor automatically calls the - * cleanup routine if we exit our scope weirdly - */ -#define pthread_cleanup_push( _rout, _arg ) \ - { \ - PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \ - (void *) (_arg) ); - -#define pthread_cleanup_pop( _execute ) \ - cleanup.execute( _execute ); \ - } - -#else - -#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. - -#endif /* __CLEANUP_CXX */ - -#endif /* __CLEANUP_C */ - -#endif /* __CLEANUP_SEH */ - -/* - * =============== - * =============== - * Methods - * =============== - * =============== - */ - -/* - * PThread Attribute Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr, - int *detachstate); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr, - void **stackaddr); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr, - size_t * stacksize); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr, - int detachstate); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr, - void *stackaddr); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr, - size_t stacksize); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr, - struct sched_param *param); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr, - const struct sched_param *param); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *, - int); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (const pthread_attr_t *, - int *); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr, - int inheritsched); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(const pthread_attr_t * attr, - int * inheritsched); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *, - int); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *, - int *); - -/* - * PThread Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, - const pthread_attr_t * attr, - void *(PTW32_CDECL *start) (void *), - void *arg); - -PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid); - -PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1, - pthread_t t2); - -PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr); - -PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread, - void **value_ptr); - -PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void); - -PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread); - -PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state, - int *oldstate); - -PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type, - int *oldtype); - -PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void); - -PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control, - void (PTW32_CDECL *init_routine) (void)); - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX -PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute); - -PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup, - ptw32_cleanup_callback_t routine, - void *arg); -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -/* - * Thread Specific Data Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key, - void (PTW32_CDECL *destructor) (void *)); - -PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key); - -PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key, - const void *value); - -PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key); - - -/* - * Mutex Attribute Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t - * attr, - int *pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, - int pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind); -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (const pthread_mutexattr_t * attr, int *kind); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setrobust( - pthread_mutexattr_t *attr, - int robust); -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getrobust( - const pthread_mutexattr_t * attr, - int * robust); - -/* - * Barrier Attribute Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t - * attr, - int *pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, - int pshared); - -/* - * Mutex Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex, - const pthread_mutexattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t * mutex, - const struct timespec *abstime); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_consistent (pthread_mutex_t * mutex); - -/* - * Spinlock Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock); - -/* - * Barrier Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier, - const pthread_barrierattr_t * attr, - unsigned int count); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier); - -/* - * Condition Variable Attribute Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr, - int *pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr, - int pshared); - -/* - * Condition Variable Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond, - const pthread_condattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond, - pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond, - pthread_mutex_t * mutex, - const struct timespec *abstime); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond); - -/* - * Scheduling - */ -PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread, - int policy, - const struct sched_param *param); - -PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread, - int *policy, - struct sched_param *param); - -PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int); - -PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void); - -/* - * Read-Write Lock Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock, - const pthread_rwlockattr_t *attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock, - const struct timespec *abstime); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock, - const struct timespec *abstime); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, - int *pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, - int pshared); - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 - -/* - * Signal Functions. Should be defined in but MSVC and MinGW32 - * already have signal.h that don't define these. - */ -PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig); - -/* - * Non-portable functions - */ - -/* - * Compatibility with Linux. - */ -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, - int kind); -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, - int *kind); -PTW32_DLLPORT int PTW32_CDECL pthread_timedjoin_np(pthread_t thread, - void **value_ptr, - const struct timespec *abstime); - -/* - * Possibly supported by other POSIX threads implementations - */ -PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval); -PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void); -PTW32_DLLPORT unsigned __int64 PTW32_CDECL pthread_getunique_np(pthread_t thread); - -/* - * Useful if an application wants to statically link - * the lib rather than load the DLL at run-time. - */ -PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void); -PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void); -PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void); -PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void); - -/* - * Features that are auto-detected at load/run time. - */ -PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int); -enum ptw32_features { - PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */ - PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */ -}; - -/* - * Register a system time change with the library. - * Causes the library to perform various functions - * in response to the change. Should be called whenever - * the application's top level window receives a - * WM_TIMECHANGE message. It can be passed directly to - * pthread_create() as a new thread if desired. - */ -PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *); - -#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */ - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX - -/* - * Returns the Win32 HANDLE for the POSIX thread. - */ -PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread); -/* - * Returns the win32 thread ID for POSIX thread. - */ -PTW32_DLLPORT DWORD PTW32_CDECL pthread_getw32threadid_np (pthread_t thread); - - -/* - * Protected Methods - * - * This function blocks until the given WIN32 handle - * is signaled or pthread_cancel had been called. - * This function allows the caller to hook into the - * PThreads cancel mechanism. It is implemented using - * - * WaitForMultipleObjects - * - * on 'waitHandle' and a manually reset WIN32 Event - * used to implement pthread_cancel. The 'timeout' - * argument to TimedWait is simply passed to - * WaitForMultipleObjects. - */ -PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle); -PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle, - DWORD timeout); - -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -/* - * Thread-Safe C Runtime Library Mappings. - */ -#if !defined(_UWIN) -# if defined(NEED_ERRNO) - PTW32_DLLPORT int * PTW32_CDECL _errno( void ); -# else -# if !defined(errno) -# if (defined(_MT) || defined(_DLL)) - __declspec(dllimport) extern int * __cdecl _errno(void); -# define errno (*_errno()) -# endif -# endif -# endif -#endif - -/* - * Some compiler environments don't define some things. - */ -#if defined(__BORLANDC__) -# define _ftime ftime -# define _timeb timeb -#endif - -#if defined(__cplusplus) - -/* - * Internal exceptions - */ -class ptw32_exception {}; -class ptw32_exception_cancel : public ptw32_exception {}; -class ptw32_exception_exit : public ptw32_exception {}; - -#endif - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX - -/* FIXME: This is only required if the library was built using SEH */ -/* - * Get internal SEH tag - */ -PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void); - -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -#if !defined(PTW32_BUILD) - -#if defined(__CLEANUP_SEH) - -/* - * Redefine the SEH __except keyword to ensure that applications - * propagate our internal exceptions up to the library's internal handlers. - */ -#define __except( E ) \ - __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \ - ? EXCEPTION_CONTINUE_SEARCH : ( E ) ) - -#endif /* __CLEANUP_SEH */ - -#if defined(__CLEANUP_CXX) - -/* - * Redefine the C++ catch keyword to ensure that applications - * propagate our internal exceptions up to the library's internal handlers. - */ -#if defined(_MSC_VER) - /* - * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll' - * if you want Pthread-Win32 cancellation and pthread_exit to work. - */ - -#if !defined(PtW32NoCatchWarn) - -#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.") -#pragma message("------------------------------------------------------------------") -#pragma message("When compiling applications with MSVC++ and C++ exception handling:") -#pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads") -#pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread") -#pragma message(" cancellation and pthread_exit to work. For example:") -#pragma message("") -#pragma message(" #if defined(PtW32CatchAll)") -#pragma message(" PtW32CatchAll") -#pragma message(" #else") -#pragma message(" catch(...)") -#pragma message(" #endif") -#pragma message(" {") -#pragma message(" /* Catchall block processing */") -#pragma message(" }") -#pragma message("------------------------------------------------------------------") - -#endif - -#define PtW32CatchAll \ - catch( ptw32_exception & ) { throw; } \ - catch( ... ) - -#else /* _MSC_VER */ - -#define catch( E ) \ - catch( ptw32_exception & ) { throw; } \ - catch( E ) - -#endif /* _MSC_VER */ - -#endif /* __CLEANUP_CXX */ - -#endif /* ! PTW32_BUILD */ - -#if defined(__cplusplus) -} /* End of extern "C" */ -#endif /* __cplusplus */ - -#if defined(PTW32__HANDLE_DEF) -# undef HANDLE -#endif -#if defined(PTW32__DWORD_DEF) -# undef DWORD -#endif - -#undef PTW32_LEVEL -#undef PTW32_LEVEL_MAX - -#endif /* ! RC_INVOKED */ - -#endif /* PTHREAD_H */ diff --git a/libraries/shared/external/sched.h b/libraries/shared/external/sched.h deleted file mode 100644 index d43ff8dcb2..0000000000 --- a/libraries/shared/external/sched.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Module: sched.h - * - * Purpose: - * Provides an implementation of POSIX realtime extensions - * as defined in - * - * POSIX 1003.1b-1993 (POSIX.1b) - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ -#if !defined(_SCHED_H) -#define _SCHED_H - -#undef PTW32_SCHED_LEVEL - -#if defined(_POSIX_SOURCE) -#define PTW32_SCHED_LEVEL 0 -/* Early POSIX */ -#endif - -#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 -#undef PTW32_SCHED_LEVEL -#define PTW32_SCHED_LEVEL 1 -/* Include 1b, 1c and 1d */ -#endif - -#if defined(INCLUDE_NP) -#undef PTW32_SCHED_LEVEL -#define PTW32_SCHED_LEVEL 2 -/* Include Non-Portable extensions */ -#endif - -#define PTW32_SCHED_LEVEL_MAX 3 - -#if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_SCHED_LEVEL) -#define PTW32_SCHED_LEVEL PTW32_SCHED_LEVEL_MAX -/* Include everything */ -#endif - - -#if defined(__GNUC__) && !defined(__declspec) -# error Please upgrade your GNU compiler to one that supports __declspec. -#endif - -/* - * When building the library, you should define PTW32_BUILD so that - * the variables/functions are exported correctly. When using the library, - * do NOT define PTW32_BUILD, and then the variables/functions will - * be imported correctly. - */ -#if !defined(PTW32_STATIC_LIB) -# if defined(PTW32_BUILD) -# define PTW32_DLLPORT __declspec (dllexport) -# else -# define PTW32_DLLPORT __declspec (dllimport) -# endif -#else -# define PTW32_DLLPORT -#endif - -/* - * This is a duplicate of what is in the autoconf config.h, - * which is only used when building the pthread-win32 libraries. - */ - -#if !defined(PTW32_CONFIG_H) -# if defined(WINCE) -# define NEED_ERRNO -# define NEED_SEM -# endif -# if defined(__MINGW64__) -# define HAVE_STRUCT_TIMESPEC -# define HAVE_MODE_T -# elif defined(_UWIN) || defined(__MINGW32__) -# define HAVE_MODE_T -# endif -#endif - -/* - * - */ - -#if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX -#if defined(NEED_ERRNO) -#include "need_errno.h" -#else -#include -#endif -#endif /* PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX */ - -#if (defined(__MINGW64__) || defined(__MINGW32__)) || defined(_UWIN) -# if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX -/* For pid_t */ -# include -/* Required by Unix 98 */ -# include -# else - typedef int pid_t; -# endif -#else - /* [i_a] fix for using pthread_win32 with mongoose code, which #define's its own pid_t akin to typedef HANDLE pid_t; */ - #undef pid_t -# if defined(_MSC_VER) - typedef void *pid_t; -# else - typedef int pid_t; -# endif -#endif - -/* Thread scheduling policies */ - -enum { - SCHED_OTHER = 0, - SCHED_FIFO, - SCHED_RR, - SCHED_MIN = SCHED_OTHER, - SCHED_MAX = SCHED_RR -}; - -struct sched_param { - int sched_priority; -}; - -#if defined(__cplusplus) -extern "C" -{ -#endif /* __cplusplus */ - -PTW32_DLLPORT int __cdecl sched_yield (void); - -PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy); - -PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy); - -PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy); - -PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid); - -/* - * Note that this macro returns ENOTSUP rather than - * ENOSYS as might be expected. However, returning ENOSYS - * should mean that sched_get_priority_{min,max} are - * not implemented as well as sched_rr_get_interval. - * This is not the case, since we just don't support - * round-robin scheduling. Therefore I have chosen to - * return the same value as sched_setscheduler when - * SCHED_RR is passed to it. - */ -#define sched_rr_get_interval(_pid, _interval) \ - ( errno = ENOTSUP, (int) -1 ) - - -#if defined(__cplusplus) -} /* End of extern "C" */ -#endif /* __cplusplus */ - -#undef PTW32_SCHED_LEVEL -#undef PTW32_SCHED_LEVEL_MAX - -#endif /* !_SCHED_H */ - From b5c8a4d2c635d4788b7c7fc6597293861fe66849 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Aug 2014 15:47:57 -0700 Subject: [PATCH 267/407] fix requirement of networking in audio library --- cmake/macros/LinkHifiLibrary.cmake | 9 ++++++++- libraries/animation/CMakeLists.txt | 9 ++++++--- libraries/audio/CMakeLists.txt | 7 +++++++ libraries/embedded-webserver/CMakeLists.txt | 8 ++++---- libraries/fbx/CMakeLists.txt | 6 +++++- libraries/metavoxels/CMakeLists.txt | 10 +++++++--- libraries/models/CMakeLists.txt | 11 +---------- libraries/networking/CMakeLists.txt | 13 ++++--------- libraries/shared/CMakeLists.txt | 10 +++++----- 9 files changed, 47 insertions(+), 36 deletions(-) diff --git a/cmake/macros/LinkHifiLibrary.cmake b/cmake/macros/LinkHifiLibrary.cmake index afb1f1febd..227ddf066a 100644 --- a/cmake/macros/LinkHifiLibrary.cmake +++ b/cmake/macros/LinkHifiLibrary.cmake @@ -17,5 +17,12 @@ macro(LINK_HIFI_LIBRARY LIBRARY TARGET ROOT_DIR) add_dependencies(${TARGET} ${LIBRARY}) - target_link_libraries(${TARGET} ${LIBRARY} ${SUB_DEPENDENCY_LIBRARIES}) + get_target_property(LINKED_TARGET_DEPENDENCY_LIBRARIES ${LIBRARY} DEPENDENCY_LIBRARIES) + + if (LINKED_TARGET_DEPENDENCY_LIBRARIES) + target_link_libraries(${TARGET} ${LIBRARY} ${LINKED_TARGET_DEPENDENCY_LIBRARIES}) + else () + target_link_libraries(${TARGET} ${LIBRARY}) + endif () + endmacro(LINK_HIFI_LIBRARY _library _target _root_dir) \ No newline at end of file diff --git a/libraries/animation/CMakeLists.txt b/libraries/animation/CMakeLists.txt index be6ed47898..20f4a59181 100644 --- a/libraries/animation/CMakeLists.txt +++ b/libraries/animation/CMakeLists.txt @@ -6,8 +6,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cm set(TARGET_NAME animation) -find_package(Qt5 COMPONENTS Script) - include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) @@ -15,7 +13,12 @@ include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") -target_link_libraries(${TARGET_NAME} Qt5::Script) +find_package(Qt5Script) + +# set a property indicating the libraries we are dependent on and link them to ourselves +set(DEPENDENCY_LIBRARIES Qt5::Script) +set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) # add a definition for ssize_t so that windows doesn't bail if (WIN32) diff --git a/libraries/audio/CMakeLists.txt b/libraries/audio/CMakeLists.txt index 2ad8a4b0bc..69cc61ca6d 100644 --- a/libraries/audio/CMakeLists.txt +++ b/libraries/audio/CMakeLists.txt @@ -20,6 +20,13 @@ include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") +find_package(Qt5Network) + +# set a property indicating the libraries we are dependent on and link them to ourselves +set(DEPENDENCY_LIBRARIES Qt5::Network) +set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES ${DEPENDENCY_LIBRARIES}) +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) + # add a definition for ssize_t so that windows doesn't bail if (WIN32) add_definitions(-Dssize_t=long) diff --git a/libraries/embedded-webserver/CMakeLists.txt b/libraries/embedded-webserver/CMakeLists.txt index f1681cdd12..eb28cae1b3 100644 --- a/libraries/embedded-webserver/CMakeLists.txt +++ b/libraries/embedded-webserver/CMakeLists.txt @@ -11,7 +11,7 @@ setup_hifi_library(${TARGET_NAME}) find_package(Qt5Network REQUIRED) -# bubble up the libraries we are dependent on and link them to ourselves -set(REQUIRED_DEPENDENCY_LIBRARIES Qt5::Network) -set(SUB_DEPENDENCY_LIBRARIES ${REQUIRED_DEPENDENCY_LIBRARIES} PARENT_SCOPE) -target_link_libraries(${TARGET_NAME} ${REQUIRED_DEPENDENCY_LIBRARIES}) \ No newline at end of file +# set a property indicating the libraries we are dependent on and link them to ourselves +set(DEPENDENCY_LIBRARIES Qt5::Network) +set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES ${DEPENDENCY_LIBRARIES}) +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) \ No newline at end of file diff --git a/libraries/fbx/CMakeLists.txt b/libraries/fbx/CMakeLists.txt index 45d1051dc6..a125de1320 100644 --- a/libraries/fbx/CMakeLists.txt +++ b/libraries/fbx/CMakeLists.txt @@ -22,7 +22,11 @@ link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") find_package(ZLIB) include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") -target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets) + +# bubble up the libraries we are dependent on and link them to ourselves +set(REQUIRED_DEPENDENCY_LIBRARIES "${ZLIB_LIBRARIES}") +set(SUB_DEPENDENCY_LIBRARIES ${REQUIRED_DEPENDENCY_LIBRARIES} PARENT_SCOPE) +target_link_libraries(${TARGET_NAME} ${REQUIRED_DEPENDENCY_LIBRARIES}) # add a definition for ssize_t so that windows doesn't bail if (WIN32) diff --git a/libraries/metavoxels/CMakeLists.txt b/libraries/metavoxels/CMakeLists.txt index c79631ce06..c419f664a0 100644 --- a/libraries/metavoxels/CMakeLists.txt +++ b/libraries/metavoxels/CMakeLists.txt @@ -6,8 +6,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cm set(TARGET_NAME metavoxels) -find_package(Qt5 COMPONENTS Network Script Widgets) - include(${MACRO_DIR}/AutoMTC.cmake) auto_mtc(${TARGET_NAME} "${ROOT_DIR}") @@ -21,7 +19,13 @@ link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} "${ROOT_DIR}") -target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script) +find_package(Qt5Script) +find_package(Qt5Widgets) + +# set a property indicating the libraries we are dependent on and link them to ourselves +set(DEPENDENCY_LIBRARIES Qt5::Script Qt5::Widgets) +set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) # add a definition for ssize_t so that windows doesn't bail if (WIN32) diff --git a/libraries/models/CMakeLists.txt b/libraries/models/CMakeLists.txt index 8056d215da..142faee2b3 100644 --- a/libraries/models/CMakeLists.txt +++ b/libraries/models/CMakeLists.txt @@ -8,11 +8,8 @@ set(TARGET_NAME models) find_package(Qt5Widgets REQUIRED) -include(${MACRO_DIR}/AutoMTC.cmake) -auto_mtc(${TARGET_NAME} "${ROOT_DIR}") - include(${MACRO_DIR}/SetupHifiLibrary.cmake) -setup_hifi_library(${TARGET_NAME} "${AUTOMTC_SRC}") +setup_hifi_library(${TARGET_NAME}) include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} "${ROOT_DIR}") @@ -27,12 +24,6 @@ link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") # for streamable link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") -# link ZLIB -find_package(ZLIB) - -include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") -target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets) - # add a definition for ssize_t so that windows doesn't bail if (WIN32) add_definitions(-Dssize_t=long) diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index 215d406133..2d47f7df9b 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -2,21 +2,16 @@ set(ROOT_DIR ../..) set(MACRO_DIR "${ROOT_DIR}/cmake/macros") set(TARGET_NAME networking) -project(${TARGET_NAME}) include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -# include GLM -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} "${ROOT_DIR}") - find_package(Qt5Network) -# bubble up the libraries we are dependent on and link them to ourselves -set(REQUIRED_DEPENDENCY_LIBRARIES Qt5::Network) -set(SUB_DEPENDENCY_LIBRARIES ${REQUIRED_DEPENDENCY_LIBRARIES} PARENT_SCOPE) -target_link_libraries(${TARGET_NAME} ${REQUIRED_DEPENDENCY_LIBRARIES}) +# set a property indicating the libraries we are dependent on and link them to ourselves +set(DEPENDENCY_LIBRARIES Qt5::Network) +set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) # add a definition for ssize_t so that windows doesn't bail if (WIN32) diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index 067551ba31..5faedff6ed 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -14,16 +14,16 @@ include_glm(${TARGET_NAME} "${ROOT_DIR}") # link required libraries on UNIX if (APPLE) find_library(CoreServices CoreServices) - list(APPEND REQUIRED_DEPENDENCY_LIBRARIES ${CoreServices}) + set(DEPENDENCY_LIBRARIES ${CoreServices}) elseif (UNIX) find_package(Threads REQUIRED) - LIST(APPEND REQUIRED_DEPENDENCY_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}") + set(DEPENDENCY_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}") endif () find_package(Qt5Network) find_package(Qt5Widgets) # bubble up the libraries we are dependent on and link them to ourselves -list(APPEND REQUIRED_DEPENDENCY_LIBRARIES Qt5::Network Qt5::Widgets) -set(SUB_DEPENDENCY_LIBRARIES ${REQUIRED_DEPENDENCY_LIBRARIES} PARENT_SCOPE) -target_link_libraries(${TARGET_NAME} ${REQUIRED_DEPENDENCY_LIBRARIES}) \ No newline at end of file +list(APPEND DEPENDENCY_LIBRARIES Qt5::Network Qt5::Widgets) +set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES ${DEPENDENCY_LIBRARIES}) +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) \ No newline at end of file From 1059e9a6355b1d72f0d9020e4c0b5f681ea908a0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Aug 2014 15:50:15 -0700 Subject: [PATCH 268/407] add back more required Qt modules --- libraries/avatars/CMakeLists.txt | 7 +++++++ libraries/fbx/CMakeLists.txt | 8 ++++---- libraries/metavoxels/CMakeLists.txt | 3 ++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index feb1e68557..c7defaafe2 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -19,6 +19,13 @@ link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") +find_package(Qt5Network) + +# set a property indicating the libraries we are dependent on and link them to ourselves +set(DEPENDENCY_LIBRARIES Qt5::Network) +set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES ${DEPENDENCY_LIBRARIES}) +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) + # add a definition for ssize_t so that windows doesn't bail if (WIN32) add_definitions(-Dssize_t=long) diff --git a/libraries/fbx/CMakeLists.txt b/libraries/fbx/CMakeLists.txt index a125de1320..ba51fe2e06 100644 --- a/libraries/fbx/CMakeLists.txt +++ b/libraries/fbx/CMakeLists.txt @@ -23,10 +23,10 @@ find_package(ZLIB) include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") -# bubble up the libraries we are dependent on and link them to ourselves -set(REQUIRED_DEPENDENCY_LIBRARIES "${ZLIB_LIBRARIES}") -set(SUB_DEPENDENCY_LIBRARIES ${REQUIRED_DEPENDENCY_LIBRARIES} PARENT_SCOPE) -target_link_libraries(${TARGET_NAME} ${REQUIRED_DEPENDENCY_LIBRARIES}) +# set a property indicating the libraries we are dependent on and link them to ourselves +set(DEPENDENCY_LIBRARIES "${ZLIB_LIBRARIES}") +set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES ${DEPENDENCY_LIBRARIES}) +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) # add a definition for ssize_t so that windows doesn't bail if (WIN32) diff --git a/libraries/metavoxels/CMakeLists.txt b/libraries/metavoxels/CMakeLists.txt index c419f664a0..10feb55199 100644 --- a/libraries/metavoxels/CMakeLists.txt +++ b/libraries/metavoxels/CMakeLists.txt @@ -21,9 +21,10 @@ include_glm(${TARGET_NAME} "${ROOT_DIR}") find_package(Qt5Script) find_package(Qt5Widgets) +find_package(Qt5Network) # set a property indicating the libraries we are dependent on and link them to ourselves -set(DEPENDENCY_LIBRARIES Qt5::Script Qt5::Widgets) +set(DEPENDENCY_LIBRARIES Qt5::Script Qt5::Widgets Qt5::Network) set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) From 2bb37f2d64b313e701dd7d6817d7e6970dd1853a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Aug 2014 15:56:39 -0700 Subject: [PATCH 269/407] more Qt module dependencies sorted out for libraries --- libraries/animation/CMakeLists.txt | 3 ++- libraries/avatars/CMakeLists.txt | 5 +++-- libraries/models/CMakeLists.txt | 8 ++++++++ libraries/octree/CMakeLists.txt | 9 ++++----- libraries/particles/CMakeLists.txt | 8 ++++++++ 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/libraries/animation/CMakeLists.txt b/libraries/animation/CMakeLists.txt index 20f4a59181..1ed0275a72 100644 --- a/libraries/animation/CMakeLists.txt +++ b/libraries/animation/CMakeLists.txt @@ -14,9 +14,10 @@ link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") find_package(Qt5Script) +find_package(Qt5Network) # set a property indicating the libraries we are dependent on and link them to ourselves -set(DEPENDENCY_LIBRARIES Qt5::Script) +set(DEPENDENCY_LIBRARIES Qt5::Script Qt5::Network) set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index c7defaafe2..2aae671146 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -20,10 +20,11 @@ link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") find_package(Qt5Network) +find_package(Qt5Script) # set a property indicating the libraries we are dependent on and link them to ourselves -set(DEPENDENCY_LIBRARIES Qt5::Network) -set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES ${DEPENDENCY_LIBRARIES}) +set(DEPENDENCY_LIBRARIES Qt5::Network Qt5::Script) +set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) # add a definition for ssize_t so that windows doesn't bail diff --git a/libraries/models/CMakeLists.txt b/libraries/models/CMakeLists.txt index 142faee2b3..0d7b3cf4fc 100644 --- a/libraries/models/CMakeLists.txt +++ b/libraries/models/CMakeLists.txt @@ -24,6 +24,14 @@ link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") # for streamable link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") +find_package(Qt5Network) +find_package(Qt5Script) + +# set a property indicating the libraries we are dependent on and link them to ourselves +set(DEPENDENCY_LIBRARIES Qt5::Network Qt5::Script) +set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) + # add a definition for ssize_t so that windows doesn't bail if (WIN32) add_definitions(-Dssize_t=long) diff --git a/libraries/octree/CMakeLists.txt b/libraries/octree/CMakeLists.txt index 99da8d1bf2..d0beade108 100644 --- a/libraries/octree/CMakeLists.txt +++ b/libraries/octree/CMakeLists.txt @@ -21,12 +21,11 @@ find_package(ZLIB) find_package(OpenSSL REQUIRED) include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}" "${OPENSSL_INCLUDE_DIR}") - -# bubble up the libraries we are dependent on -set(REQUIRED_DEPENDENCY_LIBRARIES ${REQUIRED_DEPENDENCY_LIBRARIES} - "${ZLIB_LIBRARIES}" "${OPENSSL_LIBRARIES}" PARENT_SCOPE) -target_link_libraries(${TARGET_NAME} ${REQUIRED_DEPENDENCY_LIBRARIES}) +# set a property indicating the libraries we are dependent on and link them to ourselves +set(DEPENDENCY_LIBRARIES "${ZLIB_LIBRARIES}" "${OPENSSL_LIBRARIES}") +set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES ${DEPENDENCY_LIBRARIES}) +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) # add a definition for ssize_t so that windows doesn't bail if (WIN32) diff --git a/libraries/particles/CMakeLists.txt b/libraries/particles/CMakeLists.txt index cecbdaaa21..ceac4324c0 100644 --- a/libraries/particles/CMakeLists.txt +++ b/libraries/particles/CMakeLists.txt @@ -19,6 +19,14 @@ link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") +find_package(Qt5Network) +find_package(Qt5Script) + +# set a property indicating the libraries we are dependent on and link them to ourselves +set(DEPENDENCY_LIBRARIES Qt5::Network Qt5::Script) +set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) + # add a definition for ssize_t so that windows doesn't bail if (WIN32) add_definitions(-Dssize_t=long) From 892e30c5e17e09f44a1a3514d75151250a760b57 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Aug 2014 16:13:29 -0700 Subject: [PATCH 270/407] get past assignment-client build after cmake auditing --- assignment-client/CMakeLists.txt | 14 +++++- interface/CMakeLists.txt | 52 ++++++++++----------- libraries/animation/CMakeLists.txt | 3 +- libraries/audio/CMakeLists.txt | 2 +- libraries/audio/src/AudioRingBuffer.cpp | 4 +- libraries/audio/src/AudioRingBuffer.h | 6 +-- libraries/avatars/CMakeLists.txt | 3 +- libraries/embedded-webserver/CMakeLists.txt | 2 +- libraries/metavoxels/CMakeLists.txt | 4 +- libraries/models/CMakeLists.txt | 3 +- libraries/networking/CMakeLists.txt | 2 +- libraries/particles/CMakeLists.txt | 5 +- libraries/script-engine/CMakeLists.txt | 11 ++--- libraries/shared/CMakeLists.txt | 5 +- 14 files changed, 57 insertions(+), 59 deletions(-) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index a4e26899fb..3fb0f574a5 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -9,6 +9,9 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake include("${MACRO_DIR}/SetupHifiProject.cmake") setup_hifi_project(${TARGET_NAME} TRUE) +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} "${ROOT_DIR}") + # link in the shared libraries include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") @@ -26,13 +29,20 @@ link_hifi_library(script-engine ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(embedded-webserver ${TARGET_NAME} "${ROOT_DIR}") if (UNIX) - target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS}) + list(APPEND DEPENDENCY_LIBRARIES ${CMAKE_DL_LIBS}) endif (UNIX) IF (WIN32) - target_link_libraries(${TARGET_NAME} Winmm Ws2_32) + list(APPEND DEPENDENCY_LIBRARIES Winmm Ws2_32) ENDIF(WIN32) +find_package(Qt5 COMPONENTS Gui Network Script Widgets) + +# set a property indicating the libraries we are dependent on and link them to ourselves +list(APPEND DEPENDENCY_LIBRARIES Qt5::Gui Qt5::Network Qt5::Script Qt5::Widgets) +set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) + # add a definition for ssize_t so that windows doesn't bail if (WIN32) add_definitions(-Dssize_t=long) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 5c1bec0321..e624388408 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -52,7 +52,7 @@ foreach(SUBDIR avatar devices renderer ui starfield location scripting voxels pa set(INTERFACE_SRCS ${INTERFACE_SRCS} "${SUBDIR_SRCS}") endforeach(SUBDIR) -find_package(Qt5 COMPONENTS Core Gui Multimedia Network OpenGL Script Svg WebKit WebKitWidgets Xml UiTools) +# find_package(Qt5 COMPONENTS Core Gui Multimedia Network OpenGL Script Svg WebKit WebKitWidgets Xml UiTools) # grab the ui files in resources/ui file (GLOB_RECURSE QT_UI_FILES ui/*.ui) @@ -182,8 +182,6 @@ include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes" target_link_libraries( ${TARGET_NAME} "${ZLIB_LIBRARIES}" - Qt5::Core Qt5::Gui Qt5::Multimedia Qt5::Network Qt5::OpenGL - Qt5::Script Qt5::Svg Qt5::WebKit Qt5::WebKitWidgets Qt5::Xml Qt5::UiTools ) # assume we are using a Qt build without bearer management @@ -191,30 +189,30 @@ add_definitions(-DQT_NO_BEARERMANAGEMENT) if (APPLE) # link in required OS X frameworks and include the right GL headers - find_library(AppKit AppKit) - find_library(CoreAudio CoreAudio) - find_library(CoreServices CoreServices) - find_library(Carbon Carbon) - find_library(Foundation Foundation) - find_library(GLUT GLUT) - find_library(OpenGL OpenGL) - find_library(IOKit IOKit) - find_library(QTKit QTKit) - find_library(QuartzCore QuartzCore) - - target_link_libraries( - ${TARGET_NAME} - ${AppKit} - ${CoreAudio} - ${CoreServices} - ${Carbon} - ${Foundation} - ${GLUT} - ${OpenGL} - ${IOKit} - ${QTKit} - ${QuartzCore} - ) + # find_library(AppKit AppKit) + # find_library(CoreAudio CoreAudio) + # find_library(CoreServices CoreServices) + # find_library(Carbon Carbon) + # find_library(Foundation Foundation) + # find_library(GLUT GLUT) + # find_library(OpenGL OpenGL) + # find_library(IOKit IOKit) + # find_library(QTKit QTKit) + # find_library(QuartzCore QuartzCore) + # + # target_link_libraries( + # ${TARGET_NAME} + # ${AppKit} + # ${CoreAudio} + # ${CoreServices} + # ${Carbon} + # ${Foundation} + # ${GLUT} + # ${OpenGL} + # ${IOKit} + # ${QTKit} + # ${QuartzCore} + # ) # install command for OS X bundle INSTALL(TARGETS ${TARGET_NAME} diff --git a/libraries/animation/CMakeLists.txt b/libraries/animation/CMakeLists.txt index 1ed0275a72..7891c65dcc 100644 --- a/libraries/animation/CMakeLists.txt +++ b/libraries/animation/CMakeLists.txt @@ -13,8 +13,7 @@ include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") -find_package(Qt5Script) -find_package(Qt5Network) +find_package(Qt5 COMPONENTS Network Script) # set a property indicating the libraries we are dependent on and link them to ourselves set(DEPENDENCY_LIBRARIES Qt5::Script Qt5::Network) diff --git a/libraries/audio/CMakeLists.txt b/libraries/audio/CMakeLists.txt index 69cc61ca6d..ace5f9292c 100644 --- a/libraries/audio/CMakeLists.txt +++ b/libraries/audio/CMakeLists.txt @@ -20,7 +20,7 @@ include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") -find_package(Qt5Network) +find_package(Qt5 COMPONENTS Network) # set a property indicating the libraries we are dependent on and link them to ourselves set(DEPENDENCY_LIBRARIES Qt5::Network) diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index c687ab8648..cae663758d 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -15,9 +15,9 @@ #include -#include "PacketHeaders.h" -#include "AudioRingBuffer.h" +#include +#include "AudioRingBuffer.h" AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode, int numFramesCapacity) : _frameCapacity(numFramesCapacity), diff --git a/libraries/audio/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h index ed680b18b1..b4b30b1f56 100644 --- a/libraries/audio/src/AudioRingBuffer.h +++ b/libraries/audio/src/AudioRingBuffer.h @@ -15,12 +15,10 @@ #include #include -#include - #include -#include "NodeData.h" -#include "SharedUtil.h" +#include +#include const int SAMPLE_RATE = 24000; diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index 2aae671146..1300a2e733 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -19,8 +19,7 @@ link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") -find_package(Qt5Network) -find_package(Qt5Script) +find_package(Qt5 COMPONENTS Network Script) # set a property indicating the libraries we are dependent on and link them to ourselves set(DEPENDENCY_LIBRARIES Qt5::Network Qt5::Script) diff --git a/libraries/embedded-webserver/CMakeLists.txt b/libraries/embedded-webserver/CMakeLists.txt index eb28cae1b3..5b815625ba 100644 --- a/libraries/embedded-webserver/CMakeLists.txt +++ b/libraries/embedded-webserver/CMakeLists.txt @@ -9,7 +9,7 @@ set(TARGET_NAME embedded-webserver) include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -find_package(Qt5Network REQUIRED) +find_package(Qt5 COMPONENTS Network) # set a property indicating the libraries we are dependent on and link them to ourselves set(DEPENDENCY_LIBRARIES Qt5::Network) diff --git a/libraries/metavoxels/CMakeLists.txt b/libraries/metavoxels/CMakeLists.txt index 10feb55199..799a549a3b 100644 --- a/libraries/metavoxels/CMakeLists.txt +++ b/libraries/metavoxels/CMakeLists.txt @@ -19,9 +19,7 @@ link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} "${ROOT_DIR}") -find_package(Qt5Script) -find_package(Qt5Widgets) -find_package(Qt5Network) +find_package(Qt5 COMPONENTS Network Script Widgets) # set a property indicating the libraries we are dependent on and link them to ourselves set(DEPENDENCY_LIBRARIES Qt5::Script Qt5::Widgets Qt5::Network) diff --git a/libraries/models/CMakeLists.txt b/libraries/models/CMakeLists.txt index 0d7b3cf4fc..8128741ef6 100644 --- a/libraries/models/CMakeLists.txt +++ b/libraries/models/CMakeLists.txt @@ -24,8 +24,7 @@ link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") # for streamable link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") -find_package(Qt5Network) -find_package(Qt5Script) +find_package(Qt5 COMPONENTS Network Script) # set a property indicating the libraries we are dependent on and link them to ourselves set(DEPENDENCY_LIBRARIES Qt5::Network Qt5::Script) diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index 2d47f7df9b..7bd210623b 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -6,7 +6,7 @@ set(TARGET_NAME networking) include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -find_package(Qt5Network) +find_package(Qt5 COMPONENTS Network) # set a property indicating the libraries we are dependent on and link them to ourselves set(DEPENDENCY_LIBRARIES Qt5::Network) diff --git a/libraries/particles/CMakeLists.txt b/libraries/particles/CMakeLists.txt index ceac4324c0..54398ac252 100644 --- a/libraries/particles/CMakeLists.txt +++ b/libraries/particles/CMakeLists.txt @@ -19,11 +19,10 @@ link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") -find_package(Qt5Network) -find_package(Qt5Script) +find_package(Qt5 COMPONENTS Gui Network Script) # set a property indicating the libraries we are dependent on and link them to ourselves -set(DEPENDENCY_LIBRARIES Qt5::Network Qt5::Script) +set(DEPENDENCY_LIBRARIES Qt5::Network Qt5::Script Qt5::Gui) set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 2dd40c7ece..1b0199977f 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -6,8 +6,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cm set(TARGET_NAME script-engine) -find_package(Qt5Widgets REQUIRED) - include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) @@ -23,11 +21,12 @@ link_hifi_library(particles ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(models ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") -# link ZLIB -find_package(ZLIB) +find_package(Qt5 COMPONENTS Gui Network Script Widgets) -include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") -target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets) +# set a property indicating the libraries we are dependent on and link them to ourselves +set(DEPENDENCY_LIBRARIES Qt5::Gui Qt5::Network Qt5::Script Qt5::Widgets) +set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) # add a definition for ssize_t so that windows doesn't bail if (WIN32) diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index 5faedff6ed..6badb10f8e 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -20,10 +20,9 @@ elseif (UNIX) set(DEPENDENCY_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}") endif () -find_package(Qt5Network) -find_package(Qt5Widgets) +find_package(Qt5 COMPONENTS Network Widgets) # bubble up the libraries we are dependent on and link them to ourselves list(APPEND DEPENDENCY_LIBRARIES Qt5::Network Qt5::Widgets) -set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES ${DEPENDENCY_LIBRARIES}) +set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) \ No newline at end of file From 0378fb30491b934c537e6b3d48325442f16f9e9b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Aug 2014 17:09:27 -0700 Subject: [PATCH 271/407] break glm helpers out of SharedUtil --- assignment-client/CMakeLists.txt | 13 +- domain-server/CMakeLists.txt | 5 +- libraries/shared/src/AngularConstraint.cpp | 3 +- libraries/shared/src/AngularConstraint.h | 1 - libraries/shared/src/GLMHelpers.cpp | 299 +++++++++++++++++++++ libraries/shared/src/GLMHelpers.h | 89 ++++++ libraries/shared/src/SharedUtil.cpp | 290 -------------------- libraries/shared/src/SharedUtil.h | 69 ----- 8 files changed, 397 insertions(+), 372 deletions(-) create mode 100644 libraries/shared/src/GLMHelpers.cpp create mode 100644 libraries/shared/src/GLMHelpers.h diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 3fb0f574a5..2f3739485a 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -9,9 +9,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake include("${MACRO_DIR}/SetupHifiProject.cmake") setup_hifi_project(${TARGET_NAME} TRUE) -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} "${ROOT_DIR}") - # link in the shared libraries include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") @@ -29,19 +26,15 @@ link_hifi_library(script-engine ${TARGET_NAME} "${ROOT_DIR}") link_hifi_library(embedded-webserver ${TARGET_NAME} "${ROOT_DIR}") if (UNIX) - list(APPEND DEPENDENCY_LIBRARIES ${CMAKE_DL_LIBS}) + target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES} ${CMAKE_DL_LIBS}) endif (UNIX) IF (WIN32) - list(APPEND DEPENDENCY_LIBRARIES Winmm Ws2_32) + target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES} Winmm Ws2_32) ENDIF(WIN32) find_package(Qt5 COMPONENTS Gui Network Script Widgets) - -# set a property indicating the libraries we are dependent on and link them to ourselves -list(APPEND DEPENDENCY_LIBRARIES Qt5::Gui Qt5::Network Qt5::Script Qt5::Widgets) -set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) +target_link_libraries(${TARGET_NAME} Qt5::Gui Qt5::Network Qt5::Script Qt5::Widgets) # add a definition for ssize_t so that windows doesn't bail if (WIN32) diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index 26f07cf776..656760957d 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -32,4 +32,7 @@ ENDIF(WIN32) # add a definition for ssize_t so that windows doesn't bail if (WIN32) add_definitions(-Dssize_t=long) -endif () \ No newline at end of file +endif () + +find_package(Qt5 COMPONENTS Network) +target_link_libraries(${TARGET_NAME} Qt5::Network) diff --git a/libraries/shared/src/AngularConstraint.cpp b/libraries/shared/src/AngularConstraint.cpp index 4689568ac8..b39823ee3b 100644 --- a/libraries/shared/src/AngularConstraint.cpp +++ b/libraries/shared/src/AngularConstraint.cpp @@ -11,8 +11,9 @@ #include +#include "GLMHelpers.h" + #include "AngularConstraint.h" -#include "SharedUtil.h" // helper function /// \param angle radian angle to be clamped within angleMin and angleMax diff --git a/libraries/shared/src/AngularConstraint.h b/libraries/shared/src/AngularConstraint.h index 929a58959b..74d3fdb82b 100644 --- a/libraries/shared/src/AngularConstraint.h +++ b/libraries/shared/src/AngularConstraint.h @@ -14,7 +14,6 @@ #include - class AngularConstraint { public: /// \param minAngles minumum euler angles for the constraint diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp new file mode 100644 index 0000000000..566983679b --- /dev/null +++ b/libraries/shared/src/GLMHelpers.cpp @@ -0,0 +1,299 @@ +// +// GLMHelpers.cpp +// libraries/shared/src +// +// Created by Stephen Birarda on 2014-08-07. +// 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 +// + +#include "GLMHelpers.h" + +// Safe version of glm::mix; based on the code in Nick Bobick's article, +// http://www.gamasutra.com/features/19980703/quaternions_01.htm (via Clyde, +// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java) +glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) { + float cosa = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; + float ox = q2.x, oy = q2.y, oz = q2.z, ow = q2.w, s0, s1; + + // adjust signs if necessary + if (cosa < 0.0f) { + cosa = -cosa; + ox = -ox; + oy = -oy; + oz = -oz; + ow = -ow; + } + + // calculate coefficients; if the angle is too close to zero, we must fall back + // to linear interpolation + if ((1.0f - cosa) > EPSILON) { + float angle = acosf(cosa), sina = sinf(angle); + s0 = sinf((1.0f - proportion) * angle) / sina; + s1 = sinf(proportion * angle) / sina; + + } else { + s0 = 1.0f - proportion; + s1 = proportion; + } + + return glm::normalize(glm::quat(s0 * q1.w + s1 * ow, s0 * q1.x + s1 * ox, s0 * q1.y + s1 * oy, s0 * q1.z + s1 * oz)); +} + +// Allows sending of fixed-point numbers: radix 1 makes 15.1 number, radix 8 makes 8.8 number, etc +int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix) { + int16_t outVal = (int16_t)(scalar * (float)(1 << radix)); + memcpy(buffer, &outVal, sizeof(uint16_t)); + return sizeof(uint16_t); +} + +int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, float* destinationPointer, int radix) { + *destinationPointer = *byteFixedPointer / (float)(1 << radix); + return sizeof(int16_t); +} + +int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix) { + const unsigned char* startPosition = destBuffer; + destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.x, radix); + destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.y, radix); + destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.z, radix); + return destBuffer - startPosition; +} + +int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm::vec3& destination, int radix) { + const unsigned char* startPosition = sourceBuffer; + sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.x), radix); + sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.y), radix); + sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.z), radix); + return sourceBuffer - startPosition; +} + + +int packFloatAngleToTwoByte(unsigned char* buffer, float degrees) { + const float ANGLE_CONVERSION_RATIO = (std::numeric_limits::max() / 360.f); + + uint16_t angleHolder = floorf((degrees + 180.f) * ANGLE_CONVERSION_RATIO); + memcpy(buffer, &angleHolder, sizeof(uint16_t)); + + return sizeof(uint16_t); +} + +int unpackFloatAngleFromTwoByte(const uint16_t* byteAnglePointer, float* destinationPointer) { + *destinationPointer = (*byteAnglePointer / (float) std::numeric_limits::max()) * 360.f - 180.f; + return sizeof(uint16_t); +} + +int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput) { + const float QUAT_PART_CONVERSION_RATIO = (std::numeric_limits::max() / 2.f); + uint16_t quatParts[4]; + quatParts[0] = floorf((quatInput.x + 1.f) * QUAT_PART_CONVERSION_RATIO); + quatParts[1] = floorf((quatInput.y + 1.f) * QUAT_PART_CONVERSION_RATIO); + quatParts[2] = floorf((quatInput.z + 1.f) * QUAT_PART_CONVERSION_RATIO); + quatParts[3] = floorf((quatInput.w + 1.f) * QUAT_PART_CONVERSION_RATIO); + + memcpy(buffer, &quatParts, sizeof(quatParts)); + return sizeof(quatParts); +} + +int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatOutput) { + uint16_t quatParts[4]; + memcpy(&quatParts, buffer, sizeof(quatParts)); + + quatOutput.x = ((quatParts[0] / (float) std::numeric_limits::max()) * 2.f) - 1.f; + quatOutput.y = ((quatParts[1] / (float) std::numeric_limits::max()) * 2.f) - 1.f; + quatOutput.z = ((quatParts[2] / (float) std::numeric_limits::max()) * 2.f) - 1.f; + quatOutput.w = ((quatParts[3] / (float) std::numeric_limits::max()) * 2.f) - 1.f; + + return sizeof(quatParts); +} + +// Safe version of glm::eulerAngles; uses the factorization method described in David Eberly's +// http://www.geometrictools.com/Documentation/EulerAngles.pdf (via Clyde, +// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java) +glm::vec3 safeEulerAngles(const glm::quat& q) { + float sy = 2.0f * (q.y * q.w - q.x * q.z); + glm::vec3 eulers; + if (sy < 1.0f - EPSILON) { + if (sy > -1.0f + EPSILON) { + eulers = glm::vec3( + atan2f(q.y * q.z + q.x * q.w, 0.5f - (q.x * q.x + q.y * q.y)), + asinf(sy), + atan2f(q.x * q.y + q.z * q.w, 0.5f - (q.y * q.y + q.z * q.z))); + + } else { + // not a unique solution; x + z = atan2(-m21, m11) + eulers = glm::vec3( + 0.0f, + - PI_OVER_TWO, + atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))); + } + } else { + // not a unique solution; x - z = atan2(-m21, m11) + eulers = glm::vec3( + 0.0f, + PI_OVER_TWO, + -atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))); + } + + // adjust so that z, rather than y, is in [-pi/2, pi/2] + if (eulers.z < -PI_OVER_TWO) { + if (eulers.x < 0.0f) { + eulers.x += PI; + } else { + eulers.x -= PI; + } + eulers.y = -eulers.y; + if (eulers.y < 0.0f) { + eulers.y += PI; + } else { + eulers.y -= PI; + } + eulers.z += PI; + + } else if (eulers.z > PI_OVER_TWO) { + if (eulers.x < 0.0f) { + eulers.x += PI; + } else { + eulers.x -= PI; + } + eulers.y = -eulers.y; + if (eulers.y < 0.0f) { + eulers.y += PI; + } else { + eulers.y -= PI; + } + eulers.z -= PI; + } + return eulers; +} + +// Helper function returns the positive angle (in radians) between two 3D vectors +float angleBetween(const glm::vec3& v1, const glm::vec3& v2) { + return acosf((glm::dot(v1, v2)) / (glm::length(v1) * glm::length(v2))); +} + +// Helper function return the rotation from the first vector onto the second +glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) { + float angle = angleBetween(v1, v2); + if (glm::isnan(angle) || angle < EPSILON) { + return glm::quat(); + } + glm::vec3 axis; + if (angle > 179.99f * RADIANS_PER_DEGREE) { // 180 degree rotation; must use another axis + axis = glm::cross(v1, glm::vec3(1.0f, 0.0f, 0.0f)); + float axisLength = glm::length(axis); + if (axisLength < EPSILON) { // parallel to x; y will work + axis = glm::normalize(glm::cross(v1, glm::vec3(0.0f, 1.0f, 0.0f))); + } else { + axis /= axisLength; + } + } else { + axis = glm::normalize(glm::cross(v1, v2)); + // It is possible for axis to be nan even when angle is not less than EPSILON. + // For example when angle is small but not tiny but v1 and v2 and have very short lengths. + if (glm::isnan(glm::dot(axis, axis))) { + // set angle and axis to values that will generate an identity rotation + angle = 0.0f; + axis = glm::vec3(1.0f, 0.0f, 0.0f); + } + } + return glm::angleAxis(angle, axis); +} + +glm::vec3 extractTranslation(const glm::mat4& matrix) { + return glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]); +} + +void setTranslation(glm::mat4& matrix, const glm::vec3& translation) { + matrix[3][0] = translation.x; + matrix[3][1] = translation.y; + matrix[3][2] = translation.z; +} + +glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) { + // uses the iterative polar decomposition algorithm described by Ken Shoemake at + // http://www.cs.wisc.edu/graphics/Courses/838-s2002/Papers/polar-decomp.pdf + // code adapted from Clyde, https://github.com/threerings/clyde/blob/master/core/src/main/java/com/threerings/math/Matrix4f.java + // start with the contents of the upper 3x3 portion of the matrix + glm::mat3 upper = glm::mat3(matrix); + if (!assumeOrthogonal) { + for (int i = 0; i < 10; i++) { + // store the results of the previous iteration + glm::mat3 previous = upper; + + // compute average of the matrix with its inverse transpose + float sd00 = previous[1][1] * previous[2][2] - previous[2][1] * previous[1][2]; + float sd10 = previous[0][1] * previous[2][2] - previous[2][1] * previous[0][2]; + float sd20 = previous[0][1] * previous[1][2] - previous[1][1] * previous[0][2]; + float det = previous[0][0] * sd00 + previous[2][0] * sd20 - previous[1][0] * sd10; + if (fabs(det) == 0.0f) { + // determinant is zero; matrix is not invertible + break; + } + float hrdet = 0.5f / det; + upper[0][0] = +sd00 * hrdet + previous[0][0] * 0.5f; + upper[1][0] = -sd10 * hrdet + previous[1][0] * 0.5f; + upper[2][0] = +sd20 * hrdet + previous[2][0] * 0.5f; + + upper[0][1] = -(previous[1][0] * previous[2][2] - previous[2][0] * previous[1][2]) * hrdet + previous[0][1] * 0.5f; + upper[1][1] = +(previous[0][0] * previous[2][2] - previous[2][0] * previous[0][2]) * hrdet + previous[1][1] * 0.5f; + upper[2][1] = -(previous[0][0] * previous[1][2] - previous[1][0] * previous[0][2]) * hrdet + previous[2][1] * 0.5f; + + upper[0][2] = +(previous[1][0] * previous[2][1] - previous[2][0] * previous[1][1]) * hrdet + previous[0][2] * 0.5f; + upper[1][2] = -(previous[0][0] * previous[2][1] - previous[2][0] * previous[0][1]) * hrdet + previous[1][2] * 0.5f; + upper[2][2] = +(previous[0][0] * previous[1][1] - previous[1][0] * previous[0][1]) * hrdet + previous[2][2] * 0.5f; + + // compute the difference; if it's small enough, we're done + glm::mat3 diff = upper - previous; + if (diff[0][0] * diff[0][0] + diff[1][0] * diff[1][0] + diff[2][0] * diff[2][0] + diff[0][1] * diff[0][1] + + diff[1][1] * diff[1][1] + diff[2][1] * diff[2][1] + diff[0][2] * diff[0][2] + diff[1][2] * diff[1][2] + + diff[2][2] * diff[2][2] < EPSILON) { + break; + } + } + } + + // now that we have a nice orthogonal matrix, we can extract the rotation quaternion + // using the method described in http://en.wikipedia.org/wiki/Rotation_matrix#Conversions + float x2 = fabs(1.0f + upper[0][0] - upper[1][1] - upper[2][2]); + float y2 = fabs(1.0f - upper[0][0] + upper[1][1] - upper[2][2]); + float z2 = fabs(1.0f - upper[0][0] - upper[1][1] + upper[2][2]); + float w2 = fabs(1.0f + upper[0][0] + upper[1][1] + upper[2][2]); + return glm::normalize(glm::quat(0.5f * sqrtf(w2), + 0.5f * sqrtf(x2) * (upper[1][2] >= upper[2][1] ? 1.0f : -1.0f), + 0.5f * sqrtf(y2) * (upper[2][0] >= upper[0][2] ? 1.0f : -1.0f), + 0.5f * sqrtf(z2) * (upper[0][1] >= upper[1][0] ? 1.0f : -1.0f))); +} + +glm::vec3 extractScale(const glm::mat4& matrix) { + return glm::vec3(glm::length(matrix[0]), glm::length(matrix[1]), glm::length(matrix[2])); +} + +float extractUniformScale(const glm::mat4& matrix) { + return extractUniformScale(extractScale(matrix)); +} + +float extractUniformScale(const glm::vec3& scale) { + return (scale.x + scale.y + scale.z) / 3.0f; +} + +QByteArray createByteArray(const glm::vec3& vector) { + return QByteArray::number(vector.x) + ',' + QByteArray::number(vector.y) + ',' + QByteArray::number(vector.z); +} + +bool isSimilarOrientation(const glm::quat& orientionA, const glm::quat& orientionB, float similarEnough) { + // Compute the angular distance between the two orientations + float angleOrientation = orientionA == orientionB ? 0.0f : glm::degrees(glm::angle(orientionA * glm::inverse(orientionB))); + if (isNaN(angleOrientation)) { + angleOrientation = 0.0f; + } + return (angleOrientation <= similarEnough); +} + +bool isSimilarPosition(const glm::vec3& positionA, const glm::vec3& positionB, float similarEnough) { + // Compute the distance between the two points + float positionDistance = glm::distance(positionA, positionB); + return (positionDistance <= similarEnough); +} \ No newline at end of file diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h new file mode 100644 index 0000000000..43a1d09722 --- /dev/null +++ b/libraries/shared/src/GLMHelpers.h @@ -0,0 +1,89 @@ +// +// GLMHelpers.h +// libraries/shared/src +// +// Created by Stephen Birarda on 2014-08-07. +// 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 +// + +#ifndef hifi_GLMHelpers_h +#define hifi_GLMHelpers_h + +#include + +#include +#include + +#include + +#include "SharedUtil.h" + +glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha); + +// These pack/unpack functions are designed to start specific known types in as efficient a manner +// as possible. Taking advantage of the known characteristics of the semantic types. + +// Angles are known to be between 0 and 360 degrees, this allows us to encode in 16bits with great accuracy +int packFloatAngleToTwoByte(unsigned char* buffer, float degrees); +int unpackFloatAngleFromTwoByte(const uint16_t* byteAnglePointer, float* destinationPointer); + +// Orientation Quats are known to have 4 normalized components be between -1.0 and 1.0 +// this allows us to encode each component in 16bits with great accuracy +int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput); +int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatOutput); + +// Ratios need the be highly accurate when less than 10, but not very accurate above 10, and they +// are never greater than 1000 to 1, this allows us to encode each component in 16bits +int packFloatRatioToTwoByte(unsigned char* buffer, float ratio); +int unpackFloatRatioFromTwoByte(const unsigned char* buffer, float& ratio); + +// Near/Far Clip values need the be highly accurate when less than 10, but only integer accuracy above 10 and +// they are never greater than 16,000, this allows us to encode each component in 16bits +int packClipValueToTwoByte(unsigned char* buffer, float clipValue); +int unpackClipValueFromTwoByte(const unsigned char* buffer, float& clipValue); + +// Positive floats that don't need to be very precise +int packFloatToByte(unsigned char* buffer, float value, float scaleBy); +int unpackFloatFromByte(const unsigned char* buffer, float& value, float scaleBy); + +// Allows sending of fixed-point numbers: radix 1 makes 15.1 number, radix 8 makes 8.8 number, etc +int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix); +int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, float* destinationPointer, int radix); + +// A convenience for sending vec3's as fixed-point floats +int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix); +int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm::vec3& destination, int radix); + +/// \return vec3 with euler angles in radians +glm::vec3 safeEulerAngles(const glm::quat& q); + +float angleBetween(const glm::vec3& v1, const glm::vec3& v2); + +glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2); + +glm::vec3 extractTranslation(const glm::mat4& matrix); + +void setTranslation(glm::mat4& matrix, const glm::vec3& translation); + +glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal = false); + +glm::vec3 extractScale(const glm::mat4& matrix); + +float extractUniformScale(const glm::mat4& matrix); + +float extractUniformScale(const glm::vec3& scale); + +QByteArray createByteArray(const glm::vec3& vector); + +/// \return bool are two orientations similar to each other +const float ORIENTATION_SIMILAR_ENOUGH = 5.0f; // 10 degrees in any direction +bool isSimilarOrientation(const glm::quat& orientionA, const glm::quat& orientionB, + float similarEnough = ORIENTATION_SIMILAR_ENOUGH); +const float POSITION_SIMILAR_ENOUGH = 0.1f; // 0.1 meter +bool isSimilarPosition(const glm::vec3& positionA, const glm::vec3& positionB, float similarEnough = POSITION_SIMILAR_ENOUGH); + + +#endif // hifi_GLMHelpers_h \ No newline at end of file diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 2b8b9929e5..470dfffd13 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -79,40 +79,6 @@ bool shouldDo(float desiredInterval, float deltaTime) { return randFloat() < deltaTime / desiredInterval; } -// Safe version of glm::mix; based on the code in Nick Bobick's article, -// http://www.gamasutra.com/features/19980703/quaternions_01.htm (via Clyde, -// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java) -glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) { - float cosa = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; - float ox = q2.x, oy = q2.y, oz = q2.z, ow = q2.w, s0, s1; - - // adjust signs if necessary - if (cosa < 0.0f) { - cosa = -cosa; - ox = -ox; - oy = -oy; - oz = -oz; - ow = -ow; - } - - // calculate coefficients; if the angle is too close to zero, we must fall back - // to linear interpolation - if ((1.0f - cosa) > EPSILON) { - float angle = acosf(cosa), sina = sinf(angle); - s0 = sinf((1.0f - proportion) * angle) / sina; - s1 = sinf(proportion * angle) / sina; - - } else { - s0 = 1.0f - proportion; - s1 = proportion; - } - - return glm::normalize(glm::quat(s0 * q1.w + s1 * ow, s0 * q1.x + s1 * ox, s0 * q1.y + s1 * oy, s0 * q1.z + s1 * oz)); -} - - - - void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug) { for (int i = 0; i < length; i++) { outputBits(buffer[i], continuedDebug); @@ -489,73 +455,6 @@ int removeFromSortedArrays(void* value, void** valueArray, float* keyArray, int* return -1; // error case } -// Allows sending of fixed-point numbers: radix 1 makes 15.1 number, radix 8 makes 8.8 number, etc -int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix) { - int16_t outVal = (int16_t)(scalar * (float)(1 << radix)); - memcpy(buffer, &outVal, sizeof(uint16_t)); - return sizeof(uint16_t); -} - -int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, float* destinationPointer, int radix) { - *destinationPointer = *byteFixedPointer / (float)(1 << radix); - return sizeof(int16_t); -} - -int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix) { - const unsigned char* startPosition = destBuffer; - destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.x, radix); - destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.y, radix); - destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.z, radix); - return destBuffer - startPosition; -} - -int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm::vec3& destination, int radix) { - const unsigned char* startPosition = sourceBuffer; - sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.x), radix); - sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.y), radix); - sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.z), radix); - return sourceBuffer - startPosition; -} - - -int packFloatAngleToTwoByte(unsigned char* buffer, float degrees) { - const float ANGLE_CONVERSION_RATIO = (std::numeric_limits::max() / 360.f); - - uint16_t angleHolder = floorf((degrees + 180.f) * ANGLE_CONVERSION_RATIO); - memcpy(buffer, &angleHolder, sizeof(uint16_t)); - - return sizeof(uint16_t); -} - -int unpackFloatAngleFromTwoByte(const uint16_t* byteAnglePointer, float* destinationPointer) { - *destinationPointer = (*byteAnglePointer / (float) std::numeric_limits::max()) * 360.f - 180.f; - return sizeof(uint16_t); -} - -int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput) { - const float QUAT_PART_CONVERSION_RATIO = (std::numeric_limits::max() / 2.f); - uint16_t quatParts[4]; - quatParts[0] = floorf((quatInput.x + 1.f) * QUAT_PART_CONVERSION_RATIO); - quatParts[1] = floorf((quatInput.y + 1.f) * QUAT_PART_CONVERSION_RATIO); - quatParts[2] = floorf((quatInput.z + 1.f) * QUAT_PART_CONVERSION_RATIO); - quatParts[3] = floorf((quatInput.w + 1.f) * QUAT_PART_CONVERSION_RATIO); - - memcpy(buffer, &quatParts, sizeof(quatParts)); - return sizeof(quatParts); -} - -int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatOutput) { - uint16_t quatParts[4]; - memcpy(&quatParts, buffer, sizeof(quatParts)); - - quatOutput.x = ((quatParts[0] / (float) std::numeric_limits::max()) * 2.f) - 1.f; - quatOutput.y = ((quatParts[1] / (float) std::numeric_limits::max()) * 2.f) - 1.f; - quatOutput.z = ((quatParts[2] / (float) std::numeric_limits::max()) * 2.f) - 1.f; - quatOutput.w = ((quatParts[3] / (float) std::numeric_limits::max()) * 2.f) - 1.f; - - return sizeof(quatParts); -} - float SMALL_LIMIT = 10.f; float LARGE_LIMIT = 1000.f; @@ -651,199 +550,10 @@ void debug::checkDeadBeef(void* memoryVoid, int size) { assert(memcmp((unsigned char*)memoryVoid, DEADBEEF, std::min(size, DEADBEEF_SIZE)) != 0); } -// Safe version of glm::eulerAngles; uses the factorization method described in David Eberly's -// http://www.geometrictools.com/Documentation/EulerAngles.pdf (via Clyde, -// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java) -glm::vec3 safeEulerAngles(const glm::quat& q) { - float sy = 2.0f * (q.y * q.w - q.x * q.z); - glm::vec3 eulers; - if (sy < 1.0f - EPSILON) { - if (sy > -1.0f + EPSILON) { - eulers = glm::vec3( - atan2f(q.y * q.z + q.x * q.w, 0.5f - (q.x * q.x + q.y * q.y)), - asinf(sy), - atan2f(q.x * q.y + q.z * q.w, 0.5f - (q.y * q.y + q.z * q.z))); - - } else { - // not a unique solution; x + z = atan2(-m21, m11) - eulers = glm::vec3( - 0.0f, - - PI_OVER_TWO, - atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))); - } - } else { - // not a unique solution; x - z = atan2(-m21, m11) - eulers = glm::vec3( - 0.0f, - PI_OVER_TWO, - -atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))); - } - - // adjust so that z, rather than y, is in [-pi/2, pi/2] - if (eulers.z < -PI_OVER_TWO) { - if (eulers.x < 0.0f) { - eulers.x += PI; - } else { - eulers.x -= PI; - } - eulers.y = -eulers.y; - if (eulers.y < 0.0f) { - eulers.y += PI; - } else { - eulers.y -= PI; - } - eulers.z += PI; - - } else if (eulers.z > PI_OVER_TWO) { - if (eulers.x < 0.0f) { - eulers.x += PI; - } else { - eulers.x -= PI; - } - eulers.y = -eulers.y; - if (eulers.y < 0.0f) { - eulers.y += PI; - } else { - eulers.y -= PI; - } - eulers.z -= PI; - } - return eulers; -} - -// Helper function returns the positive angle (in radians) between two 3D vectors -float angleBetween(const glm::vec3& v1, const glm::vec3& v2) { - return acosf((glm::dot(v1, v2)) / (glm::length(v1) * glm::length(v2))); -} - -// Helper function return the rotation from the first vector onto the second -glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) { - float angle = angleBetween(v1, v2); - if (glm::isnan(angle) || angle < EPSILON) { - return glm::quat(); - } - glm::vec3 axis; - if (angle > 179.99f * RADIANS_PER_DEGREE) { // 180 degree rotation; must use another axis - axis = glm::cross(v1, glm::vec3(1.0f, 0.0f, 0.0f)); - float axisLength = glm::length(axis); - if (axisLength < EPSILON) { // parallel to x; y will work - axis = glm::normalize(glm::cross(v1, glm::vec3(0.0f, 1.0f, 0.0f))); - } else { - axis /= axisLength; - } - } else { - axis = glm::normalize(glm::cross(v1, v2)); - // It is possible for axis to be nan even when angle is not less than EPSILON. - // For example when angle is small but not tiny but v1 and v2 and have very short lengths. - if (glm::isnan(glm::dot(axis, axis))) { - // set angle and axis to values that will generate an identity rotation - angle = 0.0f; - axis = glm::vec3(1.0f, 0.0f, 0.0f); - } - } - return glm::angleAxis(angle, axis); -} - -glm::vec3 extractTranslation(const glm::mat4& matrix) { - return glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]); -} - -void setTranslation(glm::mat4& matrix, const glm::vec3& translation) { - matrix[3][0] = translation.x; - matrix[3][1] = translation.y; - matrix[3][2] = translation.z; -} - -glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) { - // uses the iterative polar decomposition algorithm described by Ken Shoemake at - // http://www.cs.wisc.edu/graphics/Courses/838-s2002/Papers/polar-decomp.pdf - // code adapted from Clyde, https://github.com/threerings/clyde/blob/master/core/src/main/java/com/threerings/math/Matrix4f.java - // start with the contents of the upper 3x3 portion of the matrix - glm::mat3 upper = glm::mat3(matrix); - if (!assumeOrthogonal) { - for (int i = 0; i < 10; i++) { - // store the results of the previous iteration - glm::mat3 previous = upper; - - // compute average of the matrix with its inverse transpose - float sd00 = previous[1][1] * previous[2][2] - previous[2][1] * previous[1][2]; - float sd10 = previous[0][1] * previous[2][2] - previous[2][1] * previous[0][2]; - float sd20 = previous[0][1] * previous[1][2] - previous[1][1] * previous[0][2]; - float det = previous[0][0] * sd00 + previous[2][0] * sd20 - previous[1][0] * sd10; - if (fabs(det) == 0.0f) { - // determinant is zero; matrix is not invertible - break; - } - float hrdet = 0.5f / det; - upper[0][0] = +sd00 * hrdet + previous[0][0] * 0.5f; - upper[1][0] = -sd10 * hrdet + previous[1][0] * 0.5f; - upper[2][0] = +sd20 * hrdet + previous[2][0] * 0.5f; - - upper[0][1] = -(previous[1][0] * previous[2][2] - previous[2][0] * previous[1][2]) * hrdet + previous[0][1] * 0.5f; - upper[1][1] = +(previous[0][0] * previous[2][2] - previous[2][0] * previous[0][2]) * hrdet + previous[1][1] * 0.5f; - upper[2][1] = -(previous[0][0] * previous[1][2] - previous[1][0] * previous[0][2]) * hrdet + previous[2][1] * 0.5f; - - upper[0][2] = +(previous[1][0] * previous[2][1] - previous[2][0] * previous[1][1]) * hrdet + previous[0][2] * 0.5f; - upper[1][2] = -(previous[0][0] * previous[2][1] - previous[2][0] * previous[0][1]) * hrdet + previous[1][2] * 0.5f; - upper[2][2] = +(previous[0][0] * previous[1][1] - previous[1][0] * previous[0][1]) * hrdet + previous[2][2] * 0.5f; - - // compute the difference; if it's small enough, we're done - glm::mat3 diff = upper - previous; - if (diff[0][0] * diff[0][0] + diff[1][0] * diff[1][0] + diff[2][0] * diff[2][0] + diff[0][1] * diff[0][1] + - diff[1][1] * diff[1][1] + diff[2][1] * diff[2][1] + diff[0][2] * diff[0][2] + diff[1][2] * diff[1][2] + - diff[2][2] * diff[2][2] < EPSILON) { - break; - } - } - } - - // now that we have a nice orthogonal matrix, we can extract the rotation quaternion - // using the method described in http://en.wikipedia.org/wiki/Rotation_matrix#Conversions - float x2 = fabs(1.0f + upper[0][0] - upper[1][1] - upper[2][2]); - float y2 = fabs(1.0f - upper[0][0] + upper[1][1] - upper[2][2]); - float z2 = fabs(1.0f - upper[0][0] - upper[1][1] + upper[2][2]); - float w2 = fabs(1.0f + upper[0][0] + upper[1][1] + upper[2][2]); - return glm::normalize(glm::quat(0.5f * sqrtf(w2), - 0.5f * sqrtf(x2) * (upper[1][2] >= upper[2][1] ? 1.0f : -1.0f), - 0.5f * sqrtf(y2) * (upper[2][0] >= upper[0][2] ? 1.0f : -1.0f), - 0.5f * sqrtf(z2) * (upper[0][1] >= upper[1][0] ? 1.0f : -1.0f))); -} - -glm::vec3 extractScale(const glm::mat4& matrix) { - return glm::vec3(glm::length(matrix[0]), glm::length(matrix[1]), glm::length(matrix[2])); -} - -float extractUniformScale(const glm::mat4& matrix) { - return extractUniformScale(extractScale(matrix)); -} - -float extractUniformScale(const glm::vec3& scale) { - return (scale.x + scale.y + scale.z) / 3.0f; -} - bool isNaN(float value) { return value != value; } -bool isSimilarOrientation(const glm::quat& orientionA, const glm::quat& orientionB, float similarEnough) { - // Compute the angular distance between the two orientations - float angleOrientation = orientionA == orientionB ? 0.0f : glm::degrees(glm::angle(orientionA * glm::inverse(orientionB))); - if (isNaN(angleOrientation)) { - angleOrientation = 0.0f; - } - return (angleOrientation <= similarEnough); -} - -bool isSimilarPosition(const glm::vec3& positionA, const glm::vec3& positionB, float similarEnough) { - // Compute the distance between the two points - float positionDistance = glm::distance(positionA, positionB); - return (positionDistance <= similarEnough); -} - -QByteArray createByteArray(const glm::vec3& vector) { - return QByteArray::number(vector.x) + ',' + QByteArray::number(vector.y) + ',' + QByteArray::number(vector.z); -} - QString formatUsecTime(float usecs, int prec) { static const quint64 SECONDS_PER_MINUTE = 60; static const quint64 USECS_PER_MINUTE = USECS_PER_SECOND * SECONDS_PER_MINUTE; diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 18494d48e4..015758427a 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -19,9 +19,6 @@ #include // not on windows, not needed for mac or windows #endif -#include -#include - #include const int BYTES_PER_COLOR = 3; @@ -71,8 +68,6 @@ float randomSign(); /// \return -1.0 or 1.0 unsigned char randomColorValue(int minimum = 0); bool randomBoolean(); -glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha); - bool shouldDo(float desiredInterval, float deltaTime); void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug = NULL); @@ -108,8 +103,6 @@ int insertIntoSortedArrays(void* value, float key, int originalIndex, int removeFromSortedArrays(void* value, void** valueArray, float* keyArray, int* originalIndexArray, int currentCount, int maxCount); - - // Helper Class for debugging class debug { public: @@ -124,71 +117,9 @@ private: bool isBetween(int64_t value, int64_t max, int64_t min); -// These pack/unpack functions are designed to start specific known types in as efficient a manner -// as possible. Taking advantage of the known characteristics of the semantic types. - -// Angles are known to be between 0 and 360 degrees, this allows us to encode in 16bits with great accuracy -int packFloatAngleToTwoByte(unsigned char* buffer, float degrees); -int unpackFloatAngleFromTwoByte(const uint16_t* byteAnglePointer, float* destinationPointer); - -// Orientation Quats are known to have 4 normalized components be between -1.0 and 1.0 -// this allows us to encode each component in 16bits with great accuracy -int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput); -int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatOutput); - -// Ratios need the be highly accurate when less than 10, but not very accurate above 10, and they -// are never greater than 1000 to 1, this allows us to encode each component in 16bits -int packFloatRatioToTwoByte(unsigned char* buffer, float ratio); -int unpackFloatRatioFromTwoByte(const unsigned char* buffer, float& ratio); - -// Near/Far Clip values need the be highly accurate when less than 10, but only integer accuracy above 10 and -// they are never greater than 16,000, this allows us to encode each component in 16bits -int packClipValueToTwoByte(unsigned char* buffer, float clipValue); -int unpackClipValueFromTwoByte(const unsigned char* buffer, float& clipValue); - -// Positive floats that don't need to be very precise -int packFloatToByte(unsigned char* buffer, float value, float scaleBy); -int unpackFloatFromByte(const unsigned char* buffer, float& value, float scaleBy); - -// Allows sending of fixed-point numbers: radix 1 makes 15.1 number, radix 8 makes 8.8 number, etc -int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix); -int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, float* destinationPointer, int radix); - -// A convenience for sending vec3's as fixed-point floats -int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix); -int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm::vec3& destination, int radix); - -/// \return vec3 with euler angles in radians -glm::vec3 safeEulerAngles(const glm::quat& q); - -float angleBetween(const glm::vec3& v1, const glm::vec3& v2); - -glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2); - -glm::vec3 extractTranslation(const glm::mat4& matrix); - -void setTranslation(glm::mat4& matrix, const glm::vec3& translation); - -glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal = false); - -glm::vec3 extractScale(const glm::mat4& matrix); - -float extractUniformScale(const glm::mat4& matrix); - -float extractUniformScale(const glm::vec3& scale); - -/// \return bool are two orientations similar to each other -const float ORIENTATION_SIMILAR_ENOUGH = 5.0f; // 10 degrees in any direction -bool isSimilarOrientation(const glm::quat& orientionA, const glm::quat& orientionB, - float similarEnough = ORIENTATION_SIMILAR_ENOUGH); -const float POSITION_SIMILAR_ENOUGH = 0.1f; // 0.1 meter -bool isSimilarPosition(const glm::vec3& positionA, const glm::vec3& positionB, float similarEnough = POSITION_SIMILAR_ENOUGH); - /// \return bool is the float NaN bool isNaN(float value); -QByteArray createByteArray(const glm::vec3& vector); - QString formatUsecTime(float usecs, int prec = 3); #endif // hifi_SharedUtil_h From 31488e72fe95ff5b459e4d82664ec84cffbb5682 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 08:38:35 -0700 Subject: [PATCH 272/407] repairs for interface build to succeed --- assignment-client/CMakeLists.txt | 3 ++ .../src/avatars/ScriptableAvatar.cpp | 2 ++ cmake/macros/IncludeHifiLibraryHeaders.cmake | 16 +++++++++ cmake/macros/SetupHifiProject.cmake | 6 ++-- cmake/modules/FindLibOVR.cmake | 10 ++++-- domain-server/CMakeLists.txt | 3 +- interface/CMakeLists.txt | 35 +++++-------------- interface/src/devices/CaraFaceTracker.cpp | 2 +- interface/src/renderer/JointState.h | 1 + interface/src/ui/overlays/Base3DOverlay.h | 2 ++ libraries/audio/src/InboundAudioStream.cpp | 2 ++ libraries/avatars/src/AvatarData.cpp | 2 +- libraries/avatars/src/HeadData.cpp | 1 + libraries/avatars/src/Referential.cpp | 2 +- libraries/fbx/src/FBXReader.cpp | 2 +- libraries/metavoxels/src/MetavoxelUtil.cpp | 2 ++ libraries/models/src/ModelItem.cpp | 9 +---- libraries/octree/src/OctreePacketData.cpp | 2 ++ libraries/octree/src/OctreePacketData.h | 1 - libraries/octree/src/OctreeQuery.cpp | 2 +- libraries/particles/src/Particle.cpp | 2 +- libraries/script-engine/src/Quat.cpp | 2 +- 22 files changed, 58 insertions(+), 51 deletions(-) create mode 100644 cmake/macros/IncludeHifiLibraryHeaders.cmake diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 2f3739485a..702c4a68ea 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -9,6 +9,9 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake include("${MACRO_DIR}/SetupHifiProject.cmake") setup_hifi_project(${TARGET_NAME} TRUE) +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} "${ROOT_DIR}") + # link in the shared libraries include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index 150e364ed7..0f721ac98c 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -11,6 +11,8 @@ #include +#include + #include "ScriptableAvatar.h" ScriptableAvatar::ScriptableAvatar(ScriptEngine* scriptEngine) : _scriptEngine(scriptEngine), _animation(NULL) { diff --git a/cmake/macros/IncludeHifiLibraryHeaders.cmake b/cmake/macros/IncludeHifiLibraryHeaders.cmake new file mode 100644 index 0000000000..aa7e1118c6 --- /dev/null +++ b/cmake/macros/IncludeHifiLibraryHeaders.cmake @@ -0,0 +1,16 @@ +# +# IncludeHifiLibraryHeaders.cmake +# cmake/macros +# +# Copyright 2014 High Fidelity, Inc. +# Created by Stephen Birarda on August 8, 2014 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +macro(include_hifi_library_headers LIBRARY ROOT_DIR) + + include_directories("${ROOT_DIR}/libraries/${LIBRARY}/src") + +endmacro(include_hifi_library_headers _library _root_dir) \ No newline at end of file diff --git a/cmake/macros/SetupHifiProject.cmake b/cmake/macros/SetupHifiProject.cmake index ec731859d4..281aa42650 100644 --- a/cmake/macros/SetupHifiProject.cmake +++ b/cmake/macros/SetupHifiProject.cmake @@ -26,9 +26,7 @@ macro(SETUP_HIFI_PROJECT TARGET INCLUDE_QT) add_executable(${TARGET} ${TARGET_SRCS} ${ARGN}) if (${INCLUDE_QT}) - find_package(Qt5Core REQUIRED) - qt5_use_modules(${TARGET} Core) + find_package(Qt5 COMPONENTS Core) + target_link_libraries(${TARGET} Qt5::Core) endif () - - target_link_libraries(${TARGET} ${QT_LIBRARIES}) endmacro() \ No newline at end of file diff --git a/cmake/modules/FindLibOVR.cmake b/cmake/modules/FindLibOVR.cmake index e90afe29e4..505fd90b51 100644 --- a/cmake/modules/FindLibOVR.cmake +++ b/cmake/modules/FindLibOVR.cmake @@ -29,6 +29,8 @@ include(SelectLibraryConfigurations) if (APPLE) find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/MacOS/Debug HINTS ${OCULUS_SEARCH_DIRS}) find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/MacOS/Release HINTS ${OCULUS_SEARCH_DIRS}) + find_library(ApplicationServices ApplicationServices) + find_library(IOKit IOKit) elseif (UNIX) find_library(UDEV_LIBRARY_RELEASE udev /usr/lib/x86_64-linux-gnu/) find_library(XINERAMA_LIBRARY_RELEASE Xinerama /usr/lib/x86_64-linux-gnu/) @@ -53,12 +55,16 @@ endif () select_library_configurations(LIBOVR) set(LIBOVR_LIBRARIES "${LIBOVR_LIBRARY}") -if (UNIX AND NOT APPLE) +if (APPLE) + set(LIBOVR_LIBRARIES "${LIBOVR_LIBRARIES}" ${IOKit} ${ApplicationServices}) +elseif (UNIX) set(LIBOVR_LIBRARIES "${LIBOVR_LIBRARIES}" "${UDEV_LIBRARY}" "${XINERAMA_LIBRARY}") endif () include(FindPackageHandleStandardArgs) -if (UNIX AND NOT APPLE) +if (APPLE) + find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES IOKit ApplicationServices) +elseif (UNIX) find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES UDEV_LIBRARY XINERAMA_LIBRARY) else () find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES) diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index 656760957d..4a030179e1 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -7,7 +7,6 @@ set(MACRO_DIR "${ROOT_DIR}/cmake/macros") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") include(${MACRO_DIR}/SetupHifiProject.cmake) - setup_hifi_project(${TARGET_NAME} TRUE) # remove and then copy the files for the webserver @@ -34,5 +33,5 @@ if (WIN32) add_definitions(-Dssize_t=long) endif () -find_package(Qt5 COMPONENTS Network) +find_package(Qt5 COMPONENTS Network Widgets) target_link_libraries(${TARGET_NAME} Qt5::Network) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index e624388408..f30fcc68ff 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -52,7 +52,7 @@ foreach(SUBDIR avatar devices renderer ui starfield location scripting voxels pa set(INTERFACE_SRCS ${INTERFACE_SRCS} "${SUBDIR_SRCS}") endforeach(SUBDIR) -# find_package(Qt5 COMPONENTS Core Gui Multimedia Network OpenGL Script Svg WebKit WebKitWidgets Xml UiTools) +find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Script Svg WebKitWidgets) # grab the ui files in resources/ui file (GLOB_RECURSE QT_UI_FILES ui/*.ui) @@ -180,8 +180,8 @@ endif () include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes") target_link_libraries( - ${TARGET_NAME} - "${ZLIB_LIBRARIES}" + ${TARGET_NAME} "${ZLIB_LIBRARIES}" + Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL Qt5::Script Qt5::Svg Qt5::WebKitWidgets ) # assume we are using a Qt build without bearer management @@ -189,30 +189,11 @@ add_definitions(-DQT_NO_BEARERMANAGEMENT) if (APPLE) # link in required OS X frameworks and include the right GL headers - # find_library(AppKit AppKit) - # find_library(CoreAudio CoreAudio) - # find_library(CoreServices CoreServices) - # find_library(Carbon Carbon) - # find_library(Foundation Foundation) - # find_library(GLUT GLUT) - # find_library(OpenGL OpenGL) - # find_library(IOKit IOKit) - # find_library(QTKit QTKit) - # find_library(QuartzCore QuartzCore) - # - # target_link_libraries( - # ${TARGET_NAME} - # ${AppKit} - # ${CoreAudio} - # ${CoreServices} - # ${Carbon} - # ${Foundation} - # ${GLUT} - # ${OpenGL} - # ${IOKit} - # ${QTKit} - # ${QuartzCore} - # ) + find_library(CoreAudio CoreAudio) + find_library(GLUT GLUT) + find_library(OpenGL OpenGL) + + target_link_libraries(${TARGET_NAME} ${CoreAudio} ${GLUT} ${OpenGL}) # install command for OS X bundle INSTALL(TARGETS ${TARGET_NAME} diff --git a/interface/src/devices/CaraFaceTracker.cpp b/interface/src/devices/CaraFaceTracker.cpp index c7ae322ae8..27cf3b175b 100644 --- a/interface/src/devices/CaraFaceTracker.cpp +++ b/interface/src/devices/CaraFaceTracker.cpp @@ -10,7 +10,7 @@ // #include "CaraFaceTracker.h" -#include +#include //qt #include diff --git a/interface/src/renderer/JointState.h b/interface/src/renderer/JointState.h index 81591e816b..21961ba48c 100644 --- a/interface/src/renderer/JointState.h +++ b/interface/src/renderer/JointState.h @@ -16,6 +16,7 @@ #include #include +#include #include class AngularConstraint; diff --git a/interface/src/ui/overlays/Base3DOverlay.h b/interface/src/ui/overlays/Base3DOverlay.h index e2dcb82454..ffe73f0023 100644 --- a/interface/src/ui/overlays/Base3DOverlay.h +++ b/interface/src/ui/overlays/Base3DOverlay.h @@ -11,6 +11,8 @@ #ifndef hifi_Base3DOverlay_h #define hifi_Base3DOverlay_h +#include + #include "Overlay.h" class Base3DOverlay : public Overlay { diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 0cd9be4a18..ba8d9481b5 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "InboundAudioStream.h" #include "PacketHeaders.h" diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 96a5f2425b..039ccae4e9 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libraries/avatars/src/HeadData.cpp b/libraries/avatars/src/HeadData.cpp index b29277ddeb..538085af30 100644 --- a/libraries/avatars/src/HeadData.cpp +++ b/libraries/avatars/src/HeadData.cpp @@ -11,6 +11,7 @@ #include +#include #include #include "AvatarData.h" diff --git a/libraries/avatars/src/Referential.cpp b/libraries/avatars/src/Referential.cpp index a5a7e7e3e5..784ad3963c 100644 --- a/libraries/avatars/src/Referential.cpp +++ b/libraries/avatars/src/Referential.cpp @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include #include "AvatarData.h" #include "Referential.h" diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index cf726800a1..1a152dc217 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -23,9 +23,9 @@ #include #include +#include #include #include -#include #include diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index e414c8ebb9..2b46330961 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -24,6 +24,8 @@ #include #include +#include + #include "MetavoxelUtil.h" #include "ScriptCache.h" #include "StreamUtils.h" diff --git a/libraries/models/src/ModelItem.cpp b/libraries/models/src/ModelItem.cpp index 2a3a88fb65..d6cd8aebc5 100644 --- a/libraries/models/src/ModelItem.cpp +++ b/libraries/models/src/ModelItem.cpp @@ -11,19 +11,12 @@ #include +#include #include #include -#include // usecTimestampNow() #include #include - -// This is not ideal, but adding script-engine as a linked library, will cause a circular reference -// I'm open to other potential solutions. Could we change cmake to allow libraries to reference each others -// headers, but not link to each other, this is essentially what this construct is doing, but would be -// better to add includes to the include path, but not link -#include "../../script-engine/src/ScriptEngine.h" - #include "ModelsScriptingInterface.h" #include "ModelItem.h" #include "ModelTree.h" diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index b54a87bef8..718f2534f8 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -9,7 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include + #include "OctreePacketData.h" bool OctreePacketData::_debug = false; diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index d704923a11..9a6ebfa9ff 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -22,7 +22,6 @@ #ifndef hifi_OctreePacketData_h #define hifi_OctreePacketData_h -#include #include "OctreeConstants.h" #include "OctreeElement.h" diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 687dd18037..94d9bf458e 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include #include "OctreeConstants.h" #include "OctreeQuery.h" diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 5fffefd8b1..fef2b95fdc 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -13,7 +13,7 @@ #include #include -#include // usecTimestampNow() +#include #include #include diff --git a/libraries/script-engine/src/Quat.cpp b/libraries/script-engine/src/Quat.cpp index 66281883f0..5985858026 100644 --- a/libraries/script-engine/src/Quat.cpp +++ b/libraries/script-engine/src/Quat.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include "Quat.h" From 107cbc3f87205815a6ec97dd035a7538da2d523b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 09:22:19 -0700 Subject: [PATCH 273/407] more simplification of hifi macros to find libraries --- CMakeLists.txt | 10 ++++++++ assignment-client/CMakeLists.txt | 37 +++++++++++------------------- cmake/macros/IncludeGLM.cmake | 4 ++-- cmake/macros/LinkHifiLibrary.cmake | 10 ++++---- domain-server/CMakeLists.txt | 14 +++-------- 5 files changed, 35 insertions(+), 40 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 578c36841d..9f033e5184 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,16 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed. set(CMAKE_AUTOMOC ON) +set(HIFI_LIBRARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries") +set(MACRO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macros") +# setup for find modules +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/") + +file(GLOB HIFI_CUSTOM_MACROS "cmake/macros/*.cmake") +foreach(CUSTOM_MACRO ${HIFI_CUSTOM_MACROS}) + include(${CUSTOM_MACRO}) +endforeach() + # targets on all platforms add_subdirectory(assignment-client) add_subdirectory(domain-server) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 702c4a68ea..2d7d43227a 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -1,32 +1,23 @@ set(TARGET_NAME assignment-client) -set(ROOT_DIR ..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") - -include("${MACRO_DIR}/SetupHifiProject.cmake") setup_hifi_project(${TARGET_NAME} TRUE) -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} "${ROOT_DIR}") +include_glm(${TARGET_NAME}) # link in the shared libraries -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(audio ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(avatars ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(particles ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(models ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(script-engine ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(embedded-webserver ${TARGET_NAME} "${ROOT_DIR}") +link_hifi_library(shared ${TARGET_NAME}) +link_hifi_library(audio ${TARGET_NAME}) +link_hifi_library(avatars ${TARGET_NAME}) +link_hifi_library(octree ${TARGET_NAME}) +link_hifi_library(voxels ${TARGET_NAME}) +link_hifi_library(fbx ${TARGET_NAME}) +link_hifi_library(particles ${TARGET_NAME}) +link_hifi_library(models ${TARGET_NAME}) +link_hifi_library(metavoxels ${TARGET_NAME}) +link_hifi_library(networking ${TARGET_NAME}) +link_hifi_library(animation ${TARGET_NAME}) +link_hifi_library(script-engine ${TARGET_NAME}) +link_hifi_library(embedded-webserver ${TARGET_NAME}) if (UNIX) target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES} ${CMAKE_DL_LIBS}) diff --git a/cmake/macros/IncludeGLM.cmake b/cmake/macros/IncludeGLM.cmake index a31324993e..ec7816770f 100644 --- a/cmake/macros/IncludeGLM.cmake +++ b/cmake/macros/IncludeGLM.cmake @@ -7,7 +7,7 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # -macro(INCLUDE_GLM TARGET ROOT_DIR) +macro(INCLUDE_GLM TARGET) find_package(GLM REQUIRED) include_directories("${GLM_INCLUDE_DIRS}") @@ -16,4 +16,4 @@ macro(INCLUDE_GLM TARGET ROOT_DIR) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${GLM_INCLUDE_DIRS}") endif () -endmacro(INCLUDE_GLM _target _root_dir) \ No newline at end of file +endmacro(INCLUDE_GLM _target) \ No newline at end of file diff --git a/cmake/macros/LinkHifiLibrary.cmake b/cmake/macros/LinkHifiLibrary.cmake index 227ddf066a..95af4c6fd0 100644 --- a/cmake/macros/LinkHifiLibrary.cmake +++ b/cmake/macros/LinkHifiLibrary.cmake @@ -7,13 +7,15 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # -macro(LINK_HIFI_LIBRARY LIBRARY TARGET ROOT_DIR) +macro(LINK_HIFI_LIBRARY LIBRARY TARGET) + + file(RELATIVE_PATH RELATIVE_LIBRARY_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}/${LIBRARY}") if (NOT TARGET ${LIBRARY}) - add_subdirectory("${ROOT_DIR}/libraries/${LIBRARY}" "${ROOT_DIR}/libraries/${LIBRARY}") + add_subdirectory(${RELATIVE_LIBRARY_PATH} ${RELATIVE_LIBRARY_PATH}) endif () - include_directories("${ROOT_DIR}/libraries/${LIBRARY}/src") + include_directories("${HIFI_LIBRARY_DIR}/${LIBRARY}/src") add_dependencies(${TARGET} ${LIBRARY}) @@ -25,4 +27,4 @@ macro(LINK_HIFI_LIBRARY LIBRARY TARGET ROOT_DIR) target_link_libraries(${TARGET} ${LIBRARY}) endif () -endmacro(LINK_HIFI_LIBRARY _library _target _root_dir) \ No newline at end of file +endmacro(LINK_HIFI_LIBRARY _library _target) \ No newline at end of file diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index 4a030179e1..e98cee7437 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -1,12 +1,5 @@ set(TARGET_NAME domain-server) -set(ROOT_DIR ..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") - -include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME} TRUE) # remove and then copy the files for the webserver @@ -19,10 +12,9 @@ add_custom_command(TARGET ${TARGET_NAME} POST_BUILD $/resources/web) # link the shared hifi library -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(embedded-webserver ${TARGET_NAME} "${ROOT_DIR}") +link_hifi_library(networking ${TARGET_NAME}) +link_hifi_library(shared ${TARGET_NAME}) +link_hifi_library(embedded-webserver ${TARGET_NAME}) IF (WIN32) target_link_libraries(${TARGET_NAME} Winmm Ws2_32) From 87cf262b9e49f48ca760f3b34f4d8108fbb4a78f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 09:38:17 -0700 Subject: [PATCH 274/407] get to successful cmake after library link macro changes --- assignment-client/CMakeLists.txt | 14 +----------- cmake/macros/LinkHifiLibraries.cmake | 34 ++++++++++++++++++++++++++++ cmake/macros/LinkHifiLibrary.cmake | 30 ------------------------ domain-server/CMakeLists.txt | 4 +--- interface/CMakeLists.txt | 16 +------------ libraries/audio/CMakeLists.txt | 16 +------------ libraries/metavoxels/CMakeLists.txt | 12 +--------- libraries/octree/CMakeLists.txt | 12 +--------- libraries/shared/CMakeLists.txt | 19 ---------------- tests/audio/CMakeLists.txt | 22 +----------------- tests/jitter/CMakeLists.txt | 24 +------------------- tests/metavoxels/CMakeLists.txt | 17 +------------- tests/networking/CMakeLists.txt | 24 +------------------- tests/octree/CMakeLists.txt | 29 +----------------------- tests/physics/CMakeLists.txt | 27 +--------------------- tests/shared/CMakeLists.txt | 28 +---------------------- tools/bitstream2json/CMakeLists.txt | 25 +------------------- tools/json2bitstream/CMakeLists.txt | 25 +------------------- voxel-edit/CMakeLists.txt | 32 -------------------------- 19 files changed, 49 insertions(+), 361 deletions(-) create mode 100644 cmake/macros/LinkHifiLibraries.cmake delete mode 100644 cmake/macros/LinkHifiLibrary.cmake diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 2d7d43227a..628e473853 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -5,19 +5,7 @@ setup_hifi_project(${TARGET_NAME} TRUE) include_glm(${TARGET_NAME}) # link in the shared libraries -link_hifi_library(shared ${TARGET_NAME}) -link_hifi_library(audio ${TARGET_NAME}) -link_hifi_library(avatars ${TARGET_NAME}) -link_hifi_library(octree ${TARGET_NAME}) -link_hifi_library(voxels ${TARGET_NAME}) -link_hifi_library(fbx ${TARGET_NAME}) -link_hifi_library(particles ${TARGET_NAME}) -link_hifi_library(models ${TARGET_NAME}) -link_hifi_library(metavoxels ${TARGET_NAME}) -link_hifi_library(networking ${TARGET_NAME}) -link_hifi_library(animation ${TARGET_NAME}) -link_hifi_library(script-engine ${TARGET_NAME}) -link_hifi_library(embedded-webserver ${TARGET_NAME}) +link_hifi_libraries(${TARGET_NAME} audio avatars octree voxels fbx particles models metavoxels networking animation script-engine embedded-webserver) if (UNIX) target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES} ${CMAKE_DL_LIBS}) diff --git a/cmake/macros/LinkHifiLibraries.cmake b/cmake/macros/LinkHifiLibraries.cmake new file mode 100644 index 0000000000..cf7499c763 --- /dev/null +++ b/cmake/macros/LinkHifiLibraries.cmake @@ -0,0 +1,34 @@ +# +# LinkHifiLibrary.cmake +# +# Copyright 2013 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 +# + +macro(LINK_HIFI_LIBRARIES TARGET LIBRARIES) + + file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}") + + foreach(HIFI_LIBRARY ${LIBRARIES}) + + if (NOT TARGET ${HIFI_LIBRARY}) + add_subdirectory("${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}" "${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}") + endif () + + include_directories("${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src") + + add_dependencies(${TARGET} ${HIFI_LIBRARY}) + + get_target_property(LINKED_TARGET_DEPENDENCY_LIBRARIES ${HIFI_LIBRARY} DEPENDENCY_LIBRARIES) + + if (LINKED_TARGET_DEPENDENCY_LIBRARIES) + target_link_libraries(${TARGET} ${HIFI_LIBRARY} ${LINKED_TARGET_DEPENDENCY_LIBRARIES}) + else () + target_link_libraries(${TARGET} ${HIFI_LIBRARY}) + endif () + + endforeach() + +endmacro(LINK_HIFI_LIBRARIES _target _libraries) \ No newline at end of file diff --git a/cmake/macros/LinkHifiLibrary.cmake b/cmake/macros/LinkHifiLibrary.cmake deleted file mode 100644 index 95af4c6fd0..0000000000 --- a/cmake/macros/LinkHifiLibrary.cmake +++ /dev/null @@ -1,30 +0,0 @@ -# -# LinkHifiLibrary.cmake -# -# Copyright 2013 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 -# - -macro(LINK_HIFI_LIBRARY LIBRARY TARGET) - - file(RELATIVE_PATH RELATIVE_LIBRARY_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}/${LIBRARY}") - - if (NOT TARGET ${LIBRARY}) - add_subdirectory(${RELATIVE_LIBRARY_PATH} ${RELATIVE_LIBRARY_PATH}) - endif () - - include_directories("${HIFI_LIBRARY_DIR}/${LIBRARY}/src") - - add_dependencies(${TARGET} ${LIBRARY}) - - get_target_property(LINKED_TARGET_DEPENDENCY_LIBRARIES ${LIBRARY} DEPENDENCY_LIBRARIES) - - if (LINKED_TARGET_DEPENDENCY_LIBRARIES) - target_link_libraries(${TARGET} ${LIBRARY} ${LINKED_TARGET_DEPENDENCY_LIBRARIES}) - else () - target_link_libraries(${TARGET} ${LIBRARY}) - endif () - -endmacro(LINK_HIFI_LIBRARY _library _target) \ No newline at end of file diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index e98cee7437..ae130af5ed 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -12,9 +12,7 @@ add_custom_command(TARGET ${TARGET_NAME} POST_BUILD $/resources/web) # link the shared hifi library -link_hifi_library(networking ${TARGET_NAME}) -link_hifi_library(shared ${TARGET_NAME}) -link_hifi_library(embedded-webserver ${TARGET_NAME}) +link_hifi_libraries(${TARGET_NAME} embedded-webserver networking shared) IF (WIN32) target_link_libraries(${TARGET_NAME} Winmm Ws2_32) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index f30fcc68ff..ed280846fe 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -97,22 +97,8 @@ endif() # create the executable, make it a bundle on OS X add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM}) -# link in the hifi shared library -include(${MACRO_DIR}/LinkHifiLibrary.cmake) - # link required hifi libraries -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(particles ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(models ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(avatars ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(audio ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(script-engine ${TARGET_NAME} "${ROOT_DIR}") +link_hifi_libraries(${TARGET_NAME} shared octree voxels fbx metavoxels networking particles models avatars audio animation script-engine) # find any optional and required libraries find_package(Faceplus) diff --git a/libraries/audio/CMakeLists.txt b/libraries/audio/CMakeLists.txt index ace5f9292c..73d15f0b73 100644 --- a/libraries/audio/CMakeLists.txt +++ b/libraries/audio/CMakeLists.txt @@ -1,24 +1,10 @@ -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - set(TARGET_NAME audio) -find_package(Qt5 COMPONENTS Script) -include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}") - -# set up the external glm library -include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} "${ROOT_DIR}") -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") +link_hifi_libraries(${TARGET_NAME} networking shared) find_package(Qt5 COMPONENTS Network) diff --git a/libraries/metavoxels/CMakeLists.txt b/libraries/metavoxels/CMakeLists.txt index 799a549a3b..88b74194ac 100644 --- a/libraries/metavoxels/CMakeLists.txt +++ b/libraries/metavoxels/CMakeLists.txt @@ -1,22 +1,12 @@ -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - set(TARGET_NAME metavoxels) -include(${MACRO_DIR}/AutoMTC.cmake) auto_mtc(${TARGET_NAME} "${ROOT_DIR}") -include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME} "${AUTOMTC_SRC}") # link in the networking library -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") +link_hifi_libraries(${TARGET_NAME} networking) -include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} "${ROOT_DIR}") find_package(Qt5 COMPONENTS Network Script Widgets) diff --git a/libraries/octree/CMakeLists.txt b/libraries/octree/CMakeLists.txt index d0beade108..efdb1bc70a 100644 --- a/libraries/octree/CMakeLists.txt +++ b/libraries/octree/CMakeLists.txt @@ -1,20 +1,10 @@ -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - set(TARGET_NAME octree) -include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} "${ROOT_DIR}") -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") +link_hifi_libraries(${TARGET_NAME} shared networking) # link ZLIB find_package(ZLIB) diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index 6badb10f8e..b8e34739b8 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -1,25 +1,6 @@ -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - set(TARGET_NAME shared) -project(${TARGET_NAME}) - -include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -# include GLM -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} "${ROOT_DIR}") - -# link required libraries on UNIX -if (APPLE) - find_library(CoreServices CoreServices) - set(DEPENDENCY_LIBRARIES ${CoreServices}) -elseif (UNIX) - find_package(Threads REQUIRED) - set(DEPENDENCY_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}") -endif () - find_package(Qt5 COMPONENTS Network Widgets) # bubble up the libraries we are dependent on and link them to ourselves diff --git a/tests/audio/CMakeLists.txt b/tests/audio/CMakeLists.txt index b7375a0086..15da1afaa1 100644 --- a/tests/audio/CMakeLists.txt +++ b/tests/audio/CMakeLists.txt @@ -1,32 +1,12 @@ set(TARGET_NAME audio-tests) -set(ROOT_DIR ../..) -set(MACRO_DIR ${ROOT_DIR}/cmake/macros) - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - -#find_package(Qt5Network REQUIRED) -#find_package(Qt5Script REQUIRED) -#find_package(Qt5Widgets REQUIRED) - -include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME} TRUE) -include(${MACRO_DIR}/AutoMTC.cmake) -auto_mtc(${TARGET_NAME} ${ROOT_DIR}) - -#qt5_use_modules(${TARGET_NAME} Network Script Widgets) - #include glm -include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} ${ROOT_DIR}) # link in the shared libraries -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_libraries(${TARGET_NAME} shared audio networking) IF (WIN32) target_link_libraries(${TARGET_NAME} Winmm Ws2_32) diff --git a/tests/jitter/CMakeLists.txt b/tests/jitter/CMakeLists.txt index 8000e4af50..3b1d544690 100644 --- a/tests/jitter/CMakeLists.txt +++ b/tests/jitter/CMakeLists.txt @@ -1,31 +1,9 @@ set(TARGET_NAME jitter-tests) -set(ROOT_DIR ../..) -set(MACRO_DIR ${ROOT_DIR}/cmake/macros) - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - -#find_package(Qt5Network REQUIRED) -#find_package(Qt5Script REQUIRED) -#find_package(Qt5Widgets REQUIRED) - -include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME} TRUE) -#include(${MACRO_DIR}/AutoMTC.cmake) -#auto_mtc(${TARGET_NAME} ${ROOT_DIR}) - -#qt5_use_modules(${TARGET_NAME} Network Script Widgets) - -#include glm - because it's a dependency of shared utils... -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} ${ROOT_DIR}) - # link in the shared libraries -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_libraries(${TARGET_NAME} shared networking) IF (WIN32) target_link_libraries(${TARGET_NAME} Winmm Ws2_32) diff --git a/tests/metavoxels/CMakeLists.txt b/tests/metavoxels/CMakeLists.txt index f4c0695362..233988f849 100644 --- a/tests/metavoxels/CMakeLists.txt +++ b/tests/metavoxels/CMakeLists.txt @@ -1,28 +1,13 @@ set(TARGET_NAME metavoxel-tests) -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - find_package(Qt5 COMPONENTS Network Script Widgets) -include(${MACRO_DIR}/AutoMTC.cmake) auto_mtc(${TARGET_NAME} "${ROOT_DIR}") -include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME} TRUE "${AUTOMTC_SRC}") -#include glm -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} "${ROOT_DIR}") - # link in the shared libraries -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") +link_hifi_libraries(${TARGET_NAME} metavoxels networking shared) IF (WIN32) target_link_libraries(${TARGET_NAME} Winmm Ws2_32) diff --git a/tests/networking/CMakeLists.txt b/tests/networking/CMakeLists.txt index 64b5f273d1..819229d28f 100644 --- a/tests/networking/CMakeLists.txt +++ b/tests/networking/CMakeLists.txt @@ -1,31 +1,9 @@ set(TARGET_NAME networking-tests) -set(ROOT_DIR ../..) -set(MACRO_DIR ${ROOT_DIR}/cmake/macros) - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - -#find_package(Qt5Network REQUIRED) -#find_package(Qt5Script REQUIRED) -#find_package(Qt5Widgets REQUIRED) - -include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME} TRUE) -include(${MACRO_DIR}/AutoMTC.cmake) -auto_mtc(${TARGET_NAME} ${ROOT_DIR}) - -#qt5_use_modules(${TARGET_NAME} Network Script Widgets) - -#include glm -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} ${ROOT_DIR}) - # link in the shared libraries -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_libraries(${TARGET_NAME} shared networking) IF (WIN32) target_link_libraries(${TARGET_NAME} Winmm Ws2_32) diff --git a/tests/octree/CMakeLists.txt b/tests/octree/CMakeLists.txt index c7a6500b6d..a4888b2c66 100644 --- a/tests/octree/CMakeLists.txt +++ b/tests/octree/CMakeLists.txt @@ -1,36 +1,9 @@ set(TARGET_NAME octree-tests) -set(ROOT_DIR ../..) -set(MACRO_DIR ${ROOT_DIR}/cmake/macros) - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - -find_package(Qt5Network REQUIRED) -find_package(Qt5Script REQUIRED) -find_package(Qt5Widgets REQUIRED) - -include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME} TRUE) -include(${MACRO_DIR}/AutoMTC.cmake) -auto_mtc(${TARGET_NAME} ${ROOT_DIR}) - -qt5_use_modules(${TARGET_NAME} Network Script Widgets) - -#include glm -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} ${ROOT_DIR}) - # link in the shared libraries -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(models ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(animation ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(fbx ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_libraries(${TARGET_NAME} octree) IF (WIN32) # add a definition for ssize_t so that windows doesn't bail diff --git a/tests/physics/CMakeLists.txt b/tests/physics/CMakeLists.txt index 643d318f7d..2161723619 100644 --- a/tests/physics/CMakeLists.txt +++ b/tests/physics/CMakeLists.txt @@ -1,32 +1,7 @@ set(TARGET_NAME physics-tests) -set(ROOT_DIR ../..) -set(MACRO_DIR ${ROOT_DIR}/cmake/macros) - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - -#find_package(Qt5Network REQUIRED) -#find_package(Qt5Script REQUIRED) -#find_package(Qt5Widgets REQUIRED) - -include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME} TRUE) -include(${MACRO_DIR}/AutoMTC.cmake) -auto_mtc(${TARGET_NAME} ${ROOT_DIR}) - -#qt5_use_modules(${TARGET_NAME} Network Script Widgets) - -#include glm -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} ${ROOT_DIR}) - # link in the shared libraries -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) - -IF (WIN32) - #target_link_libraries(${TARGET_NAME} Winmm Ws2_32) -ENDIF(WIN32) +link_hifi_libraries(${TARGET_NAME} shared) diff --git a/tests/shared/CMakeLists.txt b/tests/shared/CMakeLists.txt index 0785314d36..bea8448f5e 100644 --- a/tests/shared/CMakeLists.txt +++ b/tests/shared/CMakeLists.txt @@ -1,32 +1,6 @@ set(TARGET_NAME shared-tests) -set(ROOT_DIR ../..) -set(MACRO_DIR ${ROOT_DIR}/cmake/macros) - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - -#find_package(Qt5Network REQUIRED) -#find_package(Qt5Script REQUIRED) -#find_package(Qt5Widgets REQUIRED) - -include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME} TRUE) -include(${MACRO_DIR}/AutoMTC.cmake) -auto_mtc(${TARGET_NAME} ${ROOT_DIR}) - -#qt5_use_modules(${TARGET_NAME} Network Script Widgets) - -#include glm -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} ${ROOT_DIR}) - # link in the shared libraries -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) - -IF (WIN32) - #target_link_libraries(${TARGET_NAME} Winmm Ws2_32) -ENDIF(WIN32) - +link_hifi_libraries(${TARGET_NAME} shared) diff --git a/tools/bitstream2json/CMakeLists.txt b/tools/bitstream2json/CMakeLists.txt index 576406e787..3b3a65c259 100644 --- a/tools/bitstream2json/CMakeLists.txt +++ b/tools/bitstream2json/CMakeLists.txt @@ -1,25 +1,2 @@ set(TARGET_NAME bitstream2json) - -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - -find_package(Qt5 COMPONENTS Network Script Widgets) - -include(${MACRO_DIR}/SetupHifiProject.cmake) -setup_hifi_project(${TARGET_NAME} TRUE) - -link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") - -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} "${ROOT_DIR}") - -IF (WIN32) - target_link_libraries(${TARGET_NAME} Winmm Ws2_32) -ENDIF(WIN32) - -target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script) +setup_hifi_project(${TARGET_NAME} TRUE) \ No newline at end of file diff --git a/tools/json2bitstream/CMakeLists.txt b/tools/json2bitstream/CMakeLists.txt index 5ff4673298..452f845356 100644 --- a/tools/json2bitstream/CMakeLists.txt +++ b/tools/json2bitstream/CMakeLists.txt @@ -1,25 +1,2 @@ set(TARGET_NAME json2bitstream) - -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - -find_package(Qt5 COMPONENTS Network Script Widgets) - -include(${MACRO_DIR}/SetupHifiProject.cmake) -setup_hifi_project(${TARGET_NAME} TRUE) - -link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") - -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} "${ROOT_DIR}") - -IF (WIN32) - target_link_libraries(${TARGET_NAME} Winmm Ws2_32) -ENDIF(WIN32) - -target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script) +setup_hifi_project(${TARGET_NAME} TRUE) \ No newline at end of file diff --git a/voxel-edit/CMakeLists.txt b/voxel-edit/CMakeLists.txt index 006dfb0599..8c315c92a0 100644 --- a/voxel-edit/CMakeLists.txt +++ b/voxel-edit/CMakeLists.txt @@ -1,39 +1,7 @@ set(TARGET_NAME voxel-edit) -set(ROOT_DIR ..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") - -# set up the external glm library -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} "${ROOT_DIR}") - -find_package(Qt5Script REQUIRED) - -include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME} TRUE) -# link in the shared library -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") - -# link in the hifi octree library -link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") - -# link in the hifi voxels library -link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") - -# link in the hifi networking library -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") - -IF (WIN32) - target_link_libraries(${TARGET_NAME} Winmm Ws2_32) -ENDIF(WIN32) - -target_link_libraries(${TARGET_NAME} Qt5::Script) - # add a definition for ssize_t so that windows doesn't bail if (WIN32) add_definitions(-Dssize_t=long) From 93b6f167f5d5b5ee5fd5aeae96b9b85334aefc0c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 09:51:20 -0700 Subject: [PATCH 275/407] change more CMakeLists to use simplified hifi library linker --- cmake/macros/LinkHifiLibraries.cmake | 7 ++++--- libraries/animation/CMakeLists.txt | 11 +---------- libraries/avatars/CMakeLists.txt | 15 +-------------- libraries/fbx/CMakeLists.txt | 14 +------------- libraries/models/CMakeLists.txt | 20 +------------------- libraries/networking/CMakeLists.txt | 6 ++---- libraries/particles/CMakeLists.txt | 15 +-------------- libraries/script-engine/CMakeLists.txt | 17 +---------------- libraries/voxels/CMakeLists.txt | 16 ++-------------- 9 files changed, 14 insertions(+), 107 deletions(-) diff --git a/cmake/macros/LinkHifiLibraries.cmake b/cmake/macros/LinkHifiLibraries.cmake index cf7499c763..4c6e2c3215 100644 --- a/cmake/macros/LinkHifiLibraries.cmake +++ b/cmake/macros/LinkHifiLibraries.cmake @@ -7,12 +7,13 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # -macro(LINK_HIFI_LIBRARIES TARGET LIBRARIES) +macro(LINK_HIFI_LIBRARIES TARGET) file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}") - foreach(HIFI_LIBRARY ${LIBRARIES}) - + set(LIBRARIES_TO_LINK ${ARGN}) + + foreach(HIFI_LIBRARY ${LIBRARIES_TO_LINK}) if (NOT TARGET ${HIFI_LIBRARY}) add_subdirectory("${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}" "${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}") endif () diff --git a/libraries/animation/CMakeLists.txt b/libraries/animation/CMakeLists.txt index 7891c65dcc..186067ba3f 100644 --- a/libraries/animation/CMakeLists.txt +++ b/libraries/animation/CMakeLists.txt @@ -1,17 +1,8 @@ -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - set(TARGET_NAME animation) -include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") +link_hifi_libraries(${TARGET_NAME} shared fbx) find_package(Qt5 COMPONENTS Network Script) diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index 1300a2e733..10507f7836 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -1,23 +1,10 @@ -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - set(TARGET_NAME avatars) -include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} "${ROOT_DIR}") -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") - -link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") +link_hifi_libraries(${TARGET_NAME} shared octree voxels networking) find_package(Qt5 COMPONENTS Network Script) diff --git a/libraries/fbx/CMakeLists.txt b/libraries/fbx/CMakeLists.txt index ba51fe2e06..3f6a969cbc 100644 --- a/libraries/fbx/CMakeLists.txt +++ b/libraries/fbx/CMakeLists.txt @@ -1,22 +1,10 @@ -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - set(TARGET_NAME fbx) -include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} "${ROOT_DIR}") -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") +link_hifi_libraries(${TARGET_NAME} shared networking octree voxels) # link ZLIB find_package(ZLIB) diff --git a/libraries/models/CMakeLists.txt b/libraries/models/CMakeLists.txt index 8128741ef6..20f6ef1ef8 100644 --- a/libraries/models/CMakeLists.txt +++ b/libraries/models/CMakeLists.txt @@ -1,28 +1,10 @@ -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - set(TARGET_NAME models) -find_package(Qt5Widgets REQUIRED) - -include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} "${ROOT_DIR}") -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") - -# for streamable -link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") +link_hifi_libraries(${TARGET_NAME} shared octree fbx networking animation) find_package(Qt5 COMPONENTS Network Script) diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index 7bd210623b..f41d410ce8 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -1,11 +1,9 @@ -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - set(TARGET_NAME networking) -include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) +link_hifi_libraries(${TARGET_NAME} shared) + find_package(Qt5 COMPONENTS Network) # set a property indicating the libraries we are dependent on and link them to ourselves diff --git a/libraries/particles/CMakeLists.txt b/libraries/particles/CMakeLists.txt index 54398ac252..0f8a555cb5 100644 --- a/libraries/particles/CMakeLists.txt +++ b/libraries/particles/CMakeLists.txt @@ -1,23 +1,10 @@ -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - set(TARGET_NAME particles) -include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} "${ROOT_DIR}") -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") +link_hifi_libraries(${TARGET_NAME} shared octree fbx networking animation) find_package(Qt5 COMPONENTS Gui Network Script) diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 1b0199977f..f9b4b7d60f 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -1,25 +1,10 @@ -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - set(TARGET_NAME script-engine) -include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} "${ROOT_DIR}") -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(particles ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(models ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") +link_hifi_libraries(${TARGET_NAME} shared octree voxels fbx particles models animation) find_package(Qt5 COMPONENTS Gui Network Script Widgets) diff --git a/libraries/voxels/CMakeLists.txt b/libraries/voxels/CMakeLists.txt index 2ae35da2c0..c421f6514f 100644 --- a/libraries/voxels/CMakeLists.txt +++ b/libraries/voxels/CMakeLists.txt @@ -1,26 +1,14 @@ -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - set(TARGET_NAME voxels) -find_package(Qt5 COMPONENTS Widgets Script) - -include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} "${ROOT_DIR}") -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") +link_hifi_libraries(${TARGET_NAME} shared octree networking) # link ZLIB find_package(ZLIB) +find_package(Qt5 COMPONENTS Widgets Script) include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets Qt5::Script) From 1a71d655b9de1974696574e69347284b035d4007 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 09:58:27 -0700 Subject: [PATCH 276/407] more cmake cleanup to remove ROOT_DIR passing --- CMakeLists.txt | 2 ++ assignment-client/CMakeLists.txt | 5 ++++- cmake/macros/AutoMTC.cmake | 2 +- cmake/macros/IncludeHifiLibraryHeaders.cmake | 4 ++-- interface/CMakeLists.txt | 7 ------- libraries/metavoxels/CMakeLists.txt | 2 +- 6 files changed, 10 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f033e5184..fb54bcbd8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,8 +44,10 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed. set(CMAKE_AUTOMOC ON) +set(ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") set(HIFI_LIBRARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries") set(MACRO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macros") + # setup for find modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/") diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 628e473853..fd11be5122 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -5,7 +5,10 @@ setup_hifi_project(${TARGET_NAME} TRUE) include_glm(${TARGET_NAME}) # link in the shared libraries -link_hifi_libraries(${TARGET_NAME} audio avatars octree voxels fbx particles models metavoxels networking animation script-engine embedded-webserver) +link_hifi_libraries(${TARGET_NAME} + audio avatars octree voxels fbx particles models metavoxels + networking animation shared script-engine embedded-webserver +) if (UNIX) target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES} ${CMAKE_DL_LIBS}) diff --git a/cmake/macros/AutoMTC.cmake b/cmake/macros/AutoMTC.cmake index 6f0216de7f..0e376fc176 100644 --- a/cmake/macros/AutoMTC.cmake +++ b/cmake/macros/AutoMTC.cmake @@ -8,7 +8,7 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # -macro(AUTO_MTC TARGET ROOT_DIR) +macro(AUTO_MTC TARGET) set(AUTOMTC_SRC ${TARGET}_automtc.cpp) file(GLOB INCLUDE_FILES src/*.h) diff --git a/cmake/macros/IncludeHifiLibraryHeaders.cmake b/cmake/macros/IncludeHifiLibraryHeaders.cmake index aa7e1118c6..7ac31f5259 100644 --- a/cmake/macros/IncludeHifiLibraryHeaders.cmake +++ b/cmake/macros/IncludeHifiLibraryHeaders.cmake @@ -9,8 +9,8 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # -macro(include_hifi_library_headers LIBRARY ROOT_DIR) +macro(include_hifi_library_headers LIBRARY) - include_directories("${ROOT_DIR}/libraries/${LIBRARY}/src") + include_directories("${HIFI_LIBRARY_DIR}/libraries/${LIBRARY}/src") endmacro(include_hifi_library_headers _library _root_dir) \ No newline at end of file diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index ed280846fe..cb2065e256 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -1,12 +1,6 @@ -set(ROOT_DIR ..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - set(TARGET_NAME interface) project(${TARGET_NAME}) -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") - # set a default root dir for each of our optional externals if it was not passed set(OPTIONAL_EXTERNALS "faceplus" "faceshift" "oculus" "priovr" "sixense" "visage" "leapmotion" "rtmidi" "qxmpp") foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) @@ -38,7 +32,6 @@ elseif (WIN32) endif () # set up the external glm library -include("${MACRO_DIR}/IncludeGLM.cmake") include_glm(${TARGET_NAME} "${ROOT_DIR}") # create the InterfaceConfig.h file based on GL_HEADERS above diff --git a/libraries/metavoxels/CMakeLists.txt b/libraries/metavoxels/CMakeLists.txt index 88b74194ac..29f7f85f9c 100644 --- a/libraries/metavoxels/CMakeLists.txt +++ b/libraries/metavoxels/CMakeLists.txt @@ -5,7 +5,7 @@ auto_mtc(${TARGET_NAME} "${ROOT_DIR}") setup_hifi_library(${TARGET_NAME} "${AUTOMTC_SRC}") # link in the networking library -link_hifi_libraries(${TARGET_NAME} networking) +link_hifi_libraries(${TARGET_NAME} shared networking) include_glm(${TARGET_NAME} "${ROOT_DIR}") From c63e886444294bdfaf2c12c8082a6df0c0b5c0a5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 10:04:34 -0700 Subject: [PATCH 277/407] don't look backwards for fbx header from avatars library --- cmake/macros/IncludeHifiLibraryHeaders.cmake | 4 +--- libraries/avatars/CMakeLists.txt | 1 + libraries/avatars/src/HeadData.cpp | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/cmake/macros/IncludeHifiLibraryHeaders.cmake b/cmake/macros/IncludeHifiLibraryHeaders.cmake index 7ac31f5259..913d1e1181 100644 --- a/cmake/macros/IncludeHifiLibraryHeaders.cmake +++ b/cmake/macros/IncludeHifiLibraryHeaders.cmake @@ -10,7 +10,5 @@ # macro(include_hifi_library_headers LIBRARY) - - include_directories("${HIFI_LIBRARY_DIR}/libraries/${LIBRARY}/src") - + include_directories("${HIFI_LIBRARY_DIR}/${LIBRARY}/src") endmacro(include_hifi_library_headers _library _root_dir) \ No newline at end of file diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index 10507f7836..138b218381 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -5,6 +5,7 @@ setup_hifi_library(${TARGET_NAME}) include_glm(${TARGET_NAME} "${ROOT_DIR}") link_hifi_libraries(${TARGET_NAME} shared octree voxels networking) +include_hifi_library_headers(fbx) find_package(Qt5 COMPONENTS Network Script) diff --git a/libraries/avatars/src/HeadData.cpp b/libraries/avatars/src/HeadData.cpp index 538085af30..2bdb203034 100644 --- a/libraries/avatars/src/HeadData.cpp +++ b/libraries/avatars/src/HeadData.cpp @@ -11,14 +11,13 @@ #include +#include #include #include #include "AvatarData.h" #include "HeadData.h" -#include "../fbx/src/FBXReader.h" - HeadData::HeadData(AvatarData* owningAvatar) : _baseYaw(0.0f), _basePitch(0.0f), From a75a3f943482f5886ef87187978428cce12f66fc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 10:06:56 -0700 Subject: [PATCH 278/407] don't look backwards for script-engine headers from particles library --- libraries/particles/CMakeLists.txt | 1 + libraries/particles/src/Particle.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/particles/CMakeLists.txt b/libraries/particles/CMakeLists.txt index 0f8a555cb5..0ab11e3f82 100644 --- a/libraries/particles/CMakeLists.txt +++ b/libraries/particles/CMakeLists.txt @@ -5,6 +5,7 @@ setup_hifi_library(${TARGET_NAME}) include_glm(${TARGET_NAME} "${ROOT_DIR}") link_hifi_libraries(${TARGET_NAME} shared octree fbx networking animation) +include_hifi_library_headers(script-engine) find_package(Qt5 COMPONENTS Gui Network Script) diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index fef2b95fdc..5db285ebeb 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -22,7 +22,7 @@ // I'm open to other potential solutions. Could we change cmake to allow libraries to reference each others // headers, but not link to each other, this is essentially what this construct is doing, but would be // better to add includes to the include path, but not link -#include "../../script-engine/src/ScriptEngine.h" +#include #include "ParticlesScriptingInterface.h" #include "Particle.h" From 17df6484d426666e4e22b053f85299a4a02aa26d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 10:14:31 -0700 Subject: [PATCH 279/407] remove ssize_t and replace with size_t or int where appropriate --- assignment-client/CMakeLists.txt | 5 ----- assignment-client/src/Agent.cpp | 2 +- domain-server/CMakeLists.txt | 5 ----- interface/CMakeLists.txt | 3 --- interface/src/voxels/OctreePacketProcessor.cpp | 2 +- libraries/animation/CMakeLists.txt | 5 ----- libraries/audio/CMakeLists.txt | 5 ----- libraries/avatars/CMakeLists.txt | 5 ----- libraries/fbx/CMakeLists.txt | 5 ----- libraries/metavoxels/CMakeLists.txt | 7 +------ libraries/models/CMakeLists.txt | 5 ----- libraries/models/src/ModelEditPacketSender.cpp | 2 +- libraries/models/src/ModelEditPacketSender.h | 2 +- libraries/models/src/ModelItem.cpp | 2 +- libraries/models/src/ModelItem.h | 2 +- libraries/networking/CMakeLists.txt | 5 ----- libraries/networking/src/PacketSender.h | 4 ---- libraries/networking/src/ReceivedPacketProcessor.h | 4 ---- libraries/octree/CMakeLists.txt | 5 ----- libraries/octree/src/EditPacketBuffer.cpp | 2 +- libraries/octree/src/EditPacketBuffer.h | 4 ++-- libraries/octree/src/JurisdictionListener.cpp | 2 +- libraries/octree/src/JurisdictionListener.h | 4 ---- libraries/octree/src/JurisdictionSender.cpp | 2 +- libraries/octree/src/OctreeEditPacketSender.cpp | 8 ++++---- libraries/octree/src/OctreeEditPacketSender.h | 10 +++++----- libraries/particles/CMakeLists.txt | 7 +------ libraries/particles/src/Particle.cpp | 2 +- libraries/particles/src/Particle.h | 2 +- libraries/particles/src/ParticleEditPacketSender.cpp | 2 +- libraries/particles/src/ParticleEditPacketSender.h | 2 +- libraries/script-engine/CMakeLists.txt | 7 +------ libraries/voxels/CMakeLists.txt | 5 ----- libraries/voxels/src/VoxelEditPacketSender.h | 2 +- tests/octree/CMakeLists.txt | 8 +------- voxel-edit/CMakeLists.txt | 7 +------ 36 files changed, 30 insertions(+), 121 deletions(-) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index fd11be5122..d4281eb185 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -20,8 +20,3 @@ ENDIF(WIN32) find_package(Qt5 COMPONENTS Gui Network Script Widgets) target_link_libraries(${TARGET_NAME} Qt5::Gui Qt5::Network Qt5::Script Qt5::Widgets) - -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () \ No newline at end of file diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index dbb1620252..09496f0179 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -115,7 +115,7 @@ void Agent::readPendingDatagrams() { sourceNode->setLastHeardMicrostamp(usecTimestampNow()); QByteArray mutablePacket = receivedPacket; - ssize_t messageLength = mutablePacket.size(); + int messageLength = mutablePacket.size(); if (datagramPacketType == PacketTypeOctreeStats) { diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index ae130af5ed..c04ba33a5d 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -18,10 +18,5 @@ IF (WIN32) target_link_libraries(${TARGET_NAME} Winmm Ws2_32) ENDIF(WIN32) -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () - find_package(Qt5 COMPONENTS Network Widgets) target_link_libraries(${TARGET_NAME} Qt5::Network) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index cb2065e256..ea4b54257b 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -206,9 +206,6 @@ else (APPLE) # we're using static GLEW, so define GLEW_STATIC add_definitions(-DGLEW_STATIC) - # add a definition for ssize_t so that windows doesn't bail - add_definitions(-Dssize_t=long) - target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" wsock32.lib opengl32.lib) endif() endif (APPLE) diff --git a/interface/src/voxels/OctreePacketProcessor.cpp b/interface/src/voxels/OctreePacketProcessor.cpp index 66190a5689..ee139ccf1d 100644 --- a/interface/src/voxels/OctreePacketProcessor.cpp +++ b/interface/src/voxels/OctreePacketProcessor.cpp @@ -26,7 +26,7 @@ void OctreePacketProcessor::processPacket(const SharedNodePointer& sendingNode, if (packetsToProcessCount() > WAY_BEHIND && Application::getInstance()->getLogger()->extraDebugging()) { qDebug("OctreePacketProcessor::processPacket() packets to process=%d", packetsToProcessCount()); } - ssize_t messageLength = mutablePacket.size(); + int messageLength = mutablePacket.size(); Application* app = Application::getInstance(); bool wasStatsPacket = false; diff --git a/libraries/animation/CMakeLists.txt b/libraries/animation/CMakeLists.txt index 186067ba3f..26b98ca17f 100644 --- a/libraries/animation/CMakeLists.txt +++ b/libraries/animation/CMakeLists.txt @@ -10,8 +10,3 @@ find_package(Qt5 COMPONENTS Network Script) set(DEPENDENCY_LIBRARIES Qt5::Script Qt5::Network) set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) - -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () \ No newline at end of file diff --git a/libraries/audio/CMakeLists.txt b/libraries/audio/CMakeLists.txt index 73d15f0b73..a066c3a73b 100644 --- a/libraries/audio/CMakeLists.txt +++ b/libraries/audio/CMakeLists.txt @@ -12,8 +12,3 @@ find_package(Qt5 COMPONENTS Network) set(DEPENDENCY_LIBRARIES Qt5::Network) set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES ${DEPENDENCY_LIBRARIES}) target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) - -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index 138b218381..9d7d452696 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -13,8 +13,3 @@ find_package(Qt5 COMPONENTS Network Script) set(DEPENDENCY_LIBRARIES Qt5::Network Qt5::Script) set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) - -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () \ No newline at end of file diff --git a/libraries/fbx/CMakeLists.txt b/libraries/fbx/CMakeLists.txt index 3f6a969cbc..12047498c2 100644 --- a/libraries/fbx/CMakeLists.txt +++ b/libraries/fbx/CMakeLists.txt @@ -15,8 +15,3 @@ include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") set(DEPENDENCY_LIBRARIES "${ZLIB_LIBRARIES}") set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES ${DEPENDENCY_LIBRARIES}) target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) - -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () \ No newline at end of file diff --git a/libraries/metavoxels/CMakeLists.txt b/libraries/metavoxels/CMakeLists.txt index 29f7f85f9c..b0e8f14374 100644 --- a/libraries/metavoxels/CMakeLists.txt +++ b/libraries/metavoxels/CMakeLists.txt @@ -14,9 +14,4 @@ find_package(Qt5 COMPONENTS Network Script Widgets) # set a property indicating the libraries we are dependent on and link them to ourselves set(DEPENDENCY_LIBRARIES Qt5::Script Qt5::Widgets Qt5::Network) set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) - -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () \ No newline at end of file +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) \ No newline at end of file diff --git a/libraries/models/CMakeLists.txt b/libraries/models/CMakeLists.txt index 20f6ef1ef8..45d0ab0b70 100644 --- a/libraries/models/CMakeLists.txt +++ b/libraries/models/CMakeLists.txt @@ -12,8 +12,3 @@ find_package(Qt5 COMPONENTS Network Script) set(DEPENDENCY_LIBRARIES Qt5::Network Qt5::Script) set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) - -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () \ No newline at end of file diff --git a/libraries/models/src/ModelEditPacketSender.cpp b/libraries/models/src/ModelEditPacketSender.cpp index 5059b8891b..c21a4a236a 100644 --- a/libraries/models/src/ModelEditPacketSender.cpp +++ b/libraries/models/src/ModelEditPacketSender.cpp @@ -38,7 +38,7 @@ void ModelEditPacketSender::sendEditModelMessage(PacketType type, ModelItemID mo } } -void ModelEditPacketSender::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) { +void ModelEditPacketSender::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew) { ModelItem::adjustEditPacketForClockSkew(codeColorBuffer, length, clockSkew); } diff --git a/libraries/models/src/ModelEditPacketSender.h b/libraries/models/src/ModelEditPacketSender.h index 198c9a3be2..332f7f729d 100644 --- a/libraries/models/src/ModelEditPacketSender.h +++ b/libraries/models/src/ModelEditPacketSender.h @@ -32,6 +32,6 @@ public: // My server type is the model server virtual char getMyNodeType() const { return NodeType::ModelServer; } - virtual void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew); + virtual void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew); }; #endif // hifi_ModelEditPacketSender_h diff --git a/libraries/models/src/ModelItem.cpp b/libraries/models/src/ModelItem.cpp index d6cd8aebc5..e555aff7ed 100644 --- a/libraries/models/src/ModelItem.cpp +++ b/libraries/models/src/ModelItem.cpp @@ -634,7 +634,7 @@ bool ModelItem::encodeModelEditMessageDetails(PacketType command, ModelItemID id } // adjust any internal timestamps to fix clock skew for this server -void ModelItem::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) { +void ModelItem::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew) { unsigned char* dataAt = codeColorBuffer; int octets = numberOfThreeBitSectionsInCode(dataAt); int lengthOfOctcode = bytesRequiredForCodeLength(octets); diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 4a9a2af2c4..be52b1e235 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -270,7 +270,7 @@ public: static bool encodeModelEditMessageDetails(PacketType command, ModelItemID id, const ModelItemProperties& details, unsigned char* bufferOut, int sizeIn, int& sizeOut); - static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew); + static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew); void update(const quint64& now); diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index f41d410ce8..fe8cd003a3 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -10,8 +10,3 @@ find_package(Qt5 COMPONENTS Network) set(DEPENDENCY_LIBRARIES Qt5::Network) set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) - -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () \ No newline at end of file diff --git a/libraries/networking/src/PacketSender.h b/libraries/networking/src/PacketSender.h index 7d2c0dc8aa..29d9287127 100644 --- a/libraries/networking/src/PacketSender.h +++ b/libraries/networking/src/PacketSender.h @@ -39,10 +39,6 @@ public: ~PacketSender(); /// Add packet to outbound queue. - /// \param HifiSockAddr& address the destination address - /// \param packetData pointer to data - /// \param ssize_t packetLength size of data - /// \thread any thread, typically the application thread void queuePacketForSending(const SharedNodePointer& destinationNode, const QByteArray& packet); void setPacketsPerSecond(int packetsPerSecond); diff --git a/libraries/networking/src/ReceivedPacketProcessor.h b/libraries/networking/src/ReceivedPacketProcessor.h index 607f9e54c2..d5fc006882 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.h +++ b/libraries/networking/src/ReceivedPacketProcessor.h @@ -24,10 +24,6 @@ public: ReceivedPacketProcessor() { } /// Add packet from network receive thread to the processing queue. - /// \param sockaddr& senderAddress the address of the sender - /// \param packetData pointer to received data - /// \param ssize_t packetLength size of received data - /// \thread network receive thread void queueReceivedPacket(const SharedNodePointer& sendingNode, const QByteArray& packet); /// Are there received packets waiting to be processed diff --git a/libraries/octree/CMakeLists.txt b/libraries/octree/CMakeLists.txt index efdb1bc70a..ca4e5caafd 100644 --- a/libraries/octree/CMakeLists.txt +++ b/libraries/octree/CMakeLists.txt @@ -16,8 +16,3 @@ include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}" "${OPENSSL_INCLUDE_DIR}") set(DEPENDENCY_LIBRARIES "${ZLIB_LIBRARIES}" "${OPENSSL_LIBRARIES}") set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES ${DEPENDENCY_LIBRARIES}) target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) - -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () \ No newline at end of file diff --git a/libraries/octree/src/EditPacketBuffer.cpp b/libraries/octree/src/EditPacketBuffer.cpp index d6e7bf0183..6d2d8cc085 100644 --- a/libraries/octree/src/EditPacketBuffer.cpp +++ b/libraries/octree/src/EditPacketBuffer.cpp @@ -20,7 +20,7 @@ EditPacketBuffer::EditPacketBuffer() : } -EditPacketBuffer::EditPacketBuffer(PacketType type, unsigned char* buffer, ssize_t length, qint64 satoshiCost, QUuid nodeUUID) : +EditPacketBuffer::EditPacketBuffer(PacketType type, unsigned char* buffer, size_t length, qint64 satoshiCost, QUuid nodeUUID) : _nodeUUID(nodeUUID), _currentType(type), _currentSize(length), diff --git a/libraries/octree/src/EditPacketBuffer.h b/libraries/octree/src/EditPacketBuffer.h index 9b52cbc5e4..e816bf6558 100644 --- a/libraries/octree/src/EditPacketBuffer.h +++ b/libraries/octree/src/EditPacketBuffer.h @@ -21,13 +21,13 @@ class EditPacketBuffer { public: EditPacketBuffer(); - EditPacketBuffer(PacketType type, unsigned char* codeColorBuffer, ssize_t length, + EditPacketBuffer(PacketType type, unsigned char* codeColorBuffer, size_t length, qint64 satoshiCost = 0, const QUuid nodeUUID = QUuid()); QUuid _nodeUUID; PacketType _currentType; unsigned char _currentBuffer[MAX_PACKET_SIZE]; - ssize_t _currentSize; + size_t _currentSize; qint64 _satoshiCost; }; diff --git a/libraries/octree/src/JurisdictionListener.cpp b/libraries/octree/src/JurisdictionListener.cpp index 453ff10a42..f3d9e31acc 100644 --- a/libraries/octree/src/JurisdictionListener.cpp +++ b/libraries/octree/src/JurisdictionListener.cpp @@ -35,7 +35,7 @@ void JurisdictionListener::nodeKilled(SharedNodePointer node) { bool JurisdictionListener::queueJurisdictionRequest() { static unsigned char buffer[MAX_PACKET_SIZE]; unsigned char* bufferOut = &buffer[0]; - ssize_t sizeOut = populatePacketHeader(reinterpret_cast(bufferOut), PacketTypeJurisdictionRequest); + int sizeOut = populatePacketHeader(reinterpret_cast(bufferOut), PacketTypeJurisdictionRequest); int nodeCount = 0; NodeList* nodeList = NodeList::getInstance(); diff --git a/libraries/octree/src/JurisdictionListener.h b/libraries/octree/src/JurisdictionListener.h index 01f0392796..eb1c27f2ff 100644 --- a/libraries/octree/src/JurisdictionListener.h +++ b/libraries/octree/src/JurisdictionListener.h @@ -47,10 +47,6 @@ public slots: protected: /// Callback for processing of received packets. Will process any queued PacketType_JURISDICTION and update the /// jurisdiction map member variable - /// \param sockaddr& senderAddress the address of the sender - /// \param packetData pointer to received data - /// \param ssize_t packetLength size of received data - /// \thread "this" individual processing thread virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet); private: diff --git a/libraries/octree/src/JurisdictionSender.cpp b/libraries/octree/src/JurisdictionSender.cpp index c151999305..d78d883204 100644 --- a/libraries/octree/src/JurisdictionSender.cpp +++ b/libraries/octree/src/JurisdictionSender.cpp @@ -47,7 +47,7 @@ bool JurisdictionSender::process() { // add our packet to our own queue, then let the PacketSender class do the rest of the work. static unsigned char buffer[MAX_PACKET_SIZE]; unsigned char* bufferOut = &buffer[0]; - ssize_t sizeOut = 0; + int sizeOut = 0; if (_jurisdictionMap) { sizeOut = _jurisdictionMap->packIntoMessage(bufferOut, MAX_PACKET_SIZE); diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 543f47273c..d4bdcaa59e 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -83,7 +83,7 @@ bool OctreeEditPacketSender::serversExist() const { // This method is called when the edit packet layer has determined that it has a fully formed packet destined for // a known nodeID. void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned char* buffer, - ssize_t length, qint64 satoshiCost) { + size_t length, qint64 satoshiCost) { NodeList* nodeList = NodeList::getInstance(); foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { @@ -161,7 +161,7 @@ void OctreeEditPacketSender::processPreServerExistsPackets() { } void OctreeEditPacketSender::queuePendingPacketToNodes(PacketType type, unsigned char* buffer, - ssize_t length, qint64 satoshiCost) { + size_t length, qint64 satoshiCost) { // If we're asked to save messages while waiting for voxel servers to arrive, then do so... if (_maxPendingMessages > 0) { @@ -179,7 +179,7 @@ void OctreeEditPacketSender::queuePendingPacketToNodes(PacketType type, unsigned } } -void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t length, qint64 satoshiCost) { +void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, size_t length, qint64 satoshiCost) { if (!_shouldSend) { return; // bail early } @@ -215,7 +215,7 @@ void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t l // NOTE: codeColorBuffer - is JUST the octcode/color and does not contain the packet header! void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, unsigned char* codeColorBuffer, - ssize_t length, qint64 satoshiCost) { + size_t length, qint64 satoshiCost) { if (!_shouldSend) { return; // bail early diff --git a/libraries/octree/src/OctreeEditPacketSender.h b/libraries/octree/src/OctreeEditPacketSender.h index a11c626003..cefa5cefb0 100644 --- a/libraries/octree/src/OctreeEditPacketSender.h +++ b/libraries/octree/src/OctreeEditPacketSender.h @@ -30,7 +30,7 @@ public: /// Queues a single edit message. Will potentially send a pending multi-command packet. Determines which server /// node or nodes the packet should be sent to. Can be called even before servers are known, in which case up to /// MaxPendingMessages will be buffered and processed when servers are known. - void queueOctreeEditMessage(PacketType type, unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0); + void queueOctreeEditMessage(PacketType type, unsigned char* buffer, size_t length, qint64 satoshiCost = 0); /// Releases all queued messages even if those messages haven't filled an MTU packet. This will move the packed message /// packets onto the send queue. If running in threaded mode, the caller does not need to do any further processing to @@ -81,7 +81,7 @@ public: // you must override these... virtual char getMyNodeType() const = 0; - virtual void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) { }; + virtual void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew) { }; bool hasDestinationWalletUUID() const { return !_destinationWalletUUID.isNull(); } void setDestinationWalletUUID(const QUuid& destinationWalletUUID) { _destinationWalletUUID = destinationWalletUUID; } @@ -97,9 +97,9 @@ signals: protected: bool _shouldSend; - void queuePacketToNode(const QUuid& nodeID, unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0); - void queuePendingPacketToNodes(PacketType type, unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0); - void queuePacketToNodes(unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0); + void queuePacketToNode(const QUuid& nodeID, unsigned char* buffer, size_t length, qint64 satoshiCost = 0); + void queuePendingPacketToNodes(PacketType type, unsigned char* buffer, size_t length, qint64 satoshiCost = 0); + void queuePacketToNodes(unsigned char* buffer, size_t length, qint64 satoshiCost = 0); void initializePacket(EditPacketBuffer& packetBuffer, PacketType type); void releaseQueuedPacket(EditPacketBuffer& packetBuffer); // releases specific queued packet diff --git a/libraries/particles/CMakeLists.txt b/libraries/particles/CMakeLists.txt index 0ab11e3f82..8efeedc9d9 100644 --- a/libraries/particles/CMakeLists.txt +++ b/libraries/particles/CMakeLists.txt @@ -12,9 +12,4 @@ find_package(Qt5 COMPONENTS Gui Network Script) # set a property indicating the libraries we are dependent on and link them to ourselves set(DEPENDENCY_LIBRARIES Qt5::Network Qt5::Script Qt5::Gui) set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) - -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () \ No newline at end of file +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) \ No newline at end of file diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 5db285ebeb..e3b568365b 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -856,7 +856,7 @@ bool Particle::encodeParticleEditMessageDetails(PacketType command, ParticleID i } // adjust any internal timestamps to fix clock skew for this server -void Particle::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) { +void Particle::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew) { unsigned char* dataAt = codeColorBuffer; int octets = numberOfThreeBitSectionsInCode(dataAt); int lengthOfOctcode = bytesRequiredForCodeLength(octets); diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index c243363241..1ee0f6e79b 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -292,7 +292,7 @@ public: static bool encodeParticleEditMessageDetails(PacketType command, ParticleID id, const ParticleProperties& details, unsigned char* bufferOut, int sizeIn, int& sizeOut); - static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew); + static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew); void applyHardCollision(const CollisionInfo& collisionInfo); diff --git a/libraries/particles/src/ParticleEditPacketSender.cpp b/libraries/particles/src/ParticleEditPacketSender.cpp index 21a910ff16..689b734521 100644 --- a/libraries/particles/src/ParticleEditPacketSender.cpp +++ b/libraries/particles/src/ParticleEditPacketSender.cpp @@ -38,7 +38,7 @@ void ParticleEditPacketSender::sendEditParticleMessage(PacketType type, Particle } } -void ParticleEditPacketSender::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) { +void ParticleEditPacketSender::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew) { Particle::adjustEditPacketForClockSkew(codeColorBuffer, length, clockSkew); } diff --git a/libraries/particles/src/ParticleEditPacketSender.h b/libraries/particles/src/ParticleEditPacketSender.h index 5a367347ea..2ee6d84eb8 100644 --- a/libraries/particles/src/ParticleEditPacketSender.h +++ b/libraries/particles/src/ParticleEditPacketSender.h @@ -31,6 +31,6 @@ public: // My server type is the particle server virtual char getMyNodeType() const { return NodeType::ParticleServer; } - virtual void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew); + virtual void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew); }; #endif // hifi_ParticleEditPacketSender_h diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index f9b4b7d60f..0b79530210 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -11,9 +11,4 @@ find_package(Qt5 COMPONENTS Gui Network Script Widgets) # set a property indicating the libraries we are dependent on and link them to ourselves set(DEPENDENCY_LIBRARIES Qt5::Gui Qt5::Network Qt5::Script Qt5::Widgets) set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) - -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () \ No newline at end of file +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) \ No newline at end of file diff --git a/libraries/voxels/CMakeLists.txt b/libraries/voxels/CMakeLists.txt index c421f6514f..739fe3ef62 100644 --- a/libraries/voxels/CMakeLists.txt +++ b/libraries/voxels/CMakeLists.txt @@ -12,8 +12,3 @@ find_package(Qt5 COMPONENTS Widgets Script) include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets Qt5::Script) - -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () \ No newline at end of file diff --git a/libraries/voxels/src/VoxelEditPacketSender.h b/libraries/voxels/src/VoxelEditPacketSender.h index 560c585ed5..3b85155036 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.h +++ b/libraries/voxels/src/VoxelEditPacketSender.h @@ -28,7 +28,7 @@ public: /// Queues a single voxel edit message. Will potentially send a pending multi-command packet. Determines which voxel-server /// node or nodes the packet should be sent to. Can be called even before voxel servers are known, in which case up to /// MaxPendingMessages will be buffered and processed when voxel servers are known. - void queueVoxelEditMessage(PacketType type, unsigned char* codeColorBuffer, ssize_t length) { + void queueVoxelEditMessage(PacketType type, unsigned char* codeColorBuffer, size_t length) { queueOctreeEditMessage(type, codeColorBuffer, length); } diff --git a/tests/octree/CMakeLists.txt b/tests/octree/CMakeLists.txt index a4888b2c66..85442db783 100644 --- a/tests/octree/CMakeLists.txt +++ b/tests/octree/CMakeLists.txt @@ -6,11 +6,5 @@ setup_hifi_project(${TARGET_NAME} TRUE) link_hifi_libraries(${TARGET_NAME} octree) IF (WIN32) - # add a definition for ssize_t so that windows doesn't bail - add_definitions(-Dssize_t=long) - - #target_link_libraries(${TARGET_NAME} Winmm Ws2_32) - target_link_libraries(${TARGET_NAME} wsock32.lib) + target_link_libraries(${TARGET_NAME} wsock32.lib) ENDIF(WIN32) - - diff --git a/voxel-edit/CMakeLists.txt b/voxel-edit/CMakeLists.txt index 8c315c92a0..db22f040b7 100644 --- a/voxel-edit/CMakeLists.txt +++ b/voxel-edit/CMakeLists.txt @@ -1,8 +1,3 @@ set(TARGET_NAME voxel-edit) -setup_hifi_project(${TARGET_NAME} TRUE) - -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () \ No newline at end of file +setup_hifi_project(${TARGET_NAME} TRUE) \ No newline at end of file From 1f0a722d0db68c11419102223911697959cdf077 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 10:17:29 -0700 Subject: [PATCH 280/407] remove antequated windows libraries that have been replaced by Qt usage --- assignment-client/CMakeLists.txt | 4 ---- domain-server/CMakeLists.txt | 4 ---- tests/audio/CMakeLists.txt | 5 ----- tests/jitter/CMakeLists.txt | 7 +------ tests/metavoxels/CMakeLists.txt | 4 ---- tests/networking/CMakeLists.txt | 4 ---- 6 files changed, 1 insertion(+), 27 deletions(-) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index d4281eb185..ab448bc5bd 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -14,9 +14,5 @@ if (UNIX) target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES} ${CMAKE_DL_LIBS}) endif (UNIX) -IF (WIN32) - target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES} Winmm Ws2_32) -ENDIF(WIN32) - find_package(Qt5 COMPONENTS Gui Network Script Widgets) target_link_libraries(${TARGET_NAME} Qt5::Gui Qt5::Network Qt5::Script Qt5::Widgets) diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index c04ba33a5d..7f9dc2db37 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -14,9 +14,5 @@ add_custom_command(TARGET ${TARGET_NAME} POST_BUILD # link the shared hifi library link_hifi_libraries(${TARGET_NAME} embedded-webserver networking shared) -IF (WIN32) - target_link_libraries(${TARGET_NAME} Winmm Ws2_32) -ENDIF(WIN32) - find_package(Qt5 COMPONENTS Network Widgets) target_link_libraries(${TARGET_NAME} Qt5::Network) diff --git a/tests/audio/CMakeLists.txt b/tests/audio/CMakeLists.txt index 15da1afaa1..51b42780c8 100644 --- a/tests/audio/CMakeLists.txt +++ b/tests/audio/CMakeLists.txt @@ -7,8 +7,3 @@ include_glm(${TARGET_NAME} ${ROOT_DIR}) # link in the shared libraries link_hifi_libraries(${TARGET_NAME} shared audio networking) - -IF (WIN32) - target_link_libraries(${TARGET_NAME} Winmm Ws2_32) -ENDIF(WIN32) - diff --git a/tests/jitter/CMakeLists.txt b/tests/jitter/CMakeLists.txt index 3b1d544690..4fb3d56492 100644 --- a/tests/jitter/CMakeLists.txt +++ b/tests/jitter/CMakeLists.txt @@ -3,9 +3,4 @@ set(TARGET_NAME jitter-tests) setup_hifi_project(${TARGET_NAME} TRUE) # link in the shared libraries -link_hifi_libraries(${TARGET_NAME} shared networking) - -IF (WIN32) - target_link_libraries(${TARGET_NAME} Winmm Ws2_32) -ENDIF(WIN32) - +link_hifi_libraries(${TARGET_NAME} shared networking) \ No newline at end of file diff --git a/tests/metavoxels/CMakeLists.txt b/tests/metavoxels/CMakeLists.txt index 233988f849..d459ea1fed 100644 --- a/tests/metavoxels/CMakeLists.txt +++ b/tests/metavoxels/CMakeLists.txt @@ -9,9 +9,5 @@ setup_hifi_project(${TARGET_NAME} TRUE "${AUTOMTC_SRC}") # link in the shared libraries link_hifi_libraries(${TARGET_NAME} metavoxels networking shared) -IF (WIN32) - target_link_libraries(${TARGET_NAME} Winmm Ws2_32) -ENDIF(WIN32) - target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script) diff --git a/tests/networking/CMakeLists.txt b/tests/networking/CMakeLists.txt index 819229d28f..ec48bb80cd 100644 --- a/tests/networking/CMakeLists.txt +++ b/tests/networking/CMakeLists.txt @@ -5,7 +5,3 @@ setup_hifi_project(${TARGET_NAME} TRUE) # link in the shared libraries link_hifi_libraries(${TARGET_NAME} shared networking) -IF (WIN32) - target_link_libraries(${TARGET_NAME} Winmm Ws2_32) -ENDIF(WIN32) - From c9f8433a2dba2c78951cb5a35ef0fe17ceb0f3a1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 10:44:58 -0700 Subject: [PATCH 281/407] tweak setup_hifi_library to bubble up full path of Qt modules --- cmake/macros/SetupHifiLibrary.cmake | 28 +++++++++++++++------ libraries/animation/CMakeLists.txt | 12 +++------ libraries/audio/CMakeLists.txt | 12 +++------ libraries/avatars/CMakeLists.txt | 12 +++------ libraries/embedded-webserver/CMakeLists.txt | 17 ++----------- libraries/fbx/CMakeLists.txt | 1 + libraries/metavoxels/CMakeLists.txt | 12 +++------ libraries/models/CMakeLists.txt | 12 +++------ libraries/networking/CMakeLists.txt | 12 +++------ libraries/octree/CMakeLists.txt | 3 ++- libraries/particles/CMakeLists.txt | 12 +++------ libraries/script-engine/CMakeLists.txt | 12 +++------ libraries/shared/CMakeLists.txt | 9 ++----- libraries/voxels/CMakeLists.txt | 10 +++++--- tests/audio/CMakeLists.txt | 2 +- tools/CMakeLists.txt | 1 - tools/mtc/CMakeLists.txt | 5 ---- 17 files changed, 59 insertions(+), 113 deletions(-) diff --git a/cmake/macros/SetupHifiLibrary.cmake b/cmake/macros/SetupHifiLibrary.cmake index ff4ae3b4f3..6da3755ea4 100644 --- a/cmake/macros/SetupHifiLibrary.cmake +++ b/cmake/macros/SetupHifiLibrary.cmake @@ -13,14 +13,28 @@ macro(SETUP_HIFI_LIBRARY TARGET) # grab the implemenation and header files file(GLOB LIB_SRCS src/*.h src/*.cpp) - set(LIB_SRCS ${LIB_SRCS} ${WRAPPED_SRCS}) + set(LIB_SRCS ${LIB_SRCS}) - # create a library and set the property so it can be referenced later - add_library(${TARGET} ${LIB_SRCS} ${ARGN}) + # create a library and set the property so it can be referenced later + add_library(${TARGET} ${LIB_SRCS} ${AUTOMTC_SRC}) - find_package(Qt5Core REQUIRED) - qt5_use_modules(${TARGET} Core) - - target_link_libraries(${TARGET} ${QT_LIBRARIES}) + set(QT_MODULES_TO_LINK ${ARGN}) + list(APPEND QT_MODULES_TO_LINK Core) + + find_package(Qt5 COMPONENTS ${QT_MODULES_TO_LINK}) + + foreach(QT_MODULE ${QT_MODULES_TO_LINK}) + # link this Qt module to ourselves + target_link_libraries(${TARGET} Qt5::${QT_MODULE}) + + get_target_property(QT_LIBRARY_LOCATION Qt5::${QT_MODULE} LOCATION) + + # add the actual path to the Qt module to a QT_LIBRARIES variable + list(APPEND QT_LIBRARIES ${QT_LIBRARY_LOCATION}) + endforeach() + + if (QT_LIBRARIES) + set_target_properties(${TARGET} PROPERTIES DEPENDENCY_LIBRARIES "${QT_LIBRARIES}") + endif () endmacro(SETUP_HIFI_LIBRARY _target) \ No newline at end of file diff --git a/libraries/animation/CMakeLists.txt b/libraries/animation/CMakeLists.txt index 26b98ca17f..9c419d9369 100644 --- a/libraries/animation/CMakeLists.txt +++ b/libraries/animation/CMakeLists.txt @@ -1,12 +1,6 @@ set(TARGET_NAME animation) -setup_hifi_library(${TARGET_NAME}) +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library(${TARGET_NAME} Network Script) -link_hifi_libraries(${TARGET_NAME} shared fbx) - -find_package(Qt5 COMPONENTS Network Script) - -# set a property indicating the libraries we are dependent on and link them to ourselves -set(DEPENDENCY_LIBRARIES Qt5::Script Qt5::Network) -set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) +link_hifi_libraries(${TARGET_NAME} shared fbx) \ No newline at end of file diff --git a/libraries/audio/CMakeLists.txt b/libraries/audio/CMakeLists.txt index a066c3a73b..354a3772dd 100644 --- a/libraries/audio/CMakeLists.txt +++ b/libraries/audio/CMakeLists.txt @@ -1,14 +1,8 @@ set(TARGET_NAME audio) -setup_hifi_library(${TARGET_NAME}) +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library(${TARGET_NAME} Network) include_glm(${TARGET_NAME} "${ROOT_DIR}") -link_hifi_libraries(${TARGET_NAME} networking shared) - -find_package(Qt5 COMPONENTS Network) - -# set a property indicating the libraries we are dependent on and link them to ourselves -set(DEPENDENCY_LIBRARIES Qt5::Network) -set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES ${DEPENDENCY_LIBRARIES}) -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) +link_hifi_libraries(${TARGET_NAME} networking shared) \ No newline at end of file diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index 9d7d452696..d05faf3b27 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -1,15 +1,9 @@ set(TARGET_NAME avatars) -setup_hifi_library(${TARGET_NAME}) +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library(${TARGET_NAME} Network Script) include_glm(${TARGET_NAME} "${ROOT_DIR}") link_hifi_libraries(${TARGET_NAME} shared octree voxels networking) -include_hifi_library_headers(fbx) - -find_package(Qt5 COMPONENTS Network Script) - -# set a property indicating the libraries we are dependent on and link them to ourselves -set(DEPENDENCY_LIBRARIES Qt5::Network Qt5::Script) -set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) +include_hifi_library_headers(fbx) \ No newline at end of file diff --git a/libraries/embedded-webserver/CMakeLists.txt b/libraries/embedded-webserver/CMakeLists.txt index 5b815625ba..c299aa654d 100644 --- a/libraries/embedded-webserver/CMakeLists.txt +++ b/libraries/embedded-webserver/CMakeLists.txt @@ -1,17 +1,4 @@ -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - set(TARGET_NAME embedded-webserver) -include(${MACRO_DIR}/SetupHifiLibrary.cmake) -setup_hifi_library(${TARGET_NAME}) - -find_package(Qt5 COMPONENTS Network) - -# set a property indicating the libraries we are dependent on and link them to ourselves -set(DEPENDENCY_LIBRARIES Qt5::Network) -set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES ${DEPENDENCY_LIBRARIES}) -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) \ No newline at end of file +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library(${TARGET_NAME} Network) \ No newline at end of file diff --git a/libraries/fbx/CMakeLists.txt b/libraries/fbx/CMakeLists.txt index 12047498c2..e9658de4a2 100644 --- a/libraries/fbx/CMakeLists.txt +++ b/libraries/fbx/CMakeLists.txt @@ -1,5 +1,6 @@ set(TARGET_NAME fbx) +# use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library(${TARGET_NAME}) include_glm(${TARGET_NAME} "${ROOT_DIR}") diff --git a/libraries/metavoxels/CMakeLists.txt b/libraries/metavoxels/CMakeLists.txt index b0e8f14374..20b448725f 100644 --- a/libraries/metavoxels/CMakeLists.txt +++ b/libraries/metavoxels/CMakeLists.txt @@ -2,16 +2,10 @@ set(TARGET_NAME metavoxels) auto_mtc(${TARGET_NAME} "${ROOT_DIR}") -setup_hifi_library(${TARGET_NAME} "${AUTOMTC_SRC}") +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library(${TARGET_NAME} Network Scripts Widgets) # link in the networking library link_hifi_libraries(${TARGET_NAME} shared networking) -include_glm(${TARGET_NAME} "${ROOT_DIR}") - -find_package(Qt5 COMPONENTS Network Script Widgets) - -# set a property indicating the libraries we are dependent on and link them to ourselves -set(DEPENDENCY_LIBRARIES Qt5::Script Qt5::Widgets Qt5::Network) -set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) \ No newline at end of file +include_glm(${TARGET_NAME} "${ROOT_DIR}") \ No newline at end of file diff --git a/libraries/models/CMakeLists.txt b/libraries/models/CMakeLists.txt index 45d0ab0b70..c0610b0501 100644 --- a/libraries/models/CMakeLists.txt +++ b/libraries/models/CMakeLists.txt @@ -1,14 +1,8 @@ set(TARGET_NAME models) -setup_hifi_library(${TARGET_NAME}) +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library(${TARGET_NAME} Network Script) include_glm(${TARGET_NAME} "${ROOT_DIR}") -link_hifi_libraries(${TARGET_NAME} shared octree fbx networking animation) - -find_package(Qt5 COMPONENTS Network Script) - -# set a property indicating the libraries we are dependent on and link them to ourselves -set(DEPENDENCY_LIBRARIES Qt5::Network Qt5::Script) -set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) +link_hifi_libraries(${TARGET_NAME} shared octree fbx networking animation) \ No newline at end of file diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index fe8cd003a3..fb9f07b81a 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -1,12 +1,6 @@ set(TARGET_NAME networking) -setup_hifi_library(${TARGET_NAME}) +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library(${TARGET_NAME} Network) -link_hifi_libraries(${TARGET_NAME} shared) - -find_package(Qt5 COMPONENTS Network) - -# set a property indicating the libraries we are dependent on and link them to ourselves -set(DEPENDENCY_LIBRARIES Qt5::Network) -set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) +link_hifi_libraries(${TARGET_NAME} shared) \ No newline at end of file diff --git a/libraries/octree/CMakeLists.txt b/libraries/octree/CMakeLists.txt index ca4e5caafd..340b2393e6 100644 --- a/libraries/octree/CMakeLists.txt +++ b/libraries/octree/CMakeLists.txt @@ -1,5 +1,6 @@ set(TARGET_NAME octree) +# use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library(${TARGET_NAME}) include_glm(${TARGET_NAME} "${ROOT_DIR}") @@ -15,4 +16,4 @@ include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}" "${OPENSSL_INCLUDE_DIR}") # set a property indicating the libraries we are dependent on and link them to ourselves set(DEPENDENCY_LIBRARIES "${ZLIB_LIBRARIES}" "${OPENSSL_LIBRARIES}") set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES ${DEPENDENCY_LIBRARIES}) -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) +target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) \ No newline at end of file diff --git a/libraries/particles/CMakeLists.txt b/libraries/particles/CMakeLists.txt index 8efeedc9d9..2f523b22f7 100644 --- a/libraries/particles/CMakeLists.txt +++ b/libraries/particles/CMakeLists.txt @@ -1,15 +1,9 @@ set(TARGET_NAME particles) -setup_hifi_library(${TARGET_NAME}) +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library(${TARGET_NAME} Gui Network Script) include_glm(${TARGET_NAME} "${ROOT_DIR}") link_hifi_libraries(${TARGET_NAME} shared octree fbx networking animation) -include_hifi_library_headers(script-engine) - -find_package(Qt5 COMPONENTS Gui Network Script) - -# set a property indicating the libraries we are dependent on and link them to ourselves -set(DEPENDENCY_LIBRARIES Qt5::Network Qt5::Script Qt5::Gui) -set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) \ No newline at end of file +include_hifi_library_headers(script-engine) \ No newline at end of file diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 0b79530210..cce7d8d07b 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -1,14 +1,8 @@ set(TARGET_NAME script-engine) -setup_hifi_library(${TARGET_NAME}) +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library(${TARGET_NAME} Gui Network Script Widgets) include_glm(${TARGET_NAME} "${ROOT_DIR}") -link_hifi_libraries(${TARGET_NAME} shared octree voxels fbx particles models animation) - -find_package(Qt5 COMPONENTS Gui Network Script Widgets) - -# set a property indicating the libraries we are dependent on and link them to ourselves -set(DEPENDENCY_LIBRARIES Qt5::Gui Qt5::Network Qt5::Script Qt5::Widgets) -set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) \ No newline at end of file +link_hifi_libraries(${TARGET_NAME} shared octree voxels fbx particles models animation) \ No newline at end of file diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index b8e34739b8..9cc1b968dc 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -1,9 +1,4 @@ set(TARGET_NAME shared) -setup_hifi_library(${TARGET_NAME}) -find_package(Qt5 COMPONENTS Network Widgets) - -# bubble up the libraries we are dependent on and link them to ourselves -list(APPEND DEPENDENCY_LIBRARIES Qt5::Network Qt5::Widgets) -set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${DEPENDENCY_LIBRARIES}") -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) \ No newline at end of file +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library(${TARGET_NAME} Network Widgets) \ No newline at end of file diff --git a/libraries/voxels/CMakeLists.txt b/libraries/voxels/CMakeLists.txt index 739fe3ef62..7f200523de 100644 --- a/libraries/voxels/CMakeLists.txt +++ b/libraries/voxels/CMakeLists.txt @@ -1,6 +1,7 @@ set(TARGET_NAME voxels) -setup_hifi_library(${TARGET_NAME}) +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library(${TARGET_NAME} Widgets Script) include_glm(${TARGET_NAME} "${ROOT_DIR}") @@ -8,7 +9,8 @@ link_hifi_libraries(${TARGET_NAME} shared octree networking) # link ZLIB find_package(ZLIB) -find_package(Qt5 COMPONENTS Widgets Script) - include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") -target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets Qt5::Script) + +get_target_property(LINKED_LIBRARIES ${TARGET_NAME} DEPENDENCY_LIBRARIES) +list(APPEND DEPENDENCY_LIBRARIES "${ZLIB_LIBRARIES}") +list(REMOVE_DUPLICATES DEPENDENCY_LIBRARIES) \ No newline at end of file diff --git a/tests/audio/CMakeLists.txt b/tests/audio/CMakeLists.txt index 51b42780c8..34d053b008 100644 --- a/tests/audio/CMakeLists.txt +++ b/tests/audio/CMakeLists.txt @@ -6,4 +6,4 @@ setup_hifi_project(${TARGET_NAME} TRUE) include_glm(${TARGET_NAME} ${ROOT_DIR}) # link in the shared libraries -link_hifi_libraries(${TARGET_NAME} shared audio networking) +link_hifi_libraries(${TARGET_NAME} shared audio networking) \ No newline at end of file diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index c9c0690cc7..32a82627a3 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,4 +1,3 @@ - # add the tool directories add_subdirectory(bitstream2json) add_subdirectory(json2bitstream) diff --git a/tools/mtc/CMakeLists.txt b/tools/mtc/CMakeLists.txt index 582c5e3bfd..467d03d241 100644 --- a/tools/mtc/CMakeLists.txt +++ b/tools/mtc/CMakeLists.txt @@ -1,7 +1,2 @@ set(TARGET_NAME mtc) - -set(ROOT_DIR ../..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME} TRUE) \ No newline at end of file From fc92b93326755028d74bf0ba951da6ae6d85c3ac Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 10:46:05 -0700 Subject: [PATCH 282/407] fix typo in metavoxels library setup --- libraries/metavoxels/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metavoxels/CMakeLists.txt b/libraries/metavoxels/CMakeLists.txt index 20b448725f..a8d6de698b 100644 --- a/libraries/metavoxels/CMakeLists.txt +++ b/libraries/metavoxels/CMakeLists.txt @@ -3,7 +3,7 @@ set(TARGET_NAME metavoxels) auto_mtc(${TARGET_NAME} "${ROOT_DIR}") # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(${TARGET_NAME} Network Scripts Widgets) +setup_hifi_library(${TARGET_NAME} Network Script Widgets) # link in the networking library link_hifi_libraries(${TARGET_NAME} shared networking) From 26f7b1ba62bf37cb1c0e0f780bac16be7f651d3e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 11:45:10 -0700 Subject: [PATCH 283/407] add macro to link shared dependencies to target --- assignment-client/CMakeLists.txt | 7 +++--- cmake/macros/LinkHifiLibraries.cmake | 11 ++++---- .../LinkSharedDependenciesToTarget.cmake | 25 +++++++++++++++++++ cmake/macros/SetupHifiLibrary.cmake | 15 +++-------- cmake/macros/SetupHifiProject.cmake | 21 +++++++++++----- domain-server/CMakeLists.txt | 2 +- libraries/animation/CMakeLists.txt | 5 +++- libraries/audio/CMakeLists.txt | 5 +++- libraries/avatars/CMakeLists.txt | 5 +++- libraries/embedded-webserver/CMakeLists.txt | 5 +++- libraries/fbx/CMakeLists.txt | 9 +++---- libraries/metavoxels/CMakeLists.txt | 5 +++- libraries/models/CMakeLists.txt | 5 +++- libraries/networking/CMakeLists.txt | 5 +++- libraries/octree/CMakeLists.txt | 14 ++++++----- libraries/particles/CMakeLists.txt | 5 +++- libraries/script-engine/CMakeLists.txt | 5 +++- libraries/shared/CMakeLists.txt | 5 +++- libraries/voxels/CMakeLists.txt | 10 +++++--- tests/audio/CMakeLists.txt | 2 +- tests/jitter/CMakeLists.txt | 2 +- tests/metavoxels/CMakeLists.txt | 2 +- tests/networking/CMakeLists.txt | 2 +- tests/octree/CMakeLists.txt | 2 +- tests/physics/CMakeLists.txt | 2 +- tests/shared/CMakeLists.txt | 2 +- tools/bitstream2json/CMakeLists.txt | 2 +- tools/json2bitstream/CMakeLists.txt | 2 +- tools/mtc/CMakeLists.txt | 2 +- voxel-edit/CMakeLists.txt | 2 +- 30 files changed, 121 insertions(+), 65 deletions(-) create mode 100644 cmake/macros/LinkSharedDependenciesToTarget.cmake diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index ab448bc5bd..9f8542c42e 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME assignment-client) -setup_hifi_project(${TARGET_NAME} TRUE) +setup_hifi_project(${TARGET_NAME} Core Gui Network Script Widgets) include_glm(${TARGET_NAME}) @@ -11,8 +11,7 @@ link_hifi_libraries(${TARGET_NAME} ) if (UNIX) - target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES} ${CMAKE_DL_LIBS}) + list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK ${CMAKE_DL_LIBS}) endif (UNIX) -find_package(Qt5 COMPONENTS Gui Network Script Widgets) -target_link_libraries(${TARGET_NAME} Qt5::Gui Qt5::Network Qt5::Script Qt5::Widgets) +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/cmake/macros/LinkHifiLibraries.cmake b/cmake/macros/LinkHifiLibraries.cmake index 4c6e2c3215..96c5d82cae 100644 --- a/cmake/macros/LinkHifiLibraries.cmake +++ b/cmake/macros/LinkHifiLibraries.cmake @@ -22,13 +22,12 @@ macro(LINK_HIFI_LIBRARIES TARGET) add_dependencies(${TARGET} ${HIFI_LIBRARY}) + # link the actual library + list(APPEND ${TARGET}_LIBRARIES_TO_LINK ${HIFI_LIBRARY}) + + # ask the library what its dynamic dependencies are and link them get_target_property(LINKED_TARGET_DEPENDENCY_LIBRARIES ${HIFI_LIBRARY} DEPENDENCY_LIBRARIES) - - if (LINKED_TARGET_DEPENDENCY_LIBRARIES) - target_link_libraries(${TARGET} ${HIFI_LIBRARY} ${LINKED_TARGET_DEPENDENCY_LIBRARIES}) - else () - target_link_libraries(${TARGET} ${HIFI_LIBRARY}) - endif () + list(APPEND ${TARGET}_LIBRARIES_TO_LINK ${LINKED_TARGET_DEPENDENCY_LIBRARIES}) endforeach() diff --git a/cmake/macros/LinkSharedDependenciesToTarget.cmake b/cmake/macros/LinkSharedDependenciesToTarget.cmake new file mode 100644 index 0000000000..42f7109807 --- /dev/null +++ b/cmake/macros/LinkSharedDependenciesToTarget.cmake @@ -0,0 +1,25 @@ +# +# LinkHifiLibrary.cmake +# cmake/macros +# +# Copyright 2014 High Fidelity, Inc. +# Created by Stephen Birarda on August 8, 2014 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +macro(LINK_SHARED_DEPENDENCIES_TO_TARGET TARGET) + if (${TARGET}_LIBRARIES_TO_LINK) + list(REMOVE_DUPLICATES ${TARGET}_LIBRARIES_TO_LINK) + + # link these libraries to our target + target_link_libraries(${TARGET} ${${TARGET}_LIBRARIES_TO_LINK}) + endif () + + # we've already linked our Qt modules, but we need to bubble them up to parents + list(APPEND ${TARGET}_LIBRARIES_TO_LINK "${${TARGET}_QT_MODULES_TO_LINK}") + + # set the property on this target so it can be retreived by targets linking to us + set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${${TARGET}_LIBRARIES_TO_LINK}") +endmacro(LINK_SHARED_DEPENDENCIES_TO_TARGET _target) \ No newline at end of file diff --git a/cmake/macros/SetupHifiLibrary.cmake b/cmake/macros/SetupHifiLibrary.cmake index 6da3755ea4..73ee208b98 100644 --- a/cmake/macros/SetupHifiLibrary.cmake +++ b/cmake/macros/SetupHifiLibrary.cmake @@ -15,7 +15,7 @@ macro(SETUP_HIFI_LIBRARY TARGET) file(GLOB LIB_SRCS src/*.h src/*.cpp) set(LIB_SRCS ${LIB_SRCS}) - # create a library and set the property so it can be referenced later + # create a library and set the property so it can be referenced later add_library(${TARGET} ${LIB_SRCS} ${AUTOMTC_SRC}) set(QT_MODULES_TO_LINK ${ARGN}) @@ -24,17 +24,10 @@ macro(SETUP_HIFI_LIBRARY TARGET) find_package(Qt5 COMPONENTS ${QT_MODULES_TO_LINK}) foreach(QT_MODULE ${QT_MODULES_TO_LINK}) - # link this Qt module to ourselves - target_link_libraries(${TARGET} Qt5::${QT_MODULE}) - get_target_property(QT_LIBRARY_LOCATION Qt5::${QT_MODULE} LOCATION) - # add the actual path to the Qt module to a QT_LIBRARIES variable - list(APPEND QT_LIBRARIES ${QT_LIBRARY_LOCATION}) + # add the actual path to the Qt module to our LIBRARIES_TO_LINK variable + target_link_libraries(${TARGET} Qt5::${QT_MODULE}) + list(APPEND ${TARGET}_QT_MODULES_TO_LINK ${QT_LIBRARY_LOCATION}) endforeach() - - if (QT_LIBRARIES) - set_target_properties(${TARGET} PROPERTIES DEPENDENCY_LIBRARIES "${QT_LIBRARIES}") - endif () - endmacro(SETUP_HIFI_LIBRARY _target) \ No newline at end of file diff --git a/cmake/macros/SetupHifiProject.cmake b/cmake/macros/SetupHifiProject.cmake index 281aa42650..c680790f02 100644 --- a/cmake/macros/SetupHifiProject.cmake +++ b/cmake/macros/SetupHifiProject.cmake @@ -7,7 +7,7 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # -macro(SETUP_HIFI_PROJECT TARGET INCLUDE_QT) +macro(SETUP_HIFI_PROJECT TARGET) project(${TARGET}) # grab the implemenation and header files @@ -23,10 +23,19 @@ macro(SETUP_HIFI_PROJECT TARGET INCLUDE_QT) endforeach() # add the executable, include additional optional sources - add_executable(${TARGET} ${TARGET_SRCS} ${ARGN}) + add_executable(${TARGET} ${TARGET_SRCS} "${AUTOMTC_SRC}") + + set(QT_MODULES_TO_LINK ${ARGN}) + list(APPEND QT_MODULES_TO_LINK Core) + + find_package(Qt5 COMPONENTS ${QT_MODULES_TO_LINK}) + + foreach(QT_MODULE ${QT_MODULES_TO_LINK}) + target_link_libraries(${TARGET} Qt5::${QT_MODULE}) + + # add the actual path to the Qt module to our LIBRARIES_TO_LINK variable + get_target_property(QT_LIBRARY_LOCATION Qt5::${QT_MODULE} LOCATION) + list(APPEND ${TARGET}_QT_MODULES_TO_LINK ${QT_LIBRARY_LOCATION}) + endforeach() - if (${INCLUDE_QT}) - find_package(Qt5 COMPONENTS Core) - target_link_libraries(${TARGET} Qt5::Core) - endif () endmacro() \ No newline at end of file diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index 7f9dc2db37..3c1d34ba01 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME domain-server) -setup_hifi_project(${TARGET_NAME} TRUE) +setup_hifi_project(${TARGET_NAME}) # remove and then copy the files for the webserver add_custom_command(TARGET ${TARGET_NAME} POST_BUILD diff --git a/libraries/animation/CMakeLists.txt b/libraries/animation/CMakeLists.txt index 9c419d9369..19fa087092 100644 --- a/libraries/animation/CMakeLists.txt +++ b/libraries/animation/CMakeLists.txt @@ -3,4 +3,7 @@ set(TARGET_NAME animation) # use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library(${TARGET_NAME} Network Script) -link_hifi_libraries(${TARGET_NAME} shared fbx) \ No newline at end of file +link_hifi_libraries(${TARGET_NAME} shared fbx) + +# call macro to link our dependencies and bubble them up via a property on our target +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/libraries/audio/CMakeLists.txt b/libraries/audio/CMakeLists.txt index 354a3772dd..8487f48ad3 100644 --- a/libraries/audio/CMakeLists.txt +++ b/libraries/audio/CMakeLists.txt @@ -5,4 +5,7 @@ setup_hifi_library(${TARGET_NAME} Network) include_glm(${TARGET_NAME} "${ROOT_DIR}") -link_hifi_libraries(${TARGET_NAME} networking shared) \ No newline at end of file +link_hifi_libraries(${TARGET_NAME} networking shared) + +# call macro to link our dependencies and bubble them up via a property on our target +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index d05faf3b27..2791589abb 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -6,4 +6,7 @@ setup_hifi_library(${TARGET_NAME} Network Script) include_glm(${TARGET_NAME} "${ROOT_DIR}") link_hifi_libraries(${TARGET_NAME} shared octree voxels networking) -include_hifi_library_headers(fbx) \ No newline at end of file +include_hifi_library_headers(fbx) + +# call macro to link our dependencies and bubble them up via a property on our target +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/libraries/embedded-webserver/CMakeLists.txt b/libraries/embedded-webserver/CMakeLists.txt index c299aa654d..b397003133 100644 --- a/libraries/embedded-webserver/CMakeLists.txt +++ b/libraries/embedded-webserver/CMakeLists.txt @@ -1,4 +1,7 @@ set(TARGET_NAME embedded-webserver) # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(${TARGET_NAME} Network) \ No newline at end of file +setup_hifi_library(${TARGET_NAME} Network) + +# call macro to link our dependencies and bubble them up via a property on our target +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/libraries/fbx/CMakeLists.txt b/libraries/fbx/CMakeLists.txt index e9658de4a2..d02cc918fc 100644 --- a/libraries/fbx/CMakeLists.txt +++ b/libraries/fbx/CMakeLists.txt @@ -7,12 +7,9 @@ include_glm(${TARGET_NAME} "${ROOT_DIR}") link_hifi_libraries(${TARGET_NAME} shared networking octree voxels) -# link ZLIB find_package(ZLIB) - include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") +list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${ZLIB_LIBRARIES}") -# set a property indicating the libraries we are dependent on and link them to ourselves -set(DEPENDENCY_LIBRARIES "${ZLIB_LIBRARIES}") -set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES ${DEPENDENCY_LIBRARIES}) -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) +# call macro to link our dependencies and bubble them up via a property on our target +link_shared_dependencies_to_target(${TARGET_NAME}) diff --git a/libraries/metavoxels/CMakeLists.txt b/libraries/metavoxels/CMakeLists.txt index a8d6de698b..b9a03bf0f4 100644 --- a/libraries/metavoxels/CMakeLists.txt +++ b/libraries/metavoxels/CMakeLists.txt @@ -8,4 +8,7 @@ setup_hifi_library(${TARGET_NAME} Network Script Widgets) # link in the networking library link_hifi_libraries(${TARGET_NAME} shared networking) -include_glm(${TARGET_NAME} "${ROOT_DIR}") \ No newline at end of file +include_glm(${TARGET_NAME} "${ROOT_DIR}") + +# call macro to link our dependencies and bubble them up via a property on our target +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/libraries/models/CMakeLists.txt b/libraries/models/CMakeLists.txt index c0610b0501..89178f193a 100644 --- a/libraries/models/CMakeLists.txt +++ b/libraries/models/CMakeLists.txt @@ -5,4 +5,7 @@ setup_hifi_library(${TARGET_NAME} Network Script) include_glm(${TARGET_NAME} "${ROOT_DIR}") -link_hifi_libraries(${TARGET_NAME} shared octree fbx networking animation) \ No newline at end of file +link_hifi_libraries(${TARGET_NAME} shared octree fbx networking animation) + +# call macro to link our dependencies and bubble them up via a property on our target +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index fb9f07b81a..c2b86e2218 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -3,4 +3,7 @@ set(TARGET_NAME networking) # use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library(${TARGET_NAME} Network) -link_hifi_libraries(${TARGET_NAME} shared) \ No newline at end of file +link_hifi_libraries(${TARGET_NAME} shared) + +# call macro to link our dependencies and bubble them up via a property on our target +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/libraries/octree/CMakeLists.txt b/libraries/octree/CMakeLists.txt index 340b2393e6..1fa730aad7 100644 --- a/libraries/octree/CMakeLists.txt +++ b/libraries/octree/CMakeLists.txt @@ -7,13 +7,15 @@ include_glm(${TARGET_NAME} "${ROOT_DIR}") link_hifi_libraries(${TARGET_NAME} shared networking) -# link ZLIB +# find ZLIB and OpenSSL find_package(ZLIB) find_package(OpenSSL REQUIRED) include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}" "${OPENSSL_INCLUDE_DIR}") - -# set a property indicating the libraries we are dependent on and link them to ourselves -set(DEPENDENCY_LIBRARIES "${ZLIB_LIBRARIES}" "${OPENSSL_LIBRARIES}") -set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES ${DEPENDENCY_LIBRARIES}) -target_link_libraries(${TARGET_NAME} ${DEPENDENCY_LIBRARIES}) \ No newline at end of file + +# append ZLIB and OpenSSL to our list of libraries to link +list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${ZLIB_LIBRARIES}") +list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${OPENSSL_LIBRARIES}") + +# call macro to link our dependencies and bubble them up via a property on our target +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/libraries/particles/CMakeLists.txt b/libraries/particles/CMakeLists.txt index 2f523b22f7..f306c0a749 100644 --- a/libraries/particles/CMakeLists.txt +++ b/libraries/particles/CMakeLists.txt @@ -6,4 +6,7 @@ setup_hifi_library(${TARGET_NAME} Gui Network Script) include_glm(${TARGET_NAME} "${ROOT_DIR}") link_hifi_libraries(${TARGET_NAME} shared octree fbx networking animation) -include_hifi_library_headers(script-engine) \ No newline at end of file +include_hifi_library_headers(script-engine) + +# call macro to link our dependencies and bubble them up via a property on our target +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index cce7d8d07b..a16d6270c9 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -5,4 +5,7 @@ setup_hifi_library(${TARGET_NAME} Gui Network Script Widgets) include_glm(${TARGET_NAME} "${ROOT_DIR}") -link_hifi_libraries(${TARGET_NAME} shared octree voxels fbx particles models animation) \ No newline at end of file +link_hifi_libraries(${TARGET_NAME} shared octree voxels fbx particles models animation) + +# call macro to link our dependencies and bubble them up via a property on our target +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index 9cc1b968dc..1a6b39ea59 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -1,4 +1,7 @@ set(TARGET_NAME shared) # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(${TARGET_NAME} Network Widgets) \ No newline at end of file +setup_hifi_library(${TARGET_NAME} Network Widgets) + +# call macro to link our dependencies and bubble them up via a property on our target +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/libraries/voxels/CMakeLists.txt b/libraries/voxels/CMakeLists.txt index 7f200523de..87841ca29f 100644 --- a/libraries/voxels/CMakeLists.txt +++ b/libraries/voxels/CMakeLists.txt @@ -7,10 +7,12 @@ include_glm(${TARGET_NAME} "${ROOT_DIR}") link_hifi_libraries(${TARGET_NAME} shared octree networking) -# link ZLIB +# find ZLIB find_package(ZLIB) include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") -get_target_property(LINKED_LIBRARIES ${TARGET_NAME} DEPENDENCY_LIBRARIES) -list(APPEND DEPENDENCY_LIBRARIES "${ZLIB_LIBRARIES}") -list(REMOVE_DUPLICATES DEPENDENCY_LIBRARIES) \ No newline at end of file +# add it to our list of libraries to link +list(APPEND ${TARGET}_LIBRARIES_TO_LINK "${ZLIB_LIBRARIES}") + +# call macro to link our dependencies and bubble them up via a property on our target +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/tests/audio/CMakeLists.txt b/tests/audio/CMakeLists.txt index 34d053b008..f5d9388508 100644 --- a/tests/audio/CMakeLists.txt +++ b/tests/audio/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME audio-tests) -setup_hifi_project(${TARGET_NAME} TRUE) +setup_hifi_project(${TARGET_NAME}) #include glm include_glm(${TARGET_NAME} ${ROOT_DIR}) diff --git a/tests/jitter/CMakeLists.txt b/tests/jitter/CMakeLists.txt index 4fb3d56492..9c861eac3e 100644 --- a/tests/jitter/CMakeLists.txt +++ b/tests/jitter/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME jitter-tests) -setup_hifi_project(${TARGET_NAME} TRUE) +setup_hifi_project(${TARGET_NAME}) # link in the shared libraries link_hifi_libraries(${TARGET_NAME} shared networking) \ No newline at end of file diff --git a/tests/metavoxels/CMakeLists.txt b/tests/metavoxels/CMakeLists.txt index d459ea1fed..358a959eb0 100644 --- a/tests/metavoxels/CMakeLists.txt +++ b/tests/metavoxels/CMakeLists.txt @@ -4,7 +4,7 @@ find_package(Qt5 COMPONENTS Network Script Widgets) auto_mtc(${TARGET_NAME} "${ROOT_DIR}") -setup_hifi_project(${TARGET_NAME} TRUE "${AUTOMTC_SRC}") +setup_hifi_project(${TARGET_NAME}) # link in the shared libraries link_hifi_libraries(${TARGET_NAME} metavoxels networking shared) diff --git a/tests/networking/CMakeLists.txt b/tests/networking/CMakeLists.txt index ec48bb80cd..68de37a1d2 100644 --- a/tests/networking/CMakeLists.txt +++ b/tests/networking/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME networking-tests) -setup_hifi_project(${TARGET_NAME} TRUE) +setup_hifi_project(${TARGET_NAME}) # link in the shared libraries link_hifi_libraries(${TARGET_NAME} shared networking) diff --git a/tests/octree/CMakeLists.txt b/tests/octree/CMakeLists.txt index 85442db783..a8e27e0084 100644 --- a/tests/octree/CMakeLists.txt +++ b/tests/octree/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME octree-tests) -setup_hifi_project(${TARGET_NAME} TRUE) +setup_hifi_project(${TARGET_NAME}) # link in the shared libraries link_hifi_libraries(${TARGET_NAME} octree) diff --git a/tests/physics/CMakeLists.txt b/tests/physics/CMakeLists.txt index 2161723619..01bdf5a96b 100644 --- a/tests/physics/CMakeLists.txt +++ b/tests/physics/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME physics-tests) -setup_hifi_project(${TARGET_NAME} TRUE) +setup_hifi_project(${TARGET_NAME}) # link in the shared libraries link_hifi_libraries(${TARGET_NAME} shared) diff --git a/tests/shared/CMakeLists.txt b/tests/shared/CMakeLists.txt index bea8448f5e..828559936b 100644 --- a/tests/shared/CMakeLists.txt +++ b/tests/shared/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME shared-tests) -setup_hifi_project(${TARGET_NAME} TRUE) +setup_hifi_project(${TARGET_NAME}) # link in the shared libraries link_hifi_libraries(${TARGET_NAME} shared) diff --git a/tools/bitstream2json/CMakeLists.txt b/tools/bitstream2json/CMakeLists.txt index 3b3a65c259..a5077dc181 100644 --- a/tools/bitstream2json/CMakeLists.txt +++ b/tools/bitstream2json/CMakeLists.txt @@ -1,2 +1,2 @@ set(TARGET_NAME bitstream2json) -setup_hifi_project(${TARGET_NAME} TRUE) \ No newline at end of file +setup_hifi_project(${TARGET_NAME}) \ No newline at end of file diff --git a/tools/json2bitstream/CMakeLists.txt b/tools/json2bitstream/CMakeLists.txt index 452f845356..28c18f6762 100644 --- a/tools/json2bitstream/CMakeLists.txt +++ b/tools/json2bitstream/CMakeLists.txt @@ -1,2 +1,2 @@ set(TARGET_NAME json2bitstream) -setup_hifi_project(${TARGET_NAME} TRUE) \ No newline at end of file +setup_hifi_project(${TARGET_NAME}) \ No newline at end of file diff --git a/tools/mtc/CMakeLists.txt b/tools/mtc/CMakeLists.txt index 467d03d241..0b1c438393 100644 --- a/tools/mtc/CMakeLists.txt +++ b/tools/mtc/CMakeLists.txt @@ -1,2 +1,2 @@ set(TARGET_NAME mtc) -setup_hifi_project(${TARGET_NAME} TRUE) \ No newline at end of file +setup_hifi_project(${TARGET_NAME}) \ No newline at end of file diff --git a/voxel-edit/CMakeLists.txt b/voxel-edit/CMakeLists.txt index db22f040b7..5fa4061117 100644 --- a/voxel-edit/CMakeLists.txt +++ b/voxel-edit/CMakeLists.txt @@ -1,3 +1,3 @@ set(TARGET_NAME voxel-edit) -setup_hifi_project(${TARGET_NAME} TRUE) \ No newline at end of file +setup_hifi_project(${TARGET_NAME}) \ No newline at end of file From e4d01d269c9d53739a0b315ce78adcaba15e1ffb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 11:51:12 -0700 Subject: [PATCH 284/407] use shared dependency linking macro in hifi projects --- domain-server/CMakeLists.txt | 9 +++++---- interface/CMakeLists.txt | 3 +++ tests/audio/CMakeLists.txt | 5 ++++- tests/jitter/CMakeLists.txt | 5 ++++- tests/metavoxels/CMakeLists.txt | 8 +++----- tests/networking/CMakeLists.txt | 2 ++ tests/octree/CMakeLists.txt | 5 ++--- tests/physics/CMakeLists.txt | 2 ++ tests/shared/CMakeLists.txt | 3 +++ tools/bitstream2json/CMakeLists.txt | 5 ++++- tools/mtc/CMakeLists.txt | 5 ++++- voxel-edit/CMakeLists.txt | 5 ++++- 12 files changed, 40 insertions(+), 17 deletions(-) diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index 3c1d34ba01..99e57cb0e6 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -1,6 +1,7 @@ set(TARGET_NAME domain-server) -setup_hifi_project(${TARGET_NAME}) +# setup the project and link required Qt modules +setup_hifi_project(${TARGET_NAME} Network) # remove and then copy the files for the webserver add_custom_command(TARGET ${TARGET_NAME} POST_BUILD @@ -11,8 +12,8 @@ add_custom_command(TARGET ${TARGET_NAME} POST_BUILD "${PROJECT_SOURCE_DIR}/resources/web" $/resources/web) -# link the shared hifi library +# link the shared hifi libraries link_hifi_libraries(${TARGET_NAME} embedded-webserver networking shared) -find_package(Qt5 COMPONENTS Network Widgets) -target_link_libraries(${TARGET_NAME} Qt5::Network) +# link any shared dependencies +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index ea4b54257b..a2770943a7 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -209,3 +209,6 @@ else (APPLE) target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" wsock32.lib opengl32.lib) endif() endif (APPLE) + +# link any dependencies bubbled up from our linked dependencies +link_shared_dependencies_to_target(${TARGET_NAME}) diff --git a/tests/audio/CMakeLists.txt b/tests/audio/CMakeLists.txt index f5d9388508..973726852d 100644 --- a/tests/audio/CMakeLists.txt +++ b/tests/audio/CMakeLists.txt @@ -6,4 +6,7 @@ setup_hifi_project(${TARGET_NAME}) include_glm(${TARGET_NAME} ${ROOT_DIR}) # link in the shared libraries -link_hifi_libraries(${TARGET_NAME} shared audio networking) \ No newline at end of file +link_hifi_libraries(${TARGET_NAME} shared audio networking) + +# link any shared dependencies +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/tests/jitter/CMakeLists.txt b/tests/jitter/CMakeLists.txt index 9c861eac3e..577591227f 100644 --- a/tests/jitter/CMakeLists.txt +++ b/tests/jitter/CMakeLists.txt @@ -3,4 +3,7 @@ set(TARGET_NAME jitter-tests) setup_hifi_project(${TARGET_NAME}) # link in the shared libraries -link_hifi_libraries(${TARGET_NAME} shared networking) \ No newline at end of file +link_hifi_libraries(${TARGET_NAME} shared networking) + +# link any shared dependencies +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/tests/metavoxels/CMakeLists.txt b/tests/metavoxels/CMakeLists.txt index 358a959eb0..6432b9a259 100644 --- a/tests/metavoxels/CMakeLists.txt +++ b/tests/metavoxels/CMakeLists.txt @@ -1,13 +1,11 @@ set(TARGET_NAME metavoxel-tests) -find_package(Qt5 COMPONENTS Network Script Widgets) - auto_mtc(${TARGET_NAME} "${ROOT_DIR}") -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project(${TARGET_NAME} Network Script Widgets) # link in the shared libraries link_hifi_libraries(${TARGET_NAME} metavoxels networking shared) -target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script) - +# link any shared dependencies +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/tests/networking/CMakeLists.txt b/tests/networking/CMakeLists.txt index 68de37a1d2..214b66fd1f 100644 --- a/tests/networking/CMakeLists.txt +++ b/tests/networking/CMakeLists.txt @@ -5,3 +5,5 @@ setup_hifi_project(${TARGET_NAME}) # link in the shared libraries link_hifi_libraries(${TARGET_NAME} shared networking) +# link any shared dependencies +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/tests/octree/CMakeLists.txt b/tests/octree/CMakeLists.txt index a8e27e0084..e9a06bd1c1 100644 --- a/tests/octree/CMakeLists.txt +++ b/tests/octree/CMakeLists.txt @@ -5,6 +5,5 @@ setup_hifi_project(${TARGET_NAME}) # link in the shared libraries link_hifi_libraries(${TARGET_NAME} octree) -IF (WIN32) - target_link_libraries(${TARGET_NAME} wsock32.lib) -ENDIF(WIN32) +# link any shared dependencies +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/tests/physics/CMakeLists.txt b/tests/physics/CMakeLists.txt index 01bdf5a96b..74049b158b 100644 --- a/tests/physics/CMakeLists.txt +++ b/tests/physics/CMakeLists.txt @@ -5,3 +5,5 @@ setup_hifi_project(${TARGET_NAME}) # link in the shared libraries link_hifi_libraries(${TARGET_NAME} shared) +# link any shared dependencies +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/tests/shared/CMakeLists.txt b/tests/shared/CMakeLists.txt index 828559936b..294a60d130 100644 --- a/tests/shared/CMakeLists.txt +++ b/tests/shared/CMakeLists.txt @@ -4,3 +4,6 @@ setup_hifi_project(${TARGET_NAME}) # link in the shared libraries link_hifi_libraries(${TARGET_NAME} shared) + +# link any shared dependencies +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/tools/bitstream2json/CMakeLists.txt b/tools/bitstream2json/CMakeLists.txt index a5077dc181..884f9f9c2c 100644 --- a/tools/bitstream2json/CMakeLists.txt +++ b/tools/bitstream2json/CMakeLists.txt @@ -1,2 +1,5 @@ set(TARGET_NAME bitstream2json) -setup_hifi_project(${TARGET_NAME}) \ No newline at end of file +setup_hifi_project(${TARGET_NAME}) + +# link any shared dependencies +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/tools/mtc/CMakeLists.txt b/tools/mtc/CMakeLists.txt index 0b1c438393..dc30da8098 100644 --- a/tools/mtc/CMakeLists.txt +++ b/tools/mtc/CMakeLists.txt @@ -1,2 +1,5 @@ set(TARGET_NAME mtc) -setup_hifi_project(${TARGET_NAME}) \ No newline at end of file +setup_hifi_project(${TARGET_NAME}) + +# link any shared dependencies +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/voxel-edit/CMakeLists.txt b/voxel-edit/CMakeLists.txt index 5fa4061117..f9f8ed185b 100644 --- a/voxel-edit/CMakeLists.txt +++ b/voxel-edit/CMakeLists.txt @@ -1,3 +1,6 @@ set(TARGET_NAME voxel-edit) -setup_hifi_project(${TARGET_NAME}) \ No newline at end of file +setup_hifi_project(${TARGET_NAME}) + +# link any shared dependencies +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file From 0449660f66adf279ef09e0e74dd3a0ffaa33fe2c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 11:52:41 -0700 Subject: [PATCH 285/407] don't bubble up hifi libraries since they are static --- cmake/macros/LinkHifiLibraries.cmake | 4 ++-- tools/json2bitstream/CMakeLists.txt | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cmake/macros/LinkHifiLibraries.cmake b/cmake/macros/LinkHifiLibraries.cmake index 96c5d82cae..00020cc059 100644 --- a/cmake/macros/LinkHifiLibraries.cmake +++ b/cmake/macros/LinkHifiLibraries.cmake @@ -22,8 +22,8 @@ macro(LINK_HIFI_LIBRARIES TARGET) add_dependencies(${TARGET} ${HIFI_LIBRARY}) - # link the actual library - list(APPEND ${TARGET}_LIBRARIES_TO_LINK ${HIFI_LIBRARY}) + # link the actual library - it is static so don't bubble it up + target_link_libraries(${TARGET} ${HIFI_LIBRARY}) # ask the library what its dynamic dependencies are and link them get_target_property(LINKED_TARGET_DEPENDENCY_LIBRARIES ${HIFI_LIBRARY} DEPENDENCY_LIBRARIES) diff --git a/tools/json2bitstream/CMakeLists.txt b/tools/json2bitstream/CMakeLists.txt index 28c18f6762..3868b551ea 100644 --- a/tools/json2bitstream/CMakeLists.txt +++ b/tools/json2bitstream/CMakeLists.txt @@ -1,2 +1,5 @@ set(TARGET_NAME json2bitstream) -setup_hifi_project(${TARGET_NAME}) \ No newline at end of file +setup_hifi_project(${TARGET_NAME}) + +# link any shared dependencies +link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file From 27419b7b6b9b8b7bbb089f771ac07419159e6ae1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 12:41:41 -0700 Subject: [PATCH 286/407] fix some build blockers in test directory --- libraries/shared/src/MovingMinMaxAvg.h | 1 + tests/metavoxels/CMakeLists.txt | 2 ++ tests/networking/src/SequenceNumberStatsTests.cpp | 7 ++++--- tests/octree/CMakeLists.txt | 6 ++++-- tests/physics/CMakeLists.txt | 2 ++ tests/shared/CMakeLists.txt | 2 ++ 6 files changed, 15 insertions(+), 5 deletions(-) diff --git a/libraries/shared/src/MovingMinMaxAvg.h b/libraries/shared/src/MovingMinMaxAvg.h index 734018b469..7d4b3df124 100644 --- a/libraries/shared/src/MovingMinMaxAvg.h +++ b/libraries/shared/src/MovingMinMaxAvg.h @@ -12,6 +12,7 @@ #ifndef hifi_MovingMinMaxAvg_h #define hifi_MovingMinMaxAvg_h +#include #include #include "RingBufferHistory.h" diff --git a/tests/metavoxels/CMakeLists.txt b/tests/metavoxels/CMakeLists.txt index 6432b9a259..0fad728764 100644 --- a/tests/metavoxels/CMakeLists.txt +++ b/tests/metavoxels/CMakeLists.txt @@ -2,6 +2,8 @@ set(TARGET_NAME metavoxel-tests) auto_mtc(${TARGET_NAME} "${ROOT_DIR}") +include_glm(${TARGET_NAME}) + setup_hifi_project(${TARGET_NAME} Network Script Widgets) # link in the shared libraries diff --git a/tests/networking/src/SequenceNumberStatsTests.cpp b/tests/networking/src/SequenceNumberStatsTests.cpp index 901a018235..ded67b1ab6 100644 --- a/tests/networking/src/SequenceNumberStatsTests.cpp +++ b/tests/networking/src/SequenceNumberStatsTests.cpp @@ -9,11 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "SequenceNumberStatsTests.h" - -#include "SharedUtil.h" +#include #include +#include + +#include "SequenceNumberStatsTests.h" void SequenceNumberStatsTests::runAllTests() { rolloverTest(); diff --git a/tests/octree/CMakeLists.txt b/tests/octree/CMakeLists.txt index e9a06bd1c1..baae258643 100644 --- a/tests/octree/CMakeLists.txt +++ b/tests/octree/CMakeLists.txt @@ -1,9 +1,11 @@ set(TARGET_NAME octree-tests) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project(${TARGET_NAME} Script Network) + +include_glm(${TARGET_NAME}) # link in the shared libraries -link_hifi_libraries(${TARGET_NAME} octree) +link_hifi_libraries(${TARGET_NAME} animation fbx models networking octree shared) # link any shared dependencies link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file diff --git a/tests/physics/CMakeLists.txt b/tests/physics/CMakeLists.txt index 74049b158b..e2affa7b47 100644 --- a/tests/physics/CMakeLists.txt +++ b/tests/physics/CMakeLists.txt @@ -2,6 +2,8 @@ set(TARGET_NAME physics-tests) setup_hifi_project(${TARGET_NAME}) +include_glm(${TARGET_NAME}) + # link in the shared libraries link_hifi_libraries(${TARGET_NAME} shared) diff --git a/tests/shared/CMakeLists.txt b/tests/shared/CMakeLists.txt index 294a60d130..f819a2734b 100644 --- a/tests/shared/CMakeLists.txt +++ b/tests/shared/CMakeLists.txt @@ -2,6 +2,8 @@ set(TARGET_NAME shared-tests) setup_hifi_project(${TARGET_NAME}) +include_glm(${TARGET_NAME}) + # link in the shared libraries link_hifi_libraries(${TARGET_NAME} shared) From b1310c065ce7e37d1c61026e53614b99207d6311 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 12:55:06 -0700 Subject: [PATCH 287/407] remove TARGET_NAME from cmake macros where it is not required --- assignment-client/CMakeLists.txt | 8 ++++---- cmake/macros/AutoMTC.cmake | 4 ++-- cmake/macros/IncludeGLM.cmake | 4 ++-- cmake/macros/LinkHifiLibraries.cmake | 10 +++++----- ...ToTarget.cmake => LinkSharedDependencies.cmake} | 14 +++++++------- cmake/macros/SetupHifiLibrary.cmake | 12 ++++++------ cmake/macros/SetupHifiProject.cmake | 10 +++++----- domain-server/CMakeLists.txt | 6 +++--- interface/CMakeLists.txt | 6 +++--- libraries/animation/CMakeLists.txt | 6 +++--- libraries/audio/CMakeLists.txt | 8 ++++---- libraries/avatars/CMakeLists.txt | 8 ++++---- libraries/embedded-webserver/CMakeLists.txt | 4 ++-- libraries/fbx/CMakeLists.txt | 8 ++++---- libraries/metavoxels/CMakeLists.txt | 10 +++++----- libraries/models/CMakeLists.txt | 8 ++++---- libraries/networking/CMakeLists.txt | 6 +++--- libraries/octree/CMakeLists.txt | 8 ++++---- libraries/particles/CMakeLists.txt | 8 ++++---- libraries/script-engine/CMakeLists.txt | 8 ++++---- libraries/shared/CMakeLists.txt | 4 ++-- libraries/voxels/CMakeLists.txt | 8 ++++---- tests/audio/CMakeLists.txt | 9 ++++----- tests/jitter/CMakeLists.txt | 6 +++--- tests/metavoxels/CMakeLists.txt | 10 +++++----- tests/networking/CMakeLists.txt | 6 +++--- tests/octree/CMakeLists.txt | 8 ++++---- tests/physics/CMakeLists.txt | 8 ++++---- tests/shared/CMakeLists.txt | 8 ++++---- tools/bitstream2json/CMakeLists.txt | 4 ++-- tools/json2bitstream/CMakeLists.txt | 4 ++-- tools/mtc/CMakeLists.txt | 4 ++-- voxel-edit/CMakeLists.txt | 4 ++-- 33 files changed, 119 insertions(+), 120 deletions(-) rename cmake/macros/{LinkSharedDependenciesToTarget.cmake => LinkSharedDependencies.cmake} (61%) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 9f8542c42e..972c6ac220 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -1,11 +1,11 @@ set(TARGET_NAME assignment-client) -setup_hifi_project(${TARGET_NAME} Core Gui Network Script Widgets) +setup_hifi_project(Core Gui Network Script Widgets) -include_glm(${TARGET_NAME}) +include_glm() # link in the shared libraries -link_hifi_libraries(${TARGET_NAME} +link_hifi_libraries( audio avatars octree voxels fbx particles models metavoxels networking animation shared script-engine embedded-webserver ) @@ -14,4 +14,4 @@ if (UNIX) list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK ${CMAKE_DL_LIBS}) endif (UNIX) -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/cmake/macros/AutoMTC.cmake b/cmake/macros/AutoMTC.cmake index 0e376fc176..4d433e7b69 100644 --- a/cmake/macros/AutoMTC.cmake +++ b/cmake/macros/AutoMTC.cmake @@ -8,8 +8,8 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # -macro(AUTO_MTC TARGET) - set(AUTOMTC_SRC ${TARGET}_automtc.cpp) +macro(AUTO_MTC) + set(AUTOMTC_SRC ${TARGET_NAME}_automtc.cpp) file(GLOB INCLUDE_FILES src/*.h) diff --git a/cmake/macros/IncludeGLM.cmake b/cmake/macros/IncludeGLM.cmake index ec7816770f..e2fa981a3b 100644 --- a/cmake/macros/IncludeGLM.cmake +++ b/cmake/macros/IncludeGLM.cmake @@ -7,7 +7,7 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # -macro(INCLUDE_GLM TARGET) +macro(INCLUDE_GLM) find_package(GLM REQUIRED) include_directories("${GLM_INCLUDE_DIRS}") @@ -16,4 +16,4 @@ macro(INCLUDE_GLM TARGET) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${GLM_INCLUDE_DIRS}") endif () -endmacro(INCLUDE_GLM _target) \ No newline at end of file +endmacro(INCLUDE_GLM) \ No newline at end of file diff --git a/cmake/macros/LinkHifiLibraries.cmake b/cmake/macros/LinkHifiLibraries.cmake index 00020cc059..9d73963fea 100644 --- a/cmake/macros/LinkHifiLibraries.cmake +++ b/cmake/macros/LinkHifiLibraries.cmake @@ -7,7 +7,7 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # -macro(LINK_HIFI_LIBRARIES TARGET) +macro(LINK_HIFI_LIBRARIES) file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}") @@ -20,15 +20,15 @@ macro(LINK_HIFI_LIBRARIES TARGET) include_directories("${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src") - add_dependencies(${TARGET} ${HIFI_LIBRARY}) + add_dependencies(${TARGET_NAME} ${HIFI_LIBRARY}) # link the actual library - it is static so don't bubble it up - target_link_libraries(${TARGET} ${HIFI_LIBRARY}) + target_link_libraries(${TARGET_NAME} ${HIFI_LIBRARY}) # ask the library what its dynamic dependencies are and link them get_target_property(LINKED_TARGET_DEPENDENCY_LIBRARIES ${HIFI_LIBRARY} DEPENDENCY_LIBRARIES) - list(APPEND ${TARGET}_LIBRARIES_TO_LINK ${LINKED_TARGET_DEPENDENCY_LIBRARIES}) + list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK ${LINKED_TARGET_DEPENDENCY_LIBRARIES}) endforeach() -endmacro(LINK_HIFI_LIBRARIES _target _libraries) \ No newline at end of file +endmacro(LINK_HIFI_LIBRARIES) \ No newline at end of file diff --git a/cmake/macros/LinkSharedDependenciesToTarget.cmake b/cmake/macros/LinkSharedDependencies.cmake similarity index 61% rename from cmake/macros/LinkSharedDependenciesToTarget.cmake rename to cmake/macros/LinkSharedDependencies.cmake index 42f7109807..ae478ca530 100644 --- a/cmake/macros/LinkSharedDependenciesToTarget.cmake +++ b/cmake/macros/LinkSharedDependencies.cmake @@ -1,5 +1,5 @@ # -# LinkHifiLibrary.cmake +# LinkSharedDependencies.cmake # cmake/macros # # Copyright 2014 High Fidelity, Inc. @@ -9,17 +9,17 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # -macro(LINK_SHARED_DEPENDENCIES_TO_TARGET TARGET) - if (${TARGET}_LIBRARIES_TO_LINK) - list(REMOVE_DUPLICATES ${TARGET}_LIBRARIES_TO_LINK) +macro(LINK_SHARED_DEPENDENCIES) + if (${TARGET_NAME}_LIBRARIES_TO_LINK) + list(REMOVE_DUPLICATES ${TARGET_NAME}_LIBRARIES_TO_LINK) # link these libraries to our target - target_link_libraries(${TARGET} ${${TARGET}_LIBRARIES_TO_LINK}) + target_link_libraries(${TARGET_NAME} ${${TARGET_NAME}_LIBRARIES_TO_LINK}) endif () # we've already linked our Qt modules, but we need to bubble them up to parents - list(APPEND ${TARGET}_LIBRARIES_TO_LINK "${${TARGET}_QT_MODULES_TO_LINK}") + list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${${TARGET}_QT_MODULES_TO_LINK}") # set the property on this target so it can be retreived by targets linking to us set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${${TARGET}_LIBRARIES_TO_LINK}") -endmacro(LINK_SHARED_DEPENDENCIES_TO_TARGET _target) \ No newline at end of file +endmacro(LINK_SHARED_DEPENDENCIES) \ No newline at end of file diff --git a/cmake/macros/SetupHifiLibrary.cmake b/cmake/macros/SetupHifiLibrary.cmake index 73ee208b98..3c2590d38d 100644 --- a/cmake/macros/SetupHifiLibrary.cmake +++ b/cmake/macros/SetupHifiLibrary.cmake @@ -7,16 +7,16 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # -macro(SETUP_HIFI_LIBRARY TARGET) +macro(SETUP_HIFI_LIBRARY) - project(${TARGET}) + project(${TARGET_NAME}) # grab the implemenation and header files file(GLOB LIB_SRCS src/*.h src/*.cpp) set(LIB_SRCS ${LIB_SRCS}) # create a library and set the property so it can be referenced later - add_library(${TARGET} ${LIB_SRCS} ${AUTOMTC_SRC}) + add_library(${TARGET_NAME} ${LIB_SRCS} ${AUTOMTC_SRC}) set(QT_MODULES_TO_LINK ${ARGN}) list(APPEND QT_MODULES_TO_LINK Core) @@ -27,7 +27,7 @@ macro(SETUP_HIFI_LIBRARY TARGET) get_target_property(QT_LIBRARY_LOCATION Qt5::${QT_MODULE} LOCATION) # add the actual path to the Qt module to our LIBRARIES_TO_LINK variable - target_link_libraries(${TARGET} Qt5::${QT_MODULE}) - list(APPEND ${TARGET}_QT_MODULES_TO_LINK ${QT_LIBRARY_LOCATION}) + target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE}) + list(APPEND ${TARGET_NAME}_QT_MODULES_TO_LINK ${QT_LIBRARY_LOCATION}) endforeach() -endmacro(SETUP_HIFI_LIBRARY _target) \ No newline at end of file +endmacro(SETUP_HIFI_LIBRARY) \ No newline at end of file diff --git a/cmake/macros/SetupHifiProject.cmake b/cmake/macros/SetupHifiProject.cmake index c680790f02..62c215e595 100644 --- a/cmake/macros/SetupHifiProject.cmake +++ b/cmake/macros/SetupHifiProject.cmake @@ -7,8 +7,8 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # -macro(SETUP_HIFI_PROJECT TARGET) - project(${TARGET}) +macro(SETUP_HIFI_PROJECT) + project(${TARGET_NAME}) # grab the implemenation and header files file(GLOB TARGET_SRCS src/*) @@ -23,7 +23,7 @@ macro(SETUP_HIFI_PROJECT TARGET) endforeach() # add the executable, include additional optional sources - add_executable(${TARGET} ${TARGET_SRCS} "${AUTOMTC_SRC}") + add_executable(${TARGET_NAME} ${TARGET_SRCS} "${AUTOMTC_SRC}") set(QT_MODULES_TO_LINK ${ARGN}) list(APPEND QT_MODULES_TO_LINK Core) @@ -31,11 +31,11 @@ macro(SETUP_HIFI_PROJECT TARGET) find_package(Qt5 COMPONENTS ${QT_MODULES_TO_LINK}) foreach(QT_MODULE ${QT_MODULES_TO_LINK}) - target_link_libraries(${TARGET} Qt5::${QT_MODULE}) + target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE}) # add the actual path to the Qt module to our LIBRARIES_TO_LINK variable get_target_property(QT_LIBRARY_LOCATION Qt5::${QT_MODULE} LOCATION) - list(APPEND ${TARGET}_QT_MODULES_TO_LINK ${QT_LIBRARY_LOCATION}) + list(APPEND ${TARGET_NAME}_QT_MODULES_TO_LINK ${QT_LIBRARY_LOCATION}) endforeach() endmacro() \ No newline at end of file diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index 99e57cb0e6..bc9269b9ce 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -1,7 +1,7 @@ set(TARGET_NAME domain-server) # setup the project and link required Qt modules -setup_hifi_project(${TARGET_NAME} Network) +setup_hifi_project(Network) # remove and then copy the files for the webserver add_custom_command(TARGET ${TARGET_NAME} POST_BUILD @@ -13,7 +13,7 @@ add_custom_command(TARGET ${TARGET_NAME} POST_BUILD $/resources/web) # link the shared hifi libraries -link_hifi_libraries(${TARGET_NAME} embedded-webserver networking shared) +link_hifi_libraries(embedded-webserver networking shared) # link any shared dependencies -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index a2770943a7..d58bea6f9e 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -32,7 +32,7 @@ elseif (WIN32) endif () # set up the external glm library -include_glm(${TARGET_NAME} "${ROOT_DIR}") +include_glm() # create the InterfaceConfig.h file based on GL_HEADERS above configure_file(InterfaceConfig.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceConfig.h") @@ -91,7 +91,7 @@ endif() add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM}) # link required hifi libraries -link_hifi_libraries(${TARGET_NAME} shared octree voxels fbx metavoxels networking particles models avatars audio animation script-engine) +link_hifi_libraries(shared octree voxels fbx metavoxels networking particles models avatars audio animation script-engine) # find any optional and required libraries find_package(Faceplus) @@ -211,4 +211,4 @@ else (APPLE) endif (APPLE) # link any dependencies bubbled up from our linked dependencies -link_shared_dependencies_to_target(${TARGET_NAME}) +link_shared_dependencies() diff --git a/libraries/animation/CMakeLists.txt b/libraries/animation/CMakeLists.txt index 19fa087092..3f65c1ab6c 100644 --- a/libraries/animation/CMakeLists.txt +++ b/libraries/animation/CMakeLists.txt @@ -1,9 +1,9 @@ set(TARGET_NAME animation) # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(${TARGET_NAME} Network Script) +setup_hifi_library(Network Script) -link_hifi_libraries(${TARGET_NAME} shared fbx) +link_hifi_libraries(shared fbx) # call macro to link our dependencies and bubble them up via a property on our target -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/libraries/audio/CMakeLists.txt b/libraries/audio/CMakeLists.txt index 8487f48ad3..6ade1fc423 100644 --- a/libraries/audio/CMakeLists.txt +++ b/libraries/audio/CMakeLists.txt @@ -1,11 +1,11 @@ set(TARGET_NAME audio) # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(${TARGET_NAME} Network) +setup_hifi_library(Network) -include_glm(${TARGET_NAME} "${ROOT_DIR}") +include_glm() -link_hifi_libraries(${TARGET_NAME} networking shared) +link_hifi_libraries(networking shared) # call macro to link our dependencies and bubble them up via a property on our target -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index 2791589abb..1d287ee7a2 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -1,12 +1,12 @@ set(TARGET_NAME avatars) # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(${TARGET_NAME} Network Script) +setup_hifi_library(Network Script) -include_glm(${TARGET_NAME} "${ROOT_DIR}") +include_glm() -link_hifi_libraries(${TARGET_NAME} shared octree voxels networking) +link_hifi_libraries(shared octree voxels networking) include_hifi_library_headers(fbx) # call macro to link our dependencies and bubble them up via a property on our target -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/libraries/embedded-webserver/CMakeLists.txt b/libraries/embedded-webserver/CMakeLists.txt index b397003133..6e4b92e217 100644 --- a/libraries/embedded-webserver/CMakeLists.txt +++ b/libraries/embedded-webserver/CMakeLists.txt @@ -1,7 +1,7 @@ set(TARGET_NAME embedded-webserver) # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(${TARGET_NAME} Network) +setup_hifi_library(Network) # call macro to link our dependencies and bubble them up via a property on our target -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/libraries/fbx/CMakeLists.txt b/libraries/fbx/CMakeLists.txt index d02cc918fc..3cc510aed9 100644 --- a/libraries/fbx/CMakeLists.txt +++ b/libraries/fbx/CMakeLists.txt @@ -1,15 +1,15 @@ set(TARGET_NAME fbx) # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(${TARGET_NAME}) +setup_hifi_library() -include_glm(${TARGET_NAME} "${ROOT_DIR}") +include_glm("${ROOT_DIR}") -link_hifi_libraries(${TARGET_NAME} shared networking octree voxels) +link_hifi_libraries(shared networking octree voxels) find_package(ZLIB) include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${ZLIB_LIBRARIES}") # call macro to link our dependencies and bubble them up via a property on our target -link_shared_dependencies_to_target(${TARGET_NAME}) +link_shared_dependencies() diff --git a/libraries/metavoxels/CMakeLists.txt b/libraries/metavoxels/CMakeLists.txt index b9a03bf0f4..aab8d2184d 100644 --- a/libraries/metavoxels/CMakeLists.txt +++ b/libraries/metavoxels/CMakeLists.txt @@ -1,14 +1,14 @@ set(TARGET_NAME metavoxels) -auto_mtc(${TARGET_NAME} "${ROOT_DIR}") +auto_mtc() # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(${TARGET_NAME} Network Script Widgets) +setup_hifi_library(Network Script Widgets) # link in the networking library -link_hifi_libraries(${TARGET_NAME} shared networking) +link_hifi_libraries(shared networking) -include_glm(${TARGET_NAME} "${ROOT_DIR}") +include_glm() # call macro to link our dependencies and bubble them up via a property on our target -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/libraries/models/CMakeLists.txt b/libraries/models/CMakeLists.txt index 89178f193a..858d01efa1 100644 --- a/libraries/models/CMakeLists.txt +++ b/libraries/models/CMakeLists.txt @@ -1,11 +1,11 @@ set(TARGET_NAME models) # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(${TARGET_NAME} Network Script) +setup_hifi_library(Network Script) -include_glm(${TARGET_NAME} "${ROOT_DIR}") +include_glm() -link_hifi_libraries(${TARGET_NAME} shared octree fbx networking animation) +link_hifi_libraries(shared octree fbx networking animation) # call macro to link our dependencies and bubble them up via a property on our target -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index c2b86e2218..3191cfe67b 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -1,9 +1,9 @@ set(TARGET_NAME networking) # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(${TARGET_NAME} Network) +setup_hifi_library(Network) -link_hifi_libraries(${TARGET_NAME} shared) +link_hifi_libraries(shared) # call macro to link our dependencies and bubble them up via a property on our target -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/libraries/octree/CMakeLists.txt b/libraries/octree/CMakeLists.txt index 1fa730aad7..193b058466 100644 --- a/libraries/octree/CMakeLists.txt +++ b/libraries/octree/CMakeLists.txt @@ -1,11 +1,11 @@ set(TARGET_NAME octree) # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(${TARGET_NAME}) +setup_hifi_library() -include_glm(${TARGET_NAME} "${ROOT_DIR}") +include_glm() -link_hifi_libraries(${TARGET_NAME} shared networking) +link_hifi_libraries(shared networking) # find ZLIB and OpenSSL find_package(ZLIB) @@ -18,4 +18,4 @@ list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${ZLIB_LIBRARIES}") list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${OPENSSL_LIBRARIES}") # call macro to link our dependencies and bubble them up via a property on our target -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/libraries/particles/CMakeLists.txt b/libraries/particles/CMakeLists.txt index f306c0a749..27fc816530 100644 --- a/libraries/particles/CMakeLists.txt +++ b/libraries/particles/CMakeLists.txt @@ -1,12 +1,12 @@ set(TARGET_NAME particles) # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(${TARGET_NAME} Gui Network Script) +setup_hifi_library(Gui Network Script) -include_glm(${TARGET_NAME} "${ROOT_DIR}") +include_glm() -link_hifi_libraries(${TARGET_NAME} shared octree fbx networking animation) +link_hifi_libraries(shared octree fbx networking animation) include_hifi_library_headers(script-engine) # call macro to link our dependencies and bubble them up via a property on our target -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index a16d6270c9..dd28e77b7e 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -1,11 +1,11 @@ set(TARGET_NAME script-engine) # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(${TARGET_NAME} Gui Network Script Widgets) +setup_hifi_library(Gui Network Script Widgets) -include_glm(${TARGET_NAME} "${ROOT_DIR}") +include_glm() -link_hifi_libraries(${TARGET_NAME} shared octree voxels fbx particles models animation) +link_hifi_libraries(shared octree voxels fbx particles models animation) # call macro to link our dependencies and bubble them up via a property on our target -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index 1a6b39ea59..17ccbdc6ce 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -1,7 +1,7 @@ set(TARGET_NAME shared) # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(${TARGET_NAME} Network Widgets) +setup_hifi_library(Network Widgets) # call macro to link our dependencies and bubble them up via a property on our target -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/libraries/voxels/CMakeLists.txt b/libraries/voxels/CMakeLists.txt index 87841ca29f..d9d8717fba 100644 --- a/libraries/voxels/CMakeLists.txt +++ b/libraries/voxels/CMakeLists.txt @@ -1,11 +1,11 @@ set(TARGET_NAME voxels) # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(${TARGET_NAME} Widgets Script) +setup_hifi_library(Widgets Script) -include_glm(${TARGET_NAME} "${ROOT_DIR}") +include_glm() -link_hifi_libraries(${TARGET_NAME} shared octree networking) +link_hifi_libraries(shared octree networking) # find ZLIB find_package(ZLIB) @@ -15,4 +15,4 @@ include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") list(APPEND ${TARGET}_LIBRARIES_TO_LINK "${ZLIB_LIBRARIES}") # call macro to link our dependencies and bubble them up via a property on our target -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/tests/audio/CMakeLists.txt b/tests/audio/CMakeLists.txt index 973726852d..3ef87ede28 100644 --- a/tests/audio/CMakeLists.txt +++ b/tests/audio/CMakeLists.txt @@ -1,12 +1,11 @@ set(TARGET_NAME audio-tests) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project() -#include glm -include_glm(${TARGET_NAME} ${ROOT_DIR}) +include_glm() # link in the shared libraries -link_hifi_libraries(${TARGET_NAME} shared audio networking) +link_hifi_libraries(shared audio networking) # link any shared dependencies -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/tests/jitter/CMakeLists.txt b/tests/jitter/CMakeLists.txt index 577591227f..28a312540f 100644 --- a/tests/jitter/CMakeLists.txt +++ b/tests/jitter/CMakeLists.txt @@ -1,9 +1,9 @@ set(TARGET_NAME jitter-tests) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project() # link in the shared libraries -link_hifi_libraries(${TARGET_NAME} shared networking) +link_hifi_libraries(shared networking) # link any shared dependencies -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/tests/metavoxels/CMakeLists.txt b/tests/metavoxels/CMakeLists.txt index 0fad728764..53b6da4301 100644 --- a/tests/metavoxels/CMakeLists.txt +++ b/tests/metavoxels/CMakeLists.txt @@ -1,13 +1,13 @@ set(TARGET_NAME metavoxel-tests) -auto_mtc(${TARGET_NAME} "${ROOT_DIR}") +auto_mtc() -include_glm(${TARGET_NAME}) +include_glm() -setup_hifi_project(${TARGET_NAME} Network Script Widgets) +setup_hifi_project(Network Script Widgets) # link in the shared libraries -link_hifi_libraries(${TARGET_NAME} metavoxels networking shared) +link_hifi_libraries(metavoxels networking shared) # link any shared dependencies -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/tests/networking/CMakeLists.txt b/tests/networking/CMakeLists.txt index 214b66fd1f..28fdb539b7 100644 --- a/tests/networking/CMakeLists.txt +++ b/tests/networking/CMakeLists.txt @@ -1,9 +1,9 @@ set(TARGET_NAME networking-tests) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project() # link in the shared libraries -link_hifi_libraries(${TARGET_NAME} shared networking) +link_hifi_libraries(shared networking) # link any shared dependencies -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/tests/octree/CMakeLists.txt b/tests/octree/CMakeLists.txt index baae258643..b59344f7f0 100644 --- a/tests/octree/CMakeLists.txt +++ b/tests/octree/CMakeLists.txt @@ -1,11 +1,11 @@ set(TARGET_NAME octree-tests) -setup_hifi_project(${TARGET_NAME} Script Network) +setup_hifi_project(Script Network) -include_glm(${TARGET_NAME}) +include_glm() # link in the shared libraries -link_hifi_libraries(${TARGET_NAME} animation fbx models networking octree shared) +link_hifi_libraries(animation fbx models networking octree shared) # link any shared dependencies -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/tests/physics/CMakeLists.txt b/tests/physics/CMakeLists.txt index e2affa7b47..c2c9327fa0 100644 --- a/tests/physics/CMakeLists.txt +++ b/tests/physics/CMakeLists.txt @@ -1,11 +1,11 @@ set(TARGET_NAME physics-tests) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project() -include_glm(${TARGET_NAME}) +include_glm() # link in the shared libraries -link_hifi_libraries(${TARGET_NAME} shared) +link_hifi_libraries(shared) # link any shared dependencies -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/tests/shared/CMakeLists.txt b/tests/shared/CMakeLists.txt index f819a2734b..8fa2a1c3c4 100644 --- a/tests/shared/CMakeLists.txt +++ b/tests/shared/CMakeLists.txt @@ -1,11 +1,11 @@ set(TARGET_NAME shared-tests) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project() -include_glm(${TARGET_NAME}) +include_glm() # link in the shared libraries -link_hifi_libraries(${TARGET_NAME} shared) +link_hifi_libraries(shared) # link any shared dependencies -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/tools/bitstream2json/CMakeLists.txt b/tools/bitstream2json/CMakeLists.txt index 884f9f9c2c..5cf833eaef 100644 --- a/tools/bitstream2json/CMakeLists.txt +++ b/tools/bitstream2json/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME bitstream2json) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project() # link any shared dependencies -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/tools/json2bitstream/CMakeLists.txt b/tools/json2bitstream/CMakeLists.txt index 3868b551ea..d8619d95a3 100644 --- a/tools/json2bitstream/CMakeLists.txt +++ b/tools/json2bitstream/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME json2bitstream) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project() # link any shared dependencies -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/tools/mtc/CMakeLists.txt b/tools/mtc/CMakeLists.txt index dc30da8098..2a530f3c66 100644 --- a/tools/mtc/CMakeLists.txt +++ b/tools/mtc/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME mtc) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project() # link any shared dependencies -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file diff --git a/voxel-edit/CMakeLists.txt b/voxel-edit/CMakeLists.txt index f9f8ed185b..fea2e27ab1 100644 --- a/voxel-edit/CMakeLists.txt +++ b/voxel-edit/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME voxel-edit) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project() # link any shared dependencies -link_shared_dependencies_to_target(${TARGET_NAME}) \ No newline at end of file +link_shared_dependencies() \ No newline at end of file From a99b19d28ac8757cf48cacff335aca3583f9516d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 12:57:46 -0700 Subject: [PATCH 288/407] make Qt5 and ZLIB required finds, add OpenSSL to interface --- cmake/macros/SetupHifiLibrary.cmake | 2 +- cmake/macros/SetupHifiProject.cmake | 2 +- interface/CMakeLists.txt | 7 +++++-- libraries/fbx/CMakeLists.txt | 2 +- libraries/octree/CMakeLists.txt | 2 +- libraries/voxels/CMakeLists.txt | 2 +- 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/cmake/macros/SetupHifiLibrary.cmake b/cmake/macros/SetupHifiLibrary.cmake index 3c2590d38d..7bb85f68f5 100644 --- a/cmake/macros/SetupHifiLibrary.cmake +++ b/cmake/macros/SetupHifiLibrary.cmake @@ -21,7 +21,7 @@ macro(SETUP_HIFI_LIBRARY) set(QT_MODULES_TO_LINK ${ARGN}) list(APPEND QT_MODULES_TO_LINK Core) - find_package(Qt5 COMPONENTS ${QT_MODULES_TO_LINK}) + find_package(Qt5 COMPONENTS ${QT_MODULES_TO_LINK} REQUIRED) foreach(QT_MODULE ${QT_MODULES_TO_LINK}) get_target_property(QT_LIBRARY_LOCATION Qt5::${QT_MODULE} LOCATION) diff --git a/cmake/macros/SetupHifiProject.cmake b/cmake/macros/SetupHifiProject.cmake index 62c215e595..d21e2c11bb 100644 --- a/cmake/macros/SetupHifiProject.cmake +++ b/cmake/macros/SetupHifiProject.cmake @@ -28,7 +28,7 @@ macro(SETUP_HIFI_PROJECT) set(QT_MODULES_TO_LINK ${ARGN}) list(APPEND QT_MODULES_TO_LINK Core) - find_package(Qt5 COMPONENTS ${QT_MODULES_TO_LINK}) + find_package(Qt5 COMPONENTS ${QT_MODULES_TO_LINK} REQUIRED) foreach(QT_MODULE ${QT_MODULES_TO_LINK}) target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE}) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index d58bea6f9e..a042cfd1c1 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -102,10 +102,12 @@ find_package(SDL) find_package(Sixense) find_package(Visage) find_package(LeapMotion) -find_package(ZLIB) find_package(Qxmpp) find_package(RtMidi) +find_package(ZLIB REQUIRED) +find_package(OpenSSL REQUIRED) + # perform standard include and linking for found externals foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) string(TOUPPER ${EXTERNAL} UPPER_EXTERNAL) @@ -157,9 +159,10 @@ endif () # include headers for interface and InterfaceConfig. include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes") +include_directories("${OPENSSL_INCLUDE_DIR}") target_link_libraries( - ${TARGET_NAME} "${ZLIB_LIBRARIES}" + ${TARGET_NAME} "${ZLIB_LIBRARIES}" "${OPENSSL_LIBRARIES}" Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL Qt5::Script Qt5::Svg Qt5::WebKitWidgets ) diff --git a/libraries/fbx/CMakeLists.txt b/libraries/fbx/CMakeLists.txt index 3cc510aed9..794c6edbe6 100644 --- a/libraries/fbx/CMakeLists.txt +++ b/libraries/fbx/CMakeLists.txt @@ -7,7 +7,7 @@ include_glm("${ROOT_DIR}") link_hifi_libraries(shared networking octree voxels) -find_package(ZLIB) +find_package(ZLIB REQUIRED) include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${ZLIB_LIBRARIES}") diff --git a/libraries/octree/CMakeLists.txt b/libraries/octree/CMakeLists.txt index 193b058466..da641d1524 100644 --- a/libraries/octree/CMakeLists.txt +++ b/libraries/octree/CMakeLists.txt @@ -8,7 +8,7 @@ include_glm() link_hifi_libraries(shared networking) # find ZLIB and OpenSSL -find_package(ZLIB) +find_package(ZLIB REQUIRED) find_package(OpenSSL REQUIRED) include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}" "${OPENSSL_INCLUDE_DIR}") diff --git a/libraries/voxels/CMakeLists.txt b/libraries/voxels/CMakeLists.txt index d9d8717fba..3214978a2a 100644 --- a/libraries/voxels/CMakeLists.txt +++ b/libraries/voxels/CMakeLists.txt @@ -8,7 +8,7 @@ include_glm() link_hifi_libraries(shared octree networking) # find ZLIB -find_package(ZLIB) +find_package(ZLIB REQUIRED) include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") # add it to our list of libraries to link From 2fda95ae8fda3cfb7231d2d0c92dee33e9253f8a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 13:06:23 -0700 Subject: [PATCH 289/407] repair build of various tools --- domain-server/CMakeLists.txt | 1 - tests/audio/CMakeLists.txt | 1 - tests/jitter/CMakeLists.txt | 1 - tests/metavoxels/CMakeLists.txt | 1 - tests/networking/CMakeLists.txt | 1 - tests/octree/CMakeLists.txt | 1 - tests/physics/CMakeLists.txt | 1 - tests/shared/CMakeLists.txt | 1 - tools/bitstream2json/CMakeLists.txt | 7 +++++-- tools/json2bitstream/CMakeLists.txt | 7 +++++-- tools/mtc/CMakeLists.txt | 1 - voxel-edit/CMakeLists.txt | 5 ++++- 12 files changed, 14 insertions(+), 14 deletions(-) diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index bc9269b9ce..0fb9d25b5f 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -15,5 +15,4 @@ add_custom_command(TARGET ${TARGET_NAME} POST_BUILD # link the shared hifi libraries link_hifi_libraries(embedded-webserver networking shared) -# link any shared dependencies link_shared_dependencies() \ No newline at end of file diff --git a/tests/audio/CMakeLists.txt b/tests/audio/CMakeLists.txt index 3ef87ede28..974b4dcd09 100644 --- a/tests/audio/CMakeLists.txt +++ b/tests/audio/CMakeLists.txt @@ -7,5 +7,4 @@ include_glm() # link in the shared libraries link_hifi_libraries(shared audio networking) -# link any shared dependencies link_shared_dependencies() \ No newline at end of file diff --git a/tests/jitter/CMakeLists.txt b/tests/jitter/CMakeLists.txt index 28a312540f..d0b366e7ef 100644 --- a/tests/jitter/CMakeLists.txt +++ b/tests/jitter/CMakeLists.txt @@ -5,5 +5,4 @@ setup_hifi_project() # link in the shared libraries link_hifi_libraries(shared networking) -# link any shared dependencies link_shared_dependencies() \ No newline at end of file diff --git a/tests/metavoxels/CMakeLists.txt b/tests/metavoxels/CMakeLists.txt index 53b6da4301..732c974f95 100644 --- a/tests/metavoxels/CMakeLists.txt +++ b/tests/metavoxels/CMakeLists.txt @@ -9,5 +9,4 @@ setup_hifi_project(Network Script Widgets) # link in the shared libraries link_hifi_libraries(metavoxels networking shared) -# link any shared dependencies link_shared_dependencies() \ No newline at end of file diff --git a/tests/networking/CMakeLists.txt b/tests/networking/CMakeLists.txt index 28fdb539b7..a7293226b3 100644 --- a/tests/networking/CMakeLists.txt +++ b/tests/networking/CMakeLists.txt @@ -5,5 +5,4 @@ setup_hifi_project() # link in the shared libraries link_hifi_libraries(shared networking) -# link any shared dependencies link_shared_dependencies() \ No newline at end of file diff --git a/tests/octree/CMakeLists.txt b/tests/octree/CMakeLists.txt index b59344f7f0..5d37b51abe 100644 --- a/tests/octree/CMakeLists.txt +++ b/tests/octree/CMakeLists.txt @@ -7,5 +7,4 @@ include_glm() # link in the shared libraries link_hifi_libraries(animation fbx models networking octree shared) -# link any shared dependencies link_shared_dependencies() \ No newline at end of file diff --git a/tests/physics/CMakeLists.txt b/tests/physics/CMakeLists.txt index c2c9327fa0..96aaf48860 100644 --- a/tests/physics/CMakeLists.txt +++ b/tests/physics/CMakeLists.txt @@ -7,5 +7,4 @@ include_glm() # link in the shared libraries link_hifi_libraries(shared) -# link any shared dependencies link_shared_dependencies() \ No newline at end of file diff --git a/tests/shared/CMakeLists.txt b/tests/shared/CMakeLists.txt index 8fa2a1c3c4..fe3843e9eb 100644 --- a/tests/shared/CMakeLists.txt +++ b/tests/shared/CMakeLists.txt @@ -7,5 +7,4 @@ include_glm() # link in the shared libraries link_hifi_libraries(shared) -# link any shared dependencies link_shared_dependencies() \ No newline at end of file diff --git a/tools/bitstream2json/CMakeLists.txt b/tools/bitstream2json/CMakeLists.txt index 5cf833eaef..bc23a1e193 100644 --- a/tools/bitstream2json/CMakeLists.txt +++ b/tools/bitstream2json/CMakeLists.txt @@ -1,5 +1,8 @@ set(TARGET_NAME bitstream2json) -setup_hifi_project() +setup_hifi_project(Widgets Script) + +include_glm() + +link_hifi_libraries(metavoxels) -# link any shared dependencies link_shared_dependencies() \ No newline at end of file diff --git a/tools/json2bitstream/CMakeLists.txt b/tools/json2bitstream/CMakeLists.txt index d8619d95a3..91b56c18fd 100644 --- a/tools/json2bitstream/CMakeLists.txt +++ b/tools/json2bitstream/CMakeLists.txt @@ -1,5 +1,8 @@ set(TARGET_NAME json2bitstream) -setup_hifi_project() +setup_hifi_project(Widgets Script) + +include_glm() + +link_hifi_libraries(metavoxels) -# link any shared dependencies link_shared_dependencies() \ No newline at end of file diff --git a/tools/mtc/CMakeLists.txt b/tools/mtc/CMakeLists.txt index 2a530f3c66..4dfa8421ff 100644 --- a/tools/mtc/CMakeLists.txt +++ b/tools/mtc/CMakeLists.txt @@ -1,5 +1,4 @@ set(TARGET_NAME mtc) setup_hifi_project() -# link any shared dependencies link_shared_dependencies() \ No newline at end of file diff --git a/voxel-edit/CMakeLists.txt b/voxel-edit/CMakeLists.txt index fea2e27ab1..b61ee6d132 100644 --- a/voxel-edit/CMakeLists.txt +++ b/voxel-edit/CMakeLists.txt @@ -2,5 +2,8 @@ set(TARGET_NAME voxel-edit) setup_hifi_project() -# link any shared dependencies +include_glm() + +link_hifi_libraries(networking octree shared voxels) + link_shared_dependencies() \ No newline at end of file From 9d8818eee53287689dd01cfba42f1c4ea5faf278 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 13:18:32 -0700 Subject: [PATCH 290/407] remove OpenSSL requirement from octree library --- libraries/octree/CMakeLists.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/octree/CMakeLists.txt b/libraries/octree/CMakeLists.txt index da641d1524..c302a082be 100644 --- a/libraries/octree/CMakeLists.txt +++ b/libraries/octree/CMakeLists.txt @@ -7,15 +7,13 @@ include_glm() link_hifi_libraries(shared networking) -# find ZLIB and OpenSSL +# find ZLIB find_package(ZLIB REQUIRED) -find_package(OpenSSL REQUIRED) -include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}" "${OPENSSL_INCLUDE_DIR}") +include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") # append ZLIB and OpenSSL to our list of libraries to link list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${ZLIB_LIBRARIES}") -list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${OPENSSL_LIBRARIES}") # call macro to link our dependencies and bubble them up via a property on our target link_shared_dependencies() \ No newline at end of file From 92b2fe6d68f17a0209df58a2712a34ad5e9ed0ae Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 13:22:00 -0700 Subject: [PATCH 291/407] remove ROOT_DIR param in include_glm, remove ROOT_DIR from root CMakeLists --- CMakeLists.txt | 4 ++-- libraries/fbx/CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fb54bcbd8a..28ff00cc96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,13 +44,13 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed. set(CMAKE_AUTOMOC ON) -set(ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") set(HIFI_LIBRARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries") -set(MACRO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macros") # setup for find modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/") +set(MACRO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macros") + file(GLOB HIFI_CUSTOM_MACROS "cmake/macros/*.cmake") foreach(CUSTOM_MACRO ${HIFI_CUSTOM_MACROS}) include(${CUSTOM_MACRO}) diff --git a/libraries/fbx/CMakeLists.txt b/libraries/fbx/CMakeLists.txt index 794c6edbe6..894fa14c33 100644 --- a/libraries/fbx/CMakeLists.txt +++ b/libraries/fbx/CMakeLists.txt @@ -3,7 +3,7 @@ set(TARGET_NAME fbx) # use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library() -include_glm("${ROOT_DIR}") +include_glm() link_hifi_libraries(shared networking octree voxels) From 6eb2c736247180a1cfdcdc955d9e10411b657264 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 13:23:54 -0700 Subject: [PATCH 292/407] add assert include to SharedUtil --- libraries/shared/src/SharedUtil.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 470dfffd13..ecf96e0190 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include #include From d8dadc3199b83379361e26fc5060cdf6e4e26eff Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 13:31:09 -0700 Subject: [PATCH 293/407] link the socket library to the hifi networking library --- libraries/networking/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index 3191cfe67b..501437fab2 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -5,5 +5,10 @@ setup_hifi_library(Network) link_hifi_libraries(shared) +if (WIN32) + # we need ws2_32.lib on windows, but it's static so we don't bubble it up + target_link_libraries(${TARGET_NAME} ws2_32.lib) +endif () + # call macro to link our dependencies and bubble them up via a property on our target link_shared_dependencies() \ No newline at end of file From 0dfbc8b8ba7288ddad1144c0726956561710c9a9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 13:32:34 -0700 Subject: [PATCH 294/407] add the xml library to QXMPP_LIBRARIES --- cmake/modules/FindQxmpp.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/modules/FindQxmpp.cmake b/cmake/modules/FindQxmpp.cmake index e5b6e6506a..3c0e97c998 100644 --- a/cmake/modules/FindQxmpp.cmake +++ b/cmake/modules/FindQxmpp.cmake @@ -26,10 +26,12 @@ find_path(QXMPP_INCLUDE_DIRS QXmppClient.h PATH_SUFFIXES include/qxmpp HINTS ${Q find_library(QXMPP_LIBRARY_RELEASE NAMES qxmpp PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS}) find_library(QXMPP_LIBRARY_DEBUG NAMES qxmpp_d PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS}) +find_package(Qt5 COMPONENTS Xml REQUIRED) + include(SelectLibraryConfigurations) select_library_configurations(QXMPP) -set(QXMPP_LIBRARIES "${QXMPP_LIBRARY}") +set(QXMPP_LIBRARIES "${QXMPP_LIBRARY}" Qt5::Xml) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(QXMPP DEFAULT_MSG QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES) From d1701c12cab3182a1a26db5b14621559f0440a63 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 8 Aug 2014 13:36:01 -0700 Subject: [PATCH 295/407] Rewrite FST content so that it includes changed and new properties --- examples/editModels.js | 64 +++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 39dcea7cad..02e7dbf8fb 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -329,33 +329,69 @@ var modelUploader = (function () { }; } - function readMapping(fstBuffer) { - var dv = new DataView(fstBuffer.buffer), + function readMapping(buffer) { + var dv = new DataView(buffer.buffer), lines, line, - values, + tokens, + i, name, - i; + value, + remainder; - // Simplified to target values relevant to model uploading. + mapping = {}; // { name : value | name : { value : remainder } } lines = dv.string(0, dv.byteLength).split(/\r\n|\r|\n/); for (i = 0; i < lines.length; i += 1) { line = lines[i].trim(); if (line.length > 0 && line[0] !== "#") { - values = line.split(/\s*=\s*/); - name = values[0].toLowerCase(); - if (values.length === 2) { - mapping[name] = values[1]; - } else if (values.length === 3 && name === "lod") { - if (mapping[name] === undefined) { - mapping[name] = {}; + tokens = line.split(/\s*=\s*/); + if (tokens.length > 1) { + name = tokens[0]; + value = tokens[1]; + if (tokens.length === 2) { + mapping[name] = value; + } else { + // We're only interested in the first two fields so put the rest in the remainder + remainder = tokens.slice(2, tokens.length).join(" = "); + if (mapping[name] === undefined) { + mapping[name] = {}; + } + mapping[name][value] = remainder; } - mapping[name][values[1]] = values[2]; } } } } + function writeMapping(buffer) { + var name, + value, + remainder, + string = ""; + + for (name in mapping) { + if (mapping.hasOwnProperty(name)) { + if (typeof mapping[name] === "string") { + string += (name + " = " + mapping[name] + "\n"); + } else { + for (value in mapping[name]) { + if (mapping[name].hasOwnProperty(value)) { + remainder = mapping[name][value]; + if (remainder === null) { + remainder = ""; + } else { + remainder = " = " + remainder; + } + string += (name + " = " + value + remainder + "\n"); + } + } + } + } + } + + buffer.buffer = string.toArrayBuffer(); + } + function readGeometry(fbxBuffer) { var textures, view, @@ -591,6 +627,8 @@ var modelUploader = (function () { mapping[ROLL_FIELD] = form[5].value; mapping[SCALE_FIELD] = form[6].value; + writeMapping(fstBuffer); + return true; } From 5b772749696c1c5b558ef4fe6738f69ed64093b9 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 8 Aug 2014 13:39:11 -0700 Subject: [PATCH 296/407] Remove animation, pitch, yaw, and roll from Set Model Properties dialog --- examples/editModels.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 02e7dbf8fb..1704368c6a 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -291,10 +291,6 @@ var modelUploader = (function () { SCALE_FIELD = "scale", FILENAME_FIELD = "filename", TEXDIR_FIELD = "texdir", - ANIMATION_URL_FIELD = "animationurl", - PITCH_FIELD = "pitch", - YAW_FIELD = "yaw", - ROLL_FIELD = "roll", MAX_TEXTURE_SIZE = 1024; function error(message) { @@ -604,10 +600,6 @@ var modelUploader = (function () { errorMessage: "Texture directory must be subdirectory of model directory." }); - form.push({ label: "Animation URL:", value: "" }); - form.push({ label: "Pitch:", value: (0).toFixed(decimals) }); - form.push({ label: "Yaw:", value: (0).toFixed(decimals) }); - form.push({ label: "Roll:", value: (0).toFixed(decimals) }); form.push({ label: "Scale:", value: mapping[SCALE_FIELD].toFixed(decimals) }); form.push({ button: "Cancel" }); @@ -621,10 +613,6 @@ var modelUploader = (function () { if (mapping[TEXDIR_FIELD] === "") { mapping[TEXDIR_FIELD] = "."; } - mapping[ANIMATION_URL_FIELD] = form[2].value; - mapping[PITCH_FIELD] = form[3].value; - mapping[YAW_FIELD] = form[4].value; - mapping[ROLL_FIELD] = form[5].value; mapping[SCALE_FIELD] = form[6].value; writeMapping(fstBuffer); From 2badf9ab1a5d8fefa4c987b918c14d4f0ee38dc6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 13:42:07 -0700 Subject: [PATCH 297/407] don't quote linked ZLIB and OpenSSL libs for interface --- interface/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index a042cfd1c1..82b102adf3 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -162,7 +162,7 @@ include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes" include_directories("${OPENSSL_INCLUDE_DIR}") target_link_libraries( - ${TARGET_NAME} "${ZLIB_LIBRARIES}" "${OPENSSL_LIBRARIES}" + ${TARGET_NAME} ${ZLIB_LIBRARIES} ${OPENSSL_LIBRARIES} Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL Qt5::Script Qt5::Svg Qt5::WebKitWidgets ) From c50be5a872ecd19ac739b8515d43c7438828ac41 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 8 Aug 2014 13:43:25 -0700 Subject: [PATCH 298/407] Miscellaneous fixes --- examples/editModels.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 1704368c6a..8aaeedd7f8 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -613,7 +613,7 @@ var modelUploader = (function () { if (mapping[TEXDIR_FIELD] === "") { mapping[TEXDIR_FIELD] = "."; } - mapping[SCALE_FIELD] = form[6].value; + mapping[SCALE_FIELD] = form[2].value; writeMapping(fstBuffer); @@ -800,7 +800,7 @@ var modelUploader = (function () { //debugResponse(); if (req.readyState === req.DONE) { if (req.status === 200) { - uploadedChecks = 30; + uploadedChecks = UPLOADED_CHECKS; checkUploaded(); } else { print("Error: " + req.status + " " + req.statusText); From 234920b5bce2ccf4583a035ef380ad07c0269612 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 14:04:22 -0700 Subject: [PATCH 299/407] add QuartzCore to FindVisage module --- cmake/modules/FindVisage.cmake | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/cmake/modules/FindVisage.cmake b/cmake/modules/FindVisage.cmake index 070905d6ff..36981827b1 100644 --- a/cmake/modules/FindVisage.cmake +++ b/cmake/modules/FindVisage.cmake @@ -32,6 +32,7 @@ if (APPLE) find_library(VISAGE_VISION_LIBRARY NAME vsvision PATH_SUFFIXES lib HINTS ${VISAGE_SEARCH_DIRS}) find_library(VISAGE_OPENCV_LIBRARY NAME OpenCV PATH_SUFFIXES dependencies/OpenCV_MacOSX/lib HINTS ${VISAGE_SEARCH_DIRS}) + find_library(QuartzCore QuartzCore) elseif (WIN32) find_path(VISAGE_XML_INCLUDE_DIR libxml/xmlreader.h PATH_SUFFIXES dependencies/libxml2/include HINTS ${VISAGE_SEARCH_DIRS}) find_path(VISAGE_OPENCV_INCLUDE_DIR opencv/cv.h PATH_SUFFIXES dependencies/OpenCV/include HINTS ${VISAGE_SEARCH_DIRS}) @@ -43,14 +44,26 @@ elseif (WIN32) endif () include(FindPackageHandleStandardArgs) + +set(VISAGE_ARGS_LIST "VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR + VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR + VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY") + +if (APPLE) + list(APPEND VISAGE_ARGS_LIST QuartzCore) +endif () + find_package_handle_standard_args(VISAGE DEFAULT_MSG - VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR - VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY + VISAGE_ARGS_LIST ) set(VISAGE_INCLUDE_DIRS "${VISAGE_XML_INCLUDE_DIR}" "${VISAGE_OPENCV_INCLUDE_DIR}" "${VISAGE_OPENCV2_INCLUDE_DIR}" "${VISAGE_BASE_INCLUDE_DIR}") set(VISAGE_LIBRARIES "${VISAGE_CORE_LIBRARY}" "${VISAGE_VISION_LIBRARY}" "${VISAGE_OPENCV_LIBRARY}") +if (APPLE) + list(APPEND VISAGE_LIBRARIES ${QuartzCore}) +endif () + mark_as_advanced( VISAGE_INCLUDE_DIRS VISAGE_LIBRARIES VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR From e74c8f5e56a00c65c30b265852c4bd0620ff0abd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 14:08:18 -0700 Subject: [PATCH 300/407] don't set visage find args list as quoted string --- cmake/modules/FindVisage.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/modules/FindVisage.cmake b/cmake/modules/FindVisage.cmake index 36981827b1..d84bfbb69d 100644 --- a/cmake/modules/FindVisage.cmake +++ b/cmake/modules/FindVisage.cmake @@ -45,9 +45,9 @@ endif () include(FindPackageHandleStandardArgs) -set(VISAGE_ARGS_LIST "VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR +set(VISAGE_ARGS_LIST VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR - VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY") + VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY) if (APPLE) list(APPEND VISAGE_ARGS_LIST QuartzCore) From e24ff0130f03c0255c7647a081fa828a767e3268 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 8 Aug 2014 14:10:44 -0700 Subject: [PATCH 301/407] Basic color/height painting. --- interface/src/ui/MetavoxelEditor.cpp | 37 +++- interface/src/ui/MetavoxelEditor.h | 32 +++- .../metavoxels/src/MetavoxelMessages.cpp | 163 ++++++++++++++++++ libraries/metavoxels/src/MetavoxelMessages.h | 34 ++++ libraries/metavoxels/src/MetavoxelUtil.h | 2 + 5 files changed, 262 insertions(+), 6 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 48fa2ed070..bac8c56bc5 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -118,7 +118,8 @@ MetavoxelEditor::MetavoxelEditor() : addTool(new SetSpannerTool(this)); addTool(new ImportHeightfieldTool(this)); addTool(new EraseHeightfieldTool(this)); - addTool(new HeightBrushTool(this)); + addTool(new HeightfieldHeightBrushTool(this)); + addTool(new HeightfieldColorBrushTool(this)); updateAttributes(); @@ -1108,11 +1109,26 @@ void HeightfieldBrushTool::render() { if (!Application::getInstance()->getMetavoxels()->findFirstRayHeightfieldIntersection(origin, direction, distance)) { return; } - glm::vec3 point = origin + distance * direction; - Application::getInstance()->getMetavoxels()->renderHeightfieldCursor(point, _radius->value()); + Application::getInstance()->getMetavoxels()->renderHeightfieldCursor( + _position = origin + distance * direction, _radius->value()); } -HeightBrushTool::HeightBrushTool(MetavoxelEditor* editor) : +bool HeightfieldBrushTool::eventFilter(QObject* watched, QEvent* event) { + if (event->type() == QEvent::Wheel) { + float angle = static_cast(event)->angleDelta().y(); + const float ANGLE_SCALE = 1.0f / 1000.0f; + _radius->setValue(_radius->value() * glm::pow(2.0f, angle * ANGLE_SCALE)); + return true; + + } else if (event->type() == QEvent::MouseButtonPress) { + MetavoxelEditMessage message = { createEdit(static_cast(event)->button() == Qt::RightButton) }; + Application::getInstance()->getMetavoxels()->applyEdit(message, true); + return true; + } + return false; +} + +HeightfieldHeightBrushTool::HeightfieldHeightBrushTool(MetavoxelEditor* editor) : HeightfieldBrushTool(editor, "Height Brush") { _form->addRow("Height:", _height = new QDoubleSpinBox()); @@ -1121,3 +1137,16 @@ HeightBrushTool::HeightBrushTool(MetavoxelEditor* editor) : _height->setValue(1.0); } +QVariant HeightfieldHeightBrushTool::createEdit(bool alternate) { + return QVariant::fromValue(PaintHeightfieldHeightEdit(_position, _radius->value(), _height->value())); +} + +HeightfieldColorBrushTool::HeightfieldColorBrushTool(MetavoxelEditor* editor) : + HeightfieldBrushTool(editor, "Color Brush") { + + _form->addRow("Color:", _color = new QColorEditor(this)); +} + +QVariant HeightfieldColorBrushTool::createEdit(bool alternate) { + return QVariant::fromValue(PaintHeightfieldColorEdit(_position, _radius->value(), _color->getColor())); +} diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index 50b477a2bf..87d95a6927 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -18,6 +18,7 @@ #include "MetavoxelSystem.h" #include "renderer/ProgramObject.h" +class QColorEditor; class QComboBox; class QDoubleSpinBox; class QGroupBox; @@ -312,23 +313,50 @@ public: virtual void render(); + virtual bool eventFilter(QObject* watched, QEvent* event); + protected: + virtual QVariant createEdit(bool alternate) = 0; + QFormLayout* _form; QDoubleSpinBox* _radius; + + glm::vec3 _position; }; /// Allows raising or lowering parts of the heightfield. -class HeightBrushTool : public HeightfieldBrushTool { +class HeightfieldHeightBrushTool : public HeightfieldBrushTool { Q_OBJECT public: - HeightBrushTool(MetavoxelEditor* editor); + HeightfieldHeightBrushTool(MetavoxelEditor* editor); + +protected: + + virtual QVariant createEdit(bool alternate); private: QDoubleSpinBox* _height; }; +/// Allows coloring parts of the heightfield. +class HeightfieldColorBrushTool : public HeightfieldBrushTool { + Q_OBJECT + +public: + + HeightfieldColorBrushTool(MetavoxelEditor* editor); + +protected: + + virtual QVariant createEdit(bool alternate); + +private: + + QColorEditor* _color; +}; + #endif // hifi_MetavoxelEditor_h diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index dba9bc9c5c..dfd647fdb5 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -318,3 +318,166 @@ SetDataEdit::SetDataEdit(const glm::vec3& minimum, const MetavoxelData& data, bo void SetDataEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { data.set(minimum, this->data, blend); } + +PaintHeightfieldHeightEdit::PaintHeightfieldHeightEdit(const glm::vec3& position, float radius, float height) : + position(position), + radius(radius), + height(height) { +} + +class PaintHeightfieldHeightEditVisitor : public MetavoxelVisitor { +public: + + PaintHeightfieldHeightEditVisitor(const PaintHeightfieldHeightEdit& edit); + + virtual int visit(MetavoxelInfo& info); + +private: + + PaintHeightfieldHeightEdit _edit; + Box _bounds; +}; + +PaintHeightfieldHeightEditVisitor::PaintHeightfieldHeightEditVisitor(const PaintHeightfieldHeightEdit& edit) : + MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getHeightfieldAttribute(), + QVector() << AttributeRegistry::getInstance()->getHeightfieldAttribute()), + _edit(edit) { + + glm::vec3 extents(_edit.radius, _edit.radius, _edit.radius); + _bounds = Box(_edit.position - extents, _edit.position + extents); +} + +int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) { + if (!info.getBounds().intersects(_bounds)) { + return STOP_RECURSION; + } + if (!info.isLeaf) { + return DEFAULT_ORDER; + } + HeightfieldDataPointer pointer = info.inputValues.at(0).getInlineValue(); + if (!pointer) { + return STOP_RECURSION; + } + QByteArray contents(pointer->getContents()); + int size = glm::sqrt((float)contents.size()); + int highest = size - 1; + float heightScale = highest / info.size; + + glm::vec3 center = (_edit.position - info.minimum) * heightScale; + float scaledRadius = _edit.radius * heightScale; + glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius); + + glm::vec3 start = glm::floor(center - extents); + glm::vec3 end = glm::ceil(center + extents); + + float z = qMax(start.z, 0.0f); + float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest); + uchar* lineDest = (uchar*)contents.data() + (int)z * size + (int)startX; + float squaredRadius = scaledRadius * scaledRadius; + float squaredRadiusReciprocal = 1.0f / squaredRadius; + const int EIGHT_BIT_MAXIMUM = 255; + float scaledHeight = _edit.height * EIGHT_BIT_MAXIMUM / info.size; + for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) { + uchar* dest = lineDest; + for (float x = startX; x <= endX; x += 1.0f, dest++) { + float dx = x - center.x, dz = z - center.z; + float distanceSquared = dx * dx + dz * dz; + if (distanceSquared <= squaredRadius) { + int value = *dest + scaledHeight * (squaredRadius - distanceSquared) * squaredRadiusReciprocal; + *dest = qMin(qMax(value, 0), EIGHT_BIT_MAXIMUM); + } + } + lineDest += size; + } + + HeightfieldDataPointer newPointer(new HeightfieldData(contents)); + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(newPointer)); + return STOP_RECURSION; +} + +void PaintHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { + PaintHeightfieldHeightEditVisitor visitor(*this); + data.guide(visitor); +} + +PaintHeightfieldColorEdit::PaintHeightfieldColorEdit(const glm::vec3& position, float radius, const QColor& color) : + position(position), + radius(radius), + color(color) { +} + +class PaintHeightfieldColorEditVisitor : public MetavoxelVisitor { +public: + + PaintHeightfieldColorEditVisitor(const PaintHeightfieldColorEdit& edit); + + virtual int visit(MetavoxelInfo& info); + +private: + + PaintHeightfieldColorEdit _edit; + Box _bounds; +}; + +PaintHeightfieldColorEditVisitor::PaintHeightfieldColorEditVisitor(const PaintHeightfieldColorEdit& edit) : + MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), + QVector() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute()), + _edit(edit) { + + glm::vec3 extents(_edit.radius, _edit.radius, _edit.radius); + _bounds = Box(_edit.position - extents, _edit.position + extents); +} + +int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) { + if (!info.getBounds().intersects(_bounds)) { + return STOP_RECURSION; + } + if (!info.isLeaf) { + return DEFAULT_ORDER; + } + HeightfieldDataPointer pointer = info.inputValues.at(0).getInlineValue(); + if (!pointer) { + return STOP_RECURSION; + } + QByteArray contents(pointer->getContents()); + const int BYTES_PER_PIXEL = 3; + int size = glm::sqrt((float)contents.size() / BYTES_PER_PIXEL); + int highest = size - 1; + float heightScale = highest / info.size; + + glm::vec3 center = (_edit.position - info.minimum) * heightScale; + float scaledRadius = _edit.radius * heightScale; + glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius); + + glm::vec3 start = glm::floor(center - extents); + glm::vec3 end = glm::ceil(center + extents); + + float z = qMax(start.z, 0.0f); + float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest); + int stride = size * BYTES_PER_PIXEL; + char* lineDest = contents.data() + (int)z * stride + (int)startX * BYTES_PER_PIXEL; + float squaredRadius = scaledRadius * scaledRadius; + char red = _edit.color.red(), green = _edit.color.green(), blue = _edit.color.blue(); + for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) { + char* dest = lineDest; + for (float x = startX; x <= endX; x += 1.0f, dest += BYTES_PER_PIXEL) { + float dx = x - center.x, dz = z - center.z; + if (dx * dx + dz * dz <= squaredRadius) { + dest[0] = red; + dest[1] = green; + dest[2] = blue; + } + } + lineDest += stride; + } + + HeightfieldDataPointer newPointer(new HeightfieldData(contents)); + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(newPointer)); + return STOP_RECURSION; +} + +void PaintHeightfieldColorEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { + PaintHeightfieldColorEditVisitor visitor(*this); + data.guide(visitor); +} + diff --git a/libraries/metavoxels/src/MetavoxelMessages.h b/libraries/metavoxels/src/MetavoxelMessages.h index 91d73c08a9..2fc8cbf030 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -207,4 +207,38 @@ public: DECLARE_STREAMABLE_METATYPE(SetDataEdit) +/// An edit that sets a region of a heightfield height. +class PaintHeightfieldHeightEdit : public MetavoxelEdit { + STREAMABLE + +public: + + STREAM glm::vec3 position; + STREAM float radius; + STREAM float height; + + PaintHeightfieldHeightEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, float height = 0.0f); + + virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; +}; + +DECLARE_STREAMABLE_METATYPE(PaintHeightfieldHeightEdit) + +/// An edit that sets a region of a heightfield color. +class PaintHeightfieldColorEdit : public MetavoxelEdit { + STREAMABLE + +public: + + STREAM glm::vec3 position; + STREAM float radius; + STREAM QColor color; + + PaintHeightfieldColorEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, const QColor& color = QColor()); + + virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; +}; + +DECLARE_STREAMABLE_METATYPE(PaintHeightfieldColorEdit) + #endif // hifi_MetavoxelMessages_h diff --git a/libraries/metavoxels/src/MetavoxelUtil.h b/libraries/metavoxels/src/MetavoxelUtil.h index a2b0586708..339c07a21e 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.h +++ b/libraries/metavoxels/src/MetavoxelUtil.h @@ -138,6 +138,8 @@ public: QColorEditor(QWidget* parent); + const QColor& getColor() const { return _color; } + signals: void colorChanged(const QColor& color); From e638bbca3a766718981fe3ea54d658e65e379232 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 14:10:58 -0700 Subject: [PATCH 302/407] fix find package standard args call for visage --- cmake/modules/FindVisage.cmake | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/cmake/modules/FindVisage.cmake b/cmake/modules/FindVisage.cmake index d84bfbb69d..6c8d4f5b76 100644 --- a/cmake/modules/FindVisage.cmake +++ b/cmake/modules/FindVisage.cmake @@ -45,17 +45,15 @@ endif () include(FindPackageHandleStandardArgs) -set(VISAGE_ARGS_LIST VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR +set(VISAGE_ARGS_LIST "VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR - VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY) + VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY") if (APPLE) list(APPEND VISAGE_ARGS_LIST QuartzCore) endif () -find_package_handle_standard_args(VISAGE DEFAULT_MSG - VISAGE_ARGS_LIST -) +find_package_handle_standard_args(VISAGE DEFAULT_MSG ${VISAGE_ARGS_LIST}) set(VISAGE_INCLUDE_DIRS "${VISAGE_XML_INCLUDE_DIR}" "${VISAGE_OPENCV_INCLUDE_DIR}" "${VISAGE_OPENCV2_INCLUDE_DIR}" "${VISAGE_BASE_INCLUDE_DIR}") set(VISAGE_LIBRARIES "${VISAGE_CORE_LIBRARY}" "${VISAGE_VISION_LIBRARY}" "${VISAGE_OPENCV_LIBRARY}") @@ -64,8 +62,4 @@ if (APPLE) list(APPEND VISAGE_LIBRARIES ${QuartzCore}) endif () -mark_as_advanced( - VISAGE_INCLUDE_DIRS VISAGE_LIBRARIES - VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR - VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY VISAGE_SEARCH_DIRS -) +mark_as_advanced(VISAGE_INCLUDE_DIRS VISAGE_LIBRARIES) From 768410ca0b1c8b5f8a6322a31990b0ef81c0e38a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 8 Aug 2014 14:14:35 -0700 Subject: [PATCH 303/407] A couple comments, let right mouse button decrease height. --- interface/src/ui/MetavoxelEditor.cpp | 3 ++- libraries/metavoxels/src/MetavoxelMessages.cpp | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index bac8c56bc5..b6f5eb11b3 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -1138,7 +1138,8 @@ HeightfieldHeightBrushTool::HeightfieldHeightBrushTool(MetavoxelEditor* editor) } QVariant HeightfieldHeightBrushTool::createEdit(bool alternate) { - return QVariant::fromValue(PaintHeightfieldHeightEdit(_position, _radius->value(), _height->value())); + return QVariant::fromValue(PaintHeightfieldHeightEdit(_position, _radius->value(), + alternate ? (-_height->value() : _height->value()))); } HeightfieldColorBrushTool::HeightfieldColorBrushTool(MetavoxelEditor* editor) : diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index dfd647fdb5..926d839991 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -370,6 +370,7 @@ int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) { glm::vec3 start = glm::floor(center - extents); glm::vec3 end = glm::ceil(center + extents); + // raise/lower all points within the radius float z = qMax(start.z, 0.0f); float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest); uchar* lineDest = (uchar*)contents.data() + (int)z * size + (int)startX; @@ -383,6 +384,7 @@ int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) { float dx = x - center.x, dz = z - center.z; float distanceSquared = dx * dx + dz * dz; if (distanceSquared <= squaredRadius) { + // height falls off towards edges int value = *dest + scaledHeight * (squaredRadius - distanceSquared) * squaredRadiusReciprocal; *dest = qMin(qMax(value, 0), EIGHT_BIT_MAXIMUM); } @@ -452,6 +454,7 @@ int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) { glm::vec3 start = glm::floor(center - extents); glm::vec3 end = glm::ceil(center + extents); + // paint all points within the radius float z = qMax(start.z, 0.0f); float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest); int stride = size * BYTES_PER_PIXEL; From 2f6ff36d2239dfafc14bfb069cd38ef9114126e8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 14:17:36 -0700 Subject: [PATCH 304/407] fix list of args for visage find module --- cmake/modules/FindVisage.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/modules/FindVisage.cmake b/cmake/modules/FindVisage.cmake index 6c8d4f5b76..5c420fb0b5 100644 --- a/cmake/modules/FindVisage.cmake +++ b/cmake/modules/FindVisage.cmake @@ -45,9 +45,9 @@ endif () include(FindPackageHandleStandardArgs) -set(VISAGE_ARGS_LIST "VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR +list(APPEND VISAGE_ARGS_LIST VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR - VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY") + VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY) if (APPLE) list(APPEND VISAGE_ARGS_LIST QuartzCore) From 468a3d4d67d7c888db3e6926ff5169d95ac3e42c Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 8 Aug 2014 14:18:32 -0700 Subject: [PATCH 305/407] Bump up the packet version. --- interface/src/ui/MetavoxelEditor.cpp | 2 +- libraries/networking/src/PacketHeaders.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index b6f5eb11b3..d35ed93f1b 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -1139,7 +1139,7 @@ HeightfieldHeightBrushTool::HeightfieldHeightBrushTool(MetavoxelEditor* editor) QVariant HeightfieldHeightBrushTool::createEdit(bool alternate) { return QVariant::fromValue(PaintHeightfieldHeightEdit(_position, _radius->value(), - alternate ? (-_height->value() : _height->value()))); + alternate ? -_height->value() : _height->value())); } HeightfieldColorBrushTool::HeightfieldColorBrushTool(MetavoxelEditor* editor) : diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index f17715ddfe..1b48a2e333 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -80,6 +80,8 @@ PacketVersion versionForPacketType(PacketType type) { return 1; case PacketTypeAudioStreamStats: return 1; + case PacketTypeMetavoxelData: + return 1; default: return 0; } From 18256a657e812405da4b91f566eb0ffc6893abd3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 8 Aug 2014 14:25:02 -0700 Subject: [PATCH 306/407] Removed unused uniform. --- interface/src/MetavoxelSystem.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index f62a85025b..597542778a 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -558,7 +558,6 @@ void DefaultMetavoxelRendererImplementation::init() { _heightfieldCursorProgram.bind(); _heightfieldCursorProgram.setUniformValue("heightMap", 0); - _heightfieldCursorProgram.setUniformValue("cursorMap", 1); _cursorHeightScaleLocation = _heightfieldCursorProgram.uniformLocation("heightScale"); _heightfieldCursorProgram.release(); } From 9abfb0f503d25550c2d15e5f0d1e8dfacb7c53d2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 8 Aug 2014 14:25:55 -0700 Subject: [PATCH 307/407] Added Recorder suite --- interface/src/Recorder.cpp | 12 ++++++ interface/src/Recorder.h | 85 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 interface/src/Recorder.cpp create mode 100644 interface/src/Recorder.h diff --git a/interface/src/Recorder.cpp b/interface/src/Recorder.cpp new file mode 100644 index 0000000000..49ef833309 --- /dev/null +++ b/interface/src/Recorder.cpp @@ -0,0 +1,12 @@ +// +// Recorder.cpp +// +// +// Created by Clement on 8/7/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 +// + +#include "Recorder.h" diff --git a/interface/src/Recorder.h b/interface/src/Recorder.h new file mode 100644 index 0000000000..ffb013723c --- /dev/null +++ b/interface/src/Recorder.h @@ -0,0 +1,85 @@ +// +// Recorder.h +// +// +// Created by Clement on 8/7/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 +// + +#ifndef hifi_Recorder_h +#define hifi_Recorder_h + +#include +#include +#include +#include + +#include + +/// Stores the different values associated to one recording frame +class RecordingFrame { +public: + QVector getBlendshapeCoefficients() const { return _blendshapeCoefficients; } + QVector getJointRotations() const { return _jointRotations; } + glm::vec3 getTranslation() const { return _translation; } + +private: + + QVector _blendshapeCoefficients; + QVector _jointRotations; + glm::vec3 _translation; +}; + +/// Stores a recording +class Recording { +public: + bool isEmpty() const { return _timestamps.isEmpty(); } + int getLength() const { return _timestamps.last(); } // in ms + + qint32 getFrameTimestamp(int i) const { return _timestamps[i]; } + const RecordingFrame& getFrame(int i) const { return _frames[i]; } + +protected: + void addFrame(int timestamp, RecordingFrame& frame); + void clear(); + +private: + QVector _timestamps; + QVector _frames; + + friend class Recorder; + friend void writeRecordingToFile(Recording& recording, QString file); + friend Recording& readRecordingFromFile(QString file); +}; + + +/// Records a recording +class Recorder { +public: + Recorder(); + + bool isRecording() const; + qint64 elapsed() const; + +public slots: + void startRecording(); + void stopRecording(); + void saveToFile(QString file); + +private: + QElapsedTimer _timer; + Recording _recording; +}; + +/// Plays back a recording +class Player { +public: + +private: + Recording _recording; +}; + +#endif // hifi_Recorder_h \ No newline at end of file From 5b4a3bd5f5eaed8bbfcb3a31a2c18ac8848799c5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 8 Aug 2014 14:26:16 -0700 Subject: [PATCH 308/407] Recording ground work --- interface/src/Recorder.cpp | 49 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/interface/src/Recorder.cpp b/interface/src/Recorder.cpp index 49ef833309..85e2535141 100644 --- a/interface/src/Recorder.cpp +++ b/interface/src/Recorder.cpp @@ -10,3 +10,52 @@ // #include "Recorder.h" + +void Recording::addFrame(int timestamp, RecordingFrame &frame) { + _timestamps << timestamp; + _frames << frame; +} + +void Recording::clear() { + _timestamps.clear(); + _frames.clear(); +} + +void writeRecordingToFile(Recording& recording, QString file) { + qDebug() << "Writing recording to " << file; +} + +Recording& readRecordingFromFile(QString file) { + qDebug() << "Reading recording from " << file; + return *(new Recording()); +} + + +bool Recorder::isRecording() const { + return _timer.isValid(); +} + +qint64 Recorder::elapsed() const { + if (isRecording()) { + return _timer.elapsed(); + } else { + return 0; + } +} + +void Recorder::startRecording() { + _recording.clear(); + _timer.start(); +} + +void Recorder::stopRecording() { + _timer.invalidate(); +} + +void Recorder::saveToFile(QString file) { + if (_recording.isEmpty()) { + qDebug() << "Cannot save recording to file, recording is empty."; + } + + writeRecordingToFile(_recording, file); +} \ No newline at end of file From 36a3bc40d6d01988550dc4010b34376f83211aed Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 14:44:37 -0700 Subject: [PATCH 309/407] add AppKit to required Visage libraries --- cmake/modules/FindVisage.cmake | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmake/modules/FindVisage.cmake b/cmake/modules/FindVisage.cmake index 5c420fb0b5..e2e66ec993 100644 --- a/cmake/modules/FindVisage.cmake +++ b/cmake/modules/FindVisage.cmake @@ -32,6 +32,7 @@ if (APPLE) find_library(VISAGE_VISION_LIBRARY NAME vsvision PATH_SUFFIXES lib HINTS ${VISAGE_SEARCH_DIRS}) find_library(VISAGE_OPENCV_LIBRARY NAME OpenCV PATH_SUFFIXES dependencies/OpenCV_MacOSX/lib HINTS ${VISAGE_SEARCH_DIRS}) + find_library(AppKit AppKit) find_library(QuartzCore QuartzCore) elseif (WIN32) find_path(VISAGE_XML_INCLUDE_DIR libxml/xmlreader.h PATH_SUFFIXES dependencies/libxml2/include HINTS ${VISAGE_SEARCH_DIRS}) @@ -50,7 +51,7 @@ list(APPEND VISAGE_ARGS_LIST VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY) if (APPLE) - list(APPEND VISAGE_ARGS_LIST QuartzCore) + list(APPEND VISAGE_ARGS_LIST QuartzCore AppKit) endif () find_package_handle_standard_args(VISAGE DEFAULT_MSG ${VISAGE_ARGS_LIST}) @@ -59,7 +60,7 @@ set(VISAGE_INCLUDE_DIRS "${VISAGE_XML_INCLUDE_DIR}" "${VISAGE_OPENCV_INCLUDE_DIR set(VISAGE_LIBRARIES "${VISAGE_CORE_LIBRARY}" "${VISAGE_VISION_LIBRARY}" "${VISAGE_OPENCV_LIBRARY}") if (APPLE) - list(APPEND VISAGE_LIBRARIES ${QuartzCore}) + list(APPEND VISAGE_LIBRARIES ${QuartzCore} ${AppKit}) endif () mark_as_advanced(VISAGE_INCLUDE_DIRS VISAGE_LIBRARIES) From b09cc55d6f91b0511858201f133b2f5475c741c9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Aug 2014 15:01:47 -0700 Subject: [PATCH 310/407] add QTKit to frameworks required for Visage --- cmake/modules/FindVisage.cmake | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmake/modules/FindVisage.cmake b/cmake/modules/FindVisage.cmake index e2e66ec993..f14f15515a 100644 --- a/cmake/modules/FindVisage.cmake +++ b/cmake/modules/FindVisage.cmake @@ -34,6 +34,7 @@ if (APPLE) find_library(AppKit AppKit) find_library(QuartzCore QuartzCore) + find_library(QTKit QTKit) elseif (WIN32) find_path(VISAGE_XML_INCLUDE_DIR libxml/xmlreader.h PATH_SUFFIXES dependencies/libxml2/include HINTS ${VISAGE_SEARCH_DIRS}) find_path(VISAGE_OPENCV_INCLUDE_DIR opencv/cv.h PATH_SUFFIXES dependencies/OpenCV/include HINTS ${VISAGE_SEARCH_DIRS}) @@ -51,7 +52,7 @@ list(APPEND VISAGE_ARGS_LIST VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY) if (APPLE) - list(APPEND VISAGE_ARGS_LIST QuartzCore AppKit) + list(APPEND VISAGE_ARGS_LIST QuartzCore AppKit QTKit) endif () find_package_handle_standard_args(VISAGE DEFAULT_MSG ${VISAGE_ARGS_LIST}) @@ -60,7 +61,7 @@ set(VISAGE_INCLUDE_DIRS "${VISAGE_XML_INCLUDE_DIR}" "${VISAGE_OPENCV_INCLUDE_DIR set(VISAGE_LIBRARIES "${VISAGE_CORE_LIBRARY}" "${VISAGE_VISION_LIBRARY}" "${VISAGE_OPENCV_LIBRARY}") if (APPLE) - list(APPEND VISAGE_LIBRARIES ${QuartzCore} ${AppKit}) + list(APPEND VISAGE_LIBRARIES ${QuartzCore} ${AppKit} ${QTKit}) endif () mark_as_advanced(VISAGE_INCLUDE_DIRS VISAGE_LIBRARIES) From 198fa47409642241a7ce06ace84c0965ecedbc72 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 8 Aug 2014 16:38:27 -0700 Subject: [PATCH 311/407] Get "naked" FBX model content uploading working Include an automatically created FST file in the upload --- examples/editModels.js | 44 +++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 8aaeedd7f8..5525f0b128 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -298,6 +298,18 @@ var modelUploader = (function () { Window.alert(message); } + function randomChar(length) { + var characters = "0123457689abcdefghijklmnopqrstuvwxyz", + string = "", + i; + + for (i = 0; i < length; i += 1) { + string += characters[Math.floor(Math.random() * 36)]; + } + + return string; + } + function resetDataObjects() { fstBuffer = null; fbxBuffer = null; @@ -506,7 +518,7 @@ var modelUploader = (function () { print("Reading model file: " + modelFile); - if (modelFile.toLowerCase().slice(-4) === ".fst") { + if (modelFile.toLowerCase().fileType() === "fst") { fstBuffer = readFile(modelFile); if (fstBuffer === null) { return false; @@ -526,18 +538,24 @@ var modelUploader = (function () { error("Model file name not found in FST file!"); return false; } - - } else if (modelFile.toLowerCase().slice(-4) === ".fbx") { - fbxFilename = modelFile; - mapping[FILENAME_FIELD] = modelFile.fileName(); - - } else if (modelFile.toLowerCase().slice(-4) === ".svo") { - svoFilename = modelFile; - mapping[FILENAME_FIELD] = modelFile.fileName(); - } else { - error("Unrecognized file type: " + modelFile); - return false; + fstBuffer = { + filename: "Interface." + randomChar(6), // Simulate avatar model uploading behaviour + buffer: null + }; + + if (modelFile.toLowerCase().fileType() === "fbx") { + fbxFilename = modelFile; + mapping[FILENAME_FIELD] = modelFile.fileName(); + + } else if (modelFile.toLowerCase().fileType() === "svo") { + svoFilename = modelFile; + mapping[FILENAME_FIELD] = modelFile.fileName(); + + } else { + error("Unrecognized file type: " + modelFile); + return false; + } } if (fbxFilename) { @@ -851,7 +869,7 @@ var modelUploader = (function () { print("Sending model to High Fidelity"); modelName = mapping[NAME_FIELD]; - modelURL = MODEL_URL + "\/" + mapping[NAME_FIELD] + ".fst"; // DJRTODO: Do all models get a FST? + modelURL = MODEL_URL + "\/" + mapping[NAME_FIELD] + ".fst"; // All models are uploaded as an FST requestUpload(); } From 0f9da8e13fdd5b753fe5c11fcb330b59b45851c6 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 8 Aug 2014 17:34:08 -0700 Subject: [PATCH 312/407] Make mapping writing more robust --- examples/editModels.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 5525f0b128..a7eac56773 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -379,9 +379,7 @@ var modelUploader = (function () { for (name in mapping) { if (mapping.hasOwnProperty(name)) { - if (typeof mapping[name] === "string") { - string += (name + " = " + mapping[name] + "\n"); - } else { + if (typeof mapping[name] === "object") { for (value in mapping[name]) { if (mapping[name].hasOwnProperty(value)) { remainder = mapping[name][value]; @@ -393,6 +391,8 @@ var modelUploader = (function () { string += (name + " = " + value + remainder + "\n"); } } + } else { + string += (name + " = " + mapping[name] + "\n"); } } } From 35bc1a03af0506a7b612bbbad025cd104e52397d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 8 Aug 2014 17:35:36 -0700 Subject: [PATCH 313/407] Simplify model scale to be that specified in FST or 1.0 No UI --- examples/editModels.js | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index a7eac56773..593c6d20ce 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -445,11 +445,6 @@ var modelUploader = (function () { textures[filename] = ""; geometry.textures.push(filename); } - - } else if (name === "author") { - author = view.string(index + 5, view.getUint32(index + 1, true)); - geometry.author = author; - } index += (propertyListLength); @@ -476,12 +471,6 @@ var modelUploader = (function () { charCode = view[index]; if (charCode === 10) { // Can ignore EOF line = String.fromCharCode.apply(String, charCodes).trim(); - - if (line.slice(0, 7).toLowerCase() === "author:") { - author = line.slice(line.indexOf("\""), line.lastIndexOf("\"") - line.length); - geometry.author = author; - - } if (line.slice(0, 17).toLowerCase() === "relativefilename:") { filename = line.slice(line.indexOf("\""), line.lastIndexOf("\"") - line.length).fileName(); if (!textures.hasOwnProperty(filename)) { @@ -489,7 +478,6 @@ var modelUploader = (function () { geometry.textures.push(filename); } } - charCodes = []; } else { charCodes.push(charCode); @@ -574,12 +562,6 @@ var modelUploader = (function () { } } - if (mapping.hasOwnProperty(SCALE_FIELD)) { - mapping[SCALE_FIELD] = parseFloat(mapping[SCALE_FIELD]); - } else { - mapping[SCALE_FIELD] = (geometry.author === "www.makehuman.org" ? 150.0 : 15.0); - } - // Add any missing basic mappings if (!mapping.hasOwnProperty(NAME_FIELD)) { mapping[NAME_FIELD] = modelFile.fileName().fileBase(); @@ -588,7 +570,7 @@ var modelUploader = (function () { mapping[TEXDIR_FIELD] = "."; } if (!mapping.hasOwnProperty(SCALE_FIELD)) { - mapping[SCALE_FIELD] = 0.2; // For SVO models. + mapping[SCALE_FIELD] = 1.0; } return true; @@ -618,7 +600,6 @@ var modelUploader = (function () { errorMessage: "Texture directory must be subdirectory of model directory." }); - form.push({ label: "Scale:", value: mapping[SCALE_FIELD].toFixed(decimals) }); form.push({ button: "Cancel" }); if (!Window.form("Set Model Properties", form)) { @@ -631,7 +612,6 @@ var modelUploader = (function () { if (mapping[TEXDIR_FIELD] === "") { mapping[TEXDIR_FIELD] = "."; } - mapping[SCALE_FIELD] = form[2].value; writeMapping(fstBuffer); From 54ea86d6be7bec8a9d0dad7d86588336683b8cbf Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 8 Aug 2014 20:40:15 -0700 Subject: [PATCH 314/407] Fix texture directory display and validation --- examples/editModels.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 593c6d20ce..ffd3940814 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -83,6 +83,12 @@ if (typeof String.prototype.path !== "function") { }; } +if (typeof String.prototype.regExpEscape !== "function") { + String.prototype.regExpEscape = function () { + return this.replace(/([$^.+*?|\\\/{}()\[\]])/g, '\\$1'); + } +} + if (typeof String.prototype.toArrayBuffer !== "function") { String.prototype.toArrayBuffer = function () { var length, @@ -588,8 +594,8 @@ var modelUploader = (function () { form.push({ label: "Name:", value: mapping[NAME_FIELD] }); directory = modelFile.path() + "/" + mapping[TEXDIR_FIELD]; - displayAs = new RegExp("^" + modelFile.path().replace(/[\\\\\\\/]/, "[\\\\\\\/]") + "[\\\\\\\/](.*)"); - validateAs = new RegExp("^" + modelFile.path().replace(/[\\\\\\\/]/, "[\\\\\\\/]") + "([\\\\\\\/].*)?"); + displayAs = new RegExp("^" + modelFile.path().regExpEscape() + "[\\\\\\\/](.*)"); + validateAs = new RegExp("^" + modelFile.path().regExpEscape() + "([\\\\\\\/].*)?"); form.push({ label: "Texture directory:", @@ -597,7 +603,7 @@ var modelUploader = (function () { title: "Choose Texture Directory", displayAs: displayAs, validateAs: validateAs, - errorMessage: "Texture directory must be subdirectory of model directory." + errorMessage: "Texture directory must be subdirectory of the model directory." }); form.push({ button: "Cancel" }); From 9a21f1c355581ae607a548ef72ac120e335dd7ba Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 8 Aug 2014 21:51:14 -0700 Subject: [PATCH 315/407] Fix FST file reading and writing --- examples/editModels.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index ffd3940814..5fda380d55 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -103,7 +103,7 @@ if (typeof String.prototype.toArrayBuffer !== "function") { length = this.length; for (i = 0; i < length; i += 1) { charCode = this.charCodeAt(i); - if (i <= 255) { + if (charCode <= 255) { charCodes.push(charCode); } else { charCodes.push(charCode / 256); @@ -351,7 +351,8 @@ var modelUploader = (function () { i, name, value, - remainder; + remainder, + existing; mapping = {}; // { name : value | name : { value : remainder } } lines = dv.string(0, dv.byteLength).split(/\r\n|\r|\n/); @@ -362,13 +363,19 @@ var modelUploader = (function () { if (tokens.length > 1) { name = tokens[0]; value = tokens[1]; - if (tokens.length === 2) { + if (tokens.length > 2) { + remainder = tokens.slice(2, tokens.length).join(" = "); + } else { + remainder = null; + } + if (tokens.length === 2 && mapping[name] === undefined) { mapping[name] = value; } else { - // We're only interested in the first two fields so put the rest in the remainder - remainder = tokens.slice(2, tokens.length).join(" = "); if (mapping[name] === undefined) { mapping[name] = {}; + } else if (typeof mapping[name] !== "object") { + existing = mapping[name]; + mapping[name] = { existing: null }; } mapping[name][value] = remainder; } From 481108ecd1f14db4d8dc71fc37a7021c64598493 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sun, 10 Aug 2014 22:47:27 -0700 Subject: [PATCH 316/407] added support for biquad, parametric, and multi-band filter eq --- interface/src/Audio.cpp | 44 ++++- interface/src/Audio.h | 17 +- interface/src/Menu.cpp | 42 ++++ interface/src/Menu.h | 5 + libraries/audio/src/AudioFilter.cpp | 23 +++ libraries/audio/src/AudioFilter.h | 295 ++++++++++++++++++++++++++++ 6 files changed, 421 insertions(+), 5 deletions(-) create mode 100644 libraries/audio/src/AudioFilter.cpp create mode 100644 libraries/audio/src/AudioFilter.h diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 2cba22b630..0484860c65 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -56,7 +56,6 @@ static const int MUTE_ICON_SIZE = 24; static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 100; - Audio::Audio(QObject* parent) : AbstractAudioInterface(parent), _audioInput(NULL), @@ -83,6 +82,7 @@ Audio::Audio(QObject* parent) : _noiseGateSampleCounter(0), _noiseGateOpen(false), _noiseGateEnabled(true), + _peqEnabled(false), _toneInjectionEnabled(false), _noiseGateFramesToClose(0), _totalInputAudioSamples(0), @@ -132,6 +132,7 @@ void Audio::init(QGLWidget *parent) { void Audio::reset() { _receivedAudioStream.reset(); resetStats(); + _peq.reset(); } void Audio::resetStats() { @@ -418,9 +419,15 @@ void Audio::start() { if (!outputFormatSupported) { qDebug() << "Unable to set up audio output because of a problem with output format."; } + + _peq.initialize( _inputFormat.sampleRate(), _audioInput->bufferSize() ); + } void Audio::stop() { + + _peq.finalize(); + // "switch" to invalid devices in order to shut down the state switchInputToAudioDevice(QAudioDeviceInfo()); switchOutputToAudioDevice(QAudioDeviceInfo()); @@ -462,7 +469,15 @@ void Audio::handleAudioInput() { int inputSamplesRequired = (int)((float)NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * inputToNetworkInputRatio); QByteArray inputByteArray = _inputDevice->readAll(); - + + if (_peqEnabled && !_muted) { + // we wish to pre-filter our captured input, prior to loopback + + int16_t* ioBuffer = (int16_t*)inputByteArray.data(); + + _peq.render( ioBuffer, ioBuffer, inputByteArray.size() / sizeof(int16_t) ); + } + if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio) && !_muted && _audioOutput) { // if this person wants local loopback add that to the locally injected audio @@ -1172,6 +1187,31 @@ void Audio::renderToolBox(int x, int y, bool boxed) { glDisable(GL_TEXTURE_2D); } +void Audio::toggleAudioFilter() { + _peqEnabled = !_peqEnabled; +} + +void Audio::selectAudioFilterFlat() { + if (Menu::getInstance()->isOptionChecked(MenuOption::AudioFilterFlat)) { + _peq.loadProfile(0); + } +} +void Audio::selectAudioFilterTrebleCut() { + if (Menu::getInstance()->isOptionChecked(MenuOption::AudioFilterTrebleCut)) { + _peq.loadProfile(1); + } +} +void Audio::selectAudioFilterBassCut() { + if (Menu::getInstance()->isOptionChecked(MenuOption::AudioFilterBassCut)) { + _peq.loadProfile(2); + } +} +void Audio::selectAudioFilterSmiley() { + if (Menu::getInstance()->isOptionChecked(MenuOption::AudioFilterSmiley)) { + _peq.loadProfile(3); + } +} + void Audio::toggleScope() { _scopeEnabled = !_scopeEnabled; if (_scopeEnabled) { diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 8fae6f3bdd..4fb54218af 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -19,6 +19,7 @@ #include "AudioStreamStats.h" #include "RingBufferHistory.h" #include "MovingMinMaxAvg.h" +#include "AudioFilter.h" #include #include @@ -125,7 +126,12 @@ public slots: void selectAudioScopeFiveFrames(); void selectAudioScopeTwentyFrames(); void selectAudioScopeFiftyFrames(); - + void toggleAudioFilter(); + void selectAudioFilterFlat(); + void selectAudioFilterTrebleCut(); + void selectAudioFilterBassCut(); + void selectAudioFilterSmiley(); + virtual void handleAudioByteArray(const QByteArray& audioByteArray); void sendDownstreamAudioStatsPacket(); @@ -252,12 +258,12 @@ private: // Audio scope methods for rendering void renderBackground(const float* color, int x, int y, int width, int height); void renderGrid(const float* color, int x, int y, int width, int height, int rows, int cols); - void renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray* byteArray); + void renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray* byteArray); // audio stats methods for rendering void renderAudioStreamStats(const AudioStreamStats& streamStats, int horizontalOffset, int& verticalOffset, float scale, float rotation, int font, const float* color, bool isDownstreamStats = false); - + // Audio scope data static const unsigned int NETWORK_SAMPLES_PER_FRAME = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; static const unsigned int DEFAULT_FRAMES_PER_SCOPE = 5; @@ -270,6 +276,11 @@ private: int _scopeOutputOffset; int _framesPerScope; int _samplesPerScope; + + // Multi-band parametric EQ + bool _peqEnabled; + AudioFilterPEQ3 _peq; + QMutex _guard; QByteArray* _scopeInput; QByteArray* _scopeOutputLeft; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 43d9fde01a..e6850aac6d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -486,6 +486,48 @@ Menu::Menu() : true, appInstance->getAudio(), SLOT(toggleAudioNoiseReduction())); + + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioFilter, + 0, + false, + appInstance->getAudio(), + SLOT(toggleAudioFilter())); + + QMenu* audioFilterMenu = audioDebugMenu->addMenu("Audio Filter Options"); + addDisabledActionAndSeparator(audioFilterMenu, "Filter Response"); + { + QAction *flat = addCheckableActionToQMenuAndActionHash(audioFilterMenu, MenuOption::AudioFilterFlat, + 0, + true, + appInstance->getAudio(), + SLOT(selectAudioFilterFlat())); + + QAction *trebleCut = addCheckableActionToQMenuAndActionHash(audioFilterMenu, MenuOption::AudioFilterTrebleCut, + 0, + false, + appInstance->getAudio(), + SLOT(selectAudioFilterTrebleCut())); + + QAction *bassCut = addCheckableActionToQMenuAndActionHash(audioFilterMenu, MenuOption::AudioFilterBassCut, + 0, + false, + appInstance->getAudio(), + SLOT(selectAudioFilterBassCut())); + + QAction *smiley = addCheckableActionToQMenuAndActionHash(audioFilterMenu, MenuOption::AudioFilterSmiley, + 0, + false, + appInstance->getAudio(), + SLOT(selectAudioFilterSmiley())); + + + QActionGroup* audioFilterGroup = new QActionGroup(audioFilterMenu); + audioFilterGroup->addAction(flat); + audioFilterGroup->addAction(trebleCut); + audioFilterGroup->addAction(bassCut); + audioFilterGroup->addAction(smiley); + } + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::StereoAudio, 0, false, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3bef306bef..7ef744e62e 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -311,6 +311,11 @@ namespace MenuOption { const QString Animations = "Animations..."; const QString Atmosphere = "Atmosphere"; const QString Attachments = "Attachments..."; + const QString AudioFilter = "Audio Filter Bank"; + const QString AudioFilterFlat = "Flat Response"; + const QString AudioFilterTrebleCut= "Treble Cut"; + const QString AudioFilterBassCut = "Bass Cut"; + const QString AudioFilterSmiley = "Smiley Curve"; const QString AudioNoiseReduction = "Audio Noise Reduction"; const QString AudioScope = "Audio Scope"; const QString AudioScopeFiftyFrames = "Fifty"; diff --git a/libraries/audio/src/AudioFilter.cpp b/libraries/audio/src/AudioFilter.cpp new file mode 100644 index 0000000000..61e5e20171 --- /dev/null +++ b/libraries/audio/src/AudioFilter.cpp @@ -0,0 +1,23 @@ +// +// AudioFilter.cpp +// hifi +// +// Created by Craig Hansen-Sturm on 8/10/14. +// +// + +#include +#include +#include +#include "AudioRingBuffer.h" +#include "AudioFilter.h" + +template<> +AudioFilterPEQ3::FilterParameter AudioFilterPEQ3::_profiles[ AudioFilterPEQ3::_profileCount ][ AudioFilterPEQ3::_filterCount ] = { + + { { 300., 1., 1. }, { 1000., 1., 1. }, { 4000., 1., 1. } }, // flat response (default) + { { 300., 1., 1. }, { 1000., 1., 1. }, { 4000., .1, 1. } }, // treble cut + { { 300., .1, 1. }, { 1000., 1., 1. }, { 4000., 1., 1. } }, // bass cut + { { 300., 1.5, 0.71 }, { 1000., .5, 1. }, { 4000., 1.5, 0.71 } } // smiley curve +}; + diff --git a/libraries/audio/src/AudioFilter.h b/libraries/audio/src/AudioFilter.h new file mode 100644 index 0000000000..44dcd261d6 --- /dev/null +++ b/libraries/audio/src/AudioFilter.h @@ -0,0 +1,295 @@ +// +// AudioFilter.h +// hifi +// +// Created by Craig Hansen-Sturm on 8/9/14. +// +// + +#ifndef hifi_AudioFilter_h +#define hifi_AudioFilter_h + +//////////////////////////////////////////////////////////////////////////////////////////// +// Implements a standard biquad filter in "Direct Form 1" +// Reference http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt +// +class AudioBiquad { + + // + // private data + // + float _a0; // gain + float _a1; // feedforward 1 + float _a2; // feedforward 2 + float _b1; // feedback 1 + float _b2; // feedback 2 + + float _xm1; + float _xm2; + float _ym1; + float _ym2; + +public: + + // + // ctor/dtor + // + AudioBiquad() + : _xm1(0.) + , _xm2(0.) + , _ym1(0.) + , _ym2(0.) { + setParameters(0.,0.,0.,0.,0.); + } + + ~AudioBiquad() { + } + + // + // public interface + // + void setParameters( const float a0, const float a1, const float a2, const float b1, const float b2 ) { + _a0 = a0; _a1 = a1; _a2 = a2; _b1 = b1; _b2 = b2; + } + + void getParameters( float& a0, float& a1, float& a2, float& b1, float& b2 ) { + a0 = _a0; a1 = _a1; a2 = _a2; b1 = _b1; b2 = _b2; + } + + void render( const float* in, float* out, const int frames) { + + float x; + float y; + + for (int i = 0; i < frames; ++i) { + + x = *in++; + + // biquad + y = (_a0 * x) + + (_a1 * _xm1) + + (_a2 * _xm2) + - (_b1 * _ym1) + - (_b2 * _ym2); + + // update delay line + _xm2 = _xm1; + _xm1 = x; + _ym2 = _ym1; + _ym1 = y; + + *out++ = y; + } + } + + void reset() { + _xm1 = _xm2 = _ym1 = _ym2 = 0.; + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////// +// Implements a single-band parametric EQ using a biquad "peaking EQ" configuration +// +// gain > 1.0 boosts the center frequency +// gain < 1.0 cuts the center frequency +// +class AudioParametricEQ { + + // + // private data + // + AudioBiquad _kernel; + float _sampleRate; + float _frequency; + float _gain; + float _slope; + + // helpers + void updateKernel() { + + /* + a0 = 1 + alpha*A + a1 = -2*cos(w0) + a2 = 1 - alpha*A + b1 = -2*cos(w0) + b2 = 1 - alpha/A + */ + + const float a = _gain; + const float omega = TWO_PI * _frequency / _sampleRate; + const float alpha = 0.5 * sinf(omega) / _slope; + const float gamma = 1.0 / ( 1.0 + (alpha/a) ); + + const float a0 = 1.0 + (alpha*a); + const float a1 = -2.0 * cosf(omega); + const float a2 = 1.0 - (alpha*a); + const float b1 = a1; + const float b2 = 1.0 - (alpha/a); + + _kernel.setParameters( a0*gamma,a1*gamma,a2*gamma,b1*gamma,b2*gamma ); + } + +public: + // + // ctor/dtor + // + AudioParametricEQ() { + + setParameters(0.,0.,0.,0.); + updateKernel(); + } + + ~AudioParametricEQ() { + } + + // + // public interface + // + void setParameters( const float sampleRate, const float frequency, const float gain, const float slope ) { + + _sampleRate = std::max(sampleRate,1.0f); + _frequency = std::max(frequency,2.0f); + _gain = std::max(gain,0.0f); + _slope = std::max(slope,0.00001f); + + updateKernel(); + } + + void getParameters( float& sampleRate, float& frequency, float& gain, float& slope ) { + sampleRate = _sampleRate; frequency = _frequency; gain = _gain; slope = _slope; + } + + void render(const float* in, float* out, const int frames ) { + _kernel.render(in,out,frames); + } + + void reset() { + _kernel.reset(); + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////// +// Helper/convenience class that implements a bank of EQ objects +// +template< typename T, const int N> +class AudioFilterBank { + + // + // types + // + struct FilterParameter { + float _p1; + float _p2; + float _p3; + }; + + // + // private static data + // + static const int _filterCount = N; + static const int _profileCount = 4; + + static FilterParameter _profiles[_profileCount][_filterCount]; + + // + // private data + // + T _filters[ _filterCount ]; + float* _buffer; + float _sampleRate; + uint16_t _frameCount; + +public: + + // + // ctor/dtor + // + AudioFilterBank() + : _buffer(NULL) + , _sampleRate(0.) + , _frameCount(0) { + } + + ~AudioFilterBank() { + finalize(); + } + + // + // public interface + // + void initialize( const float sampleRate, const int frameCount ) { + finalize(); + + _buffer = (float*)malloc( frameCount * sizeof(float) ); + if(!_buffer) { + return; + } + + _sampleRate = sampleRate; + _frameCount = frameCount; + + reset(); + loadProfile(0); // load default profile "flat response" into the bank (see AudioFilter.cpp) + } + + void finalize() { + if (_buffer ) { + free (_buffer); + _buffer = NULL; + } + } + + void loadProfile( int profileIndex ) { + if (profileIndex >= 0 && profileIndex < _profileCount) { + + for (int i = 0; i < _filterCount; ++i) { + FilterParameter p = _profiles[profileIndex][i]; + + _filters[i].setParameters(_sampleRate,p._p1,p._p2,p._p3); + } + } + } + + void render( const float* in, float* out, const int frameCount ) { + for (int i = 0; i < _filterCount; ++i) { + _filters[i].render( in, out, frameCount ); + } + } + + void render( const int16_t* in, int16_t* out, const int frameCount ) { + if( !_buffer || ( frameCount > _frameCount ) ) + return; + + const int scale = (2 << ((8*sizeof(int16_t))-1)); + + // convert int16_t to float32 (normalized to -1. ... 1.) + for (int i = 0; i < frameCount; ++i) { + _buffer[i] = ((float)(*in++)) / scale; + } + // for this filter, we share input/output buffers at each stage, but our design does not mandate this + render( _buffer, _buffer, frameCount ); + + // convert float32 to int16_t + for (int i = 0; i < frameCount; ++i) { + *out++ = (int16_t)(_buffer[i] * scale); + } + } + + void reset() { + for (int i = 0; i < _filterCount; ++i ) { + _filters[i].reset(); + } + } + +}; + +//////////////////////////////////////////////////////////////////////////////////////////// +// Specializations of AudioFilterBank +// +typedef AudioFilterBank< AudioParametricEQ, 1> AudioFilterPEQ1; // bank with one band of PEQ +typedef AudioFilterBank< AudioParametricEQ, 2> AudioFilterPEQ2; // bank with two bands of PEQ +typedef AudioFilterBank< AudioParametricEQ, 3> AudioFilterPEQ3; // bank with three bands of PEQ +// etc.... + + +#endif // hifi_AudioFilter_h From 405e79fe6d7f329e71875e9a8ecfbe2972ebbc76 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Aug 2014 09:51:36 -0700 Subject: [PATCH 317/407] allow command line specification that an external be required --- cmake/modules/FindFaceplus.cmake | 2 +- cmake/modules/FindFaceshift.cmake | 2 +- cmake/modules/FindLeapMotion.cmake | 2 +- cmake/modules/FindLibOVR.cmake | 24 ++++++------ cmake/modules/FindPrioVR.cmake | 2 +- cmake/modules/FindQxmpp.cmake | 2 +- cmake/modules/FindRtMidi.cmake | 2 +- cmake/modules/FindSixense.cmake | 2 +- cmake/modules/FindVisage.cmake | 2 +- interface/CMakeLists.txt | 39 +++++++------------ .../external/{oculus => libovr}/readme.txt | 0 11 files changed, 35 insertions(+), 44 deletions(-) rename interface/external/{oculus => libovr}/readme.txt (100%) diff --git a/cmake/modules/FindFaceplus.cmake b/cmake/modules/FindFaceplus.cmake index 1050493c69..e97fce3edb 100644 --- a/cmake/modules/FindFaceplus.cmake +++ b/cmake/modules/FindFaceplus.cmake @@ -19,6 +19,6 @@ if (WIN32) endif (WIN32) include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(FACEPLUS DEFAULT_MSG FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES) +find_package_handle_standard_args(Faceplus DEFAULT_MSG FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES) mark_as_advanced(FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES) \ No newline at end of file diff --git a/cmake/modules/FindFaceshift.cmake b/cmake/modules/FindFaceshift.cmake index 2641475fa3..0dcbcbb7dd 100644 --- a/cmake/modules/FindFaceshift.cmake +++ b/cmake/modules/FindFaceshift.cmake @@ -40,6 +40,6 @@ select_library_configurations(FACESHIFT) set(FACESHIFT_LIBRARIES ${FACESHIFT_LIBRARY}) include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(FACESHIFT DEFAULT_MSG FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES) +find_package_handle_standard_args(Faceshift DEFAULT_MSG FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES) mark_as_advanced(FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES FACESHIFT_SEARCH_DIRS) \ No newline at end of file diff --git a/cmake/modules/FindLeapMotion.cmake b/cmake/modules/FindLeapMotion.cmake index a64fc22e48..cb49ceb597 100644 --- a/cmake/modules/FindLeapMotion.cmake +++ b/cmake/modules/FindLeapMotion.cmake @@ -30,6 +30,6 @@ select_library_configurations(LEAPMOTION) set(LEAPMOTION_LIBRARIES "${LEAPMOTION_LIBRARY}") include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(LEAPMOTION DEFAULT_MSG LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES) +find_package_handle_standard_args(LeapMotion DEFAULT_MSG LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES) mark_as_advanced(LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES LEAPMOTION_SEARCH_DIRS) diff --git a/cmake/modules/FindLibOVR.cmake b/cmake/modules/FindLibOVR.cmake index 505fd90b51..e1fce969e5 100644 --- a/cmake/modules/FindLibOVR.cmake +++ b/cmake/modules/FindLibOVR.cmake @@ -19,16 +19,16 @@ # include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") -hifi_library_search_hints("oculus") +hifi_library_search_hints("libovr") -find_path(LIBOVR_INCLUDE_DIRS OVR.h PATH_SUFFIXES Include HINTS ${OCULUS_SEARCH_DIRS}) -find_path(LIBOVR_SRC_DIR Util_Render_Stereo.h PATH_SUFFIXES Src/Util HINTS ${OCULUS_SEARCH_DIRS}) +find_path(LIBOVR_INCLUDE_DIRS OVR.h PATH_SUFFIXES Include HINTS ${LIBOVR_SEARCH_DIRS}) +find_path(LIBOVR_SRC_DIR Util_Render_Stereo.h PATH_SUFFIXES Src/Util HINTS ${LIBOVR_SEARCH_DIRS}) include(SelectLibraryConfigurations) if (APPLE) - find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/MacOS/Debug HINTS ${OCULUS_SEARCH_DIRS}) - find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/MacOS/Release HINTS ${OCULUS_SEARCH_DIRS}) + find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/MacOS/Debug HINTS ${LIBOVR_SEARCH_DIRS}) + find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/MacOS/Release HINTS ${LIBOVR_SEARCH_DIRS}) find_library(ApplicationServices ApplicationServices) find_library(IOKit IOKit) elseif (UNIX) @@ -41,15 +41,15 @@ elseif (UNIX) set(LINUX_ARCH_DIR "x86_64") endif() - find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/Linux/Debug/${LINUX_ARCH_DIR} HINTS ${OCULUS_SEARCH_DIRS}) - find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/Linux/Release/${LINUX_ARCH_DIR} HINTS ${OCULUS_SEARCH_DIRS}) + find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/Linux/Debug/${LINUX_ARCH_DIR} HINTS ${LIBOVR_SEARCH_DIRS}) + find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/Linux/Release/${LINUX_ARCH_DIR} HINTS ${LIBOVR_SEARCH_DIRS}) select_library_configurations(UDEV) select_library_configurations(XINERAMA) elseif (WIN32) - find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${OCULUS_SEARCH_DIRS}) - find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${OCULUS_SEARCH_DIRS}) + find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS}) + find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS}) endif () select_library_configurations(LIBOVR) @@ -63,11 +63,11 @@ endif () include(FindPackageHandleStandardArgs) if (APPLE) - find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES IOKit ApplicationServices) + find_package_handle_standard_args(LibOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES IOKit ApplicationServices) elseif (UNIX) - find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES UDEV_LIBRARY XINERAMA_LIBRARY) + find_package_handle_standard_args(LibOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES UDEV_LIBRARY XINERAMA_LIBRARY) else () - find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES) + find_package_handle_standard_args(LibOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES) endif () mark_as_advanced(LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES OCULUS_SEARCH_DIRS) diff --git a/cmake/modules/FindPrioVR.cmake b/cmake/modules/FindPrioVR.cmake index af2c0aca52..691ba85689 100644 --- a/cmake/modules/FindPrioVR.cmake +++ b/cmake/modules/FindPrioVR.cmake @@ -19,6 +19,6 @@ if (WIN32) endif (WIN32) include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(PRIOVR DEFAULT_MSG PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES) +find_package_handle_standard_args(PrioVR DEFAULT_MSG PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES) mark_as_advanced(PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES) \ No newline at end of file diff --git a/cmake/modules/FindQxmpp.cmake b/cmake/modules/FindQxmpp.cmake index 3c0e97c998..8d8c0e22a2 100644 --- a/cmake/modules/FindQxmpp.cmake +++ b/cmake/modules/FindQxmpp.cmake @@ -34,6 +34,6 @@ select_library_configurations(QXMPP) set(QXMPP_LIBRARIES "${QXMPP_LIBRARY}" Qt5::Xml) include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(QXMPP DEFAULT_MSG QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES) +find_package_handle_standard_args(QXmpp DEFAULT_MSG QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES) mark_as_advanced(QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES QXMPP_SEARCH_DIRS) \ No newline at end of file diff --git a/cmake/modules/FindRtMidi.cmake b/cmake/modules/FindRtMidi.cmake index 93f1cc69cc..3b57c76f25 100644 --- a/cmake/modules/FindRtMidi.cmake +++ b/cmake/modules/FindRtMidi.cmake @@ -25,6 +25,6 @@ find_path(RTMIDI_INCLUDE_DIRS RtMidi.h PATH_SUFFIXES include HINTS ${RTMIDI_SEAR find_library(RTMIDI_LIBRARIES NAMES rtmidi PATH_SUFFIXES lib HINTS ${RTMIDI_SEARCH_DIRS}) include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(RTMIDI DEFAULT_MSG RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES) +find_package_handle_standard_args(RtMidi DEFAULT_MSG RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES) mark_as_advanced(RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES RTMIDI_SEARCH_DIRS) \ No newline at end of file diff --git a/cmake/modules/FindSixense.cmake b/cmake/modules/FindSixense.cmake index a24131698b..f772c42e41 100644 --- a/cmake/modules/FindSixense.cmake +++ b/cmake/modules/FindSixense.cmake @@ -40,6 +40,6 @@ select_library_configurations(SIXENSE) set(SIXENSE_LIBRARIES "${SIXENSE_LIBRARY}") include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(SIXENSE DEFAULT_MSG SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES) +find_package_handle_standard_args(Sixense DEFAULT_MSG SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES) mark_as_advanced(SIXENSE_LIBRARIES SIXENSE_INCLUDE_DIRS SIXENSE_SEARCH_DIRS) diff --git a/cmake/modules/FindVisage.cmake b/cmake/modules/FindVisage.cmake index f14f15515a..96176a2648 100644 --- a/cmake/modules/FindVisage.cmake +++ b/cmake/modules/FindVisage.cmake @@ -55,7 +55,7 @@ if (APPLE) list(APPEND VISAGE_ARGS_LIST QuartzCore AppKit QTKit) endif () -find_package_handle_standard_args(VISAGE DEFAULT_MSG ${VISAGE_ARGS_LIST}) +find_package_handle_standard_args(Visage DEFAULT_MSG ${VISAGE_ARGS_LIST}) set(VISAGE_INCLUDE_DIRS "${VISAGE_XML_INCLUDE_DIR}" "${VISAGE_OPENCV_INCLUDE_DIR}" "${VISAGE_OPENCV2_INCLUDE_DIR}" "${VISAGE_BASE_INCLUDE_DIR}") set(VISAGE_LIBRARIES "${VISAGE_CORE_LIBRARY}" "${VISAGE_VISION_LIBRARY}" "${VISAGE_OPENCV_LIBRARY}") diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 82b102adf3..44b8a88d6d 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -2,11 +2,13 @@ set(TARGET_NAME interface) project(${TARGET_NAME}) # set a default root dir for each of our optional externals if it was not passed -set(OPTIONAL_EXTERNALS "faceplus" "faceshift" "oculus" "priovr" "sixense" "visage" "leapmotion" "rtmidi" "qxmpp") +set(OPTIONAL_EXTERNALS "Faceplus" "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp") foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) - string(TOUPPER ${EXTERNAL} UPPER_EXTERNAL) - if (NOT ${UPPER_EXTERNAL}_ROOT_DIR) - set(${UPPER_EXTERNAL}_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/${EXTERNAL}") + string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE) + if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR) + string(TOLOWER ${EXTERNAL} ${EXTERNAL}_LOWERCASE) + set(${${EXTERNAL}_UPPERCASE}_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/${${EXTERNAL}_LOWERCASE}") + message("Dir for ${EXTERNAL} is ${${${EXTERNAL}_UPPERCASE}_ROOT_DIR}") endif () endforeach() @@ -94,43 +96,32 @@ add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM}) link_hifi_libraries(shared octree voxels fbx metavoxels networking particles models avatars audio animation script-engine) # find any optional and required libraries -find_package(Faceplus) -find_package(Faceshift) -find_package(LibOVR) -find_package(PrioVR) -find_package(SDL) -find_package(Sixense) -find_package(Visage) -find_package(LeapMotion) -find_package(Qxmpp) -find_package(RtMidi) - find_package(ZLIB REQUIRED) find_package(OpenSSL REQUIRED) # perform standard include and linking for found externals foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) - string(TOUPPER ${EXTERNAL} UPPER_EXTERNAL) - if (${UPPER_EXTERNAL} MATCHES "OCULUS") - # the oculus directory is named OCULUS and not LIBOVR so hack to fix that here - set(UPPER_EXTERNAL "LIBOVR") + if (${${EXTERNAL}_UPPERCASE}_REQUIRED) + find_package(${EXTERNAL} REQUIRED) + else () + find_package(${EXTERNAL}) endif () - if (${UPPER_EXTERNAL}_FOUND AND NOT DISABLE_${UPPER_EXTERNAL}) - add_definitions(-DHAVE_${UPPER_EXTERNAL}) + if (${${EXTERNAL}_UPPERCASE}_FOUND AND NOT DISABLE_${${EXTERNAL}_UPPERCASE}) + add_definitions(-DHAVE_${${EXTERNAL}_UPPERCASE}) # include the library directories (ignoring warnings) - include_directories(SYSTEM ${${UPPER_EXTERNAL}_INCLUDE_DIRS}) + include_directories(SYSTEM ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS}) # perform the system include hack for OS X to ignore warnings if (APPLE) - foreach(EXTERNAL_INCLUDE_DIR ${${UPPER_EXTERNAL}_INCLUDE_DIRS}) + foreach(EXTERNAL_INCLUDE_DIR ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS}) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${EXTERNAL_INCLUDE_DIR}") endforeach() endif () - target_link_libraries(${TARGET_NAME} ${${UPPER_EXTERNAL}_LIBRARIES}) + target_link_libraries(${TARGET_NAME} ${${${EXTERNAL}_UPPERCASE}_LIBRARIES}) endif () endforeach() diff --git a/interface/external/oculus/readme.txt b/interface/external/libovr/readme.txt similarity index 100% rename from interface/external/oculus/readme.txt rename to interface/external/libovr/readme.txt From 2469d958d6b750ed5ddf02780bb6f94aee815cf8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Aug 2014 09:57:13 -0700 Subject: [PATCH 318/407] include CoreFoundation for Audio.cpp defaultAudioDeviceForMode --- interface/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 82b102adf3..d705464479 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -172,10 +172,11 @@ add_definitions(-DQT_NO_BEARERMANAGEMENT) if (APPLE) # link in required OS X frameworks and include the right GL headers find_library(CoreAudio CoreAudio) + find_library(CoreFoundation CoreFoundation) find_library(GLUT GLUT) find_library(OpenGL OpenGL) - target_link_libraries(${TARGET_NAME} ${CoreAudio} ${GLUT} ${OpenGL}) + target_link_libraries(${TARGET_NAME} ${CoreFoundation} ${CoreAudio} ${GLUT} ${OpenGL}) # install command for OS X bundle INSTALL(TARGETS ${TARGET_NAME} From cadfaab770d894759f410862cd7f03f6c87a1ceb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Aug 2014 09:58:21 -0700 Subject: [PATCH 319/407] fix order now that I know my ABCs --- interface/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index d705464479..ce8400a413 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -176,7 +176,7 @@ if (APPLE) find_library(GLUT GLUT) find_library(OpenGL OpenGL) - target_link_libraries(${TARGET_NAME} ${CoreFoundation} ${CoreAudio} ${GLUT} ${OpenGL}) + target_link_libraries(${TARGET_NAME} ${CoreAudio} ${CoreFoundation} ${GLUT} ${OpenGL}) # install command for OS X bundle INSTALL(TARGETS ${TARGET_NAME} From f12973d5d0ed88b0425cdcbe99b2786aeb4ec97d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 11 Aug 2014 10:12:47 -0700 Subject: [PATCH 320/407] Cater for multiple mapping values --- examples/editModels.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 5fda380d55..8b54b9e48a 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -354,7 +354,7 @@ var modelUploader = (function () { remainder, existing; - mapping = {}; // { name : value | name : { value : remainder } } + mapping = {}; // { name : value | name : { value : [remainder] } } lines = dv.string(0, dv.byteLength).split(/\r\n|\r|\n/); for (i = 0; i < lines.length; i += 1) { line = lines[i].trim(); @@ -373,11 +373,16 @@ var modelUploader = (function () { } else { if (mapping[name] === undefined) { mapping[name] = {}; + } else if (typeof mapping[name] !== "object") { existing = mapping[name]; - mapping[name] = { existing: null }; + mapping[name] = { existing : null }; } - mapping[name][value] = remainder; + + if (mapping[name][value] === undefined) { + mapping[name][value] = []; + } + mapping[name][value].push(remainder); } } } @@ -388,6 +393,7 @@ var modelUploader = (function () { var name, value, remainder, + i, string = ""; for (name in mapping) { @@ -397,11 +403,12 @@ var modelUploader = (function () { if (mapping[name].hasOwnProperty(value)) { remainder = mapping[name][value]; if (remainder === null) { - remainder = ""; + string += (name + " = " + value + "\n"); } else { - remainder = " = " + remainder; + for (i = 0; i < remainder.length; i += 1) { + string += (name + " = " + value + " = " + remainder[i] + "\n"); + } } - string += (name + " = " + value + remainder + "\n"); } } } else { From 0b979d2e1ecd786b07733282afa5cca93e420156 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 11 Aug 2014 10:54:46 -0700 Subject: [PATCH 321/407] Disabled SVO model uploading: server doesn't support SVO file uploads --- examples/editModels.js | 43 +++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 8b54b9e48a..a047562dcd 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -288,7 +288,7 @@ var modelUploader = (function () { modelFile, fstBuffer, fbxBuffer, - svoBuffer, + //svoBuffer, mapping, geometry, API_URL = "https://data.highfidelity.io/api/v1/models", @@ -319,7 +319,7 @@ var modelUploader = (function () { function resetDataObjects() { fstBuffer = null; fbxBuffer = null; - svoBuffer = null; + //svoBuffer = null; mapping = {}; geometry = {}; geometry.textures = []; @@ -521,7 +521,7 @@ var modelUploader = (function () { function readModel() { var fbxFilename, - svoFilename, + //svoFilename, fileType; print("Reading model file: " + modelFile); @@ -536,8 +536,8 @@ var modelUploader = (function () { if (mapping.hasOwnProperty(FILENAME_FIELD)) { if (fileType === "fbx") { fbxFilename = modelFile.path() + "\\" + mapping[FILENAME_FIELD]; - } else if (fileType === "svo") { - svoFilename = modelFile.path() + "\\" + mapping[FILENAME_FIELD]; + //} else if (fileType === "svo") { + // svoFilename = modelFile.path() + "\\" + mapping[FILENAME_FIELD]; } else { error("Unrecognized model type in FST file!"); return false; @@ -556,9 +556,9 @@ var modelUploader = (function () { fbxFilename = modelFile; mapping[FILENAME_FIELD] = modelFile.fileName(); - } else if (modelFile.toLowerCase().fileType() === "svo") { - svoFilename = modelFile; - mapping[FILENAME_FIELD] = modelFile.fileName(); + //} else if (modelFile.toLowerCase().fileType() === "svo") { + // svoFilename = modelFile; + // mapping[FILENAME_FIELD] = modelFile.fileName(); } else { error("Unrecognized file type: " + modelFile); @@ -575,12 +575,12 @@ var modelUploader = (function () { readGeometry(fbxBuffer); } - if (svoFilename) { - svoBuffer = readFile(svoFilename); - if (svoBuffer === null) { - return false; - } - } + //if (svoFilename) { + // svoBuffer = readFile(svoFilename); + // if (svoBuffer === null) { + // return false; + // } + //} // Add any missing basic mappings if (!mapping.hasOwnProperty(NAME_FIELD)) { @@ -680,12 +680,12 @@ var modelUploader = (function () { } // SVO file - if (svoBuffer) { - httpMultiPart.add({ - name : "svo", - buffer: svoBuffer - }); - } + //if (svoBuffer) { + // httpMultiPart.add({ + // name : "svo", + // buffer: svoBuffer + // }); + //} // LOD files lodCount = 0; @@ -1044,7 +1044,8 @@ var toolBar = (function () { toggleToolbar(false); file = Window.browse("Select your model file ...", Settings.getValue("LastModelUploadLocation").path(), - "Model files (*.fst *.fbx *.svo)"); + "Model files (*.fst *.fbx)"); + //"Model files (*.fst *.fbx *.svo)"); if (file !== null) { Settings.setValue("LastModelUploadLocation", file); modelUploader.upload(file, addModel); From 53602c2ef2dc1bb4216b6dec40c57bfd709123e1 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 11 Aug 2014 10:55:31 -0700 Subject: [PATCH 322/407] Miscellaneous tidying --- examples/editModels.js | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index a047562dcd..3d93fca0bf 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -85,8 +85,8 @@ if (typeof String.prototype.path !== "function") { if (typeof String.prototype.regExpEscape !== "function") { String.prototype.regExpEscape = function () { - return this.replace(/([$^.+*?|\\\/{}()\[\]])/g, '\\$1'); - } + return this.replace(/([$\^.+*?|\\\/{}()\[\]])/g, '\\$1'); + }; } if (typeof String.prototype.toArrayBuffer !== "function") { @@ -333,7 +333,7 @@ var modelUploader = (function () { req.responseType = "arraybuffer"; req.send(); if (req.status !== 200) { - error("Could not read file: " + filename + " : " + req.status + " " + req.statusText); + error("Could not read file: " + filename + " : " + req.statusText); return null; } @@ -439,8 +439,7 @@ var modelUploader = (function () { propertyListLength, nameLength, name, - filename, - author; + filename; endOffset = view.getUint32(index, true); numProperties = view.getUint32(index + 4, true); @@ -480,7 +479,6 @@ var modelUploader = (function () { viewLength, charCode, charCodes, - author, filename; view = new Uint8Array(fbxBuffer.buffer); @@ -598,7 +596,6 @@ var modelUploader = (function () { function setProperties() { var form = [], - decimals = 3, directory, displayAs, validateAs; @@ -749,16 +746,16 @@ var modelUploader = (function () { error("Model upload failed: Internet request timed out!"); } - function debugResponse() { - print("req.errorCode = " + req.errorCode); - print("req.readyState = " + req.readyState); - print("req.status = " + req.status); - print("req.statusText = " + req.statusText); - print("req.responseType = " + req.responseType); - print("req.responseText = " + req.responseText); - print("req.response = " + req.response); - print("req.getAllResponseHeaders() = " + req.getAllResponseHeaders()); - } + //function debugResponse() { + // print("req.errorCode = " + req.errorCode); + // print("req.readyState = " + req.readyState); + // print("req.status = " + req.status); + // print("req.statusText = " + req.statusText); + // print("req.responseType = " + req.responseType); + // print("req.responseText = " + req.responseText); + // print("req.response = " + req.response); + // print("req.getAllResponseHeaders() = " + req.getAllResponseHeaders()); + //} function checkUploaded() { print("Checking uploaded model"); From 3d95f28fb9a1efbbed78087372f0c65eeb576f9f Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Mon, 11 Aug 2014 11:51:49 -0700 Subject: [PATCH 323/407] added apache licensing/removed implicit double<->float conversions/addressed style guide issues --- libraries/audio/src/AudioFilter.cpp | 13 ++++++++----- libraries/audio/src/AudioFilter.h | 17 ++++++++++------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/libraries/audio/src/AudioFilter.cpp b/libraries/audio/src/AudioFilter.cpp index 61e5e20171..28e7716578 100644 --- a/libraries/audio/src/AudioFilter.cpp +++ b/libraries/audio/src/AudioFilter.cpp @@ -3,7 +3,10 @@ // hifi // // Created by Craig Hansen-Sturm on 8/10/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 // #include @@ -15,9 +18,9 @@ template<> AudioFilterPEQ3::FilterParameter AudioFilterPEQ3::_profiles[ AudioFilterPEQ3::_profileCount ][ AudioFilterPEQ3::_filterCount ] = { - { { 300., 1., 1. }, { 1000., 1., 1. }, { 4000., 1., 1. } }, // flat response (default) - { { 300., 1., 1. }, { 1000., 1., 1. }, { 4000., .1, 1. } }, // treble cut - { { 300., .1, 1. }, { 1000., 1., 1. }, { 4000., 1., 1. } }, // bass cut - { { 300., 1.5, 0.71 }, { 1000., .5, 1. }, { 4000., 1.5, 0.71 } } // smiley curve + // Freq Gain Q Freq Gain Q Freq Gain Q + { { 300.0f, 1.0f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 1.0f, 1.0f } }, // flat response (default) + { { 300.0f, 1.0f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 0.1f, 1.0f } }, // treble cut + { { 300.0f, 0.1f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 1.0f, 1.0f } }, // bass cut + { { 300.0f, 1.5f, 0.71f }, { 1000.0f, 0.5f, 1.0f }, { 4000.0f, 1.50f, 0.71f } } // smiley curve }; - diff --git a/libraries/audio/src/AudioFilter.h b/libraries/audio/src/AudioFilter.h index 44dcd261d6..0f3ec06f64 100644 --- a/libraries/audio/src/AudioFilter.h +++ b/libraries/audio/src/AudioFilter.h @@ -3,7 +3,10 @@ // hifi // // Created by Craig Hansen-Sturm on 8/9/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 // #ifndef hifi_AudioFilter_h @@ -117,14 +120,14 @@ class AudioParametricEQ { const float a = _gain; const float omega = TWO_PI * _frequency / _sampleRate; - const float alpha = 0.5 * sinf(omega) / _slope; - const float gamma = 1.0 / ( 1.0 + (alpha/a) ); + const float alpha = 0.5f * sinf(omega) / _slope; + const float gamma = 1.0f / ( 1.0f + (alpha/a) ); - const float a0 = 1.0 + (alpha*a); - const float a1 = -2.0 * cosf(omega); - const float a2 = 1.0 - (alpha*a); + const float a0 = 1.0f + (alpha*a); + const float a1 = -2.0f * cosf(omega); + const float a2 = 1.0f - (alpha*a); const float b1 = a1; - const float b2 = 1.0 - (alpha/a); + const float b2 = 1.0f - (alpha/a); _kernel.setParameters( a0*gamma,a1*gamma,a2*gamma,b1*gamma,b2*gamma ); } @@ -257,7 +260,7 @@ public: } void render( const int16_t* in, int16_t* out, const int frameCount ) { - if( !_buffer || ( frameCount > _frameCount ) ) + if (!_buffer || ( frameCount > _frameCount )) return; const int scale = (2 << ((8*sizeof(int16_t))-1)); From 96ee9e3f750fa0326956616c1c5239782f2a0823 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 11 Aug 2014 13:54:36 -0700 Subject: [PATCH 324/407] Work on Recording structure --- interface/src/Recorder.cpp | 70 +++++++++++++++++++++++++++++++++----- interface/src/Recorder.h | 40 ++++++++++++++++++++-- 2 files changed, 99 insertions(+), 11 deletions(-) diff --git a/interface/src/Recorder.cpp b/interface/src/Recorder.cpp index 85e2535141..87352fed98 100644 --- a/interface/src/Recorder.cpp +++ b/interface/src/Recorder.cpp @@ -11,6 +11,18 @@ #include "Recorder.h" +void RecordingFrame::setBlendshapeCoefficients(QVector blendshapeCoefficients) { + _blendshapeCoefficients = blendshapeCoefficients; +} + +void RecordingFrame::setJointRotations(QVector jointRotations) { + _jointRotations = jointRotations; +} + +void RecordingFrame::setTranslation(glm::vec3 translation) { + _translation = translation; +} + void Recording::addFrame(int timestamp, RecordingFrame &frame) { _timestamps << timestamp; _frames << frame; @@ -21,16 +33,9 @@ void Recording::clear() { _frames.clear(); } -void writeRecordingToFile(Recording& recording, QString file) { - qDebug() << "Writing recording to " << file; +Recorder::Recorder(AvatarData* avatar) : _avatar(avatar) { } -Recording& readRecordingFromFile(QString file) { - qDebug() << "Reading recording from " << file; - return *(new Recording()); -} - - bool Recorder::isRecording() const { return _timer.isValid(); } @@ -58,4 +63,53 @@ void Recorder::saveToFile(QString file) { } writeRecordingToFile(_recording, file); +} + +void Recorder::record() { + qDebug() << "Recording " << _avatar; + RecordingFrame frame; + frame.setBlendshapeCoefficients(_avatar->_) +} + +Player::Player(AvatarData* avatar) : _avatar(avatar) { +} + +bool Player::isPlaying() const { + return _timer.isValid(); +} + +qint64 Player::elapsed() const { + if (isPlaying()) { + return _timer.elapsed(); + } else { + return 0; + } +} + +void Player::startPlaying() { + _timer.start(); +} + +void Player::stopPlaying() { + _timer.invalidate(); +} + +void Player::loadFromFile(QString file) { + _recording.clear(); + readRecordingFromFile(_recording, file); +} + +void Player::play() { + qDebug() << "Playing " << _avatar; +} + +void writeRecordingToFile(Recording& recording, QString file) { + // TODO + qDebug() << "Writing recording to " << file; +} + +Recording& readRecordingFromFile(Recording& recording, QString file) { + // TODO + qDebug() << "Reading recording from " << file; + return recording; } \ No newline at end of file diff --git a/interface/src/Recorder.h b/interface/src/Recorder.h index ffb013723c..2d32e4a9b0 100644 --- a/interface/src/Recorder.h +++ b/interface/src/Recorder.h @@ -17,8 +17,14 @@ #include #include +#include +#include + +#include #include +class Recording; + /// Stores the different values associated to one recording frame class RecordingFrame { public: @@ -26,11 +32,19 @@ public: QVector getJointRotations() const { return _jointRotations; } glm::vec3 getTranslation() const { return _translation; } -private: +protected: + void setBlendshapeCoefficients(QVector blendshapeCoefficients); + void setJointRotations(QVector jointRotations); + void setTranslation(glm::vec3 translation); +private: QVector _blendshapeCoefficients; QVector _jointRotations; glm::vec3 _translation; + + friend class Recorder; + friend void writeRecordingToFile(Recording& recording, QString file); + friend Recording* readRecordingFromFile(QString file); }; /// Stores a recording @@ -51,15 +65,16 @@ private: QVector _frames; friend class Recorder; + friend class Player; friend void writeRecordingToFile(Recording& recording, QString file); - friend Recording& readRecordingFromFile(QString file); + friend Recording* readRecordingFromFile(QString file); }; /// Records a recording class Recorder { public: - Recorder(); + Recorder(AvatarData* avatar); bool isRecording() const; qint64 elapsed() const; @@ -68,18 +83,37 @@ public slots: void startRecording(); void stopRecording(); void saveToFile(QString file); + void record(); private: QElapsedTimer _timer; Recording _recording; + + AvatarData* _avatar; }; /// Plays back a recording class Player { public: + Player(AvatarData* avatar); + + bool isPlaying() const; + qint64 elapsed() const; + +public slots: + void startPlaying(); + void stopPlaying(); + void loadFromFile(QString file); + void play(); private: + QElapsedTimer _timer; Recording _recording; + + AvatarData* _avatar; }; +void writeRecordingToFile(Recording& recording, QString file); +Recording& readRecordingFromFile(Recording& recording, QString file); + #endif // hifi_Recorder_h \ No newline at end of file From 8804fa37109ff82a8f15cc847d2091780f442815 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 11 Aug 2014 14:29:53 -0700 Subject: [PATCH 325/407] Switch to PNG encoding, send only the changed portion of the image for deltas. --- .../metavoxels/src/AttributeRegistry.cpp | 275 +++++++++++++++--- libraries/metavoxels/src/AttributeRegistry.h | 24 +- .../metavoxels/src/MetavoxelMessages.cpp | 22 +- 3 files changed, 268 insertions(+), 53 deletions(-) diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 9f656ef5d3..2943ac152b 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -490,21 +490,52 @@ HeightfieldData::HeightfieldData(const QByteArray& contents) : } const int BYTES_PER_PIXEL = 3; +const int ZERO_OFFSET = 128; -HeightfieldData::HeightfieldData(Bitstream& in, int bytes, bool color) : - _encoded(in.readAligned(bytes)) { +HeightfieldData::HeightfieldData(Bitstream& in, int bytes, bool color) { + read(in, bytes, color); +} + +HeightfieldData::HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& reference, bool color) { + if (!reference) { + read(in, bytes, color); + return; + } + QMutexLocker locker(&reference->_encodedDeltaMutex); + reference->_encodedDelta = in.readAligned(bytes); + reference->_deltaData = this; + _contents = reference->_contents; - QImage image = QImage::fromData(_encoded).convertToFormat(QImage::Format_RGB888); + QBuffer buffer(&reference->_encodedDelta); + buffer.open(QIODevice::ReadOnly); + QImage image; + image.load(&buffer, "PNG"); + QPoint offset = image.offset(); + image = image.convertToFormat(QImage::Format_RGB888); + if (offset.x() == 0) { + set(image, color); + return; + } + int minX = offset.x() - 1; + int minY = offset.y() - 1; if (color) { - _contents.resize(image.width() * image.height() * BYTES_PER_PIXEL); - memcpy(_contents.data(), image.constBits(), _contents.size()); - + int size = glm::sqrt(_contents.size() / (float)BYTES_PER_PIXEL); + char* dest = _contents.data() + (minY * size + minX) * BYTES_PER_PIXEL; + int destStride = size * BYTES_PER_PIXEL; + int srcStride = image.width() * BYTES_PER_PIXEL; + for (int y = 0; y < image.height(); y++) { + memcpy(dest, image.constScanLine(y), srcStride); + dest += destStride; + } } else { - _contents.resize(image.width() * image.height()); - char* dest = _contents.data(); - for (const uchar* src = image.constBits(), *end = src + _contents.size() * BYTES_PER_PIXEL; - src != end; src += BYTES_PER_PIXEL) { - *dest++ = *src; + int size = glm::sqrt((float)_contents.size()); + char* lineDest = _contents.data() + minY * size + minX; + for (int y = 0; y < image.height(); y++) { + const uchar* src = image.constScanLine(y); + for (char* dest = lineDest, *end = dest + image.width(); dest != end; dest++, src += BYTES_PER_PIXEL) { + *dest = *src; + } + lineDest += size; } } } @@ -528,36 +559,168 @@ void HeightfieldData::write(Bitstream& out, bool color) { } QBuffer buffer(&_encoded); buffer.open(QIODevice::WriteOnly); - image.save(&buffer, "JPG"); + image.save(&buffer, "PNG"); } out << _encoded.size(); out.writeAligned(_encoded); } +void HeightfieldData::writeDelta(Bitstream& out, const HeightfieldDataPointer& reference, bool color) { + if (!reference || reference->getContents().size() != _contents.size()) { + write(out, color); + return; + } + QMutexLocker locker(&reference->_encodedDeltaMutex); + if (reference->_encodedDelta.isEmpty() || reference->_deltaData != this) { + QImage image; + int minX, minY; + if (color) { + int size = glm::sqrt(_contents.size() / (float)BYTES_PER_PIXEL); + minX = size; + minY = size; + int maxX = -1, maxY = -1; + const char* src = _contents.constData(); + const char* ref = reference->_contents.constData(); + for (int y = 0; y < size; y++) { + bool difference = false; + for (int x = 0; x < size; x++, src += BYTES_PER_PIXEL, ref += BYTES_PER_PIXEL) { + if (src[0] != ref[0] || src[1] != ref[1] || src[2] != ref[2]) { + minX = qMin(minX, x); + maxX = qMax(maxX, x); + difference = true; + } + } + if (difference) { + minY = qMin(minY, y); + maxY = qMax(maxY, y); + } + } + int width = qMax(maxX - minX + 1, 0); + int height = qMax(maxY - minY + 1, 0); + image = QImage(width, height, QImage::Format_RGB888); + src = _contents.constData() + (minY * size + minX) * BYTES_PER_PIXEL; + int srcStride = size * BYTES_PER_PIXEL; + int destStride = width * BYTES_PER_PIXEL; + for (int y = 0; y < height; y++) { + memcpy(image.scanLine(y), src, destStride); + src += srcStride; + } + } else { + int size = glm::sqrt((float)_contents.size()); + minX = size; + minY = size; + int maxX = -1, maxY = -1; + const char* src = _contents.constData(); + const char* ref = reference->_contents.constData(); + for (int y = 0; y < size; y++) { + bool difference = false; + for (int x = 0; x < size; x++) { + if (*src++ != *ref++) { + minX = qMin(minX, x); + maxX = qMax(maxX, x); + difference = true; + } + } + if (difference) { + minY = qMin(minY, y); + maxY = qMax(maxY, y); + } + } + int width = qMax(maxX - minX + 1, 0); + int height = qMax(maxY - minY + 1, 0); + image = QImage(width, height, QImage::Format_RGB888); + const uchar* lineSrc = (const uchar*)_contents.constData() + minY * size + minX; + for (int y = 0; y < height; y++) { + uchar* dest = image.scanLine(y); + for (const uchar* src = lineSrc, *end = src + width; src != end; src++) { + *dest++ = *src; + *dest++ = *src; + *dest++ = *src; + } + lineSrc += size; + } + } + QBuffer buffer(&reference->_encodedDelta); + buffer.open(QIODevice::WriteOnly); + image.setOffset(QPoint(minX + 1, minY + 1)); + image.save(&buffer, "PNG"); + reference->_deltaData = this; + } + out << reference->_encodedDelta.size(); + out.writeAligned(reference->_encodedDelta); +} + +void HeightfieldData::read(Bitstream& in, int bytes, bool color) { + set(QImage::fromData(_encoded = in.readAligned(bytes)).convertToFormat(QImage::Format_RGB888), color); +} + +void HeightfieldData::set(const QImage& image, bool color) { + if (color) { + _contents.resize(image.width() * image.height() * BYTES_PER_PIXEL); + memcpy(_contents.data(), image.constBits(), _contents.size()); + + } else { + _contents.resize(image.width() * image.height()); + char* dest = _contents.data(); + for (const uchar* src = image.constBits(), *end = src + _contents.size() * BYTES_PER_PIXEL; + src != end; src += BYTES_PER_PIXEL) { + *dest++ = *src; + } + } +} + HeightfieldAttribute::HeightfieldAttribute(const QString& name) : InlineAttribute(name) { } void HeightfieldAttribute::read(Bitstream& in, void*& value, bool isLeaf) const { - if (isLeaf) { - int size; - in >> size; - if (size == 0) { - *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(); - } else { - *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, false)); - } + if (!isLeaf) { + return; + } + int size; + in >> size; + if (size == 0) { + *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(); + } else { + *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, false)); } } void HeightfieldAttribute::write(Bitstream& out, void* value, bool isLeaf) const { - if (isLeaf) { - HeightfieldDataPointer data = decodeInline(value); - if (data) { - data->write(out, false); - } else { - out << 0; - } + if (!isLeaf) { + return; + } + HeightfieldDataPointer data = decodeInline(value); + if (data) { + data->write(out, false); + } else { + out << 0; + } +} + +void HeightfieldAttribute::readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const { + if (!isLeaf) { + return; + } + int size; + in >> size; + if (size == 0) { + *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(); + } else { + *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData( + in, size, decodeInline(reference), false)); + } +} + +void HeightfieldAttribute::writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const { + if (!isLeaf) { + return; + } + HeightfieldDataPointer data = decodeInline(value); + if (data) { + data->writeDelta(out, decodeInline(reference), false); + } else { + out << 0; } } @@ -635,25 +798,53 @@ HeightfieldColorAttribute::HeightfieldColorAttribute(const QString& name) : } void HeightfieldColorAttribute::read(Bitstream& in, void*& value, bool isLeaf) const { - if (isLeaf) { - int size; - in >> size; - if (size == 0) { - *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(); - } else { - *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, true)); - } + if (!isLeaf) { + return; + } + int size; + in >> size; + if (size == 0) { + *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(); + } else { + *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, true)); } } void HeightfieldColorAttribute::write(Bitstream& out, void* value, bool isLeaf) const { - if (isLeaf) { - HeightfieldDataPointer data = decodeInline(value); - if (data) { - data->write(out, true); - } else { - out << 0; - } + if (!isLeaf) { + return; + } + HeightfieldDataPointer data = decodeInline(value); + if (data) { + data->write(out, true); + } else { + out << 0; + } +} + +void HeightfieldColorAttribute::readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const { + if (!isLeaf) { + return; + } + int size; + in >> size; + if (size == 0) { + *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(); + } else { + *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData( + in, size, decodeInline(reference), true)); + } +} + +void HeightfieldColorAttribute::writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const { + if (!isLeaf) { + return; + } + HeightfieldDataPointer data = decodeInline(value); + if (data) { + data->writeDelta(out, decodeInline(reference), true); + } else { + out << 0; } } diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 5d973341ad..d0f1cdf836 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -28,6 +28,7 @@ class QScriptEngine; class QScriptValue; class Attribute; +class HeightfieldData; class MetavoxelData; class MetavoxelLOD; class MetavoxelNode; @@ -421,26 +422,35 @@ public: virtual AttributeValue inherit(const AttributeValue& parentValue) const; }; +typedef QExplicitlySharedDataPointer HeightfieldDataPointer; + /// Contains a block of heightfield data. class HeightfieldData : public QSharedData { public: HeightfieldData(const QByteArray& contents); HeightfieldData(Bitstream& in, int bytes, bool color); - + HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& reference, bool color); + const QByteArray& getContents() const { return _contents; } void write(Bitstream& out, bool color); + void writeDelta(Bitstream& out, const HeightfieldDataPointer& reference, bool color); private: + void read(Bitstream& in, int bytes, bool color); + void set(const QImage& image, bool color); + QByteArray _contents; QByteArray _encoded; QMutex _encodedMutex; + + HeightfieldDataPointer _deltaData; + QByteArray _encodedDelta; + QMutex _encodedDeltaMutex; }; -typedef QExplicitlySharedDataPointer HeightfieldDataPointer; - /// An attribute that stores heightfield data. class HeightfieldAttribute : public InlineAttribute { Q_OBJECT @@ -451,7 +461,10 @@ public: virtual void read(Bitstream& in, void*& value, bool isLeaf) const; virtual void write(Bitstream& out, void* value, bool isLeaf) const; - + + virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const; + virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const; + virtual bool merge(void*& parent, void* children[], bool postRead = false) const; }; @@ -466,6 +479,9 @@ public: virtual void read(Bitstream& in, void*& value, bool isLeaf) const; virtual void write(Bitstream& out, void* value, bool isLeaf) const; + virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const; + virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const; + virtual bool merge(void*& parent, void* children[], bool postRead = false) const; }; diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 926d839991..ad3c36eb03 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -378,6 +378,7 @@ int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) { float squaredRadiusReciprocal = 1.0f / squaredRadius; const int EIGHT_BIT_MAXIMUM = 255; float scaledHeight = _edit.height * EIGHT_BIT_MAXIMUM / info.size; + bool changed = false; for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) { uchar* dest = lineDest; for (float x = startX; x <= endX; x += 1.0f, dest++) { @@ -386,14 +387,18 @@ int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) { if (distanceSquared <= squaredRadius) { // height falls off towards edges int value = *dest + scaledHeight * (squaredRadius - distanceSquared) * squaredRadiusReciprocal; - *dest = qMin(qMax(value, 0), EIGHT_BIT_MAXIMUM); + if (value != *dest) { + *dest = qMin(qMax(value, 0), EIGHT_BIT_MAXIMUM); + changed = true; + } } } lineDest += size; } - - HeightfieldDataPointer newPointer(new HeightfieldData(contents)); - info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(newPointer)); + if (changed) { + HeightfieldDataPointer newPointer(new HeightfieldData(contents)); + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(newPointer)); + } return STOP_RECURSION; } @@ -461,6 +466,7 @@ int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) { char* lineDest = contents.data() + (int)z * stride + (int)startX * BYTES_PER_PIXEL; float squaredRadius = scaledRadius * scaledRadius; char red = _edit.color.red(), green = _edit.color.green(), blue = _edit.color.blue(); + bool changed = false; for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) { char* dest = lineDest; for (float x = startX; x <= endX; x += 1.0f, dest += BYTES_PER_PIXEL) { @@ -469,13 +475,15 @@ int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) { dest[0] = red; dest[1] = green; dest[2] = blue; + changed = true; } } lineDest += stride; } - - HeightfieldDataPointer newPointer(new HeightfieldData(contents)); - info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(newPointer)); + if (changed) { + HeightfieldDataPointer newPointer(new HeightfieldData(contents)); + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(newPointer)); + } return STOP_RECURSION; } From 2918feddf0c3a79b696f5dedb5228efd63b91901 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 11 Aug 2014 14:51:42 -0700 Subject: [PATCH 326/407] reduce acceptable error for ragdoll simulation --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f59064732c..7481aa9ef8 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -206,7 +206,7 @@ void MyAvatar::simulate(float deltaTime) { { PerformanceTimer perfTimer("ragdoll"); if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { - const float minError = 0.01f; + const float minError = 0.00001f; const float maxIterations = 10; const quint64 maxUsec = 2000; _physicsSimulation.setTranslation(_position); From 10315f15d452adf0051679692cfcffe395588798 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 11 Aug 2014 15:15:33 -0700 Subject: [PATCH 327/407] Simplify image loading. --- libraries/metavoxels/src/AttributeRegistry.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 2943ac152b..7e70d7b315 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -505,11 +505,7 @@ HeightfieldData::HeightfieldData(Bitstream& in, int bytes, const HeightfieldData reference->_encodedDelta = in.readAligned(bytes); reference->_deltaData = this; _contents = reference->_contents; - - QBuffer buffer(&reference->_encodedDelta); - buffer.open(QIODevice::ReadOnly); - QImage image; - image.load(&buffer, "PNG"); + QImage image = QImage::fromData(reference->_encodedDelta); QPoint offset = image.offset(); image = image.convertToFormat(QImage::Format_RGB888); if (offset.x() == 0) { From d1672b510d5aec85145369e862984c36720909b3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 11 Aug 2014 18:41:07 -0700 Subject: [PATCH 328/407] Add DomainHandler::disconnectedFromDomain signal --- libraries/networking/src/DomainHandler.cpp | 5 ++++- libraries/networking/src/DomainHandler.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index fcd284fd4a..91166129ad 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -36,6 +36,7 @@ DomainHandler::DomainHandler(QObject* parent) : void DomainHandler::clearConnectionInfo() { _uuid = QUuid(); _isConnected = false; + emit disconnectedFromDomain(); if (_handshakeTimer) { _handshakeTimer->stop(); @@ -129,6 +130,8 @@ void DomainHandler::setIsConnected(bool isConnected) { // we've connected to new domain - time to ask it for global settings requestDomainSettings(); + } else { + emit disconnectedFromDomain(); } } } @@ -196,4 +199,4 @@ void DomainHandler::parseDTLSRequirementPacket(const QByteArray& dtlsRequirement _sockAddr.setPort(dtlsPort); // initializeDTLSSession(); -} \ No newline at end of file +} diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 28433c5455..91caddca22 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -70,6 +70,7 @@ private slots: signals: void hostnameChanged(const QString& hostname); void connectedToDomain(const QString& hostname); + void disconnectedFromDomain(); void settingsReceived(const QJsonObject& domainSettingsObject); void settingsReceiveFail(); From 0296d0deeb77e31b3703b868cbda3e7e2191c280 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 11 Aug 2014 18:43:26 -0700 Subject: [PATCH 329/407] Add domain connection status to window title --- interface/src/Application.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6f7212e68f..9f14023dfc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -242,6 +242,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&))); connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&))); + connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(updateWindowTitle())); + connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); connect(&domainHandler, &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived); // hookup VoxelEditSender to PaymentManager so we can pay for octree edits @@ -3320,9 +3322,10 @@ void Application::updateWindowTitle(){ QString buildVersion = " (build " + applicationVersion() + ")"; NodeList* nodeList = NodeList::getInstance(); + QString connectionStatus = nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED) "; QString username = AccountManager::getInstance().getAccountInfo().getUsername(); QString title = QString() + (!username.isEmpty() ? username + " @ " : QString()) - + nodeList->getDomainHandler().getHostname() + buildVersion; + + nodeList->getDomainHandler().getHostname() + connectionStatus + buildVersion; AccountManager& accountManager = AccountManager::getInstance(); if (accountManager.getAccountInfo().hasBalance()) { From 4852fcc034964dd3027bef184209df6cc24986e2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 11 Aug 2014 18:43:49 -0700 Subject: [PATCH 330/407] Add red border to main window when not connected to domain --- interface/src/ui/ApplicationOverlay.cpp | 29 +++++++++++++++++++++++++ interface/src/ui/ApplicationOverlay.h | 3 ++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index c49873b5f5..7dcb50c314 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -57,6 +57,9 @@ ApplicationOverlay::~ApplicationOverlay() { const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f }; +const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f }; +const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f; + // Renders the overlays either to a texture or to the screen void ApplicationOverlay::renderOverlay(bool renderToTexture) { @@ -115,6 +118,8 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { renderPointers(); + renderDomainConnectionStatusBorder(); + glPopMatrix(); @@ -1234,6 +1239,30 @@ void ApplicationOverlay::renderTexturedHemisphere() { } +void ApplicationOverlay::renderDomainConnectionStatusBorder() { + NodeList* nodeList = NodeList::getInstance(); + + if (nodeList && !nodeList->getDomainHandler().isConnected()) { + QGLWidget* glWidget = Application::getInstance()->getGLWidget(); + int right = glWidget->width(); + int bottom = glWidget->height(); + + glColor3f(CONNECTION_STATUS_BORDER_COLOR[0], + CONNECTION_STATUS_BORDER_COLOR[1], + CONNECTION_STATUS_BORDER_COLOR[2]); + glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH); + + glBegin(GL_LINE_LOOP); + + glVertex2i(0, 0); + glVertex2i(0, bottom); + glVertex2i(right, bottom); + glVertex2i(right, 0); + + glEnd(); + } +} + QOpenGLFramebufferObject* ApplicationOverlay::getFramebufferObject() { QSize size = Application::getInstance()->getGLWidget()->size(); if (!_framebufferObject || _framebufferObject->size() != size) { diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 0c2ccc7b21..a493f6cd1b 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -56,6 +56,7 @@ private: void renderAudioMeter(); void renderStatsAndLogs(); void renderTexturedHemisphere(); + void renderDomainConnectionStatusBorder(); QOpenGLFramebufferObject* _framebufferObject; float _trailingAudioLoudness; @@ -76,4 +77,4 @@ private: GLuint _crosshairTexture; }; -#endif // hifi_ApplicationOverlay_h \ No newline at end of file +#endif // hifi_ApplicationOverlay_h From 4ff7ff61e8c8e2379224cc1eb3eeaf63826636b8 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 12 Aug 2014 13:25:22 +0200 Subject: [PATCH 331/407] OSX compatibility with SDK 0.4.1 --- interface/src/devices/OculusManager.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index ab30ee7c8b..96df5b6c7c 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -66,7 +66,7 @@ void OculusManager::connect() { UserActivityLogger::getInstance().connectedDevice("hmd", "oculus"); } _isConnected = true; -#ifdef _WIN32 +#if defined(__APPLE__) || defined(_WIN32) _eyeFov[0] = _ovrHmd->DefaultEyeFov[0]; _eyeFov[1] = _ovrHmd->DefaultEyeFov[1]; #else @@ -88,13 +88,13 @@ void OculusManager::connect() { _eyeRenderDesc[0] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Left, _eyeFov[0]); _eyeRenderDesc[1] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Right, _eyeFov[1]); -#ifdef _WIN32 +#if defined(__APPLE__) || defined(_WIN32) ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence); #else ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_LatencyTest); #endif -#ifdef _WIN32 +#if defined(__APPLE__) || defined(_WIN32) ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, ovrTrackingCap_Orientation); @@ -195,7 +195,7 @@ void OculusManager::generateDistortionMesh() { DistortionVertex* v = pVBVerts; ovrDistortionVertex* ov = meshData.pVertexData; for (unsigned int vertNum = 0; vertNum < meshData.VertexCount; vertNum++) { -#ifdef _WIN32 +#if defined(__APPLE__) || defined(_WIN32) v->pos.x = ov->ScreenPosNDC.x; v->pos.y = ov->ScreenPosNDC.y; v->texR.x = ov->TanEyeAnglesR.x; @@ -317,7 +317,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p //Render each eye into an fbo for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) { -#ifdef _WIN32 +#if defined(__APPLE__) || defined(_WIN32) ovrEyeType eye = _ovrHmd->EyeRenderOrder[eyeIndex]; #else ovrEyeType eye = _ovrHmdDesc.EyeRenderOrder[eyeIndex]; @@ -458,18 +458,18 @@ void OculusManager::reset() { //Gets the current predicted angles from the oculus sensors void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { #ifdef HAVE_LIBOVR -#ifdef _WIN32 +#if defined(__APPLE__) || defined(_WIN32) ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); #else ovrSensorState ss = ovrHmd_GetSensorState(_ovrHmd, _hmdFrameTiming.ScanoutMidpointSeconds); #endif -#ifdef _WIN32 +#if defined(__APPLE__) || defined(_WIN32) if (ts.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { #else if (ss.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { #endif -#ifdef _WIN32 +#if defined(__APPLE__) || defined(_WIN32) ovrPosef pose = ts.CameraPose; #else ovrPosef pose = ss.Predicted.Pose; From 2c0f8ff57ec0b70fbe72ba97ddd12473c5ac90e8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 12 Aug 2014 10:56:15 -0700 Subject: [PATCH 332/407] Working on rejiggering the heightfield tiles. --- .../shaders/metavoxel_heightfield.vert | 7 +- .../shaders/metavoxel_heightfield_cursor.vert | 3 - interface/src/MetavoxelSystem.cpp | 100 +++++++++++++----- interface/src/MetavoxelSystem.h | 6 +- interface/src/ui/MetavoxelEditor.cpp | 30 +++--- 5 files changed, 100 insertions(+), 46 deletions(-) diff --git a/interface/resources/shaders/metavoxel_heightfield.vert b/interface/resources/shaders/metavoxel_heightfield.vert index cc4f68e9e0..4932ad1b2b 100644 --- a/interface/resources/shaders/metavoxel_heightfield.vert +++ b/interface/resources/shaders/metavoxel_heightfield.vert @@ -17,6 +17,9 @@ uniform sampler2D heightMap; // the distance between height points in texture space uniform float heightScale; +// the scale between height and color textures +uniform float colorScale; + // the interpolated normal varying vec4 normal; @@ -29,8 +32,8 @@ void main(void) { texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r; normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0)); - // pass along the texture coordinates - gl_TexCoord[0] = gl_MultiTexCoord0; + // pass along the scaled/offset texture coordinates + gl_TexCoord[0] = (gl_MultiTexCoord0 - vec4(heightScale, heightScale, 0.0, 0.0)) * colorScale; // add the height to the position float height = texture2D(heightMap, heightCoord).r; diff --git a/interface/resources/shaders/metavoxel_heightfield_cursor.vert b/interface/resources/shaders/metavoxel_heightfield_cursor.vert index 20502fbdce..93ed36449e 100644 --- a/interface/resources/shaders/metavoxel_heightfield_cursor.vert +++ b/interface/resources/shaders/metavoxel_heightfield_cursor.vert @@ -14,9 +14,6 @@ // the height texture uniform sampler2D heightMap; -// the distance between height points in texture space -uniform float heightScale; - void main(void) { // compute the view space coordinates float height = texture2D(heightMap, gl_MultiTexCoord0.st).r; diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 597542778a..7be3955de7 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -366,6 +366,7 @@ void HeightfieldBuffer::render(bool cursor) { if (_heightTextureID == 0) { glGenTextures(1, &_heightTextureID); glBindTexture(GL_TEXTURE_2D, _heightTextureID); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -385,7 +386,7 @@ void HeightfieldBuffer::render(bool cursor) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, WHITE_COLOR); } else { - int colorSize = glm::sqrt(_color.size() / 3); + int colorSize = glm::sqrt(_color.size() / 3); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, colorSize, colorSize, 0, GL_RGB, GL_UNSIGNED_BYTE, _color.constData()); if (_clearAfterLoading) { _color.clear(); @@ -393,24 +394,27 @@ void HeightfieldBuffer::render(bool cursor) { } } // create the buffer objects lazily - int sizeWithSkirt = _heightSize + 2; - int vertexCount = sizeWithSkirt * sizeWithSkirt; - int rows = sizeWithSkirt - 1; + int innerSize = _heightSize - 2; + int vertexCount = _heightSize * _heightSize; + int rows = _heightSize - 1; int indexCount = rows * rows * 4; BufferPair& bufferPair = _bufferPairs[_heightSize]; if (!bufferPair.first.isCreated()) { QVector vertices(vertexCount); HeightfieldPoint* point = vertices.data(); - float step = 1.0f / (_heightSize - 1); - float z = -step; - for (int i = 0; i < sizeWithSkirt; i++, z += step) { - float x = -step; + float vertexStep = 1.0f / (innerSize - 1); + float z = -vertexStep; + float textureStep = 1.0f / _heightSize; + float t = textureStep / 2.0f; + for (int i = 0; i < _heightSize; i++, z += vertexStep, t += textureStep) { + float x = -vertexStep; + float s = textureStep / 2.0f; const float SKIRT_LENGTH = 0.25f; - float baseY = (i == 0 || i == sizeWithSkirt - 1) ? -SKIRT_LENGTH : 0.0f; - for (int j = 0; j < sizeWithSkirt; j++, point++, x += step) { - point->vertex = glm::vec3(x, (j == 0 || j == sizeWithSkirt - 1) ? -SKIRT_LENGTH : baseY, z); - point->textureCoord = glm::vec2(x, z); + float baseY = (i == 0 || i == _heightSize - 1) ? -SKIRT_LENGTH : 0.0f; + for (int j = 0; j < _heightSize; j++, point++, x += vertexStep, s += textureStep) { + point->vertex = glm::vec3(x, (j == 0 || j == _heightSize - 1) ? -SKIRT_LENGTH : baseY, z); + point->textureCoord = glm::vec2(s, t); } } @@ -422,8 +426,8 @@ void HeightfieldBuffer::render(bool cursor) { QVector indices(indexCount); int* index = indices.data(); for (int i = 0; i < rows; i++) { - int lineIndex = i * sizeWithSkirt; - int nextLineIndex = (i + 1) * sizeWithSkirt; + int lineIndex = i * _heightSize; + int nextLineIndex = (i + 1) * _heightSize; for (int j = 0; j < rows; j++) { *index++ = lineIndex + j; *index++ = nextLineIndex + j; @@ -452,17 +456,15 @@ void HeightfieldBuffer::render(bool cursor) { glBindTexture(GL_TEXTURE_2D, _heightTextureID); - int heightScaleLocation; - if (cursor) { - heightScaleLocation = DefaultMetavoxelRendererImplementation::getCursorHeightScaleLocation(); - } else { - heightScaleLocation = DefaultMetavoxelRendererImplementation::getHeightScaleLocation(); + if (!cursor) { + DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue( + DefaultMetavoxelRendererImplementation::getHeightScaleLocation(), 1.0f / _heightSize); + DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue( + DefaultMetavoxelRendererImplementation::getColorScaleLocation(), (float)_heightSize / innerSize); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _colorTextureID); } - DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue(heightScaleLocation, 1.0f / _heightSize); - glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); if (!cursor) { @@ -548,6 +550,7 @@ void DefaultMetavoxelRendererImplementation::init() { _heightfieldProgram.setUniformValue("heightMap", 0); _heightfieldProgram.setUniformValue("diffuseMap", 1); _heightScaleLocation = _heightfieldProgram.uniformLocation("heightScale"); + _colorScaleLocation = _heightfieldProgram.uniformLocation("colorScale"); _heightfieldProgram.release(); _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + @@ -558,7 +561,6 @@ void DefaultMetavoxelRendererImplementation::init() { _heightfieldCursorProgram.bind(); _heightfieldCursorProgram.setUniformValue("heightMap", 0); - _cursorHeightScaleLocation = _heightfieldCursorProgram.uniformLocation("heightScale"); _heightfieldCursorProgram.release(); } } @@ -648,14 +650,62 @@ HeightfieldAugmentVisitor::HeightfieldAugmentVisitor(const MetavoxelLOD& lod) : Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod) { } +class BorderFetchVisitor : public MetavoxelVisitor { +public: + + BorderFetchVisitor(const MetavoxelLOD& lod, QByteArray& height); + + virtual int visit(MetavoxelInfo& info); + +private: + + QByteArray& _height; +}; + +BorderFetchVisitor::BorderFetchVisitor(const MetavoxelLOD& lod, QByteArray& height) : + MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getHeightfieldAttribute(), + QVector(), lod), + _height(height) { +} + +int BorderFetchVisitor::visit(MetavoxelInfo& info) { + if (!info.isLeaf) { + return DEFAULT_ORDER; + } + return STOP_RECURSION; +} + int HeightfieldAugmentVisitor::visit(MetavoxelInfo& info) { if (info.isLeaf) { HeightfieldBuffer* buffer = NULL; HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue(); if (height) { + const QByteArray& heightContents = height->getContents(); + int size = glm::sqrt(heightContents.size()); + int extendedSize = size + 3; + QByteArray extendedHeightContents(extendedSize * extendedSize, 0); + char* dest = extendedHeightContents.data() + extendedSize + 1; + const char* src = heightContents.constData(); + for (int z = 0; z < size; z++, src += size, dest += extendedSize) { + memcpy(dest, src, size); + } + QByteArray extendedColorContents; HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue(); - buffer = new HeightfieldBuffer(info.minimum, info.size, height->getContents(), - color ? color->getContents() : QByteArray()); + if (color) { + const QByteArray& colorContents = color->getContents(); + const int BYTES_PER_PIXEL = 3; + int colorSize = glm::sqrt(colorContents.size() / BYTES_PER_PIXEL); + int extendedColorSize = colorSize + 1; + extendedColorContents = QByteArray(extendedColorSize * extendedColorSize * BYTES_PER_PIXEL, 0); + char* dest = extendedColorContents.data(); + const char* src = colorContents.constData(); + int srcStride = colorSize * BYTES_PER_PIXEL; + int destStride = extendedColorSize * BYTES_PER_PIXEL; + for (int z = 0; z < colorSize; z++, src += srcStride, dest += destStride) { + memcpy(dest, src, srcStride); + } + } + buffer = new HeightfieldBuffer(info.minimum, info.size, extendedHeightContents, extendedColorContents); } info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer))); return STOP_RECURSION; @@ -856,8 +906,8 @@ ProgramObject DefaultMetavoxelRendererImplementation::_pointProgram; int DefaultMetavoxelRendererImplementation::_pointScaleLocation; ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldProgram; int DefaultMetavoxelRendererImplementation::_heightScaleLocation; +int DefaultMetavoxelRendererImplementation::_colorScaleLocation; ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldCursorProgram; -int DefaultMetavoxelRendererImplementation::_cursorHeightScaleLocation; static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { GLdouble coefficients[] = { x, y, z, w }; diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 7b681ff3a9..0940ea4d19 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -194,9 +194,9 @@ public: static ProgramObject& getHeightfieldProgram() { return _heightfieldProgram; } static int getHeightScaleLocation() { return _heightScaleLocation; } - + static int getColorScaleLocation() { return _colorScaleLocation; } + static ProgramObject& getHeightfieldCursorProgram() { return _heightfieldCursorProgram; } - static int getCursorHeightScaleLocation() { return _cursorHeightScaleLocation; } Q_INVOKABLE DefaultMetavoxelRendererImplementation(); @@ -211,9 +211,9 @@ private: static ProgramObject _heightfieldProgram; static int _heightScaleLocation; + static int _colorScaleLocation; static ProgramObject _heightfieldCursorProgram; - static int _cursorHeightScaleLocation; }; /// Base class for spanner renderers; provides clipping. diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index d35ed93f1b..260d3c2b3b 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -1003,30 +1003,34 @@ void ImportHeightfieldTool::updatePreview() { if (_heightImage.width() > 0 && _heightImage.height() > 0) { float z = 0.0f; int blockSize = pow(2.0, _blockSize->value()); - int blockAdvancement = blockSize - 1; - for (int i = 0; i < _heightImage.height(); i += blockAdvancement, z++) { + int heightSize = blockSize + 3; + int colorSize = blockSize + 1; + for (int i = 0; i < _heightImage.height(); i += blockSize, z++) { float x = 0.0f; - for (int j = 0; j < _heightImage.width(); j += blockAdvancement, x++) { - QByteArray height(blockSize * blockSize, 0); - int rows = qMin(blockSize, _heightImage.height() - i); - int columns = qMin(blockSize, _heightImage.width() - j); + for (int j = 0; j < _heightImage.width(); j += blockSize, x++) { + QByteArray height(heightSize * heightSize, 0); + int extendedI = qMax(i - 1, 0); + int extendedJ = qMax(j - 1, 0); + int offsetY = extendedI - i + 1; + int offsetX = extendedJ - j + 1; + int rows = qMin(heightSize - offsetY, _heightImage.height() - extendedI); + int columns = qMin(heightSize - offsetX, _heightImage.width() - extendedJ); const int BYTES_PER_COLOR = 3; for (int y = 0; y < rows; y++) { - uchar* src = _heightImage.scanLine(i + y) + j * BYTES_PER_COLOR; - char* dest = height.data() + y * blockSize; + uchar* src = _heightImage.scanLine(extendedI + y) + extendedJ * BYTES_PER_COLOR; + char* dest = height.data() + (y + offsetY) * heightSize + offsetX; for (int x = 0; x < columns; x++) { *dest++ = *src; src += BYTES_PER_COLOR; } } - QByteArray color; if (!_colorImage.isNull()) { - color = QByteArray(blockSize * blockSize * BYTES_PER_COLOR, 0); - rows = qMax(0, qMin(blockSize, _colorImage.height() - i)); - columns = qMax(0, qMin(blockSize, _colorImage.width() - j)); + color = QByteArray(colorSize * colorSize * BYTES_PER_COLOR, 0); + rows = qMax(0, qMin(colorSize, _colorImage.height() - i)); + columns = qMax(0, qMin(colorSize, _colorImage.width() - j)); for (int y = 0; y < rows; y++) { - memcpy(color.data() + y * blockSize * BYTES_PER_COLOR, + memcpy(color.data() + y * colorSize * BYTES_PER_COLOR, _colorImage.scanLine(i + y) + j * BYTES_PER_COLOR, columns * BYTES_PER_COLOR); } } From ee01d85b5ed3769cd8bcc64b7105c0bc59c45274 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 12 Aug 2014 12:01:07 -0700 Subject: [PATCH 333/407] Attempting to remove some number magic. --- interface/src/MetavoxelSystem.cpp | 54 ++++++++++----- interface/src/MetavoxelSystem.h | 13 ++-- interface/src/ui/MetavoxelEditor.cpp | 30 ++++---- .../metavoxels/src/AttributeRegistry.cpp | 69 +++++++++---------- libraries/metavoxels/src/AttributeRegistry.h | 2 + 5 files changed, 95 insertions(+), 73 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 7be3955de7..9286b9037b 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -333,12 +333,11 @@ void PointBuffer::render(bool cursor) { } HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale, - const QByteArray& height, const QByteArray& color, bool clearAfterLoading) : + const QByteArray& height, const QByteArray& color) : _translation(translation), _scale(scale), _height(height), _color(color), - _clearAfterLoading(clearAfterLoading), _heightTextureID(0), _colorTextureID(0), _heightSize(glm::sqrt(height.size())) { @@ -355,6 +354,32 @@ HeightfieldBuffer::~HeightfieldBuffer() { } } +QByteArray HeightfieldBuffer::getUnextendedHeight() const { + int srcSize = glm::sqrt(_height.size()); + int destSize = srcSize - 3; + QByteArray unextended(destSize * destSize, 0); + const char* src = _height.constData() + srcSize + 1; + char* dest = unextended.data(); + for (int z = 0; z < destSize; z++, src += srcSize, dest += destSize) { + memcpy(dest, src, destSize); + } + return unextended; +} + +QByteArray HeightfieldBuffer::getUnextendedColor() const { + int srcSize = glm::sqrt(_color.size() / HeightfieldData::COLOR_BYTES); + int destSize = srcSize - 1; + QByteArray unextended(destSize * destSize * HeightfieldData::COLOR_BYTES, 0); + const char* src = _color.constData(); + int srcStride = srcSize * HeightfieldData::COLOR_BYTES; + char* dest = unextended.data(); + int destStride = destSize * HeightfieldData::COLOR_BYTES; + for (int z = 0; z < destSize; z++, src += srcStride, dest += destStride) { + memcpy(dest, src, destStride); + } + return unextended; +} + class HeightfieldPoint { public: glm::vec2 textureCoord; @@ -372,9 +397,6 @@ void HeightfieldBuffer::render(bool cursor) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, _heightSize, _heightSize, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, _height.constData()); - if (_clearAfterLoading) { - _height.clear(); - } glGenTextures(1, &_colorTextureID); glBindTexture(GL_TEXTURE_2D, _colorTextureID); @@ -386,15 +408,12 @@ void HeightfieldBuffer::render(bool cursor) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, WHITE_COLOR); } else { - int colorSize = glm::sqrt(_color.size() / 3); + int colorSize = glm::sqrt(_color.size() / HeightfieldData::COLOR_BYTES); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, colorSize, colorSize, 0, GL_RGB, GL_UNSIGNED_BYTE, _color.constData()); - if (_clearAfterLoading) { - _color.clear(); - } } } // create the buffer objects lazily - int innerSize = _heightSize - 2; + int innerSize = _heightSize - 2 * HeightfieldBuffer::HEIGHT_BORDER; int vertexCount = _heightSize * _heightSize; int rows = _heightSize - 1; int indexCount = rows * rows * 4; @@ -682,9 +701,9 @@ int HeightfieldAugmentVisitor::visit(MetavoxelInfo& info) { if (height) { const QByteArray& heightContents = height->getContents(); int size = glm::sqrt(heightContents.size()); - int extendedSize = size + 3; + int extendedSize = size + HeightfieldBuffer::HEIGHT_EXTENSION; QByteArray extendedHeightContents(extendedSize * extendedSize, 0); - char* dest = extendedHeightContents.data() + extendedSize + 1; + char* dest = extendedHeightContents.data() + (extendedSize + 1) * HeightfieldBuffer::HEIGHT_BORDER; const char* src = heightContents.constData(); for (int z = 0; z < size; z++, src += size, dest += extendedSize) { memcpy(dest, src, size); @@ -693,14 +712,13 @@ int HeightfieldAugmentVisitor::visit(MetavoxelInfo& info) { HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue(); if (color) { const QByteArray& colorContents = color->getContents(); - const int BYTES_PER_PIXEL = 3; - int colorSize = glm::sqrt(colorContents.size() / BYTES_PER_PIXEL); - int extendedColorSize = colorSize + 1; - extendedColorContents = QByteArray(extendedColorSize * extendedColorSize * BYTES_PER_PIXEL, 0); + int colorSize = glm::sqrt(colorContents.size() / HeightfieldData::COLOR_BYTES); + int extendedColorSize = colorSize + HeightfieldBuffer::SHARED_EDGE; + extendedColorContents = QByteArray(extendedColorSize * extendedColorSize * HeightfieldData::COLOR_BYTES, 0); char* dest = extendedColorContents.data(); const char* src = colorContents.constData(); - int srcStride = colorSize * BYTES_PER_PIXEL; - int destStride = extendedColorSize * BYTES_PER_PIXEL; + int srcStride = colorSize * HeightfieldData::COLOR_BYTES; + int destStride = extendedColorSize * HeightfieldData::COLOR_BYTES; for (int z = 0; z < colorSize; z++, src += srcStride, dest += destStride) { memcpy(dest, src, srcStride); } diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 0940ea4d19..a35155dbd6 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -131,10 +131,11 @@ private: class HeightfieldBuffer : public BufferData { public: - /// Creates a new heightfield buffer. - /// \param clearAfterLoading if true, clear the data arrays after we load them into textures in order to reclaim the space - HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color, - bool clearAfterLoading = true); + static const int HEIGHT_BORDER = 1; + static const int SHARED_EDGE = 1; + static const int HEIGHT_EXTENSION = 2 * HEIGHT_BORDER + SHARED_EDGE; + + HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color); ~HeightfieldBuffer(); const glm::vec3& getTranslation() const { return _translation; } @@ -142,6 +143,9 @@ public: const QByteArray& getHeight() const { return _height; } const QByteArray& getColor() const { return _color; } + QByteArray getUnextendedHeight() const; + QByteArray getUnextendedColor() const; + virtual void render(bool cursor = false); private: @@ -150,7 +154,6 @@ private: float _scale; QByteArray _height; QByteArray _color; - bool _clearAfterLoading; GLuint _heightTextureID; GLuint _colorTextureID; int _heightSize; diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 260d3c2b3b..b7057532fb 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -956,11 +956,11 @@ void ImportHeightfieldTool::apply() { HeightfieldBuffer* buffer = static_cast(bufferData.data()); MetavoxelData data; data.setSize(scale); - HeightfieldDataPointer heightPointer(new HeightfieldData(buffer->getHeight())); + HeightfieldDataPointer heightPointer(new HeightfieldData(buffer->getUnextendedHeight())); data.setRoot(AttributeRegistry::getInstance()->getHeightfieldAttribute(), new MetavoxelNode(AttributeValue( AttributeRegistry::getInstance()->getHeightfieldAttribute(), encodeInline(heightPointer)))); if (!buffer->getColor().isEmpty()) { - HeightfieldDataPointer colorPointer(new HeightfieldData(buffer->getColor())); + HeightfieldDataPointer colorPointer(new HeightfieldData(buffer->getUnextendedColor())); data.setRoot(AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), new MetavoxelNode(AttributeValue( AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), encodeInline(colorPointer)))); } @@ -1003,38 +1003,38 @@ void ImportHeightfieldTool::updatePreview() { if (_heightImage.width() > 0 && _heightImage.height() > 0) { float z = 0.0f; int blockSize = pow(2.0, _blockSize->value()); - int heightSize = blockSize + 3; - int colorSize = blockSize + 1; + int heightSize = blockSize + HeightfieldBuffer::HEIGHT_EXTENSION; + int colorSize = blockSize + HeightfieldBuffer::SHARED_EDGE; for (int i = 0; i < _heightImage.height(); i += blockSize, z++) { float x = 0.0f; for (int j = 0; j < _heightImage.width(); j += blockSize, x++) { QByteArray height(heightSize * heightSize, 0); - int extendedI = qMax(i - 1, 0); - int extendedJ = qMax(j - 1, 0); - int offsetY = extendedI - i + 1; - int offsetX = extendedJ - j + 1; + int extendedI = qMax(i - HeightfieldBuffer::HEIGHT_BORDER, 0); + int extendedJ = qMax(j - HeightfieldBuffer::HEIGHT_BORDER, 0); + int offsetY = extendedI - i + HeightfieldBuffer::HEIGHT_BORDER; + int offsetX = extendedJ - j + HeightfieldBuffer::HEIGHT_BORDER; int rows = qMin(heightSize - offsetY, _heightImage.height() - extendedI); int columns = qMin(heightSize - offsetX, _heightImage.width() - extendedJ); - const int BYTES_PER_COLOR = 3; for (int y = 0; y < rows; y++) { - uchar* src = _heightImage.scanLine(extendedI + y) + extendedJ * BYTES_PER_COLOR; + uchar* src = _heightImage.scanLine(extendedI + y) + extendedJ * HeightfieldData::COLOR_BYTES; char* dest = height.data() + (y + offsetY) * heightSize + offsetX; for (int x = 0; x < columns; x++) { *dest++ = *src; - src += BYTES_PER_COLOR; + src += HeightfieldData::COLOR_BYTES; } } QByteArray color; if (!_colorImage.isNull()) { - color = QByteArray(colorSize * colorSize * BYTES_PER_COLOR, 0); + color = QByteArray(colorSize * colorSize * HeightfieldData::COLOR_BYTES, 0); rows = qMax(0, qMin(colorSize, _colorImage.height() - i)); columns = qMax(0, qMin(colorSize, _colorImage.width() - j)); for (int y = 0; y < rows; y++) { - memcpy(color.data() + y * colorSize * BYTES_PER_COLOR, - _colorImage.scanLine(i + y) + j * BYTES_PER_COLOR, columns * BYTES_PER_COLOR); + memcpy(color.data() + y * colorSize * HeightfieldData::COLOR_BYTES, + _colorImage.scanLine(i + y) + j * HeightfieldData::COLOR_BYTES, + columns * HeightfieldData::COLOR_BYTES); } } - buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, height, color, false))); + buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, height, color))); } } } diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 7e70d7b315..0f974b82df 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -489,9 +489,6 @@ HeightfieldData::HeightfieldData(const QByteArray& contents) : _contents(contents) { } -const int BYTES_PER_PIXEL = 3; -const int ZERO_OFFSET = 128; - HeightfieldData::HeightfieldData(Bitstream& in, int bytes, bool color) { read(in, bytes, color); } @@ -515,10 +512,10 @@ HeightfieldData::HeightfieldData(Bitstream& in, int bytes, const HeightfieldData int minX = offset.x() - 1; int minY = offset.y() - 1; if (color) { - int size = glm::sqrt(_contents.size() / (float)BYTES_PER_PIXEL); - char* dest = _contents.data() + (minY * size + minX) * BYTES_PER_PIXEL; - int destStride = size * BYTES_PER_PIXEL; - int srcStride = image.width() * BYTES_PER_PIXEL; + int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES); + char* dest = _contents.data() + (minY * size + minX) * COLOR_BYTES; + int destStride = size * COLOR_BYTES; + int srcStride = image.width() * COLOR_BYTES; for (int y = 0; y < image.height(); y++) { memcpy(dest, image.constScanLine(y), srcStride); dest += destStride; @@ -528,7 +525,7 @@ HeightfieldData::HeightfieldData(Bitstream& in, int bytes, const HeightfieldData char* lineDest = _contents.data() + minY * size + minX; for (int y = 0; y < image.height(); y++) { const uchar* src = image.constScanLine(y); - for (char* dest = lineDest, *end = dest + image.width(); dest != end; dest++, src += BYTES_PER_PIXEL) { + for (char* dest = lineDest, *end = dest + image.width(); dest != end; dest++, src += COLOR_BYTES) { *dest = *src; } lineDest += size; @@ -541,7 +538,7 @@ void HeightfieldData::write(Bitstream& out, bool color) { if (_encoded.isEmpty()) { QImage image; if (color) { - int size = glm::sqrt(_contents.size() / (float)BYTES_PER_PIXEL); + int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES); image = QImage((uchar*)_contents.data(), size, size, QImage::Format_RGB888); } else { int size = glm::sqrt((float)_contents.size()); @@ -571,7 +568,7 @@ void HeightfieldData::writeDelta(Bitstream& out, const HeightfieldDataPointer& r QImage image; int minX, minY; if (color) { - int size = glm::sqrt(_contents.size() / (float)BYTES_PER_PIXEL); + int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES); minX = size; minY = size; int maxX = -1, maxY = -1; @@ -579,7 +576,7 @@ void HeightfieldData::writeDelta(Bitstream& out, const HeightfieldDataPointer& r const char* ref = reference->_contents.constData(); for (int y = 0; y < size; y++) { bool difference = false; - for (int x = 0; x < size; x++, src += BYTES_PER_PIXEL, ref += BYTES_PER_PIXEL) { + for (int x = 0; x < size; x++, src += COLOR_BYTES, ref += COLOR_BYTES) { if (src[0] != ref[0] || src[1] != ref[1] || src[2] != ref[2]) { minX = qMin(minX, x); maxX = qMax(maxX, x); @@ -594,9 +591,9 @@ void HeightfieldData::writeDelta(Bitstream& out, const HeightfieldDataPointer& r int width = qMax(maxX - minX + 1, 0); int height = qMax(maxY - minY + 1, 0); image = QImage(width, height, QImage::Format_RGB888); - src = _contents.constData() + (minY * size + minX) * BYTES_PER_PIXEL; - int srcStride = size * BYTES_PER_PIXEL; - int destStride = width * BYTES_PER_PIXEL; + src = _contents.constData() + (minY * size + minX) * COLOR_BYTES; + int srcStride = size * COLOR_BYTES; + int destStride = width * COLOR_BYTES; for (int y = 0; y < height; y++) { memcpy(image.scanLine(y), src, destStride); src += srcStride; @@ -652,14 +649,14 @@ void HeightfieldData::read(Bitstream& in, int bytes, bool color) { void HeightfieldData::set(const QImage& image, bool color) { if (color) { - _contents.resize(image.width() * image.height() * BYTES_PER_PIXEL); + _contents.resize(image.width() * image.height() * COLOR_BYTES); memcpy(_contents.data(), image.constBits(), _contents.size()); } else { _contents.resize(image.width() * image.height()); char* dest = _contents.data(); - for (const uchar* src = image.constBits(), *end = src + _contents.size() * BYTES_PER_PIXEL; - src != end; src += BYTES_PER_PIXEL) { + for (const uchar* src = image.constBits(), *end = src + _contents.size() * COLOR_BYTES; + src != end; src += COLOR_BYTES) { *dest++ = *src; } } @@ -856,8 +853,8 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(); return true; } - int size = glm::sqrt(maxSize / (float)BYTES_PER_PIXEL); - QByteArray contents(size * size * BYTES_PER_PIXEL, 0); + int size = glm::sqrt(maxSize / (float)HeightfieldData::COLOR_BYTES); + QByteArray contents(size * size * HeightfieldData::COLOR_BYTES, 0); int halfSize = size / 2; for (int i = 0; i < MERGE_COUNT; i++) { HeightfieldDataPointer child = decodeInline(children[i]); @@ -865,7 +862,7 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post continue; } const QByteArray& childContents = child->getContents(); - int childSize = glm::sqrt(childContents.size() / (float)BYTES_PER_PIXEL); + int childSize = glm::sqrt(childContents.size() / (float)HeightfieldData::COLOR_BYTES); const int INDEX_MASK = 1; int xIndex = i & INDEX_MASK; const int Y_SHIFT = 1; @@ -875,24 +872,25 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post } int Z_SHIFT = 2; int zIndex = (i >> Z_SHIFT) & INDEX_MASK; - char* dest = contents.data() + ((zIndex * halfSize * size) + (xIndex * halfSize)) * BYTES_PER_PIXEL; + char* dest = contents.data() + ((zIndex * halfSize * size) + (xIndex * halfSize)) * HeightfieldData::COLOR_BYTES; uchar* src = (uchar*)childContents.data(); - int childStride = childSize * BYTES_PER_PIXEL; - int stride = size * BYTES_PER_PIXEL; + int childStride = childSize * HeightfieldData::COLOR_BYTES; + int stride = size * HeightfieldData::COLOR_BYTES; int halfStride = stride / 2; - int childStep = 2 * BYTES_PER_PIXEL; - int redOffset3 = childStride + BYTES_PER_PIXEL; - int greenOffset1 = BYTES_PER_PIXEL + 1; + int childStep = 2 * HeightfieldData::COLOR_BYTES; + int redOffset3 = childStride + HeightfieldData::COLOR_BYTES; + int greenOffset1 = HeightfieldData::COLOR_BYTES + 1; int greenOffset2 = childStride + 1; - int greenOffset3 = childStride + BYTES_PER_PIXEL + 1; - int blueOffset1 = BYTES_PER_PIXEL + 2; + int greenOffset3 = childStride + HeightfieldData::COLOR_BYTES + 1; + int blueOffset1 = HeightfieldData::COLOR_BYTES + 2; int blueOffset2 = childStride + 2; - int blueOffset3 = childStride + BYTES_PER_PIXEL + 2; + int blueOffset3 = childStride + HeightfieldData::COLOR_BYTES + 2; if (childSize == size) { // simple case: one destination value for four child values for (int z = 0; z < halfSize; z++) { - for (char* end = dest + halfSize * BYTES_PER_PIXEL; dest != end; src += childStep) { - *dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2; + for (char* end = dest + halfSize * HeightfieldData::COLOR_BYTES; dest != end; src += childStep) { + *dest++ = ((int)src[0] + (int)src[HeightfieldData::COLOR_BYTES] + + (int)src[childStride] + (int)src[redOffset3]) >> 2; *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2; *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2; } @@ -904,13 +902,14 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post int halfChildSize = childSize / 2; int destPerSrc = size / childSize; for (int z = 0; z < halfChildSize; z++) { - for (uchar* end = src + childSize * BYTES_PER_PIXEL; src != end; src += childStep) { - *dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2; + for (uchar* end = src + childSize * HeightfieldData::COLOR_BYTES; src != end; src += childStep) { + *dest++ = ((int)src[0] + (int)src[HeightfieldData::COLOR_BYTES] + + (int)src[childStride] + (int)src[redOffset3]) >> 2; *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2; *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2; for (int j = 1; j < destPerSrc; j++) { - memcpy(dest, dest - BYTES_PER_PIXEL, BYTES_PER_PIXEL); - dest += BYTES_PER_PIXEL; + memcpy(dest, dest - HeightfieldData::COLOR_BYTES, HeightfieldData::COLOR_BYTES); + dest += HeightfieldData::COLOR_BYTES; } } dest += halfStride; diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index d0f1cdf836..ddf6105662 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -428,6 +428,8 @@ typedef QExplicitlySharedDataPointer HeightfieldDataPointer; class HeightfieldData : public QSharedData { public: + static const int COLOR_BYTES = 3; + HeightfieldData(const QByteArray& contents); HeightfieldData(Bitstream& in, int bytes, bool color); HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& reference, bool color); From 446c88824285e045da519a4b8c4424aeb8ce4ccf Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 12 Aug 2014 12:22:32 -0700 Subject: [PATCH 334/407] AudioMixer print added; untested --- assignment-client/src/audio/AudioMixer.cpp | 11 ++++- assignment-client/src/audio/AudioMixer.h | 2 + .../src/audio/AudioMixerClientData.cpp | 45 ++++++++++++++++++- .../src/audio/AudioMixerClientData.h | 5 +++ .../resources/web/settings/describe.json | 6 +++ 5 files changed, 67 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 5900e1f151..fb1f3333a4 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -71,6 +71,8 @@ bool AudioMixer::_useDynamicJitterBuffers = false; int AudioMixer::_staticDesiredJitterBufferFrames = 0; int AudioMixer::_maxFramesOverDesired = 0; +bool AudioMixer::_printStreamStats = false; + AudioMixer::AudioMixer(const QByteArray& packet) : ThreadedAssignment(packet), _trailingSleepRatio(1.0f), @@ -448,7 +450,11 @@ void AudioMixer::run() { } qDebug() << "Max frames over desired:" << _maxFramesOverDesired; - + const QString PRINT_STREAM_STATS_JSON_KEY = "H-print-stream-stats"; + _printStreamStats = audioGroupObject[PRINT_STREAM_STATS_JSON_KEY].toBool(); + if (_printStreamStats) { + qDebug() << "Stream stats will be printed to stdout"; + } const QString UNATTENUATED_ZONE_KEY = "D-unattenuated-zone"; @@ -581,6 +587,9 @@ void AudioMixer::run() { // send an audio stream stats packet if it's time if (sendAudioStreamStats) { nodeData->sendAudioStreamStatsPackets(node); + + printf("\nStats for agent %s\n:", node->getUUID().toString().toLatin1().data()); + nodeData->printUpstreamDownstreamStats(); } ++_sumListeners; diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 83769a4209..d11539e22e 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -66,6 +66,8 @@ private: static int _staticDesiredJitterBufferFrames; static int _maxFramesOverDesired; + static bool _printStreamStats; + quint64 _lastSendAudioStreamStatsTime; }; diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index fb805e11d8..ade34e2dae 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -22,7 +22,8 @@ AudioMixerClientData::AudioMixerClientData() : _audioStreams(), - _outgoingMixedAudioSequenceNumber(0) + _outgoingMixedAudioSequenceNumber(0), + _downstreamAudioStreamStats() { } @@ -263,3 +264,45 @@ QString AudioMixerClientData::getAudioStreamStatsString() const { } return result; } + +void AudioMixerClientData::printUpstreamDownstreamStats() const { + // print the upstream (mic stream) stats if the mic stream exists + if (_audioStreams.contains(QUuid())) { + printf(" Upstream:\n"); + printAudioStreamStats(_audioStreams.value(QUuid())->getAudioStreamStats()); + } + // print the downstream stats if they contain valid info + if (_downstreamAudioStreamStats._packetStreamStats._received > 0) { + printf(" Downstream:\n"); + printAudioStreamStats(_downstreamAudioStreamStats); + } +} + +void AudioMixerClientData::printAudioStreamStats(const AudioStreamStats& streamStats) const { + printf(" Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)", + streamStats._packetStreamStats.getLostRate() * 100.0f, + streamStats._packetStreamStats._lost, + streamStats._packetStreamWindowStats.getLostRate() * 100.0f, + streamStats._packetStreamWindowStats._lost); + + printf(" Ringbuffer frames | desired: %u, avg_available(10s): %u, available: %u", + streamStats._desiredJitterBufferFrames, + streamStats._framesAvailableAverage, + streamStats._framesAvailable); + + printf(" Ringbuffer stats | starves: %u, prev_starve_lasted: %u, frames_dropped: %u, overflows: %u", + streamStats._starveCount, + streamStats._consecutiveNotMixedCount, + streamStats._framesDropped, + streamStats._overflowCount); + + printf(" Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s", + formatUsecTime(streamStats._timeGapMin).toLatin1().data(), + formatUsecTime(streamStats._timeGapMax).toLatin1().data(), + formatUsecTime(streamStats._timeGapAverage).toLatin1().data()); + + printf(" Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s", + formatUsecTime(streamStats._timeGapWindowMin).toLatin1().data(), + formatUsecTime(streamStats._timeGapWindowMax).toLatin1().data(), + formatUsecTime(streamStats._timeGapWindowAverage).toLatin1().data()); +} diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index 80f3f9e3ca..0ce4ecc36a 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -38,6 +38,11 @@ public: void incrementOutgoingMixedAudioSequenceNumber() { _outgoingMixedAudioSequenceNumber++; } quint16 getOutgoingSequenceNumber() const { return _outgoingMixedAudioSequenceNumber; } + void printUpstreamDownstreamStats() const; + +private: + void printAudioStreamStats(const AudioStreamStats& streamStats) const; + private: QHash _audioStreams; // mic stream stored under key of null UUID diff --git a/domain-server/resources/web/settings/describe.json b/domain-server/resources/web/settings/describe.json index f4920a7b50..788a3ad551 100644 --- a/domain-server/resources/web/settings/describe.json +++ b/domain-server/resources/web/settings/describe.json @@ -21,6 +21,12 @@ "placeholder": "10", "default": "10" }, + "H-print-stream-stats": { + "type": "checkbox", + "label": "Print Stream Stats:", + "help": "If enabled, audio upstream and downstream stats of each agent will be printed each second to stdout", + "default": false + }, "D-unattenuated-zone": { "label": "Unattenuated Zone", "help": "Boxes for source and listener (corner x, corner y, corner z, size x, size y, size z, corner x, corner y, corner z, size x, size y, size z)", From 0007104b6a1f11709d26b48483fb70af9f866ed9 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 12 Aug 2014 12:58:30 -0700 Subject: [PATCH 335/407] stats working --- assignment-client/src/audio/AudioMixer.cpp | 13 ++++++++++--- .../src/audio/AudioMixerClientData.cpp | 14 +++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index fb1f3333a4..914d5ae63b 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -553,6 +553,7 @@ void AudioMixer::run() { sendAudioStreamStats = true; } + bool streamStatsPrinted = false; foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { if (node->getLinkedData()) { AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData(); @@ -587,15 +588,21 @@ void AudioMixer::run() { // send an audio stream stats packet if it's time if (sendAudioStreamStats) { nodeData->sendAudioStreamStatsPackets(node); - - printf("\nStats for agent %s\n:", node->getUUID().toString().toLatin1().data()); - nodeData->printUpstreamDownstreamStats(); + + if (_printStreamStats) { + printf("\nStats for agent %s:\n", node->getUUID().toString().toLatin1().data()); + nodeData->printUpstreamDownstreamStats(); + streamStatsPrinted = true; + } } ++_sumListeners; } } } + if (streamStatsPrinted) { + printf("\n----------------------------------------------------------------\n"); + } ++_numStatFrames; diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index ade34e2dae..9a8a85c3d1 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -268,40 +268,40 @@ QString AudioMixerClientData::getAudioStreamStatsString() const { void AudioMixerClientData::printUpstreamDownstreamStats() const { // print the upstream (mic stream) stats if the mic stream exists if (_audioStreams.contains(QUuid())) { - printf(" Upstream:\n"); + printf("Upstream:\n"); printAudioStreamStats(_audioStreams.value(QUuid())->getAudioStreamStats()); } // print the downstream stats if they contain valid info if (_downstreamAudioStreamStats._packetStreamStats._received > 0) { - printf(" Downstream:\n"); + printf("Downstream:\n"); printAudioStreamStats(_downstreamAudioStreamStats); } } void AudioMixerClientData::printAudioStreamStats(const AudioStreamStats& streamStats) const { - printf(" Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)", + printf(" Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)\n", streamStats._packetStreamStats.getLostRate() * 100.0f, streamStats._packetStreamStats._lost, streamStats._packetStreamWindowStats.getLostRate() * 100.0f, streamStats._packetStreamWindowStats._lost); - printf(" Ringbuffer frames | desired: %u, avg_available(10s): %u, available: %u", + printf(" Ringbuffer frames | desired: %u, avg_available(10s): %u, available: %u\n", streamStats._desiredJitterBufferFrames, streamStats._framesAvailableAverage, streamStats._framesAvailable); - printf(" Ringbuffer stats | starves: %u, prev_starve_lasted: %u, frames_dropped: %u, overflows: %u", + printf(" Ringbuffer stats | starves: %u, prev_starve_lasted: %u, frames_dropped: %u, overflows: %u\n", streamStats._starveCount, streamStats._consecutiveNotMixedCount, streamStats._framesDropped, streamStats._overflowCount); - printf(" Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s", + printf(" Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s\n", formatUsecTime(streamStats._timeGapMin).toLatin1().data(), formatUsecTime(streamStats._timeGapMax).toLatin1().data(), formatUsecTime(streamStats._timeGapAverage).toLatin1().data()); - printf(" Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s", + printf(" Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s\n", formatUsecTime(streamStats._timeGapWindowMin).toLatin1().data(), formatUsecTime(streamStats._timeGapWindowMax).toLatin1().data(), formatUsecTime(streamStats._timeGapWindowAverage).toLatin1().data()); From 406be72f41a61a0ebf436d481fd8899eaf154cf3 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 12 Aug 2014 13:46:55 -0700 Subject: [PATCH 336/407] per-report stats added to jitter tests --- tests/jitter/src/main.cpp | 46 +++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index aefed73ccf..c4e6472439 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -74,6 +74,12 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n"; MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats + + const int SAMPLES_PER_REPORT = report * MSEC_TO_USEC / gap; + + std::cout << "SAMPLES_PER_REPORT:" << SAMPLES_PER_REPORT << "\n"; + + MovingMinMaxAvg timeGapsPerReport(1, SAMPLES_PER_REPORT); quint64 last = usecTimestampNow(); quint64 lastReport = 0; @@ -89,16 +95,24 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) int gapDifferece = actualGap - gap; timeGaps.update(gapDifferece); + timeGapsPerReport.update(gapDifferece); last = now; if (now - lastReport >= (report * MSEC_TO_USEC)) { - std::cout << "SEND gap Difference From Expected " + std::cout << "\n" + << "SEND gap Difference From Expected\n" + << "Overall:\n" << "min: " << timeGaps.getMin() << " usecs, " << "max: " << timeGaps.getMax() << " usecs, " - << "avg: " << timeGaps.getAverage() << " usecs, " - << "min last 30: " << timeGaps.getWindowMin() << " usecs, " - << "max last 30: " << timeGaps.getWindowMax() << " usecs, " - << "avg last 30: " << timeGaps.getWindowAverage() << " usecs " + << "avg: " << timeGaps.getAverage() << " usecs\n" + << "Last 30s:\n" + << "min: " << timeGaps.getWindowMin() << " usecs, " + << "max: " << timeGaps.getWindowMax() << " usecs, " + << "avg: " << timeGaps.getWindowAverage() << " usecs\n" + << "Last report interval:\n" + << "min: " << timeGapsPerReport.getWindowMin() << " usecs, " + << "max: " << timeGapsPerReport.getWindowMax() << " usecs, " + << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs\n" << "\n"; lastReport = now; } @@ -129,6 +143,12 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats + const int SAMPLES_PER_REPORT = report * MSEC_TO_USEC / gap; + + std::cout << "SAMPLES_PER_REPORT:" << SAMPLES_PER_REPORT << "\n"; + + MovingMinMaxAvg timeGapsPerReport(1, SAMPLES_PER_REPORT); + if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { std::cout << "bind failed\n"; return; @@ -148,17 +168,25 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo int actualGap = now - last; int gapDifferece = actualGap - gap; timeGaps.update(gapDifferece); + timeGapsPerReport.update(gapDifferece); last = now; if (now - lastReport >= (report * MSEC_TO_USEC)) { std::cout << "RECEIVE gap Difference From Expected " + << "Overall:\n" << "min: " << timeGaps.getMin() << " usecs, " << "max: " << timeGaps.getMax() << " usecs, " - << "avg: " << timeGaps.getAverage() << " usecs, " - << "min last 30: " << timeGaps.getWindowMin() << " usecs, " - << "max last 30: " << timeGaps.getWindowMax() << " usecs, " - << "avg last 30: " << timeGaps.getWindowAverage() << " usecs " + << "avg: " << timeGaps.getAverage() << " usecs\n" + << "Last 30s:\n" + << "min: " << timeGaps.getWindowMin() << " usecs, " + << "max: " << timeGaps.getWindowMax() << " usecs, " + << "avg: " << timeGaps.getWindowAverage() << " usecs\n" + << "Last report interval:\n" + << "min: " << timeGapsPerReport.getWindowMin() << " usecs, " + << "max: " << timeGapsPerReport.getWindowMax() << " usecs, " + << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs\n" << "\n"; + lastReport = now; } } From 75aedae300a5e445837c0c5aec7edb618042083a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Aug 2014 14:12:13 -0700 Subject: [PATCH 337/407] integration of positional tracking with DK2 --- cmake/modules/FindLibOVR.cmake | 4 +-- interface/src/avatar/MyAvatar.cpp | 6 ++++ interface/src/devices/OculusManager.cpp | 39 ++++++++++++++++++++----- interface/src/devices/OculusManager.h | 1 + 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/cmake/modules/FindLibOVR.cmake b/cmake/modules/FindLibOVR.cmake index 505fd90b51..5fbe01d06b 100644 --- a/cmake/modules/FindLibOVR.cmake +++ b/cmake/modules/FindLibOVR.cmake @@ -27,8 +27,8 @@ find_path(LIBOVR_SRC_DIR Util_Render_Stereo.h PATH_SUFFIXES Src/Util HINTS ${OCU include(SelectLibraryConfigurations) if (APPLE) - find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/MacOS/Debug HINTS ${OCULUS_SEARCH_DIRS}) - find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/MacOS/Release HINTS ${OCULUS_SEARCH_DIRS}) + find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/Mac/Debug HINTS ${OCULUS_SEARCH_DIRS}) + find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/Mac/Release HINTS ${OCULUS_SEARCH_DIRS}) find_library(ApplicationServices ApplicationServices) find_library(IOKit IOKit) elseif (UNIX) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f59064732c..08d33ff252 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -255,6 +255,12 @@ void MyAvatar::updateFromTrackers(float deltaTime) { estimatedRotation.x *= -1.0f; estimatedRotation.z *= -1.0f; + } else if (OculusManager::isConnected()) { + estimatedPosition = OculusManager::getRelativePosition(); + estimatedPosition.x *= -1.0f; + + const float OCULUS_LEAN_SCALE = 0.05f; + estimatedPosition /= OCULUS_LEAN_SCALE; } else { FaceTracker* tracker = Application::getInstance()->getActiveFaceTracker(); if (tracker) { diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 96df5b6c7c..6ce77e3ca2 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -314,7 +314,16 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p glPushMatrix(); glm::quat orientation; - + glm::vec3 trackerPosition; + +#if defined(__APPLE__) || defined(_WIN32) + ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); + ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position; + + trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z); + trackerPosition = bodyOrientation * trackerPosition; +#endif + //Render each eye into an fbo for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) { #if defined(__APPLE__) || defined(_WIN32) @@ -330,7 +339,8 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p orientation.w = eyeRenderPose[eye].Orientation.w; _camera->setTargetRotation(bodyOrientation * orientation); - _camera->setTargetPosition(position); + _camera->setTargetPosition(position + trackerPosition); + _camera->update(1.0f / Application::getInstance()->getFps()); Matrix4f proj = ovrMatrix4f_Projection(_eyeRenderDesc[eye].Fov, whichCamera.getNearClip(), whichCamera.getFarClip(), true); @@ -450,8 +460,9 @@ void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) { //Tries to reconnect to the sensors void OculusManager::reset() { #ifdef HAVE_LIBOVR - disconnect(); - connect(); + if (_isConnected) { + ovrHmd_RecenterPose(_ovrHmd); + } #endif } @@ -463,18 +474,18 @@ void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { #else ovrSensorState ss = ovrHmd_GetSensorState(_ovrHmd, _hmdFrameTiming.ScanoutMidpointSeconds); #endif -#if defined(__APPLE__) || defined(_WIN32) +#if defined(__APPLE__) || defined(_WIN32) if (ts.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { #else if (ss.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { #endif #if defined(__APPLE__) || defined(_WIN32) - ovrPosef pose = ts.CameraPose; + ovrPosef headPose = ts.HeadPose.ThePose; #else - ovrPosef pose = ss.Predicted.Pose; + ovrPosef headPose = ss.Predicted.Pose; #endif - Quatf orientation = Quatf(pose.Orientation); + Quatf orientation = Quatf(headPose.Orientation); orientation.GetEulerAngles(&yaw, &pitch, &roll); } else { yaw = 0.0f; @@ -487,6 +498,18 @@ void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { roll = 0.0f; #endif } + +glm::vec3 OculusManager::getRelativePosition() { +#if defined(__APPLE__) || defined(_WIN32) + ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); + ovrVector3f headPosition = trackingState.HeadPose.ThePose.Position; + + return glm::vec3(headPosition.x, headPosition.y, headPosition.z); +#else + // no positional tracking in Linux yet + return glm::vec3(0.0f, 0.0f, 0.0f); +#endif +} //Used to set the size of the glow framebuffers QSize OculusManager::getRenderTargetSize() { diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index 8c929bb50a..3959ea1ab7 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -40,6 +40,7 @@ public: /// param \pitch[out] pitch in radians /// param \roll[out] roll in radians static void getEulerAngles(float& yaw, float& pitch, float& roll); + static glm::vec3 getRelativePosition(); static QSize getRenderTargetSize(); private: From a68af15b8271af84e51add5714c6da683143f686 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 12 Aug 2014 14:26:14 -0700 Subject: [PATCH 338/407] DDE Face tracker tweaks to start adding long term averaging --- interface/src/devices/DdeFaceTracker.cpp | 47 +++++++++++++++++++++--- interface/src/devices/DdeFaceTracker.h | 4 ++ 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 3dc5a818cc..ae5beb8c85 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -178,6 +178,31 @@ float rescaleCoef(float ddeCoef) { return (ddeCoef - DDE_MIN_RANGE) / (DDE_MAX_RANGE - DDE_MIN_RANGE); } +const int MIN = 0; +const int AVG = 1; +const int MAX = 2; +const float LONG_TERM_AVERAGE = 0.999f; + + +void resetCoefficient(float * coefficient, float currentValue) { + coefficient[MIN] = coefficient[MAX] = coefficient[AVG] = currentValue; +} + +float updateAndGetCoefficient(float * coefficient, float currentValue, bool scaleToRange = false) { + coefficient[MIN] = (currentValue < coefficient[MIN]) ? currentValue : coefficient[MIN]; + coefficient[MAX] = (currentValue > coefficient[MAX]) ? currentValue : coefficient[MAX]; + coefficient[AVG] = LONG_TERM_AVERAGE * coefficient[AVG] + (1.f - LONG_TERM_AVERAGE) * currentValue; + if (coefficient[MAX] > coefficient[MIN]) { + if (scaleToRange) { + return glm::clamp((currentValue - coefficient[AVG]) / (coefficient[MAX] - coefficient[MIN]), 0.f, 1.f); + } else { + return glm::clamp(currentValue - coefficient[AVG], 0.f, 1.f); + } + } else { + return 0.f; + } +} + void DdeFaceTracker::decodePacket(const QByteArray& buffer) { if(buffer.size() > MIN_PACKET_SIZE) { Packet packet; @@ -189,14 +214,17 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { memcpy(&translation, packet.translation, sizeof(packet.translation)); glm::quat rotation; memcpy(&rotation, &packet.rotation, sizeof(packet.rotation)); - if (_reset) { + if (_reset || (_lastReceiveTimestamp == 0)) { memcpy(&_referenceTranslation, &translation, sizeof(glm::vec3)); memcpy(&_referenceRotation, &rotation, sizeof(glm::quat)); + + resetCoefficient(_rightEye, packet.expressions[0]); + resetCoefficient(_leftEye, packet.expressions[1]); _reset = false; } // Compute relative translation - float LEAN_DAMPING_FACTOR = 40; + float LEAN_DAMPING_FACTOR = 200.0f; translation -= _referenceTranslation; translation /= LEAN_DAMPING_FACTOR; translation.x *= -1; @@ -208,10 +236,19 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { _headTranslation = translation; _headRotation = rotation; + if (_lastReceiveTimestamp == 0) { + // On first packet, reset coefficients + } + // Set blendshapes - float BLINK_MAGNIFIER = 2.0f; - _blendshapeCoefficients[_leftBlinkIndex] = rescaleCoef(packet.expressions[1]) * BLINK_MAGNIFIER; - _blendshapeCoefficients[_rightBlinkIndex] = rescaleCoef(packet.expressions[0]) * BLINK_MAGNIFIER; + float EYE_MAGNIFIER = 4.0f; + + float rightEye = (updateAndGetCoefficient(_rightEye, packet.expressions[0])) * EYE_MAGNIFIER; + _blendshapeCoefficients[_rightBlinkIndex] = rightEye; + float leftEye = (updateAndGetCoefficient(_leftEye, packet.expressions[1])) * EYE_MAGNIFIER; + _blendshapeCoefficients[_leftBlinkIndex] = leftEye; + + // Right eye = packet.expressions[0]; float leftBrow = 1.0f - rescaleCoef(packet.expressions[14]); if (leftBrow < 0.5f) { diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 96707ac94c..68d9e7d487 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -84,6 +84,10 @@ private: int _mouthSmileRightIndex; int _jawOpenIndex; + + float _leftEye[3]; + float _rightEye[3]; + }; #endif // hifi_DdeFaceTracker_h \ No newline at end of file From 9933c011d7e6a6d48dd5352d8ce84233f4a7081d Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 12 Aug 2014 14:31:40 -0700 Subject: [PATCH 339/407] Remove filtered eye position from head --- interface/src/Application.cpp | 4 ++-- interface/src/avatar/Head.cpp | 3 --- interface/src/avatar/Head.h | 2 -- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6f7212e68f..3007943643 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -599,7 +599,7 @@ void Application::paintGL() { if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { _myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay - _myCamera.setTargetPosition(_myAvatar->getHead()->getFilteredEyePosition()); + _myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition()); _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation()); } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { @@ -621,7 +621,7 @@ void Application::paintGL() { _myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition() + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0)); } else { _myCamera.setTightness(0.0f); - glm::vec3 eyePosition = _myAvatar->getHead()->getFilteredEyePosition(); + glm::vec3 eyePosition = _myAvatar->getHead()->getEyePosition(); float headHeight = eyePosition.y - _myAvatar->getPosition().y; _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight + (_raiseMirror * _myAvatar->getScale()), 0)); diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 995f3f2390..b0333b1acf 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -163,9 +163,6 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { } _eyePosition = calculateAverageEyePosition(); - float velocityFilter = glm::clamp(1.0f - glm::length(_filteredEyePosition - _eyePosition), 0.0f, 1.0f); - _filteredEyePosition = velocityFilter * _filteredEyePosition + (1.0f - velocityFilter) * _eyePosition; - } void Head::relaxLean(float deltaTime) { diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 6d1e82b97f..1de5ea7dd1 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -88,7 +88,6 @@ public: const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected) float getAverageLoudness() const { return _averageLoudness; } - glm::vec3 getFilteredEyePosition() const { return _filteredEyePosition; } /// \return the point about which scaling occurs. glm::vec3 getScalePivot() const; @@ -121,7 +120,6 @@ private: glm::vec3 _leftEyePosition; glm::vec3 _rightEyePosition; glm::vec3 _eyePosition; - glm::vec3 _filteredEyePosition; // velocity filtered world space eye position float _scale; float _lastLoudness; From 184e4b8bde60ffe05a115959c5a3fa5a8f3cb411 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 12 Aug 2014 14:38:28 -0700 Subject: [PATCH 340/407] sestets added to jitter tester --- .../networking/src/SequenceNumberStats.cpp | 25 +++++++------ .../networking/src/SequenceNumberStats.h | 13 +++++++ tests/jitter/src/main.cpp | 36 +++++++++++++++++++ 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/libraries/networking/src/SequenceNumberStats.cpp b/libraries/networking/src/SequenceNumberStats.cpp index 6a7f5e1964..f472159164 100644 --- a/libraries/networking/src/SequenceNumberStats.cpp +++ b/libraries/networking/src/SequenceNumberStats.cpp @@ -253,14 +253,19 @@ PacketStreamStats SequenceNumberStats::getStatsForHistoryWindow() const { } // calculate difference between newest stats and oldest stats to get window stats - PacketStreamStats windowStats; - windowStats._received = newestStats->_received - oldestStats->_received; - windowStats._unreasonable = newestStats->_unreasonable - oldestStats->_unreasonable; - windowStats._early = newestStats->_early - oldestStats->_early; - windowStats._late = newestStats->_late - oldestStats->_late; - windowStats._lost = newestStats->_lost - oldestStats->_lost; - windowStats._recovered = newestStats->_recovered - oldestStats->_recovered; - windowStats._expectedReceived = newestStats->_expectedReceived - oldestStats->_expectedReceived; - - return windowStats; + return *newestStats - *oldestStats; } + +PacketStreamStats SequenceNumberStats::getStatsForLastHistoryInterval() const { + + const PacketStreamStats* newestStats = _statsHistory.getNewestEntry(); + const PacketStreamStats* secondNewestStats = _statsHistory.get(1); + + // this catches cases where history is length 1 or 0 (both are NULL in case of 0) + if (newestStats == NULL || secondNewestStats == NULL) { + return PacketStreamStats(); + } + + return *newestStats - *secondNewestStats; +} + diff --git a/libraries/networking/src/SequenceNumberStats.h b/libraries/networking/src/SequenceNumberStats.h index 5e02dbc850..434d5a18db 100644 --- a/libraries/networking/src/SequenceNumberStats.h +++ b/libraries/networking/src/SequenceNumberStats.h @@ -31,6 +31,18 @@ public: _expectedReceived(0) {} + PacketStreamStats operator-(const PacketStreamStats& rhs) const { + PacketStreamStats diff; + diff._received = _received - rhs._received; + diff._unreasonable = _unreasonable - rhs._unreasonable; + diff._early = _early - rhs._early; + diff._late = _late - rhs._late; + diff._lost = _lost - rhs._lost; + diff._recovered = _recovered - rhs._recovered; + diff._expectedReceived = _expectedReceived - rhs._expectedReceived; + return diff; + } + float getLostRate() const { return (float)_lost / _expectedReceived; } quint32 _received; @@ -76,6 +88,7 @@ public: const PacketStreamStats& getStats() const { return _stats; } PacketStreamStats getStatsForHistoryWindow() const; + PacketStreamStats getStatsForLastHistoryInterval() const; const QSet& getMissingSet() const { return _missingSet; } private: diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index c4e6472439..bb6d902e86 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -16,6 +16,7 @@ #include #include // for MovingMinMaxAvg +#include #include // for usecTimestampNow const quint64 MSEC_TO_USEC = 1000; @@ -61,6 +62,8 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) char* outputBuffer = new char[size]; memset(outputBuffer, 0, size); + + quint16 outgoingSequenceNumber = 0; sockfd=socket(AF_INET,SOCK_DGRAM,0); @@ -91,7 +94,12 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) if (actualGap >= gap) { + + // pack seq num + memcpy(outputBuffer, &outgoingSequenceNumber, sizeof(quint16)); + sendto(sockfd, outputBuffer, size, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); + outgoingSequenceNumber++; int gapDifferece = actualGap - gap; timeGaps.update(gapDifferece); @@ -148,6 +156,12 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo std::cout << "SAMPLES_PER_REPORT:" << SAMPLES_PER_REPORT << "\n"; MovingMinMaxAvg timeGapsPerReport(1, SAMPLES_PER_REPORT); + + const int REPORTS_FOR_30_SECONDS = 30 * MSECS_PER_SECOND / report; + + std::cout << "REPORTS_FOR_30_SECONDS:" << REPORTS_FOR_30_SECONDS << "\n"; + + SequenceNumberStats seqStats(REPORTS_FOR_30_SECONDS); if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { std::cout << "bind failed\n"; @@ -159,6 +173,10 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo while (true) { n = recvfrom(sockfd, inputBuffer, size, 0, NULL, NULL); // we don't care about where it came from + + // parse seq num + quint16 incomingSequenceNumber = *(reinterpret_cast(inputBuffer)); + seqStats.sequenceNumberReceived(incomingSequenceNumber); if (last == 0) { last = usecTimestampNow(); @@ -172,6 +190,9 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo last = now; if (now - lastReport >= (report * MSEC_TO_USEC)) { + + seqStats.pushStatsToHistory(); + std::cout << "RECEIVE gap Difference From Expected " << "Overall:\n" << "min: " << timeGaps.getMin() << " usecs, " @@ -187,6 +208,21 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs\n" << "\n"; + PacketStreamStats packetStatsLast30s = seqStats.getStatsForHistoryWindow(); + PacketStreamStats packetStatsLastReportInterval = seqStats.getStatsForLastHistoryInterval(); + + std::cout << "RECEIVE Packet Stats " + << "Overall:\n" + << "lost: " << seqStats.getLost() << ", " + << "lost %: " << seqStats.getStats().getLostRate() * 100.0f << "%\n" + << "Last 30s:\n" + << "lost: " << packetStatsLast30s._lost << ", " + << "lost %: " << packetStatsLast30s.getLostRate() * 100.0f << "%\n" + << "Last report interval:\n" + << "lost: " << packetStatsLastReportInterval._lost << ", " + << "lost %: " << packetStatsLastReportInterval.getLostRate() * 100.0f << "%\n" + << "\n\n"; + lastReport = now; } } From 00087e81d86a4e6d450fd05b1d4ee18d288d05d9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Aug 2014 14:44:49 -0700 Subject: [PATCH 341/407] remove a line of debug that shouldn't have made its way in --- interface/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 1d91723f4d..fefdcb0ab5 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -8,7 +8,6 @@ foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR) string(TOLOWER ${EXTERNAL} ${EXTERNAL}_LOWERCASE) set(${${EXTERNAL}_UPPERCASE}_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/${${EXTERNAL}_LOWERCASE}") - message("Dir for ${EXTERNAL} is ${${${EXTERNAL}_UPPERCASE}_ROOT_DIR}") endif () endforeach() From ac4d20bb431009726fc98ea12edd51069b204bec Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Aug 2014 14:49:30 -0700 Subject: [PATCH 342/407] repairs to FindLibOVR for OS X new structure --- cmake/modules/FindLibOVR.cmake | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/cmake/modules/FindLibOVR.cmake b/cmake/modules/FindLibOVR.cmake index 6c5556fb85..9c703f9cfe 100644 --- a/cmake/modules/FindLibOVR.cmake +++ b/cmake/modules/FindLibOVR.cmake @@ -27,8 +27,8 @@ find_path(LIBOVR_SRC_DIR Util_Render_Stereo.h PATH_SUFFIXES Src/Util HINTS ${LIB include(SelectLibraryConfigurations) if (APPLE) - find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/Mac/Debug HINTS ${OCULUS_SEARCH_DIRS}) - find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/Mac/Release HINTS ${OCULUS_SEARCH_DIRS}) + find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/Mac/Debug HINTS ${LIBOVR_SEARCH_DIRS}) + find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/Mac/Release HINTS ${LIBOVR_SEARCH_DIRS}) find_library(ApplicationServices ApplicationServices) find_library(IOKit IOKit) elseif (UNIX) @@ -53,21 +53,20 @@ elseif (WIN32) endif () select_library_configurations(LIBOVR) -set(LIBOVR_LIBRARIES "${LIBOVR_LIBRARY}") +set(LIBOVR_LIBRARIES ${LIBOVR_LIBRARY}) + +list(APPEND LIBOVR_ARGS_LIST LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARY) if (APPLE) - set(LIBOVR_LIBRARIES "${LIBOVR_LIBRARIES}" ${IOKit} ${ApplicationServices}) + list(APPEND LIBOVR_LIBRARIES ${IOKit} ${ApplicationServices}) + list(APPEND LIBOVR_ARGS_LIST IOKit ApplicationServices) elseif (UNIX) - set(LIBOVR_LIBRARIES "${LIBOVR_LIBRARIES}" "${UDEV_LIBRARY}" "${XINERAMA_LIBRARY}") + list(APPEND LIBOVR_LIBRARIES "${UDEV_LIBRARY}" "${XINERAMA_LIBRARY}") + list(APPEND LIBOVR_ARGS_LIST UDEV_LIBRARY XINERAMA_LIBRARY) endif () include(FindPackageHandleStandardArgs) -if (APPLE) - find_package_handle_standard_args(LibOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES IOKit ApplicationServices) -elseif (UNIX) - find_package_handle_standard_args(LibOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES UDEV_LIBRARY XINERAMA_LIBRARY) -else () - find_package_handle_standard_args(LibOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES) -endif () -mark_as_advanced(LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES OCULUS_SEARCH_DIRS) +find_package_handle_standard_args(LibOVR DEFAULT_MSG ${LIBOVR_ARGS_LIST}) + +mark_as_advanced(LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES LIBOVR_SEARCH_DIRS) From 4bf7bbe0df8d2f5a8fb0ae34ede916dcf9e3ac63 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Aug 2014 15:20:04 -0700 Subject: [PATCH 343/407] if enable VR mode is re-checked then attempt to re-connect to Oculus --- interface/src/Application.cpp | 9 +++++++++ interface/src/devices/OculusManager.cpp | 4 ++++ interface/src/devices/SixenseManager.cpp | 4 +++- interface/src/devices/SixenseManager.h | 2 +- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3007943643..9d49dc6281 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1440,6 +1440,15 @@ void Application::setEnable3DTVMode(bool enable3DTVMode) { } void Application::setEnableVRMode(bool enableVRMode) { + if (enableVRMode) { + if (!OculusManager::isConnected()) { + // attempt to reconnect the Oculus manager - it's possible this was a workaround + // for the sixense crash + OculusManager::disconnect(); + OculusManager::connect(); + } + } + resizeGL(_glWidget->width(), _glWidget->height()); } diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 6ce77e3ca2..7d7375fad5 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -135,6 +135,10 @@ void OculusManager::connect() { } else { _isConnected = false; + + // we're definitely not in "VR mode" so tell the menu that + Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false); + ovrHmd_Destroy(_ovrHmd); ovr_Shutdown(); } diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 089d478198..803060e5d3 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -19,6 +19,7 @@ #include "UserActivityLogger.h" #ifdef HAVE_SIXENSE + const int CALIBRATION_STATE_IDLE = 0; const int CALIBRATION_STATE_X = 1; const int CALIBRATION_STATE_Y = 2; @@ -41,8 +42,9 @@ SixenseManager::SixenseManager() { // By default we assume the _neckBase (in orb frame) is as high above the orb // as the "torso" is below it. _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z); - + sixenseInit(); + #endif _hydrasConnected = false; _triggerPressed[0] = false; diff --git a/interface/src/devices/SixenseManager.h b/interface/src/devices/SixenseManager.h index 91f9e9884f..664c102f76 100644 --- a/interface/src/devices/SixenseManager.h +++ b/interface/src/devices/SixenseManager.h @@ -71,7 +71,7 @@ private: glm::vec3 _reachUp; glm::vec3 _reachForward; float _lastDistance; - + #endif bool _hydrasConnected; quint64 _lastMovement; From 4dce4c49194103935c0c550be045f27672d821e7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Aug 2014 15:23:12 -0700 Subject: [PATCH 344/407] link to ws2_32.lib if LibOVR is being linked to --- cmake/modules/FindLibOVR.cmake | 2 ++ interface/CMakeLists.txt | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cmake/modules/FindLibOVR.cmake b/cmake/modules/FindLibOVR.cmake index 9c703f9cfe..62ac572f2f 100644 --- a/cmake/modules/FindLibOVR.cmake +++ b/cmake/modules/FindLibOVR.cmake @@ -63,6 +63,8 @@ if (APPLE) elseif (UNIX) list(APPEND LIBOVR_LIBRARIES "${UDEV_LIBRARY}" "${XINERAMA_LIBRARY}") list(APPEND LIBOVR_ARGS_LIST UDEV_LIBRARY XINERAMA_LIBRARY) +elseif (WIN32) + list(APPEND LIBOVR_LIBRARIES ws2_32.lib) endif () include(FindPackageHandleStandardArgs) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index fefdcb0ab5..32070a4427 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -201,9 +201,6 @@ else (APPLE) add_definitions(-DGLEW_STATIC) target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" wsock32.lib opengl32.lib) - if (LIBOVR_FOUND) - target_link_libraries(${TARGET_NAME} ws2_32.lib) - endif() endif() endif (APPLE) From dc46d6b80fd1c9e544ae99ffd563dff5354fba47 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 12 Aug 2014 15:27:17 -0700 Subject: [PATCH 345/407] added stdev to jitter tester --- tests/jitter/src/main.cpp | 40 +++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index bb6d902e86..158860c627 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -17,6 +17,7 @@ #include // for MovingMinMaxAvg #include +#include #include // for usecTimestampNow const quint64 MSEC_TO_USEC = 1000; @@ -83,6 +84,10 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) std::cout << "SAMPLES_PER_REPORT:" << SAMPLES_PER_REPORT << "\n"; MovingMinMaxAvg timeGapsPerReport(1, SAMPLES_PER_REPORT); + + StDev stDevReportInterval; + StDev stDev30s; + StDev stDev; quint64 last = usecTimestampNow(); quint64 lastReport = 0; @@ -104,24 +109,35 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) int gapDifferece = actualGap - gap; timeGaps.update(gapDifferece); timeGapsPerReport.update(gapDifferece); + stDev.addValue(gapDifferece); last = now; if (now - lastReport >= (report * MSEC_TO_USEC)) { + std::cout << "\n" << "SEND gap Difference From Expected\n" << "Overall:\n" << "min: " << timeGaps.getMin() << " usecs, " << "max: " << timeGaps.getMax() << " usecs, " - << "avg: " << timeGaps.getAverage() << " usecs\n" + << "avg: " << timeGaps.getAverage() << " usecs, " + << "stdev: " << stDev.getStDev() << " usecs\n" << "Last 30s:\n" << "min: " << timeGaps.getWindowMin() << " usecs, " << "max: " << timeGaps.getWindowMax() << " usecs, " - << "avg: " << timeGaps.getWindowAverage() << " usecs\n" + << "avg: " << timeGaps.getWindowAverage() << " usecs, " + << "stdev: " << stDev30s.getStDev() << " usecs\n" << "Last report interval:\n" << "min: " << timeGapsPerReport.getWindowMin() << " usecs, " << "max: " << timeGapsPerReport.getWindowMax() << " usecs, " - << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs\n" + << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs, " + << "stdev: " << stDevReportInterval.getStDev() << " usecs\n" << "\n"; + + stDevReportInterval.reset(); + if (stDev30s.getSamples() > SAMPLES_FOR_30_SECONDS) { + stDev30s.reset(); + } + lastReport = now; } } @@ -162,6 +178,10 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo std::cout << "REPORTS_FOR_30_SECONDS:" << REPORTS_FOR_30_SECONDS << "\n"; SequenceNumberStats seqStats(REPORTS_FOR_30_SECONDS); + + StDev stDevReportInterval; + StDev stDev30s; + StDev stDev; if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { std::cout << "bind failed\n"; @@ -197,17 +217,25 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo << "Overall:\n" << "min: " << timeGaps.getMin() << " usecs, " << "max: " << timeGaps.getMax() << " usecs, " - << "avg: " << timeGaps.getAverage() << " usecs\n" + << "avg: " << timeGaps.getAverage() << " usecs, " + << "stdev: " << stDev.getStDev() << " usecs\n" << "Last 30s:\n" << "min: " << timeGaps.getWindowMin() << " usecs, " << "max: " << timeGaps.getWindowMax() << " usecs, " - << "avg: " << timeGaps.getWindowAverage() << " usecs\n" + << "avg: " << timeGaps.getWindowAverage() << " usecs, " + << "stdev: " << stDev30s.getStDev() << " usecs\n" << "Last report interval:\n" << "min: " << timeGapsPerReport.getWindowMin() << " usecs, " << "max: " << timeGapsPerReport.getWindowMax() << " usecs, " - << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs\n" + << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs, " + << "stdev: " << stDevReportInterval.getStDev() << " usecs\n" << "\n"; + stDevReportInterval.reset(); + if (stDev30s.getSamples() > SAMPLES_FOR_30_SECONDS) { + stDev30s.reset(); + } + PacketStreamStats packetStatsLast30s = seqStats.getStatsForHistoryWindow(); PacketStreamStats packetStatsLastReportInterval = seqStats.getStatsForLastHistoryInterval(); From d43c39fd574447b95ed8d6cf8c368af63a21d380 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 12 Aug 2014 15:28:36 -0700 Subject: [PATCH 346/407] forgot a line --- tests/jitter/src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index 158860c627..79c157c298 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -207,6 +207,7 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo int gapDifferece = actualGap - gap; timeGaps.update(gapDifferece); timeGapsPerReport.update(gapDifferece); + stDev.addValue(gapDifferece); last = now; if (now - lastReport >= (report * MSEC_TO_USEC)) { From 53d6cdd67cadbaf10cf54e0079368273f9685d43 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 12 Aug 2014 15:36:51 -0700 Subject: [PATCH 347/407] forgot more lines --- tests/jitter/src/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index 79c157c298..5ece1b8e86 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -110,6 +110,8 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) timeGaps.update(gapDifferece); timeGapsPerReport.update(gapDifferece); stDev.addValue(gapDifferece); + stDev30s.addValue(gapDifferece); + stDevReportInterval.addValue(gapDifferece); last = now; if (now - lastReport >= (report * MSEC_TO_USEC)) { @@ -208,6 +210,8 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo timeGaps.update(gapDifferece); timeGapsPerReport.update(gapDifferece); stDev.addValue(gapDifferece); + stDev30s.addValue(gapDifferece); + stDevReportInterval.addValue(gapDifferece); last = now; if (now - lastReport >= (report * MSEC_TO_USEC)) { From 3c73fd5e0b86f58b002c134f41d50eb3a2e24428 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 12 Aug 2014 15:39:03 -0700 Subject: [PATCH 348/407] forgot newline --- tests/jitter/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index 5ece1b8e86..8b8d0a00fc 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -218,7 +218,7 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo seqStats.pushStatsToHistory(); - std::cout << "RECEIVE gap Difference From Expected " + std::cout << "RECEIVE gap Difference From Expected\n" << "Overall:\n" << "min: " << timeGaps.getMin() << " usecs, " << "max: " << timeGaps.getMax() << " usecs, " From 737228e7bb9feb1d4d7d069d9185173d186d3b62 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 12 Aug 2014 15:40:58 -0700 Subject: [PATCH 349/407] another newline --- tests/jitter/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index 8b8d0a00fc..a33347f9ef 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -244,7 +244,7 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo PacketStreamStats packetStatsLast30s = seqStats.getStatsForHistoryWindow(); PacketStreamStats packetStatsLastReportInterval = seqStats.getStatsForLastHistoryInterval(); - std::cout << "RECEIVE Packet Stats " + std::cout << "RECEIVE Packet Stats\n" << "Overall:\n" << "lost: " << seqStats.getLost() << ", " << "lost %: " << seqStats.getStats().getLostRate() * 100.0f << "%\n" From 18ff49744368e23cb743137cf282d2123a61880b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 12 Aug 2014 16:11:53 -0700 Subject: [PATCH 350/407] Added all relevant curves to RecordingFrames --- interface/src/Recorder.cpp | 208 ++++++++++++++++++++++++++++++++++--- interface/src/Recorder.h | 56 +++++++++- 2 files changed, 248 insertions(+), 16 deletions(-) diff --git a/interface/src/Recorder.cpp b/interface/src/Recorder.cpp index 87352fed98..c15e17597e 100644 --- a/interface/src/Recorder.cpp +++ b/interface/src/Recorder.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "Recorder.h" void RecordingFrame::setBlendshapeCoefficients(QVector blendshapeCoefficients) { @@ -23,6 +25,34 @@ void RecordingFrame::setTranslation(glm::vec3 translation) { _translation = translation; } +void RecordingFrame::setRotation(glm::quat rotation) { + _rotation = rotation; +} + +void RecordingFrame::setScale(float scale) { + _scale = scale; +} + +void RecordingFrame::setHeadRotation(glm::quat headRotation) { + _headRotation = headRotation; +} + +void RecordingFrame::setLeanSideways(float leanSideways) { + _leanSideways = leanSideways; +} + +void RecordingFrame::setLeanForward(float leanForward) { + _leanForward = leanForward; +} + +void RecordingFrame::setEstimatedEyePitch(float estimatedEyePitch) { + _estimatedEyePitch = estimatedEyePitch; +} + +void RecordingFrame::setEstimatedEyeYaw(float estimatedEyeYaw) { + _estimatedEyeYaw = estimatedEyeYaw; +} + void Recording::addFrame(int timestamp, RecordingFrame &frame) { _timestamps << timestamp; _frames << frame; @@ -33,7 +63,10 @@ void Recording::clear() { _frames.clear(); } -Recorder::Recorder(AvatarData* avatar) : _avatar(avatar) { +Recorder::Recorder(AvatarData* avatar) : + _recording(new Recording()), + _avatar(avatar) +{ } bool Recorder::isRecording() const { @@ -49,29 +82,72 @@ qint64 Recorder::elapsed() const { } void Recorder::startRecording() { - _recording.clear(); + qDebug() << "Recorder::startRecording()"; + _recording->clear(); _timer.start(); + + RecordingFrame frame; + frame.setBlendshapeCoefficients(_avatar->getHeadData()->getBlendshapeCoefficients()); + frame.setJointRotations(_avatar->getJointRotations()); + frame.setTranslation(_avatar->getPosition()); + frame.setRotation(_avatar->getOrientation()); + frame.setScale(_avatar->getTargetScale()); + + // TODO + const HeadData* head = _avatar->getHeadData(); + glm::quat rotation = glm::quat(glm::radians(glm::vec3(head->getFinalPitch(), + head->getFinalYaw(), + head->getFinalRoll()))); + frame.setHeadRotation(rotation); + // TODO + //frame.setEstimatedEyePitch(); + //frame.setEstimatedEyeYaw(); + + _recording->addFrame(0, frame); } void Recorder::stopRecording() { + qDebug() << "Recorder::stopRecording()"; _timer.invalidate(); + + qDebug().nospace() << "Recorded " << _recording->getFrameNumber() << " during " << _recording->getLength() << " msec (" << _recording->getFrameNumber() / (_recording->getLength() / 1000.0f) << " fps)"; } void Recorder::saveToFile(QString file) { - if (_recording.isEmpty()) { + if (_recording->isEmpty()) { qDebug() << "Cannot save recording to file, recording is empty."; } - writeRecordingToFile(_recording, file); + writeRecordingToFile(*_recording, file); } void Recorder::record() { - qDebug() << "Recording " << _avatar; - RecordingFrame frame; - frame.setBlendshapeCoefficients(_avatar->_) + if (isRecording()) { + const RecordingFrame& referenceFrame = _recording->getFrame(0); + RecordingFrame frame; + frame.setBlendshapeCoefficients(_avatar->getHeadData()->getBlendshapeCoefficients()); + frame.setJointRotations(_avatar->getJointRotations()); + frame.setTranslation(_avatar->getPosition() - referenceFrame.getTranslation()); + frame.setRotation(glm::inverse(referenceFrame.getRotation()) * _avatar->getOrientation()); + frame.setScale(_avatar->getTargetScale() / referenceFrame.getScale()); + // TODO + //frame.setHeadTranslation(); + const HeadData* head = _avatar->getHeadData(); + glm::quat rotation = glm::quat(glm::radians(glm::vec3(head->getFinalPitch(), + head->getFinalYaw(), + head->getFinalRoll()))); + frame.setHeadRotation(glm::inverse(referenceFrame.getHeadRotation()) * rotation); + // TODO + //frame.setEstimatedEyePitch(); + //frame.setEstimatedEyeYaw(); + _recording->addFrame(_timer.elapsed(), frame); + } } -Player::Player(AvatarData* avatar) : _avatar(avatar) { +Player::Player(AvatarData* avatar) : + _recording(new Recording()), + _avatar(avatar) +{ } bool Player::isPlaying() const { @@ -86,21 +162,129 @@ qint64 Player::elapsed() const { } } +QVector Player::getBlendshapeCoefficients() { + computeCurrentFrame(); + return _recording->getFrame(_currentFrame).getBlendshapeCoefficients(); +} + +QVector Player::getJointRotations() { + computeCurrentFrame(); + return _recording->getFrame(_currentFrame).getJointRotations(); +} + +glm::quat Player::getRotation() { + computeCurrentFrame(); + return _recording->getFrame(_currentFrame).getRotation(); +} + +float Player::getScale() { + computeCurrentFrame(); + return _recording->getFrame(_currentFrame).getScale(); +} + +glm::quat Player::getHeadRotation() { + computeCurrentFrame(); + if (_currentFrame >= 0 && _currentFrame <= _recording->getFrameNumber()) { + if (_currentFrame == _recording->getFrameNumber()) { + return _recording->getFrame(0).getHeadRotation() * + _recording->getFrame(_currentFrame - 1).getHeadRotation(); + } + if (_currentFrame == 0) { + return _recording->getFrame(_currentFrame).getHeadRotation(); + } + + return _recording->getFrame(0).getHeadRotation() * + _recording->getFrame(_currentFrame).getHeadRotation(); + } + qWarning() << "Incorrect use of Player::getHeadRotation()"; + return glm::quat(); +} + +float Player::getEstimatedEyePitch() { + computeCurrentFrame(); + return _recording->getFrame(_currentFrame).getEstimatedEyePitch(); +} + +float Player::getEstimatedEyeYaw() { + computeCurrentFrame(); + return _recording->getFrame(_currentFrame).getEstimatedEyeYaw(); +} + + void Player::startPlaying() { - _timer.start(); + if (_recording && _recording->getFrameNumber() > 0) { + qDebug() << "Recorder::startPlaying()"; + _timer.start(); + _currentFrame = 0; + } } void Player::stopPlaying() { + qDebug() << "Recorder::stopPlaying()"; _timer.invalidate(); } void Player::loadFromFile(QString file) { - _recording.clear(); - readRecordingFromFile(_recording, file); + if (_recording) { + _recording->clear(); + } else { + _recording = RecordingPointer(new Recording()); + } + readRecordingFromFile(*_recording, file); +} + +void Player::loadRecording(RecordingPointer recording) { + _recording = recording; } void Player::play() { - qDebug() << "Playing " << _avatar; + qDebug() << "Playing " << _timer.elapsed() / 1000.0f; + computeCurrentFrame(); + if (_currentFrame < 0 || _currentFrame >= _recording->getFrameNumber()) { + // If it's the end of the recording, stop playing + stopPlaying(); + return; + } + if (_currentFrame == 0) { + _avatar->setPosition(_recording->getFrame(_currentFrame).getTranslation()); + _avatar->setOrientation(_recording->getFrame(_currentFrame).getRotation()); + _avatar->setTargetScale(_recording->getFrame(_currentFrame).getScale()); + HeadData* head = const_cast(_avatar->getHeadData()); + head->setBlendshapeCoefficients(_recording->getFrame(_currentFrame).getBlendshapeCoefficients()); + // TODO + // HEAD: Coeff, Translation, estimated eye rotations + // BODY: Joint Rotations + } else { + _avatar->setPosition(_recording->getFrame(0).getTranslation() + + _recording->getFrame(_currentFrame).getTranslation()); + _avatar->setOrientation(_recording->getFrame(0).getRotation() * + _recording->getFrame(_currentFrame).getRotation()); + _avatar->setTargetScale(_recording->getFrame(0).getScale() * + _recording->getFrame(_currentFrame).getScale()); + HeadData* head = const_cast(_avatar->getHeadData()); + head->setBlendshapeCoefficients(_recording->getFrame(_currentFrame).getBlendshapeCoefficients()); + // TODO + // HEAD: Coeff, Translation, estimated eye rotations + // BODY: Joint Rotations + } +} + +void Player::computeCurrentFrame() { + if (!isPlaying()) { + qDebug() << "Not Playing"; + _currentFrame = -1; + return; + } + if (_currentFrame < 0) { + qDebug() << "Reset to 0"; + _currentFrame = 0; + } + + while (_currentFrame < _recording->getFrameNumber() && + _recording->getFrameTimestamp(_currentFrame) < _timer.elapsed()) { + qDebug() << "Loop"; + ++_currentFrame; + } } void writeRecordingToFile(Recording& recording, QString file) { diff --git a/interface/src/Recorder.h b/interface/src/Recorder.h index 2d32e4a9b0..798e3f5ba8 100644 --- a/interface/src/Recorder.h +++ b/interface/src/Recorder.h @@ -15,7 +15,9 @@ #include #include #include +#include #include +#include #include #include @@ -23,7 +25,15 @@ #include #include +class Recorder; class Recording; +class Player; + +typedef QSharedPointer RecordingPointer; +typedef QSharedPointer RecorderPointer; +typedef QWeakPointer WeakRecorderPointer; +typedef QSharedPointer PlayerPointer; +typedef QWeakPointer WeakPlayerPointer; /// Stores the different values associated to one recording frame class RecordingFrame { @@ -31,20 +41,41 @@ public: QVector getBlendshapeCoefficients() const { return _blendshapeCoefficients; } QVector getJointRotations() const { return _jointRotations; } glm::vec3 getTranslation() const { return _translation; } + glm::quat getRotation() const { return _rotation; } + float getScale() const { return _scale; } + glm::quat getHeadRotation() const { return _headRotation; } + float getLeanSideways() const { return _leanSideways; } + float getLeanForward() const { return _leanForward; } + float getEstimatedEyePitch() const { return _estimatedEyePitch; } + float getEstimatedEyeYaw() const { return _estimatedEyeYaw; } protected: void setBlendshapeCoefficients(QVector blendshapeCoefficients); void setJointRotations(QVector jointRotations); void setTranslation(glm::vec3 translation); + void setRotation(glm::quat rotation); + void setScale(float scale); + void setHeadRotation(glm::quat headRotation); + void setLeanSideways(float leanSideways); + void setLeanForward(float leanForward); + void setEstimatedEyePitch(float estimatedEyePitch); + void setEstimatedEyeYaw(float estimatedEyeYaw); private: QVector _blendshapeCoefficients; QVector _jointRotations; glm::vec3 _translation; + glm::quat _rotation; + float _scale; + glm::quat _headRotation; + float _leanSideways; + float _leanForward; + float _estimatedEyePitch; + float _estimatedEyeYaw; friend class Recorder; friend void writeRecordingToFile(Recording& recording, QString file); - friend Recording* readRecordingFromFile(QString file); + friend RecordingPointer readRecordingFromFile(QString file); }; /// Stores a recording @@ -52,6 +83,7 @@ class Recording { public: bool isEmpty() const { return _timestamps.isEmpty(); } int getLength() const { return _timestamps.last(); } // in ms + int getFrameNumber() const { return _frames.size(); } qint32 getFrameTimestamp(int i) const { return _timestamps[i]; } const RecordingFrame& getFrame(int i) const { return _frames[i]; } @@ -67,7 +99,7 @@ private: friend class Recorder; friend class Player; friend void writeRecordingToFile(Recording& recording, QString file); - friend Recording* readRecordingFromFile(QString file); + friend RecordingPointer readRecordingFromFile(QString file); }; @@ -79,6 +111,8 @@ public: bool isRecording() const; qint64 elapsed() const; + RecordingPointer getRecording() const { return _recording; } + public slots: void startRecording(); void stopRecording(); @@ -87,7 +121,7 @@ public slots: private: QElapsedTimer _timer; - Recording _recording; + RecordingPointer _recording; AvatarData* _avatar; }; @@ -100,15 +134,29 @@ public: bool isPlaying() const; qint64 elapsed() const; + // Those should only be called if isPlaying() returns true + QVector getBlendshapeCoefficients(); + QVector getJointRotations(); + glm::quat getRotation(); + float getScale(); + glm::vec3 getHeadTranslation(); + glm::quat getHeadRotation(); + float getEstimatedEyePitch(); + float getEstimatedEyeYaw(); + public slots: void startPlaying(); void stopPlaying(); void loadFromFile(QString file); + void loadRecording(RecordingPointer recording); void play(); private: + void computeCurrentFrame(); + QElapsedTimer _timer; - Recording _recording; + RecordingPointer _recording; + int _currentFrame; AvatarData* _avatar; }; From ff0a5df2d6848e2f819f6d967ca5efa26b4511fc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 12 Aug 2014 16:12:34 -0700 Subject: [PATCH 351/407] Joint rotations manipulation helper --- libraries/avatars/src/AvatarData.cpp | 15 +++++++++++++++ libraries/avatars/src/AvatarData.h | 2 ++ libraries/avatars/src/HeadData.h | 1 + 3 files changed, 18 insertions(+) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 039ccae4e9..fad07bedfc 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -683,6 +683,21 @@ glm::quat AvatarData::getJointRotation(const QString& name) const { return getJointRotation(getJointIndex(name)); } +QVector AvatarData::getJointRotations() const { + if (QThread::currentThread() != thread()) { + QVector result; + QMetaObject::invokeMethod(const_cast(this), + "getJointRotation", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QVector, result)); + return result; + } + QVector jointRotations(_jointData.size()); + for (int i = 0; i < _jointData.size(); ++i) { + jointRotations[i] = _jointData[i].rotation; + } + return jointRotations; +} + bool AvatarData::hasIdentityChangedAfterParsing(const QByteArray &packet) { QDataStream packetStream(packet); packetStream.skipRawData(numBytesForPacketHeader(packet)); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a4bb0d48bb..eb3341ee26 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -210,6 +210,8 @@ public: Q_INVOKABLE void clearJointData(const QString& name); Q_INVOKABLE bool isJointDataValid(const QString& name) const; Q_INVOKABLE glm::quat getJointRotation(const QString& name) const; + + QVector getJointRotations() const; /// Returns the index of the joint with the specified name, or -1 if not found/unknown. Q_INVOKABLE virtual int getJointIndex(const QString& name) const { return _jointIndices.value(name) - 1; } diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index 782386c649..b6a3268ec0 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -56,6 +56,7 @@ public: void setBlendshape(QString name, float val); const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } + void setBlendshapeCoefficients(const QVector& blendshapeCoefficients) { _blendshapeCoefficients = blendshapeCoefficients; } float getPupilDilation() const { return _pupilDilation; } void setPupilDilation(float pupilDilation) { _pupilDilation = pupilDilation; } From 792f779bbff7600682bceb7907da2fcadf4862d6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 12 Aug 2014 16:16:01 -0700 Subject: [PATCH 352/407] Hooked up MyAvatar to playbacks --- interface/src/avatar/Avatar.cpp | 13 +++++++ interface/src/avatar/Avatar.h | 7 +++- interface/src/avatar/Head.cpp | 19 ++++++---- interface/src/avatar/MyAvatar.cpp | 62 +++++++++++++++++++++++++++++-- interface/src/avatar/MyAvatar.h | 9 +++++ 5 files changed, 97 insertions(+), 13 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index c9e03d15cc..498281c98c 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -29,6 +29,7 @@ #include "Menu.h" #include "ModelReferential.h" #include "Physics.h" +#include "Recorder.h" #include "world.h" #include "devices/OculusManager.h" #include "renderer/TextureCache.h" @@ -63,6 +64,7 @@ Avatar::Avatar() : _mouseRayDirection(0.0f, 0.0f, 0.0f), _moving(false), _collisionGroups(0), + _player(NULL), _initialized(false), _shouldRenderBillboard(true) { @@ -725,6 +727,17 @@ bool Avatar::findCollisions(const QVector& shapes, CollisionList& return collided; } +QVector Avatar::getJointRotations() const { + if (QThread::currentThread() != thread()) { + return AvatarData::getJointRotations(); + } + QVector jointRotations(_skeletonModel.getJointStateCount()); + for (int i = 0; i < _skeletonModel.getJointStateCount(); ++i) { + _skeletonModel.getJointState(i, jointRotations[i]); + } + return jointRotations; +} + glm::quat Avatar::getJointRotation(int index) const { if (QThread::currentThread() != thread()) { return AvatarData::getJointRotation(index); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 555a0f6d32..35dec3b8d0 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -23,6 +23,7 @@ #include "Hand.h" #include "Head.h" #include "InterfaceConfig.h" +#include "Recorder.h" #include "SkeletonModel.h" #include "world.h" @@ -121,6 +122,7 @@ public: virtual bool isMyAvatar() { return false; } + virtual QVector getJointRotations() const; virtual glm::quat getJointRotation(int index) const; virtual int getJointIndex(const QString& name) const; virtual QStringList getJointNames() const; @@ -186,6 +188,9 @@ protected: bool _moving; ///< set when position is changing quint32 _collisionGroups; + + RecorderPointer _recorder; + PlayerPointer _player; // protected methods... glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } @@ -220,8 +225,6 @@ private: void renderBillboard(); float getBillboardSize() const; - - }; #endif // hifi_Avatar_h diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 995f3f2390..d547dc41c2 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -64,13 +64,18 @@ void Head::reset() { void Head::simulate(float deltaTime, bool isMine, bool billboard) { // Update audio trailing average for rendering facial animations if (isMine) { - FaceTracker* faceTracker = Application::getInstance()->getActiveFaceTracker(); - if ((_isFaceshiftConnected = faceTracker)) { - _blendshapeCoefficients = faceTracker->getBlendshapeCoefficients(); - _isFaceshiftConnected = true; - } else if (Application::getInstance()->getDDE()->isActive()) { - faceTracker = Application::getInstance()->getDDE(); - _blendshapeCoefficients = faceTracker->getBlendshapeCoefficients(); + MyAvatar* myAvatar = static_cast(_owningAvatar); + + // Only use face trackers when not playing back a recording. + if (!myAvatar->isPlaying()) { + FaceTracker* faceTracker = Application::getInstance()->getActiveFaceTracker(); + if ((_isFaceshiftConnected = faceTracker)) { + _blendshapeCoefficients = faceTracker->getBlendshapeCoefficients(); + _isFaceshiftConnected = true; + } else if (Application::getInstance()->getDDE()->isActive()) { + faceTracker = Application::getInstance()->getDDE(); + _blendshapeCoefficients = faceTracker->getBlendshapeCoefficients(); + } } } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f59064732c..353c240507 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -35,6 +35,7 @@ #include "ModelReferential.h" #include "MyAvatar.h" #include "Physics.h" +#include "Recorder.h" #include "devices/Faceshift.h" #include "devices/OculusManager.h" #include "ui/TextRenderer.h" @@ -135,6 +136,12 @@ void MyAvatar::update(float deltaTime) { void MyAvatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); + + // Play back recording + if (_player && _player->isPlaying()) { + _player->play(); + } + if (_scale != _targetScale) { float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale; setScale(scale); @@ -147,7 +154,7 @@ void MyAvatar::simulate(float deltaTime) { updateOrientation(deltaTime); updatePosition(deltaTime); } - + { PerformanceTimer perfTimer("hand"); // update avatar skeleton and simulate hand and head @@ -242,6 +249,11 @@ void MyAvatar::simulate(float deltaTime) { } } + // Record avatars movements. + if (_recorder && _recorder->isRecording()) { + _recorder->record(); + } + // consider updating our billboard maybeUpdateBillboard(); } @@ -250,7 +262,10 @@ void MyAvatar::simulate(float deltaTime) { void MyAvatar::updateFromTrackers(float deltaTime) { glm::vec3 estimatedPosition, estimatedRotation; - if (Application::getInstance()->getPrioVR()->hasHeadRotation()) { + if (isPlaying()) { + //estimatedPosition = _player->getHeadTranslation(); + estimatedRotation = glm::degrees(safeEulerAngles(_player->getHeadRotation())); + } else if (Application::getInstance()->getPrioVR()->hasHeadRotation()) { estimatedRotation = glm::degrees(safeEulerAngles(Application::getInstance()->getPrioVR()->getHeadRotation())); estimatedRotation.x *= -1.0f; estimatedRotation.z *= -1.0f; @@ -286,7 +301,7 @@ void MyAvatar::updateFromTrackers(float deltaTime) { Head* head = getHead(); - if (OculusManager::isConnected()) { + if (OculusManager::isConnected() || isPlaying()) { head->setDeltaPitch(estimatedRotation.x); head->setDeltaYaw(estimatedRotation.y); } else { @@ -297,7 +312,7 @@ void MyAvatar::updateFromTrackers(float deltaTime) { head->setDeltaRoll(estimatedRotation.z); // the priovr can give us exact lean - if (Application::getInstance()->getPrioVR()->isActive()) { + if (Application::getInstance()->getPrioVR()->isActive() && !isPlaying()) { glm::vec3 eulers = glm::degrees(safeEulerAngles(Application::getInstance()->getPrioVR()->getTorsoRotation())); head->setLeanSideways(eulers.z); head->setLeanForward(eulers.x); @@ -474,6 +489,45 @@ bool MyAvatar::setJointReferential(int id, int jointIndex) { } } +bool MyAvatar::isRecording() const { + return _recorder && _recorder->isRecording(); +} + +RecorderPointer MyAvatar::startRecording() { + if (!_recorder) { + _recorder = RecorderPointer(new Recorder(this)); + } + _recorder->startRecording(); + return _recorder; +} + +void MyAvatar::stopRecording() { + if (_recorder) { + _recorder->stopRecording(); + } +} + +bool MyAvatar::isPlaying() const { + return _player && _player->isPlaying(); +} + +PlayerPointer MyAvatar::startPlaying() { + if (!_player) { + _player = PlayerPointer(new Player(this)); + } + if (_recorder) { + _player->loadRecording(_recorder->getRecording()); + _player->startPlaying(); + } + return _player; +} + +void MyAvatar::stopPlaying() { + if (_player) { + _player->stopPlaying(); + } +} + void MyAvatar::setLocalGravity(glm::vec3 gravity) { _motionBehaviors |= AVATAR_MOTION_OBEY_LOCAL_GRAVITY; // Environmental and Local gravities are incompatible. Since Local is being set here diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 4f2802a35a..cd211a3530 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -155,6 +155,15 @@ public slots: bool setModelReferential(int id); bool setJointReferential(int id, int jointIndex); + bool isRecording() const; + RecorderPointer startRecording(); + void stopRecording(); + + bool isPlaying() const; + PlayerPointer startPlaying(); + void stopPlaying(); + + signals: void transformChanged(); From 73a3a13c59769a1cfb5520914fa578e5beb14ad9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 12 Aug 2014 18:15:48 -0700 Subject: [PATCH 353/407] More recording work --- interface/src/Application.cpp | 13 ++- interface/src/Recorder.cpp | 123 +++++++++++++++++++------ interface/src/Recorder.h | 12 +-- interface/src/avatar/Avatar.cpp | 1 + interface/src/avatar/Head.h | 5 - interface/src/avatar/MyAvatar.cpp | 17 +++- interface/src/avatar/MyAvatar.h | 3 + interface/src/avatar/SkeletonModel.cpp | 8 +- libraries/avatars/src/AvatarData.cpp | 14 +++ libraries/avatars/src/AvatarData.h | 3 +- libraries/avatars/src/HeadData.h | 9 ++ 11 files changed, 158 insertions(+), 50 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6f7212e68f..198a3f9a8b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1048,10 +1048,19 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_R: if (isShifted) { - Menu::getInstance()->triggerOption(MenuOption::FrustumRenderMode); + if (_myAvatar->isRecording()) { + _myAvatar->stopRecording(); + } else { + _myAvatar->startRecording(); + } + } else { + if (_myAvatar->isPlaying()) { + _myAvatar->stopPlaying(); + } else { + _myAvatar->startPlaying(); + } } break; - break; case Qt::Key_Percent: Menu::getInstance()->triggerOption(MenuOption::Stats); break; diff --git a/interface/src/Recorder.cpp b/interface/src/Recorder.cpp index c15e17597e..de29a887fb 100644 --- a/interface/src/Recorder.cpp +++ b/interface/src/Recorder.cpp @@ -45,14 +45,6 @@ void RecordingFrame::setLeanForward(float leanForward) { _leanForward = leanForward; } -void RecordingFrame::setEstimatedEyePitch(float estimatedEyePitch) { - _estimatedEyePitch = estimatedEyePitch; -} - -void RecordingFrame::setEstimatedEyeYaw(float estimatedEyeYaw) { - _estimatedEyeYaw = estimatedEyeYaw; -} - void Recording::addFrame(int timestamp, RecordingFrame &frame) { _timestamps << timestamp; _frames << frame; @@ -93,15 +85,13 @@ void Recorder::startRecording() { frame.setRotation(_avatar->getOrientation()); frame.setScale(_avatar->getTargetScale()); - // TODO const HeadData* head = _avatar->getHeadData(); glm::quat rotation = glm::quat(glm::radians(glm::vec3(head->getFinalPitch(), head->getFinalYaw(), head->getFinalRoll()))); frame.setHeadRotation(rotation); - // TODO - //frame.setEstimatedEyePitch(); - //frame.setEstimatedEyeYaw(); + frame.setLeanForward(_avatar->getHeadData()->getLeanForward()); + frame.setLeanSideways(_avatar->getHeadData()->getLeanSideways()); _recording->addFrame(0, frame); } @@ -130,16 +120,16 @@ void Recorder::record() { frame.setTranslation(_avatar->getPosition() - referenceFrame.getTranslation()); frame.setRotation(glm::inverse(referenceFrame.getRotation()) * _avatar->getOrientation()); frame.setScale(_avatar->getTargetScale() / referenceFrame.getScale()); - // TODO - //frame.setHeadTranslation(); + + const HeadData* head = _avatar->getHeadData(); glm::quat rotation = glm::quat(glm::radians(glm::vec3(head->getFinalPitch(), head->getFinalYaw(), head->getFinalRoll()))); - frame.setHeadRotation(glm::inverse(referenceFrame.getHeadRotation()) * rotation); - // TODO - //frame.setEstimatedEyePitch(); - //frame.setEstimatedEyeYaw(); + frame.setHeadRotation(rotation); + frame.setLeanForward(_avatar->getHeadData()->getLeanForward()); + frame.setLeanSideways(_avatar->getHeadData()->getLeanSideways()); + _recording->addFrame(_timer.elapsed(), frame); } } @@ -164,22 +154,82 @@ qint64 Player::elapsed() const { QVector Player::getBlendshapeCoefficients() { computeCurrentFrame(); - return _recording->getFrame(_currentFrame).getBlendshapeCoefficients(); + if (_currentFrame >= 0 && _currentFrame <= _recording->getFrameNumber()) { + if (_currentFrame == _recording->getFrameNumber()) { + return _recording->getFrame(_currentFrame - 1).getBlendshapeCoefficients(); + } + + return _recording->getFrame(_currentFrame).getBlendshapeCoefficients(); + } + qWarning() << "Incorrect use of Player::getBlendshapeCoefficients()"; + return QVector(); } QVector Player::getJointRotations() { computeCurrentFrame(); - return _recording->getFrame(_currentFrame).getJointRotations(); + if (_currentFrame >= 0 && _currentFrame <= _recording->getFrameNumber()) { + if (_currentFrame == _recording->getFrameNumber()) { + return _recording->getFrame(_currentFrame - 1).getJointRotations(); + } + + return _recording->getFrame(_currentFrame).getJointRotations(); + } + qWarning() << "Incorrect use of Player::getJointRotations()"; + return QVector(); +} + +glm::vec3 Player::getPosition() { + computeCurrentFrame(); + if (_currentFrame >= 0 && _currentFrame <= _recording->getFrameNumber()) { + if (_currentFrame == _recording->getFrameNumber()) { + return _recording->getFrame(0).getTranslation() + + _recording->getFrame(_currentFrame - 1).getTranslation(); + } + if (_currentFrame == 0) { + return _recording->getFrame(_currentFrame).getTranslation(); + } + + return _recording->getFrame(0).getTranslation() + + _recording->getFrame(_currentFrame).getTranslation(); + } + qWarning() << "Incorrect use of Player::getTranslation()"; + return glm::vec3(); } glm::quat Player::getRotation() { computeCurrentFrame(); - return _recording->getFrame(_currentFrame).getRotation(); + if (_currentFrame >= 0 && _currentFrame <= _recording->getFrameNumber()) { + if (_currentFrame == _recording->getFrameNumber()) { + return _recording->getFrame(0).getRotation() * + _recording->getFrame(_currentFrame - 1).getRotation(); + } + if (_currentFrame == 0) { + return _recording->getFrame(_currentFrame).getRotation(); + } + + return _recording->getFrame(0).getRotation() * + _recording->getFrame(_currentFrame).getRotation(); + } + qWarning() << "Incorrect use of Player::getRotation()"; + return glm::quat(); } float Player::getScale() { computeCurrentFrame(); - return _recording->getFrame(_currentFrame).getScale(); + if (_currentFrame >= 0 && _currentFrame <= _recording->getFrameNumber()) { + if (_currentFrame == _recording->getFrameNumber()) { + return _recording->getFrame(0).getScale() * + _recording->getFrame(_currentFrame - 1).getScale(); + } + if (_currentFrame == 0) { + return _recording->getFrame(_currentFrame).getScale(); + } + + return _recording->getFrame(0).getScale() * + _recording->getFrame(_currentFrame).getScale(); + } + qWarning() << "Incorrect use of Player::getScale()"; + return 1.0f; } glm::quat Player::getHeadRotation() { @@ -200,14 +250,30 @@ glm::quat Player::getHeadRotation() { return glm::quat(); } -float Player::getEstimatedEyePitch() { +float Player::getLeanSideways() { computeCurrentFrame(); - return _recording->getFrame(_currentFrame).getEstimatedEyePitch(); + if (_currentFrame >= 0 && _currentFrame <= _recording->getFrameNumber()) { + if (_currentFrame == _recording->getFrameNumber()) { + return _recording->getFrame(_currentFrame - 1).getLeanSideways(); + } + + return _recording->getFrame(_currentFrame).getLeanSideways(); + } + qWarning() << "Incorrect use of Player::getLeanSideways()"; + return 0.0f; } -float Player::getEstimatedEyeYaw() { +float Player::getLeanForward() { computeCurrentFrame(); - return _recording->getFrame(_currentFrame).getEstimatedEyeYaw(); + if (_currentFrame >= 0 && _currentFrame <= _recording->getFrameNumber()) { + if (_currentFrame == _recording->getFrameNumber()) { + return _recording->getFrame(_currentFrame - 1).getLeanForward(); + } + + return _recording->getFrame(_currentFrame).getLeanForward(); + } + qWarning() << "Incorrect use of Player::getLeanForward()"; + return 0.0f; } @@ -249,10 +315,10 @@ void Player::play() { _avatar->setPosition(_recording->getFrame(_currentFrame).getTranslation()); _avatar->setOrientation(_recording->getFrame(_currentFrame).getRotation()); _avatar->setTargetScale(_recording->getFrame(_currentFrame).getScale()); + _avatar->setJointRotations(_recording->getFrame(_currentFrame).getJointRotations()); HeadData* head = const_cast(_avatar->getHeadData()); head->setBlendshapeCoefficients(_recording->getFrame(_currentFrame).getBlendshapeCoefficients()); // TODO - // HEAD: Coeff, Translation, estimated eye rotations // BODY: Joint Rotations } else { _avatar->setPosition(_recording->getFrame(0).getTranslation() + @@ -261,10 +327,10 @@ void Player::play() { _recording->getFrame(_currentFrame).getRotation()); _avatar->setTargetScale(_recording->getFrame(0).getScale() * _recording->getFrame(_currentFrame).getScale()); + _avatar->setJointRotations(_recording->getFrame(_currentFrame).getJointRotations()); HeadData* head = const_cast(_avatar->getHeadData()); head->setBlendshapeCoefficients(_recording->getFrame(_currentFrame).getBlendshapeCoefficients()); // TODO - // HEAD: Coeff, Translation, estimated eye rotations // BODY: Joint Rotations } } @@ -282,7 +348,6 @@ void Player::computeCurrentFrame() { while (_currentFrame < _recording->getFrameNumber() && _recording->getFrameTimestamp(_currentFrame) < _timer.elapsed()) { - qDebug() << "Loop"; ++_currentFrame; } } diff --git a/interface/src/Recorder.h b/interface/src/Recorder.h index 798e3f5ba8..f2a6f6a1c4 100644 --- a/interface/src/Recorder.h +++ b/interface/src/Recorder.h @@ -46,8 +46,6 @@ public: glm::quat getHeadRotation() const { return _headRotation; } float getLeanSideways() const { return _leanSideways; } float getLeanForward() const { return _leanForward; } - float getEstimatedEyePitch() const { return _estimatedEyePitch; } - float getEstimatedEyeYaw() const { return _estimatedEyeYaw; } protected: void setBlendshapeCoefficients(QVector blendshapeCoefficients); @@ -58,8 +56,6 @@ protected: void setHeadRotation(glm::quat headRotation); void setLeanSideways(float leanSideways); void setLeanForward(float leanForward); - void setEstimatedEyePitch(float estimatedEyePitch); - void setEstimatedEyeYaw(float estimatedEyeYaw); private: QVector _blendshapeCoefficients; @@ -70,8 +66,6 @@ private: glm::quat _headRotation; float _leanSideways; float _leanForward; - float _estimatedEyePitch; - float _estimatedEyeYaw; friend class Recorder; friend void writeRecordingToFile(Recording& recording, QString file); @@ -137,12 +131,12 @@ public: // Those should only be called if isPlaying() returns true QVector getBlendshapeCoefficients(); QVector getJointRotations(); + glm::vec3 getPosition(); glm::quat getRotation(); float getScale(); - glm::vec3 getHeadTranslation(); glm::quat getHeadRotation(); - float getEstimatedEyePitch(); - float getEstimatedEyeYaw(); + float getLeanSideways(); + float getLeanForward(); public slots: void startPlaying(); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 498281c98c..d50e9232ed 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -735,6 +735,7 @@ QVector Avatar::getJointRotations() const { for (int i = 0; i < _skeletonModel.getJointStateCount(); ++i) { _skeletonModel.getJointState(i, jointRotations[i]); } + qDebug() << "Get Joints"; return jointRotations; } diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 6d1e82b97f..1bcaadec73 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -48,8 +48,6 @@ public: void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; } void setReturnToCenter (bool returnHeadToCenter) { _returnHeadToCenter = returnHeadToCenter; } void setRenderLookatVectors(bool onOff) { _renderLookatVectors = onOff; } - void setLeanSideways(float leanSideways) { _leanSideways = leanSideways; } - void setLeanForward(float leanForward) { _leanForward = leanForward; } /// \return orientationBase+Delta glm::quat getFinalOrientationInLocalFrame() const; @@ -57,7 +55,6 @@ public: /// \return orientationBody * (orientationBase+Delta) glm::quat getFinalOrientationInWorldFrame() const; - /// \return orientationBody * orientationBasePitch glm::quat getCameraOrientation () const; @@ -71,8 +68,6 @@ public: glm::vec3 getRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getUpDirection() const { return getOrientation() * IDENTITY_UP; } glm::vec3 getFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } - float getLeanSideways() const { return _leanSideways; } - float getLeanForward() const { return _leanForward; } float getFinalLeanSideways() const { return _leanSideways + _deltaLeanSideways; } float getFinalLeanForward() const { return _leanForward + _deltaLeanForward; } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 353c240507..1133ac01c3 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -263,7 +263,6 @@ void MyAvatar::updateFromTrackers(float deltaTime) { glm::vec3 estimatedPosition, estimatedRotation; if (isPlaying()) { - //estimatedPosition = _player->getHeadTranslation(); estimatedRotation = glm::degrees(safeEulerAngles(_player->getHeadRotation())); } else if (Application::getInstance()->getPrioVR()->hasHeadRotation()) { estimatedRotation = glm::degrees(safeEulerAngles(Application::getInstance()->getPrioVR()->getHeadRotation())); @@ -311,14 +310,18 @@ void MyAvatar::updateFromTrackers(float deltaTime) { } head->setDeltaRoll(estimatedRotation.z); + if (isPlaying()) { + head->setLeanSideways(_player->getLeanSideways()); + head->setLeanForward(_player->getLeanForward()); + return; + } // the priovr can give us exact lean - if (Application::getInstance()->getPrioVR()->isActive() && !isPlaying()) { + if (Application::getInstance()->getPrioVR()->isActive()) { glm::vec3 eulers = glm::degrees(safeEulerAngles(Application::getInstance()->getPrioVR()->getTorsoRotation())); head->setLeanSideways(eulers.z); head->setLeanForward(eulers.x); return; } - // Update torso lean distance based on accelerometer data const float TORSO_LENGTH = 0.5f; glm::vec3 relativePosition = estimatedPosition - glm::vec3(0.0f, -TORSO_LENGTH, 0.0f); @@ -910,6 +913,14 @@ glm::vec3 MyAvatar::getUprightHeadPosition() const { const float JOINT_PRIORITY = 2.0f; +void MyAvatar::setJointRotations(QVector jointRotations) { + for (int i = 0; i < jointRotations.size(); ++i) { + if (i < _jointData.size()) { + _skeletonModel.setJointState(i, true, jointRotations[i]); + } + } +} + void MyAvatar::setJointData(int index, const glm::quat& rotation) { Avatar::setJointData(index, rotation); if (QThread::currentThread() == thread()) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index cd211a3530..bf57bf2367 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -112,6 +112,7 @@ public: void updateLookAtTargetAvatar(); void clearLookAtTargetAvatar(); + virtual void setJointRotations(QVector jointRotations); virtual void setJointData(int index, const glm::quat& rotation); virtual void clearJointData(int index); virtual void setFaceModelURL(const QUrl& faceModelURL); @@ -155,10 +156,12 @@ public slots: bool setModelReferential(int id); bool setJointReferential(int id, int jointIndex); + const RecorderPointer getRecorder() const { return _recorder; } bool isRecording() const; RecorderPointer startRecording(); void stopRecording(); + const PlayerPointer getPlayer() const { return _player; } bool isPlaying() const; PlayerPointer startPlaying(); void stopPlaying(); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 5e593526be..f4a507a8d3 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -59,9 +59,15 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { Model::simulate(deltaTime, fullUpdate); - if (!(isActive() && _owningAvatar->isMyAvatar())) { + if (!isActive() || !_owningAvatar->isMyAvatar()) { return; // only simulate for own avatar } + + MyAvatar* myAvatar = static_cast(_owningAvatar); + if (myAvatar->isPlaying()) { + // Don't take inputs if playing back a recording. + return; + } const FBXGeometry& geometry = _geometry->getFBXGeometry(); PrioVR* prioVR = Application::getInstance()->getPrioVR(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index fad07bedfc..569e099c2c 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -698,6 +698,20 @@ QVector AvatarData::getJointRotations() const { return jointRotations; } +void AvatarData::setJointRotations(QVector jointRotations) { + if (QThread::currentThread() != thread()) { + QVector result; + QMetaObject::invokeMethod(const_cast(this), + "setJointRotation", Qt::BlockingQueuedConnection, + Q_ARG(QVector, jointRotations)); + } + for (int i = 0; i < jointRotations.size(); ++i) { + if (i < _jointData.size()) { + setJointData(i, jointRotations[i]); + } + } +} + bool AvatarData::hasIdentityChangedAfterParsing(const QByteArray &packet) { QDataStream packetStream(packet); packetStream.skipRawData(numBytesForPacketHeader(packet)); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index eb3341ee26..7dec55b7e9 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -211,7 +211,8 @@ public: Q_INVOKABLE bool isJointDataValid(const QString& name) const; Q_INVOKABLE glm::quat getJointRotation(const QString& name) const; - QVector getJointRotations() const; + Q_INVOKABLE virtual QVector getJointRotations() const; + Q_INVOKABLE virtual void setJointRotations(QVector jointRotations); /// Returns the index of the joint with the specified name, or -1 if not found/unknown. Q_INVOKABLE virtual int getJointIndex(const QString& name) const { return _jointIndices.value(name) - 1; } diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index b6a3268ec0..310437689c 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -69,6 +69,15 @@ public: const glm::vec3& getLookAtPosition() const { return _lookAtPosition; } void setLookAtPosition(const glm::vec3& lookAtPosition) { _lookAtPosition = lookAtPosition; } + + float getLeanSideways() const { return _leanSideways; } + float getLeanForward() const { return _leanForward; } + virtual float getFinalLeanSideways() const { return _leanSideways; } + virtual float getFinalLeanForward() const { return _leanForward; } + + void setLeanSideways(float leanSideways) { _leanSideways = leanSideways; } + void setLeanForward(float leanForward) { _leanForward = leanForward; } + friend class AvatarData; protected: From 21d6c3c48a3785ecbde01631e3cf9458682061ff Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 12 Aug 2014 18:21:04 -0700 Subject: [PATCH 354/407] More work on edge rejiggery. --- interface/src/MetavoxelSystem.cpp | 140 +++++++++++++++++++-- interface/src/MetavoxelSystem.h | 5 +- libraries/metavoxels/src/MetavoxelUtil.cpp | 8 ++ libraries/metavoxels/src/MetavoxelUtil.h | 4 + 4 files changed, 148 insertions(+), 9 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 9286b9037b..067c1984c6 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -672,25 +672,149 @@ HeightfieldAugmentVisitor::HeightfieldAugmentVisitor(const MetavoxelLOD& lod) : class BorderFetchVisitor : public MetavoxelVisitor { public: - BorderFetchVisitor(const MetavoxelLOD& lod, QByteArray& height); + BorderFetchVisitor(const MetavoxelLOD& lod, HeightfieldBuffer* buffer); virtual int visit(MetavoxelInfo& info); private: - QByteArray& _height; + HeightfieldBuffer* _buffer; + Box _expandedBounds; + int _heightSize; + float _heightExtension; + int _colorSize; + float _colorExtension; + Box _colorBounds; }; -BorderFetchVisitor::BorderFetchVisitor(const MetavoxelLOD& lod, QByteArray& height) : - MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getHeightfieldAttribute(), - QVector(), lod), - _height(height) { +BorderFetchVisitor::BorderFetchVisitor(const MetavoxelLOD& lod, HeightfieldBuffer* buffer) : + MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getHeightfieldAttribute() << + AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), QVector(), lod), + _buffer(buffer), + _expandedBounds(_buffer->getTranslation(), _buffer->getTranslation() + + glm::vec3(_buffer->getScale(), _buffer->getScale(), _buffer->getScale())), + _heightSize(glm::sqrt(buffer->getHeight().size())), + _heightExtension(_buffer->getScale() / (_heightSize - HeightfieldBuffer::HEIGHT_EXTENSION)), + _colorSize(glm::sqrt(buffer->getColor().size() / HeightfieldData::COLOR_BYTES)), + _colorBounds(_expandedBounds) { + + _expandedBounds.minimum.x -= _heightExtension * HeightfieldBuffer::HEIGHT_BORDER; + _expandedBounds.minimum.z -= _heightExtension * HeightfieldBuffer::HEIGHT_BORDER; + _expandedBounds.maximum.x += _heightExtension * (HeightfieldBuffer::HEIGHT_BORDER + HeightfieldBuffer::SHARED_EDGE); + _expandedBounds.maximum.z += _heightExtension * (HeightfieldBuffer::HEIGHT_BORDER + HeightfieldBuffer::SHARED_EDGE); + + if (_colorSize > 0) { + _colorExtension = buffer->getScale() / (_colorSize - HeightfieldBuffer::SHARED_EDGE); + _colorBounds.maximum.x += _colorExtension * HeightfieldBuffer::SHARED_EDGE; + _colorBounds.maximum.z += _colorExtension * HeightfieldBuffer::SHARED_EDGE; + } } int BorderFetchVisitor::visit(MetavoxelInfo& info) { - if (!info.isLeaf) { + Box bounds = info.getBounds(); + if (!bounds.intersects(_expandedBounds)) { + return STOP_RECURSION; + } + if (!info.isLeaf && info.size > _buffer->getScale()) { return DEFAULT_ORDER; } + if (_expandedBounds.contains(bounds)) { + return STOP_RECURSION; // this is the principal, which we've already filled in + } + HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue(); + if (!height) { + return STOP_RECURSION; + } + Box intersection = bounds.getIntersection(_expandedBounds); + int destX = glm::round((intersection.minimum.x - _expandedBounds.minimum.x) / _heightExtension); + int destY = glm::round((intersection.minimum.z - _expandedBounds.minimum.z) / _heightExtension); + int destWidth = glm::round((intersection.maximum.x - intersection.minimum.x) / _heightExtension); + int destHeight = glm::round((intersection.maximum.z - intersection.minimum.z) / _heightExtension); + char* dest = _buffer->getHeight().data() + destY * _heightSize + destX; + + const QByteArray& srcHeight = height->getContents(); + int srcSize = glm::sqrt(srcHeight.size()); + float srcExtension = info.size / srcSize; + + if (info.size == _buffer->getScale() && srcSize == (_heightSize - HeightfieldBuffer::HEIGHT_EXTENSION)) { + // easy case: same resolution + int srcX = glm::round((intersection.minimum.x - info.minimum.x) / srcExtension); + int srcY = glm::round((intersection.minimum.z - info.minimum.z) / srcExtension); + + const char* src = srcHeight.constData() + srcY * srcSize + srcX; + for (int y = 0; y < destHeight; y++, src += srcSize, dest += _heightSize) { + memcpy(dest, src, destWidth); + } + } else { + // more difficult: different resolutions + float srcX = (intersection.minimum.x - info.minimum.x) / srcExtension; + float srcY = (intersection.minimum.z - info.minimum.z) / srcExtension; + float srcIncrement = _heightExtension / srcExtension; + int shift = 0; + float size = _buffer->getScale(); + while (size < info.size) { + shift++; + size *= 2.0f; + } + const int EIGHT_BIT_MAXIMUM = 255; + int subtract = (_buffer->getTranslation().y - info.minimum.y) * EIGHT_BIT_MAXIMUM / _buffer->getScale(); + for (int y = 0; y < destHeight; y++, dest += _heightSize, srcY += srcIncrement) { + const uchar* src = (const uchar*)srcHeight.constData() + (int)srcY * srcSize; + float lineSrcX = srcX; + for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrcX += srcIncrement) { + *lineDest = qMin(qMax(0, (src[(int)lineSrcX] << shift) - subtract), EIGHT_BIT_MAXIMUM); + } + } + } + + if (_colorSize == 0) { + return STOP_RECURSION; + } + HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue(); + if (!color) { + return STOP_RECURSION; + } + intersection = bounds.getIntersection(_colorBounds); + destX = glm::round((intersection.minimum.x - _colorBounds.minimum.x) / _colorExtension); + destY = glm::round((intersection.minimum.z - _colorBounds.minimum.z) / _colorExtension); + destWidth = glm::round((intersection.maximum.x - intersection.minimum.x) / _colorExtension); + destHeight = glm::round((intersection.maximum.z - intersection.minimum.z) / _colorExtension); + dest = _buffer->getColor().data() + (destY * _colorSize + destX) * HeightfieldData::COLOR_BYTES; + int destStride = _colorSize * HeightfieldData::COLOR_BYTES; + int destBytes = destWidth * HeightfieldData::COLOR_BYTES; + + const QByteArray& srcColor = color->getContents(); + srcSize = glm::sqrt(srcColor.size() / HeightfieldData::COLOR_BYTES); + int srcStride = srcSize * HeightfieldData::COLOR_BYTES; + srcExtension = info.size / srcSize; + + if (srcExtension == _colorExtension) { + // easy case: same resolution + int srcX = glm::round((intersection.minimum.x - info.minimum.x) / srcExtension); + int srcY = glm::round((intersection.minimum.z - info.minimum.z) / srcExtension); + + const char* src = srcColor.constData() + (srcY * srcSize + srcX) * HeightfieldData::COLOR_BYTES; + for (int y = 0; y < destHeight; y++, src += srcStride, dest += destStride) { + memcpy(dest, src, destBytes); + } + } else { + // more difficult: different resolutions + float srcX = (intersection.minimum.x - info.minimum.x) / srcExtension; + float srcY = (intersection.minimum.z - info.minimum.z) / srcExtension; + float srcIncrement = _colorExtension / srcExtension; + for (int y = 0; y < destHeight; y++, dest += destStride, srcY += srcIncrement) { + const char* src = srcColor.constData() + (int)srcY * srcStride; + float lineSrcX = srcX; + for (char* lineDest = dest, *end = dest + destBytes; lineDest != end; lineDest += HeightfieldData::COLOR_BYTES, + lineSrcX += srcIncrement) { + const char* lineSrc = src + (int)lineSrcX * HeightfieldData::COLOR_BYTES; + lineDest[0] = lineSrc[0]; + lineDest[1] = lineSrc[1]; + lineDest[2] = lineSrc[2]; + } + } + } + return STOP_RECURSION; } @@ -724,6 +848,8 @@ int HeightfieldAugmentVisitor::visit(MetavoxelInfo& info) { } } buffer = new HeightfieldBuffer(info.minimum, info.size, extendedHeightContents, extendedColorContents); + BorderFetchVisitor visitor(_lod, buffer); + _data->guide(visitor); } info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer))); return STOP_RECURSION; diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index a35155dbd6..1a86778b08 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -139,9 +139,10 @@ public: ~HeightfieldBuffer(); const glm::vec3& getTranslation() const { return _translation; } + float getScale() const { return _scale; } - const QByteArray& getHeight() const { return _height; } - const QByteArray& getColor() const { return _color; } + QByteArray& getHeight() { return _height; } + QByteArray& getColor() { return _color; } QByteArray getUnextendedHeight() const; QByteArray getUnextendedColor() const; diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index 2b46330961..4911c0e95f 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -182,6 +182,14 @@ bool Box::intersects(const Box& other) const { other.maximum.z >= minimum.z && other.minimum.z <= maximum.z; } +Box Box::getIntersection(const Box& other) const { + return Box(glm::max(minimum, other.minimum), glm::min(maximum, other.maximum)); +} + +bool Box::isEmpty() const { + return minimum.x >= maximum.x || minimum.y >= maximum.y || minimum.z >= maximum.z; +} + const int X_MAXIMUM_FLAG = 1; const int Y_MAXIMUM_FLAG = 2; const int Z_MAXIMUM_FLAG = 4; diff --git a/libraries/metavoxels/src/MetavoxelUtil.h b/libraries/metavoxels/src/MetavoxelUtil.h index 339c07a21e..2b63b81adc 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.h +++ b/libraries/metavoxels/src/MetavoxelUtil.h @@ -50,6 +50,10 @@ public: bool intersects(const Box& other) const; + Box getIntersection(const Box& other) const; + + bool isEmpty() const; + float getLongestSide() const { return qMax(qMax(maximum.x - minimum.x, maximum.y - minimum.y), maximum.z - minimum.z); } glm::vec3 getVertex(int index) const; From acda466c7656ed76a9ebca6029e100229c536f2a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Aug 2014 09:11:43 -0700 Subject: [PATCH 355/407] add atls as requirement for LibOVR --- cmake/modules/FindLibOVR.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/modules/FindLibOVR.cmake b/cmake/modules/FindLibOVR.cmake index 62ac572f2f..f950bdba58 100644 --- a/cmake/modules/FindLibOVR.cmake +++ b/cmake/modules/FindLibOVR.cmake @@ -64,6 +64,7 @@ elseif (UNIX) list(APPEND LIBOVR_LIBRARIES "${UDEV_LIBRARY}" "${XINERAMA_LIBRARY}") list(APPEND LIBOVR_ARGS_LIST UDEV_LIBRARY XINERAMA_LIBRARY) elseif (WIN32) + list(APPEND LIBOVR_LIRARIES "DEBUG atlsd.lib OPTIMIZED atls.lib") list(APPEND LIBOVR_LIBRARIES ws2_32.lib) endif () From 1ee58b7bd0355ef35b72278a6261fca08356f163 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Aug 2014 09:19:45 -0700 Subject: [PATCH 356/407] find the ATL library on windows for LibOVR --- cmake/modules/FindLibOVR.cmake | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmake/modules/FindLibOVR.cmake b/cmake/modules/FindLibOVR.cmake index f950bdba58..a1d75add3f 100644 --- a/cmake/modules/FindLibOVR.cmake +++ b/cmake/modules/FindLibOVR.cmake @@ -50,6 +50,7 @@ elseif (UNIX) elseif (WIN32) find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS}) find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS}) + find_package(ATL) endif () select_library_configurations(LIBOVR) @@ -64,8 +65,8 @@ elseif (UNIX) list(APPEND LIBOVR_LIBRARIES "${UDEV_LIBRARY}" "${XINERAMA_LIBRARY}") list(APPEND LIBOVR_ARGS_LIST UDEV_LIBRARY XINERAMA_LIBRARY) elseif (WIN32) - list(APPEND LIBOVR_LIRARIES "DEBUG atlsd.lib OPTIMIZED atls.lib") - list(APPEND LIBOVR_LIBRARIES ws2_32.lib) + list(APPEND LIBOVR_LIBRARIES ${ATL_LIBRARIES}) + list(APPEND LIBOVR_ARGS_LIST ATL_LIBRARIES) endif () include(FindPackageHandleStandardArgs) From 83952cb85cf42020bb0330fbf10e496f943d1405 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Aug 2014 09:22:07 -0700 Subject: [PATCH 357/407] add the FindATL cmake module --- cmake/modules/FindATL.cmake | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 cmake/modules/FindATL.cmake diff --git a/cmake/modules/FindATL.cmake b/cmake/modules/FindATL.cmake new file mode 100644 index 0000000000..f3affbb49e --- /dev/null +++ b/cmake/modules/FindATL.cmake @@ -0,0 +1,29 @@ +# +# FindATL.cmake +# +# Try to find the ATL library needed to use the LibOVR +# +# Once done this will define +# +# ATL_FOUND - system found ATL +# ATL_LIBRARIES - Link this to use ATL +# +# Created on 8/13/2013 by Stephen Birarda +# 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 +# + +if (WIN32) + find_library(ATL_LIBRARY_RELEASE atl PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS "C:\\WinDDK") + find_library(ATL_LIBRARY_DEBUG atld PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS "C:\\WinDDK") + + include(SelectLibraryConfigurations) + select_library_configurations(ATL) +endif () + +set(ATL_LIBRARIES "${ATL_LIBRARY}") + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(ATL DEFAULT_MSG ATL_LIBRARIES) \ No newline at end of file From da7f3d18e4cc04e7ed16a5da0df1c3a1b5d6b7b9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Aug 2014 09:27:44 -0700 Subject: [PATCH 358/407] require QXMPP_LIBRARY to be found for FindQXMPP to succeed --- cmake/modules/FindQxmpp.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/FindQxmpp.cmake b/cmake/modules/FindQxmpp.cmake index 8d8c0e22a2..8fbc63e9dc 100644 --- a/cmake/modules/FindQxmpp.cmake +++ b/cmake/modules/FindQxmpp.cmake @@ -34,6 +34,6 @@ select_library_configurations(QXMPP) set(QXMPP_LIBRARIES "${QXMPP_LIBRARY}" Qt5::Xml) include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(QXmpp DEFAULT_MSG QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES) +find_package_handle_standard_args(QXmpp DEFAULT_MSG QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES QXMPP_LIBRARY) mark_as_advanced(QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES QXMPP_SEARCH_DIRS) \ No newline at end of file From b055e07d72fa62375d3f70ab58f140101029cd9b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Aug 2014 09:29:49 -0700 Subject: [PATCH 359/407] look for atls not atl in FindATL --- cmake/modules/FindATL.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/modules/FindATL.cmake b/cmake/modules/FindATL.cmake index f3affbb49e..f95b0267eb 100644 --- a/cmake/modules/FindATL.cmake +++ b/cmake/modules/FindATL.cmake @@ -16,8 +16,8 @@ # if (WIN32) - find_library(ATL_LIBRARY_RELEASE atl PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS "C:\\WinDDK") - find_library(ATL_LIBRARY_DEBUG atld PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS "C:\\WinDDK") + find_library(ATL_LIBRARY_RELEASE atls PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS "C:\\WinDDK") + find_library(ATL_LIBRARY_DEBUG atlsd PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS "C:\\WinDDK") include(SelectLibraryConfigurations) select_library_configurations(ATL) From 8c913fe8c1a899677d947c3385d2fb6bae5f1364 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 13 Aug 2014 10:23:59 -0700 Subject: [PATCH 360/407] Add progress dialog and ability to cancel during the model upload --- examples/editModels.js | 262 +++++++++++++++++++++++++++++++++-------- 1 file changed, 216 insertions(+), 46 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index b606567ca6..dbae4fd08c 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -175,6 +175,140 @@ if (typeof DataView.prototype.string !== "function") { }; } +var progressDialog = (function () { + var that = {}, + progressBackground, + progressMessage, + cancelButton, + displayed = false, + backgroundWidth = 300, + backgroundHeight = 100, + messageHeight = 32, + cancelWidth = 70, + cancelHeight = 32, + textColor = { red: 255, green: 255, blue: 255 }, + textBackground = { red: 52, green: 52, blue: 52 }, + backgroundUrl = "http://ctrlaltstudio.com/hifi/progress-background.svg", // DJRTODO: Update with HiFi location. + //backgroundUrl = "http://public.highfidelity.io/images/tools/progress-background.svg", + windowDimensions; + + progressBackground = Overlays.addOverlay("image", { + width: backgroundWidth, + height: backgroundHeight, + imageURL: backgroundUrl, + alpha: 0.9, + visible: false + }); + + progressMessage = Overlays.addOverlay("text", { + width: backgroundWidth - 40, + height: messageHeight, + text: "", + textColor: textColor, + backgroundColor: textBackground, + alpha: 0.9, + visible: false + }); + + cancelButton = Overlays.addOverlay("text", { + width: cancelWidth, + height: cancelHeight, + text: "Cancel", + textColor: textColor, + backgroundColor: textBackground, + alpha: 0.9, + visible: false + }); + + function move() { + var progressX, + progressY; + + if (displayed) { + + if (windowDimensions.x === Window.innerWidth && windowDimensions.y === Window.innerHeight) { + return; + } + windowDimensions.x = Window.innerWidth; + windowDimensions.y = Window.innerHeight; + + progressX = (windowDimensions.x - backgroundWidth) / 2; // Center. + progressY = windowDimensions.y / 2 - backgroundHeight; // A little up from center. + + Overlays.editOverlay(progressBackground, { x: progressX, y: progressY }); + Overlays.editOverlay(progressMessage, { x: progressX + 20, y: progressY + 15 }); + Overlays.editOverlay(cancelButton, { + x: progressX + backgroundWidth - cancelWidth - 20, + y: progressY + backgroundHeight - cancelHeight - 15 + }); + } + } + that.move = move; + + that.onCancel = undefined; + + function open(message) { + if (!displayed) { + windowDimensions = { x: 0, y : 0 }; + displayed = true; + move(); + Overlays.editOverlay(progressBackground, { visible: true }); + Overlays.editOverlay(progressMessage, { visible: true, text: message }); + Overlays.editOverlay(cancelButton, { visible: true }); + } else { + throw new Error("open() called on progressDialog when already open"); + } + } + that.open = open; + + function isOpen() { + return displayed; + } + that.isOpen = isOpen; + + function update(message) { + if (displayed) { + Overlays.editOverlay(progressMessage, { text: message }); + } else { + throw new Error("update() called on progressDialog when not open"); + } + } + that.update = update; + + function close() { + if (displayed) { + Overlays.editOverlay(cancelButton, { visible: false }); + Overlays.editOverlay(progressMessage, { visible: false }); + Overlays.editOverlay(progressBackground, { visible: false }); + displayed = false; + } else { + throw new Error("close() called on progressDialog when not open"); + } + } + that.close = close; + + function mousePressEvent(event) { + if (Overlays.getOverlayAtPoint({ x: event.x, y: event.y }) === cancelButton) { + if (typeof this.onCancel === "function") { + close(); + this.onCancel(); + } + return true; + } + return false; + } + that.mousePressEvent = mousePressEvent; + + function cleanup() { + Overlays.deleteOverlay(cancelButton); + Overlays.deleteOverlay(progressMessage); + Overlays.deleteOverlay(progressBackground); + } + that.cleanup = cleanup; + + return that; +}()); + var httpMultiPart = (function () { var that = {}, parts, @@ -287,6 +421,10 @@ var httpMultiPart = (function () { var modelUploader = (function () { var that = {}, modelFile, + modelName, + modelURL, + modelCallback, + isProcessing, fstBuffer, fbxBuffer, //svoBuffer, @@ -300,7 +438,19 @@ var modelUploader = (function () { TEXDIR_FIELD = "texdir", MAX_TEXTURE_SIZE = 1024; + function info(message) { + if (progressDialog.isOpen()) { + progressDialog.update(message); + } else { + progressDialog.open(message); + } + print(message); + } + function error(message) { + if (progressDialog.isOpen()) { + progressDialog.close(); + } print(message); Window.alert(message); } @@ -523,7 +673,8 @@ var modelUploader = (function () { //svoFilename, fileType; - print("Reading model file: " + modelFile); + info("Reading model file"); + print("Model file: " + modelFile); if (modelFile.toLowerCase().fileType() === "fst") { fstBuffer = readFile(modelFile); @@ -565,12 +716,16 @@ var modelUploader = (function () { } } + if (!isProcessing) { return false; } + if (fbxFilename) { fbxBuffer = readFile(fbxFilename); if (fbxBuffer === null) { return false; } + if (!isProcessing) { return false; } + readGeometry(fbxBuffer); } @@ -601,6 +756,7 @@ var modelUploader = (function () { displayAs, validateAs; + progressDialog.close(); print("Setting model properties"); form.push({ label: "Name:", value: mapping[NAME_FIELD] }); @@ -636,8 +792,9 @@ var modelUploader = (function () { return true; } - function createHttpMessage() { - var lodCount, + function createHttpMessage(callback) { + var multiparts = [], + lodCount, lodFile, lodBuffer, textureBuffer, @@ -645,25 +802,23 @@ var modelUploader = (function () { textureTargetFormat, i; - print("Preparing to send model"); - - httpMultiPart.clear(); + info("Preparing to send model"); // Model name if (mapping.hasOwnProperty(NAME_FIELD)) { - httpMultiPart.add({ + multiparts.push({ name : "model_name", string : mapping[NAME_FIELD] }); } else { error("Model name is missing"); httpMultiPart.clear(); - return false; + return; } // FST file if (fstBuffer) { - httpMultiPart.add({ + multiparts.push({ name : "fst", buffer: fstBuffer }); @@ -671,7 +826,7 @@ var modelUploader = (function () { // FBX file if (fbxBuffer) { - httpMultiPart.add({ + multiparts.push({ name : "fbx", buffer: fbxBuffer }); @@ -679,7 +834,7 @@ var modelUploader = (function () { // SVO file //if (svoBuffer) { - // httpMultiPart.add({ + // multiparts.push({ // name : "svo", // buffer: svoBuffer // }); @@ -691,14 +846,15 @@ var modelUploader = (function () { if (mapping.lod.hasOwnProperty(lodFile)) { lodBuffer = readFile(modelFile.path() + "\/" + lodFile); if (lodBuffer === null) { - return false; + return; } - httpMultiPart.add({ + multiparts.push({ name: "lod" + lodCount, buffer: lodBuffer }); lodCount += 1; } + if (!isProcessing) { return; } } // Textures @@ -707,7 +863,7 @@ var modelUploader = (function () { + (mapping[TEXDIR_FIELD] !== "." ? mapping[TEXDIR_FIELD] + "\/" : "") + geometry.textures[i]); if (textureBuffer === null) { - return false; + return; } textureSourceFormat = geometry.textures[i].fileType().toLowerCase(); @@ -715,25 +871,37 @@ var modelUploader = (function () { textureBuffer.buffer = textureBuffer.buffer.recodeImage(textureSourceFormat, textureTargetFormat, MAX_TEXTURE_SIZE); textureBuffer.filename = textureBuffer.filename.slice(0, -textureSourceFormat.length) + textureTargetFormat; - httpMultiPart.add({ + multiparts.push({ name: "texture" + i, buffer: textureBuffer }); + if (!isProcessing) { return; } } // Model category - httpMultiPart.add({ + multiparts.push({ name : "model_category", string : "content" }); - return true; + // Create HTTP message + httpMultiPart.clear(); + Script.setTimeout(function addMultipart() { + var multipart = multiparts.shift(); + httpMultiPart.add(multipart); + + if (!isProcessing) { return; } + + if (multiparts.length > 0) { + Script.setTimeout(addMultipart, 25); + } else { + callback(); + } + }, 25); } - function sendToHighFidelity(addModelCallback) { + function sendToHighFidelity() { var req, - modelName, - modelURL, uploadedChecks, HTTP_GET_TIMEOUT = 60, // 1 minute HTTP_SEND_TIMEOUT = 900, // 15 minutes @@ -759,7 +927,9 @@ var modelUploader = (function () { //} function checkUploaded() { - print("Checking uploaded model"); + if (!isProcessing) { return; } + + info("Checking uploaded model"); req = new XMLHttpRequest(); req.open("HEAD", modelURL, true); @@ -775,8 +945,9 @@ var modelUploader = (function () { if (req.status === 200) { // Note: Unlike avatar models, for content models we don't need to refresh texture cache. print("Model uploaded: " + modelURL); + progressDialog.close(); if (Window.confirm("Your model has been uploaded as: " + modelURL + "\nDo you want to rez it?")) { - addModelCallback(modelURL); + modelCallback(modelURL); } } else if (req.status === 404) { if (uploadedChecks > 0) { @@ -797,6 +968,8 @@ var modelUploader = (function () { function uploadModel(method) { var url; + if (!isProcessing) { return; } + req = new XMLHttpRequest(); if (method === "PUT") { url = API_URL + "\/" + modelName; @@ -828,6 +1001,8 @@ var modelUploader = (function () { function requestUpload() { var url; + if (!isProcessing) { return; } + url = API_URL + "\/" + modelName; // XMLHttpRequest automatically handles authorization of API requests. req = new XMLHttpRequest(); req.open("GET", url, true); //print("GET " + url); @@ -864,41 +1039,34 @@ var modelUploader = (function () { } }; - print("Sending model to High Fidelity"); - - modelName = mapping[NAME_FIELD]; - modelURL = MODEL_URL + "\/" + mapping[NAME_FIELD] + ".fst"; // All models are uploaded as an FST + info("Sending model to High Fidelity"); requestUpload(); } - that.upload = function (file, addModelCallback) { + that.upload = function (file, callback) { modelFile = file; + modelCallback = callback; + + isProcessing = true; + + progressDialog.onCancel = function () { + print("User cancelled uploading model"); + isProcessing = false; + }; resetDataObjects(); - // Read model content ... - if (!readModel()) { - resetDataObjects(); - return; - } + if (readModel()) { + if (setProperties()) { + modelName = mapping[NAME_FIELD]; + modelURL = MODEL_URL + "\/" + mapping[NAME_FIELD] + ".fst"; // All models are uploaded as an FST - // Set model properties ... - if (!setProperties()) { - resetDataObjects(); - return; + createHttpMessage(sendToHighFidelity); + } } - // Put model in HTTP message ... - if (!createHttpMessage()) { - resetDataObjects(); - return; - } - - // Send model to High Fidelity ... - sendToHighFidelity(addModelCallback); - resetDataObjects(); }; @@ -2107,6 +2275,7 @@ function checkController(deltaTime) { } toolBar.move(); + progressDialog.move(); } var modelSelected = false; @@ -2190,7 +2359,7 @@ function mousePressEvent(event) { modelSelected = false; var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); - if (toolBar.mousePressEvent(event)) { + if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) { // Event handled; do nothing. return; } else { @@ -2484,6 +2653,7 @@ function cleanupModelMenus() { function scriptEnding() { leftController.cleanup(); rightController.cleanup(); + progressDialog.cleanup(); toolBar.cleanup(); cleanupModelMenus(); tooltip.cleanup(); From 56c6c3c972b50d053ad7b14939d78c7217ec059e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 13 Aug 2014 11:05:48 -0700 Subject: [PATCH 361/407] Working on the height/ray queries. --- interface/src/MetavoxelSystem.cpp | 268 +++++++++++++++++- interface/src/MetavoxelSystem.h | 7 + interface/src/ui/MetavoxelEditor.cpp | 11 +- .../metavoxels/src/MetavoxelClientManager.cpp | 252 ---------------- .../metavoxels/src/MetavoxelClientManager.h | 4 - 5 files changed, 283 insertions(+), 259 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 067c1984c6..238eda8784 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -118,6 +118,267 @@ void MetavoxelSystem::render() { guideToAugmented(renderVisitor); } +class RayHeightfieldIntersectionVisitor : public RayIntersectionVisitor { +public: + + float intersectionDistance; + + RayHeightfieldIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, const MetavoxelLOD& lod); + + virtual int visit(MetavoxelInfo& info, float distance); +}; + +RayHeightfieldIntersectionVisitor::RayHeightfieldIntersectionVisitor(const glm::vec3& origin, + const glm::vec3& direction, const MetavoxelLOD& lod) : + RayIntersectionVisitor(origin, direction, QVector() << + Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector(), lod), + intersectionDistance(FLT_MAX) { +} + +static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / 255.0f; +static const int HEIGHT_BORDER = 1; + +int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance) { + if (!info.isLeaf) { + return _order; + } + const HeightfieldBuffer* buffer = static_cast( + info.inputValues.at(0).getInlineValue().data()); + if (!buffer) { + return STOP_RECURSION; + } + const QByteArray& contents = buffer->getHeight(); + const uchar* src = (const uchar*)contents.constData(); + int size = glm::sqrt((float)contents.size()); + int unextendedSize = size - HeightfieldBuffer::HEIGHT_EXTENSION; + int highest = HEIGHT_BORDER + unextendedSize; + float heightScale = unextendedSize * EIGHT_BIT_MAXIMUM_RECIPROCAL; + + // find the initial location in heightfield coordinates + glm::vec3 entry = (_origin + distance * _direction - info.minimum + glm::vec3(HEIGHT_BORDER, 0.0f, HEIGHT_BORDER)) * + (float)unextendedSize / info.size; + glm::vec3 floors = glm::floor(entry); + glm::vec3 ceils = glm::ceil(entry); + if (floors.x == ceils.x) { + if (_direction.x > 0.0f) { + ceils.x += 1.0f; + } else { + floors.x -= 1.0f; + } + } + if (floors.z == ceils.z) { + if (_direction.z > 0.0f) { + ceils.z += 1.0f; + } else { + floors.z -= 1.0f; + } + } + + bool withinBounds = true; + float accumulatedDistance = 0.0f; + while (withinBounds) { + // find the heights at the corners of the current cell + int floorX = qMin(qMax((int)floors.x, HEIGHT_BORDER), highest); + int floorZ = qMin(qMax((int)floors.z, HEIGHT_BORDER), highest); + int ceilX = qMin(qMax((int)ceils.x, HEIGHT_BORDER), highest); + int ceilZ = qMin(qMax((int)ceils.z, HEIGHT_BORDER), highest); + float upperLeft = src[floorZ * size + floorX] * heightScale; + float upperRight = src[floorZ * size + ceilX] * heightScale; + float lowerLeft = src[ceilZ * size + floorX] * heightScale; + float lowerRight = src[ceilZ * size + ceilX] * heightScale; + + // find the distance to the next x coordinate + float xDistance = FLT_MAX; + if (_direction.x > 0.0f) { + xDistance = (ceils.x - entry.x) / _direction.x; + } else if (_direction.x < 0.0f) { + xDistance = (floors.x - entry.x) / _direction.x; + } + + // and the distance to the next z coordinate + float zDistance = FLT_MAX; + if (_direction.z > 0.0f) { + zDistance = (ceils.z - entry.z) / _direction.z; + } else if (_direction.z < 0.0f) { + zDistance = (floors.z - entry.z) / _direction.z; + } + + // the exit distance is the lower of those two + float exitDistance = qMin(xDistance, zDistance); + glm::vec3 exit, nextFloors = floors, nextCeils = ceils; + if (exitDistance == FLT_MAX) { + if (_direction.y > 0.0f) { + return SHORT_CIRCUIT; // line points upwards; no collisions possible + } + withinBounds = false; // line points downwards; check this cell only + + } else { + // find the exit point and the next cell, and determine whether it's still within the bounds + exit = entry + exitDistance * _direction; + withinBounds = (exit.y >= HEIGHT_BORDER && exit.y <= highest); + if (exitDistance == xDistance) { + if (_direction.x > 0.0f) { + nextFloors.x += 1.0f; + withinBounds &= (nextCeils.x += 1.0f) <= highest; + } else { + withinBounds &= (nextFloors.x -= 1.0f) >= HEIGHT_BORDER; + nextCeils.x -= 1.0f; + } + } + if (exitDistance == zDistance) { + if (_direction.z > 0.0f) { + nextFloors.z += 1.0f; + withinBounds &= (nextCeils.z += 1.0f) <= highest; + } else { + withinBounds &= (nextFloors.z -= 1.0f) >= HEIGHT_BORDER; + nextCeils.z -= 1.0f; + } + } + // check the vertical range of the ray against the ranges of the cell heights + if (qMin(entry.y, exit.y) > qMax(qMax(upperLeft, upperRight), qMax(lowerLeft, lowerRight)) || + qMax(entry.y, exit.y) < qMin(qMin(upperLeft, upperRight), qMin(lowerLeft, lowerRight))) { + entry = exit; + floors = nextFloors; + ceils = nextCeils; + accumulatedDistance += exitDistance; + continue; + } + } + // having passed the bounds check, we must check against the planes + glm::vec3 relativeEntry = entry - glm::vec3(floors.x, upperLeft, floors.z); + + // first check the triangle including the Z+ segment + glm::vec3 lowerNormal(lowerLeft - lowerRight, 1.0f, upperLeft - lowerLeft); + float lowerProduct = glm::dot(lowerNormal, _direction); + if (lowerProduct < 0.0f) { + float planeDistance = -glm::dot(lowerNormal, relativeEntry) / lowerProduct; + glm::vec3 intersection = relativeEntry + planeDistance * _direction; + if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && + intersection.z >= intersection.x) { + intersectionDistance = qMin(intersectionDistance, distance + + (accumulatedDistance + planeDistance) * (info.size / unextendedSize)); + return SHORT_CIRCUIT; + } + } + + // then the one with the X+ segment + glm::vec3 upperNormal(upperLeft - upperRight, 1.0f, upperRight - lowerRight); + float upperProduct = glm::dot(upperNormal, _direction); + if (upperProduct < 0.0f) { + float planeDistance = -glm::dot(upperNormal, relativeEntry) / upperProduct; + glm::vec3 intersection = relativeEntry + planeDistance * _direction; + if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && + intersection.x >= intersection.z) { + intersectionDistance = qMin(intersectionDistance, distance + + (accumulatedDistance + planeDistance) * (info.size / unextendedSize)); + return SHORT_CIRCUIT; + } + } + + // no joy; continue on our way + entry = exit; + floors = nextFloors; + ceils = nextCeils; + accumulatedDistance += exitDistance; + } + + return STOP_RECURSION; +} + +bool MetavoxelSystem::findFirstRayHeightfieldIntersection(const glm::vec3& origin, + const glm::vec3& direction, float& distance) { + RayHeightfieldIntersectionVisitor visitor(origin, direction, getLOD()); + guideToAugmented(visitor); + if (visitor.intersectionDistance == FLT_MAX) { + return false; + } + distance = visitor.intersectionDistance; + return true; +} + +class HeightfieldHeightVisitor : public MetavoxelVisitor { +public: + + float height; + + HeightfieldHeightVisitor(const MetavoxelLOD& lod, const glm::vec3& location); + + virtual int visit(MetavoxelInfo& info); + +private: + + glm::vec3 _location; +}; + +HeightfieldHeightVisitor::HeightfieldHeightVisitor(const MetavoxelLOD& lod, const glm::vec3& location) : + MetavoxelVisitor(QVector() << + Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector(), lod), + height(-FLT_MAX), + _location(location) { +} + +static const int REVERSE_ORDER = MetavoxelVisitor::encodeOrder(7, 6, 5, 4, 3, 2, 1, 0); + +int HeightfieldHeightVisitor::visit(MetavoxelInfo& info) { + glm::vec3 relative = _location - info.minimum; + if (relative.x < 0.0f || relative.z < 0.0f || relative.x > info.size || relative.z > info.size || + height >= info.minimum.y + info.size) { + return STOP_RECURSION; + } + if (!info.isLeaf) { + return REVERSE_ORDER; + } + const HeightfieldBuffer* buffer = static_cast( + info.inputValues.at(0).getInlineValue().data()); + if (!buffer) { + return STOP_RECURSION; + } + const QByteArray& contents = buffer->getHeight(); + const uchar* src = (const uchar*)contents.constData(); + int size = glm::sqrt((float)contents.size()); + int unextendedSize = size - HeightfieldBuffer::HEIGHT_EXTENSION; + int highest = HEIGHT_BORDER + unextendedSize; + relative *= unextendedSize / info.size; + relative.x += HEIGHT_BORDER; + relative.z += HEIGHT_BORDER; + + // find the bounds of the cell containing the point and the shared vertex heights + glm::vec3 floors = glm::floor(relative); + glm::vec3 ceils = glm::ceil(relative); + glm::vec3 fracts = glm::fract(relative); + int floorX = qMin(qMax((int)floors.x, HEIGHT_BORDER), highest); + int floorZ = qMin(qMax((int)floors.z, HEIGHT_BORDER), highest); + int ceilX = qMin(qMax((int)ceils.x, HEIGHT_BORDER), highest); + int ceilZ = qMin(qMax((int)ceils.z, HEIGHT_BORDER), highest); + float upperLeft = src[floorZ * size + floorX]; + float lowerRight = src[ceilZ * size + ceilX]; + float interpolatedHeight = glm::mix(upperLeft, lowerRight, fracts.z); + + // the final vertex (and thus which triangle we check) depends on which half we're on + if (fracts.x >= fracts.z) { + float upperRight = src[floorZ * size + ceilX]; + interpolatedHeight = glm::mix(interpolatedHeight, glm::mix(upperRight, lowerRight, fracts.z), + (fracts.x - fracts.z) / (1.0f - fracts.z)); + + } else { + float lowerLeft = src[ceilZ * size + floorX]; + interpolatedHeight = glm::mix(glm::mix(upperLeft, lowerLeft, fracts.z), interpolatedHeight, fracts.x / fracts.z); + } + if (interpolatedHeight == 0.0f) { + return STOP_RECURSION; // ignore zero values + } + + // convert the interpolated height into world space + height = qMax(height, info.minimum.y + interpolatedHeight * info.size * EIGHT_BIT_MAXIMUM_RECIPROCAL); + return SHORT_CIRCUIT; +} + +float MetavoxelSystem::getHeightfieldHeight(const glm::vec3& location) { + HeightfieldHeightVisitor visitor(getLOD(), location); + guideToAugmented(visitor); + return visitor.height; +} + class HeightfieldCursorRenderVisitor : public MetavoxelVisitor { public: @@ -416,7 +677,7 @@ void HeightfieldBuffer::render(bool cursor) { int innerSize = _heightSize - 2 * HeightfieldBuffer::HEIGHT_BORDER; int vertexCount = _heightSize * _heightSize; int rows = _heightSize - 1; - int indexCount = rows * rows * 4; + int indexCount = rows * rows * 3 * 2; BufferPair& bufferPair = _bufferPairs[_heightSize]; if (!bufferPair.first.isCreated()) { QVector vertices(vertexCount); @@ -450,8 +711,11 @@ void HeightfieldBuffer::render(bool cursor) { for (int j = 0; j < rows; j++) { *index++ = lineIndex + j; *index++ = nextLineIndex + j; + *index++ = nextLineIndex + j + 1; + *index++ = nextLineIndex + j + 1; *index++ = lineIndex + j + 1; + *index++ = lineIndex + j; } } @@ -484,7 +748,7 @@ void HeightfieldBuffer::render(bool cursor) { glBindTexture(GL_TEXTURE_2D, _colorTextureID); } - glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); + glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); if (!cursor) { glBindTexture(GL_TEXTURE_2D, 0); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 1a86778b08..fb18d4f402 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -45,6 +45,10 @@ public: void renderHeightfieldCursor(const glm::vec3& position, float radius); + bool findFirstRayHeightfieldIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance); + + Q_INVOKABLE float getHeightfieldHeight(const glm::vec3& location); + Q_INVOKABLE void deleteTextures(int heightID, int colorID); protected: @@ -142,7 +146,10 @@ public: float getScale() const { return _scale; } QByteArray& getHeight() { return _height; } + const QByteArray& getHeight() const { return _height; } + QByteArray& getColor() { return _color; } + const QByteArray& getColor() const { return _color; } QByteArray getUnextendedHeight() const; QByteArray getUnextendedColor() const; diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index b7057532fb..7c5e84132b 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -1101,7 +1101,7 @@ HeightfieldBrushTool::HeightfieldBrushTool(MetavoxelEditor* editor, const QStrin } void HeightfieldBrushTool::render() { - if (Application::getInstance()->isMouseHidden()) { + if (Application::getInstance()->isMouseHidden() && false) { return; } @@ -1115,6 +1115,15 @@ void HeightfieldBrushTool::render() { } Application::getInstance()->getMetavoxels()->renderHeightfieldCursor( _position = origin + distance * direction, _radius->value()); + + glPushMatrix(); + glTranslatef(_position.x, _position.y, _position.z); + + glColor4f(1.0f, 0.0f, 0.0f, 1.0f); + + glutSolidSphere(1.0f, 10, 10); + + glPopMatrix(); } bool HeightfieldBrushTool::eventFilter(QObject* watched, QEvent* event) { diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index 70b574d2a2..a2d3410314 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -61,180 +61,6 @@ SharedObjectPointer MetavoxelClientManager::findFirstRaySpannerIntersection(cons return closestSpanner; } -class RayHeightfieldIntersectionVisitor : public RayIntersectionVisitor { -public: - - float intersectionDistance; - - RayHeightfieldIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, const MetavoxelLOD& lod); - - virtual int visit(MetavoxelInfo& info, float distance); -}; - -RayHeightfieldIntersectionVisitor::RayHeightfieldIntersectionVisitor(const glm::vec3& origin, - const glm::vec3& direction, const MetavoxelLOD& lod) : - RayIntersectionVisitor(origin, direction, QVector() << - AttributeRegistry::getInstance()->getHeightfieldAttribute(), QVector(), lod), - intersectionDistance(FLT_MAX) { -} - -static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / 255.0f; - -int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance) { - if (!info.isLeaf) { - return _order; - } - HeightfieldDataPointer pointer = info.inputValues.at(0).getInlineValue(); - if (!pointer) { - return STOP_RECURSION; - } - const QByteArray& contents = pointer->getContents(); - const uchar* src = (const uchar*)contents.constData(); - int size = glm::sqrt((float)contents.size()); - int highest = size - 1; - float heightScale = highest * EIGHT_BIT_MAXIMUM_RECIPROCAL; - - // find the initial location in heightfield coordinates - glm::vec3 entry = (_origin + distance * _direction - info.minimum) * (float)highest / info.size; - glm::vec3 floors = glm::floor(entry); - glm::vec3 ceils = glm::ceil(entry); - if (floors.x == ceils.x) { - if (_direction.x > 0.0f) { - ceils.x += 1.0f; - } else { - floors.x -= 1.0f; - } - } - if (floors.z == ceils.z) { - if (_direction.z > 0.0f) { - ceils.z += 1.0f; - } else { - floors.z -= 1.0f; - } - } - - bool withinBounds = true; - float accumulatedDistance = 0.0f; - while (withinBounds) { - // find the heights at the corners of the current cell - int floorX = qMin(qMax((int)floors.x, 0), highest); - int floorZ = qMin(qMax((int)floors.z, 0), highest); - int ceilX = qMin(qMax((int)ceils.x, 0), highest); - int ceilZ = qMin(qMax((int)ceils.z, 0), highest); - float upperLeft = src[floorZ * size + floorX] * heightScale; - float upperRight = src[floorZ * size + ceilX] * heightScale; - float lowerLeft = src[ceilZ * size + floorX] * heightScale; - float lowerRight = src[ceilZ * size + ceilX] * heightScale; - - // find the distance to the next x coordinate - float xDistance = FLT_MAX; - if (_direction.x > 0.0f) { - xDistance = (ceils.x - entry.x) / _direction.x; - } else if (_direction.x < 0.0f) { - xDistance = (floors.x - entry.x) / _direction.x; - } - - // and the distance to the next z coordinate - float zDistance = FLT_MAX; - if (_direction.z > 0.0f) { - zDistance = (ceils.z - entry.z) / _direction.z; - } else if (_direction.z < 0.0f) { - zDistance = (floors.z - entry.z) / _direction.z; - } - - // the exit distance is the lower of those two - float exitDistance = qMin(xDistance, zDistance); - glm::vec3 exit, nextFloors = floors, nextCeils = ceils; - if (exitDistance == FLT_MAX) { - if (_direction.y > 0.0f) { - return SHORT_CIRCUIT; // line points upwards; no collisions possible - } - withinBounds = false; // line points downwards; check this cell only - - } else { - // find the exit point and the next cell, and determine whether it's still within the bounds - exit = entry + exitDistance * _direction; - withinBounds = (exit.y >= 0.0f && exit.y <= highest); - if (exitDistance == xDistance) { - if (_direction.x > 0.0f) { - nextFloors.x += 1.0f; - withinBounds &= (nextCeils.x += 1.0f) <= highest; - } else { - withinBounds &= (nextFloors.x -= 1.0f) >= 0.0f; - nextCeils.x -= 1.0f; - } - } - if (exitDistance == zDistance) { - if (_direction.z > 0.0f) { - nextFloors.z += 1.0f; - withinBounds &= (nextCeils.z += 1.0f) <= highest; - } else { - withinBounds &= (nextFloors.z -= 1.0f) >= 0.0f; - nextCeils.z -= 1.0f; - } - } - // check the vertical range of the ray against the ranges of the cell heights - if (qMin(entry.y, exit.y) > qMax(qMax(upperLeft, upperRight), qMax(lowerLeft, lowerRight)) || - qMax(entry.y, exit.y) < qMin(qMin(upperLeft, upperRight), qMin(lowerLeft, lowerRight))) { - entry = exit; - floors = nextFloors; - ceils = nextCeils; - accumulatedDistance += exitDistance; - continue; - } - } - // having passed the bounds check, we must check against the planes - glm::vec3 relativeEntry = entry - glm::vec3(floors.x, upperLeft, floors.z); - - // first check the triangle including the Z+ segment - glm::vec3 lowerNormal(lowerLeft - lowerRight, 1.0f, upperLeft - lowerLeft); - float lowerProduct = glm::dot(lowerNormal, _direction); - if (lowerProduct < 0.0f) { - float planeDistance = -glm::dot(lowerNormal, relativeEntry) / lowerProduct; - glm::vec3 intersection = relativeEntry + planeDistance * _direction; - if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && - intersection.z >= intersection.x) { - intersectionDistance = qMin(intersectionDistance, distance + - (accumulatedDistance + planeDistance) * (info.size / highest)); - return SHORT_CIRCUIT; - } - } - - // then the one with the X+ segment - glm::vec3 upperNormal(upperLeft - upperRight, 1.0f, upperRight - lowerRight); - float upperProduct = glm::dot(upperNormal, _direction); - if (upperProduct < 0.0f) { - float planeDistance = -glm::dot(upperNormal, relativeEntry) / upperProduct; - glm::vec3 intersection = relativeEntry + planeDistance * _direction; - if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && - intersection.x >= intersection.z) { - intersectionDistance = qMin(intersectionDistance, distance + - (accumulatedDistance + planeDistance) * (info.size / highest)); - return SHORT_CIRCUIT; - } - } - - // no joy; continue on our way - entry = exit; - floors = nextFloors; - ceils = nextCeils; - accumulatedDistance += exitDistance; - } - - return STOP_RECURSION; -} - -bool MetavoxelClientManager::findFirstRayHeightfieldIntersection(const glm::vec3& origin, - const glm::vec3& direction, float& distance) { - RayHeightfieldIntersectionVisitor visitor(origin, direction, getLOD()); - guide(visitor); - if (visitor.intersectionDistance == FLT_MAX) { - return false; - } - distance = visitor.intersectionDistance; - return true; -} - void MetavoxelClientManager::setSphere(const glm::vec3& center, float radius, const QColor& color) { Sphere* sphere = new Sphere(); sphere->setTranslation(center); @@ -252,84 +78,6 @@ void MetavoxelClientManager::applyEdit(const MetavoxelEditMessage& edit, bool re QMetaObject::invokeMethod(_updater, "applyEdit", Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, reliable)); } -class HeightfieldHeightVisitor : public MetavoxelVisitor { -public: - - float height; - - HeightfieldHeightVisitor(const MetavoxelLOD& lod, const glm::vec3& location); - - virtual int visit(MetavoxelInfo& info); - -private: - - glm::vec3 _location; -}; - -HeightfieldHeightVisitor::HeightfieldHeightVisitor(const MetavoxelLOD& lod, const glm::vec3& location) : - MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getHeightfieldAttribute(), - QVector(), lod), - height(-FLT_MAX), - _location(location) { -} - -static const int REVERSE_ORDER = MetavoxelVisitor::encodeOrder(7, 6, 5, 4, 3, 2, 1, 0); - -int HeightfieldHeightVisitor::visit(MetavoxelInfo& info) { - glm::vec3 relative = _location - info.minimum; - if (relative.x < 0.0f || relative.z < 0.0f || relative.x > info.size || relative.z > info.size || - height >= info.minimum.y + info.size) { - return STOP_RECURSION; - } - if (!info.isLeaf) { - return REVERSE_ORDER; - } - HeightfieldDataPointer pointer = info.inputValues.at(0).getInlineValue(); - if (!pointer) { - return STOP_RECURSION; - } - const QByteArray& contents = pointer->getContents(); - const uchar* src = (const uchar*)contents.constData(); - int size = glm::sqrt((float)contents.size()); - int highest = size - 1; - relative *= highest / info.size; - - // find the bounds of the cell containing the point and the shared vertex heights - glm::vec3 floors = glm::floor(relative); - glm::vec3 ceils = glm::ceil(relative); - glm::vec3 fracts = glm::fract(relative); - int floorX = qMin(qMax((int)floors.x, 0), highest); - int floorZ = qMin(qMax((int)floors.z, 0), highest); - int ceilX = qMin(qMax((int)ceils.x, 0), highest); - int ceilZ = qMin(qMax((int)ceils.z, 0), highest); - float upperLeft = src[floorZ * size + floorX]; - float lowerRight = src[ceilZ * size + ceilX]; - float interpolatedHeight; - - // the final vertex (and thus which triangle we check) depends on which half we're on - if (fracts.x > fracts.z) { - float upperRight = src[floorZ * size + ceilX]; - interpolatedHeight = glm::mix(glm::mix(upperLeft, upperRight, fracts.x), lowerRight, fracts.z); - - } else { - float lowerLeft = src[ceilZ * size + floorX]; - interpolatedHeight = glm::mix(upperLeft, glm::mix(lowerLeft, lowerRight, fracts.x), fracts.z); - } - if (interpolatedHeight == 0.0f) { - return STOP_RECURSION; // ignore zero values - } - - // convert the interpolated height into world space - height = qMax(height, info.minimum.y + interpolatedHeight * info.size * EIGHT_BIT_MAXIMUM_RECIPROCAL); - return SHORT_CIRCUIT; -} - -float MetavoxelClientManager::getHeightfieldHeight(const glm::vec3& location) { - HeightfieldHeightVisitor visitor(getLOD(), location); - guide(visitor); - return visitor.height; -} - MetavoxelLOD MetavoxelClientManager::getLOD() { return MetavoxelLOD(); } diff --git a/libraries/metavoxels/src/MetavoxelClientManager.h b/libraries/metavoxels/src/MetavoxelClientManager.h index 8fc9bcd38d..333b709b9e 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.h +++ b/libraries/metavoxels/src/MetavoxelClientManager.h @@ -37,16 +37,12 @@ public: SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, float& distance); - bool findFirstRayHeightfieldIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance); - Q_INVOKABLE void setSphere(const glm::vec3& center, float radius, const QColor& color = QColor(Qt::gray)); Q_INVOKABLE void setSpanner(const SharedObjectPointer& object, bool reliable = false); Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false); - Q_INVOKABLE float getHeightfieldHeight(const glm::vec3& location); - /// Returns the current LOD. This must be thread-safe, as it will be called from the updater thread. virtual MetavoxelLOD getLOD(); From 4de43b7cbe3a164521856f23c6182741286d4987 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 13 Aug 2014 11:19:32 -0700 Subject: [PATCH 362/407] cleanup and reordering of code --- libraries/shared/src/ContactPoint.cpp | 80 ++++++++++++++------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/libraries/shared/src/ContactPoint.cpp b/libraries/shared/src/ContactPoint.cpp index c34d248035..fcdd32e278 100644 --- a/libraries/shared/src/ContactPoint.cpp +++ b/libraries/shared/src/ContactPoint.cpp @@ -13,33 +13,37 @@ #include "Shape.h" #include "SharedUtil.h" -ContactPoint::ContactPoint() : _lastFrame(0), _shapeA(NULL), _shapeB(NULL), - _offsetA(0.0f), _offsetB(0.0f), _normal(0.0f) { +ContactPoint::ContactPoint() : + _lastFrame(0), _shapeA(NULL), _shapeB(NULL), + _offsetA(0.0f), _offsetB(0.0f), + _numPointsA(0), _numPoints(0), _normal(0.0f) { } -ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : _lastFrame(frame), - _shapeA(collision.getShapeA()), _shapeB(collision.getShapeB()), _offsetA(0.0f), _offsetB(0.0f), +ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : + _lastFrame(frame), _shapeA(collision.getShapeA()), _shapeB(collision.getShapeB()), + _offsetA(0.0f), _offsetB(0.0f), _numPointsA(0), _numPoints(0), _normal(0.0f) { - _contactPoint = collision._contactPoint - 0.5f * collision._penetration; - _offsetA = collision._contactPoint - _shapeA->getTranslation(); - _offsetB = collision._contactPoint - collision._penetration - _shapeB->getTranslation(); + glm::vec3 pointA = collision._contactPoint; + glm::vec3 pointB = collision._contactPoint - collision._penetration; + float pLength = glm::length(collision._penetration); if (pLength > EPSILON) { _normal = collision._penetration / pLength; } - if (_shapeA->getID() > _shapeB->getID()) { // swap so that _shapeA always has lower ID _shapeA = collision.getShapeB(); _shapeB = collision.getShapeA(); - - glm::vec3 temp = _offsetA; - _offsetA = _offsetB; - _offsetB = temp; _normal = - _normal; + pointA = pointB; + pointB = collision._contactPoint; } + _offsetA = pointA - _shapeA->getTranslation(); + _offsetB = pointB - _shapeB->getTranslation(); + _contactPoint = 0.5f * (pointA + pointB); + _shapeA->getVerletPoints(_points); _numPointsA = _points.size(); _shapeB->getVerletPoints(_points); @@ -61,8 +65,7 @@ ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : _las // virtual float ContactPoint::enforce() { - int numPoints = _points.size(); - for (int i = 0; i < numPoints; ++i) { + for (int i = 0; i < _numPoints; ++i) { glm::vec3& position = _points[i]->_position; // TODO: use a fast distance approximation float newDistance = glm::distance(_contactPoint, position); @@ -81,9 +84,9 @@ float ContactPoint::enforce() { void ContactPoint::buildConstraints() { glm::vec3 pointA = _shapeA->getTranslation() + _offsetA; glm::vec3 pointB = _shapeB->getTranslation() + _offsetB; - glm::vec3 penetration = pointA - pointB; - float pDotN = glm::dot(penetration, _normal); - bool actuallyMovePoints = (pDotN > EPSILON); + glm::vec3 penetration = pointB - pointA; + float pDotN = glm::dot(penetration, _normal); + bool constraintViolation = (pDotN < 0.0f); // the contact point will be the average of the two points on the shapes _contactPoint = 0.5f * (pointA + pointB); @@ -96,29 +99,28 @@ void ContactPoint::buildConstraints() { // that this makes it easier for limbs to tunnel through during collisions. const float HACK_STRENGTH = 0.5f; - int numPoints = _points.size(); - for (int i = 0; i < numPoints; ++i) { - VerletPoint* point = _points[i]; - glm::vec3 offset = _offsets[i]; - - // split delta into parallel and perpendicular components - glm::vec3 delta = _contactPoint + offset - point->_position; - glm::vec3 paraDelta = glm::dot(delta, _normal) * _normal; - glm::vec3 perpDelta = delta - paraDelta; - - // use the relative sizes of the components to decide how much perpenducular delta to use - // perpendicular < parallel ==> static friciton ==> perpFactor = 1.0 - // perpendicular > parallel ==> dynamic friciton ==> cap to length of paraDelta ==> perpFactor < 1.0 - float paraLength = glm::length(paraDelta); - float perpLength = glm::length(perpDelta); - float perpFactor = (perpLength > paraLength && perpLength > EPSILON) ? (paraLength / perpLength) : 1.0f; - - // recombine the two components to get the final delta - delta = paraDelta + perpFactor * perpDelta; + if (constraintViolation) { + for (int i = 0; i < _numPoints; ++i) { + VerletPoint* point = _points[i]; + glm::vec3 offset = _offsets[i]; - glm::vec3 targetPosition = point->_position + delta; - _distances[i] = glm::distance(_contactPoint, targetPosition); - if (actuallyMovePoints) { + // split delta into parallel and perpendicular components + glm::vec3 delta = _contactPoint + offset - point->_position; + glm::vec3 paraDelta = glm::dot(delta, _normal) * _normal; + glm::vec3 perpDelta = delta - paraDelta; + + // use the relative sizes of the components to decide how much perpenducular delta to use + // perpendicular < parallel ==> static friciton ==> perpFactor = 1.0 + // perpendicular > parallel ==> dynamic friciton ==> cap to length of paraDelta ==> perpFactor < 1.0 + float paraLength = glm::length(paraDelta); + float perpLength = glm::length(perpDelta); + float perpFactor = (perpLength > paraLength && perpLength > EPSILON) ? (paraLength / perpLength) : 1.0f; + + // recombine the two components to get the final delta + delta = paraDelta + perpFactor * perpDelta; + + glm::vec3 targetPosition = point->_position + delta; + _distances[i] = glm::distance(_contactPoint, targetPosition); point->_position += HACK_STRENGTH * delta; } } From bc432aa8e83f72ca60c89c3f3c42228c94ff4110 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 13 Aug 2014 11:29:54 -0700 Subject: [PATCH 363/407] use relative masses for ContactPoint contsrtaint --- libraries/shared/src/ContactPoint.cpp | 44 +++++++++++++++++++++------ libraries/shared/src/ContactPoint.h | 2 ++ 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/libraries/shared/src/ContactPoint.cpp b/libraries/shared/src/ContactPoint.cpp index fcdd32e278..84a1032565 100644 --- a/libraries/shared/src/ContactPoint.cpp +++ b/libraries/shared/src/ContactPoint.cpp @@ -16,12 +16,14 @@ ContactPoint::ContactPoint() : _lastFrame(0), _shapeA(NULL), _shapeB(NULL), _offsetA(0.0f), _offsetB(0.0f), + _relativeMassA(0.5f), _relativeMassB(0.5f), _numPointsA(0), _numPoints(0), _normal(0.0f) { } ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : _lastFrame(frame), _shapeA(collision.getShapeA()), _shapeB(collision.getShapeB()), _offsetA(0.0f), _offsetB(0.0f), + _relativeMassA(0.5f), _relativeMassB(0.5f), _numPointsA(0), _numPoints(0), _normal(0.0f) { glm::vec3 pointA = collision._contactPoint; @@ -42,13 +44,28 @@ ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : _offsetA = pointA - _shapeA->getTranslation(); _offsetB = pointB - _shapeB->getTranslation(); - _contactPoint = 0.5f * (pointA + pointB); _shapeA->getVerletPoints(_points); _numPointsA = _points.size(); _shapeB->getVerletPoints(_points); _numPoints = _points.size(); + // compute and cache relative masses + float massA = EPSILON; + for (int i = 0; i < _numPointsA; ++i) { + massA += _points[i]->getMass(); + } + float massB = EPSILON; + for (int i = _numPointsA; i < _numPoints; ++i) { + massB += _points[i]->getMass(); + } + float invTotalMass = 1.0f / (massA + massB); + _relativeMassA = massA * invTotalMass; + _relativeMassB = massB * invTotalMass; + + // _contactPoint will be the weighted average of the two + _contactPoint = _relativeMassA * pointA + _relativeMassB * pointB; + // compute offsets for shapeA for (int i = 0; i < _numPointsA; ++i) { glm::vec3 offset = _points[i]->_position - collision._contactPoint; @@ -128,9 +145,12 @@ void ContactPoint::buildConstraints() { void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) { _lastFrame = frame; - _contactPoint = collision._contactPoint - 0.5f * collision._penetration; - _offsetA = collision._contactPoint - collision._shapeA->getTranslation(); - _offsetB = collision._contactPoint - collision._penetration - collision._shapeB->getTranslation(); + + // compute contact points on surface of each shape + glm::vec3 pointA = collision._contactPoint; + glm::vec3 pointB = pointA - collision._penetration; + + // compute the normal (which points from A into B) float pLength = glm::length(collision._penetration); if (pLength > EPSILON) { _normal = collision._penetration / pLength; @@ -140,19 +160,25 @@ void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) if (collision._shapeA->getID() > collision._shapeB->getID()) { // our _shapeA always has lower ID - glm::vec3 temp = _offsetA; - _offsetA = _offsetB; - _offsetB = temp; _normal = - _normal; + pointA = pointB; + pointB = collision._contactPoint; } + // compute relative offsets to per-shape contact points + _offsetA = pointA - collision._shapeA->getTranslation(); + _offsetB = pointB - collision._shapeB->getTranslation(); + + // _contactPoint will be the weighted average of the two + _contactPoint = _relativeMassA * pointA + _relativeMassB * pointB; + // compute offsets for shapeA assert(_offsets.size() == _numPoints); for (int i = 0; i < _numPointsA; ++i) { - _offsets[i] = (_points[i]->_position - collision._contactPoint); + _offsets[i] = _points[i]->_position - pointA; } // compute offsets for shapeB for (int i = _numPointsA; i < _numPoints; ++i) { - _offsets[i] = (_points[i]->_position - collision._contactPoint + collision._penetration); + _offsets[i] = _points[i]->_position - pointB; } } diff --git a/libraries/shared/src/ContactPoint.h b/libraries/shared/src/ContactPoint.h index b7e0775bc1..5257fabee0 100644 --- a/libraries/shared/src/ContactPoint.h +++ b/libraries/shared/src/ContactPoint.h @@ -41,6 +41,8 @@ protected: glm::vec3 _offsetA; // contact point relative to A's center glm::vec3 _offsetB; // contact point relative to B's center glm::vec3 _contactPoint; // a "virtual" point that is added to the simulation + float _relativeMassA; // massA / totalMass + float _relativeMassB; // massB / totalMass int _numPointsA; // number of VerletPoints that belong to _shapeA int _numPoints; // total number of VerletPoints QVector _points; // points that belong to colliding shapes From 8c42a3a8485fa21327ff8ec10a20df474d41c7e3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 13 Aug 2014 11:30:05 -0700 Subject: [PATCH 364/407] Ray query fix. --- interface/src/MetavoxelSystem.cpp | 40 +++++++++++++++------------- interface/src/MetavoxelSystem.h | 6 ++--- interface/src/ui/MetavoxelEditor.cpp | 11 +------- 3 files changed, 26 insertions(+), 31 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 238eda8784..a5f5de5123 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -136,7 +136,6 @@ RayHeightfieldIntersectionVisitor::RayHeightfieldIntersectionVisitor(const glm:: } static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / 255.0f; -static const int HEIGHT_BORDER = 1; int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance) { if (!info.isLeaf) { @@ -151,12 +150,13 @@ int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance const uchar* src = (const uchar*)contents.constData(); int size = glm::sqrt((float)contents.size()); int unextendedSize = size - HeightfieldBuffer::HEIGHT_EXTENSION; - int highest = HEIGHT_BORDER + unextendedSize; + int highest = HeightfieldBuffer::HEIGHT_BORDER + unextendedSize; float heightScale = unextendedSize * EIGHT_BIT_MAXIMUM_RECIPROCAL; // find the initial location in heightfield coordinates - glm::vec3 entry = (_origin + distance * _direction - info.minimum + glm::vec3(HEIGHT_BORDER, 0.0f, HEIGHT_BORDER)) * - (float)unextendedSize / info.size; + glm::vec3 entry = (_origin + distance * _direction - info.minimum) * (float)unextendedSize / info.size; + entry.x += HeightfieldBuffer::HEIGHT_BORDER; + entry.z += HeightfieldBuffer::HEIGHT_BORDER; glm::vec3 floors = glm::floor(entry); glm::vec3 ceils = glm::ceil(entry); if (floors.x == ceils.x) { @@ -178,10 +178,10 @@ int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance float accumulatedDistance = 0.0f; while (withinBounds) { // find the heights at the corners of the current cell - int floorX = qMin(qMax((int)floors.x, HEIGHT_BORDER), highest); - int floorZ = qMin(qMax((int)floors.z, HEIGHT_BORDER), highest); - int ceilX = qMin(qMax((int)ceils.x, HEIGHT_BORDER), highest); - int ceilZ = qMin(qMax((int)ceils.z, HEIGHT_BORDER), highest); + int floorX = qMin(qMax((int)floors.x, HeightfieldBuffer::HEIGHT_BORDER), highest); + int floorZ = qMin(qMax((int)floors.z, HeightfieldBuffer::HEIGHT_BORDER), highest); + int ceilX = qMin(qMax((int)ceils.x, HeightfieldBuffer::HEIGHT_BORDER), highest); + int ceilZ = qMin(qMax((int)ceils.z, HeightfieldBuffer::HEIGHT_BORDER), highest); float upperLeft = src[floorZ * size + floorX] * heightScale; float upperRight = src[floorZ * size + ceilX] * heightScale; float lowerLeft = src[ceilZ * size + floorX] * heightScale; @@ -215,13 +215,13 @@ int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance } else { // find the exit point and the next cell, and determine whether it's still within the bounds exit = entry + exitDistance * _direction; - withinBounds = (exit.y >= HEIGHT_BORDER && exit.y <= highest); + withinBounds = (exit.y >= HeightfieldBuffer::HEIGHT_BORDER && exit.y <= highest); if (exitDistance == xDistance) { if (_direction.x > 0.0f) { nextFloors.x += 1.0f; withinBounds &= (nextCeils.x += 1.0f) <= highest; } else { - withinBounds &= (nextFloors.x -= 1.0f) >= HEIGHT_BORDER; + withinBounds &= (nextFloors.x -= 1.0f) >= HeightfieldBuffer::HEIGHT_BORDER; nextCeils.x -= 1.0f; } } @@ -230,7 +230,7 @@ int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance nextFloors.z += 1.0f; withinBounds &= (nextCeils.z += 1.0f) <= highest; } else { - withinBounds &= (nextFloors.z -= 1.0f) >= HEIGHT_BORDER; + withinBounds &= (nextFloors.z -= 1.0f) >= HeightfieldBuffer::HEIGHT_BORDER; nextCeils.z -= 1.0f; } } @@ -337,19 +337,19 @@ int HeightfieldHeightVisitor::visit(MetavoxelInfo& info) { const uchar* src = (const uchar*)contents.constData(); int size = glm::sqrt((float)contents.size()); int unextendedSize = size - HeightfieldBuffer::HEIGHT_EXTENSION; - int highest = HEIGHT_BORDER + unextendedSize; + int highest = HeightfieldBuffer::HEIGHT_BORDER + unextendedSize; relative *= unextendedSize / info.size; - relative.x += HEIGHT_BORDER; - relative.z += HEIGHT_BORDER; + relative.x += HeightfieldBuffer::HEIGHT_BORDER; + relative.z += HeightfieldBuffer::HEIGHT_BORDER; // find the bounds of the cell containing the point and the shared vertex heights glm::vec3 floors = glm::floor(relative); glm::vec3 ceils = glm::ceil(relative); glm::vec3 fracts = glm::fract(relative); - int floorX = qMin(qMax((int)floors.x, HEIGHT_BORDER), highest); - int floorZ = qMin(qMax((int)floors.z, HEIGHT_BORDER), highest); - int ceilX = qMin(qMax((int)ceils.x, HEIGHT_BORDER), highest); - int ceilZ = qMin(qMax((int)ceils.z, HEIGHT_BORDER), highest); + int floorX = qMin(qMax((int)floors.x, HeightfieldBuffer::HEIGHT_BORDER), highest); + int floorZ = qMin(qMax((int)floors.z, HeightfieldBuffer::HEIGHT_BORDER), highest); + int ceilX = qMin(qMax((int)ceils.x, HeightfieldBuffer::HEIGHT_BORDER), highest); + int ceilZ = qMin(qMax((int)ceils.z, HeightfieldBuffer::HEIGHT_BORDER), highest); float upperLeft = src[floorZ * size + floorX]; float lowerRight = src[ceilZ * size + ceilX]; float interpolatedHeight = glm::mix(upperLeft, lowerRight, fracts.z); @@ -593,6 +593,10 @@ void PointBuffer::render(bool cursor) { _buffer.release(); } +const int HeightfieldBuffer::HEIGHT_BORDER = 1; +const int HeightfieldBuffer::SHARED_EDGE = 1; +const int HeightfieldBuffer::HEIGHT_EXTENSION = 2 * HeightfieldBuffer::HEIGHT_BORDER + HeightfieldBuffer::SHARED_EDGE; + HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color) : _translation(translation), diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index fb18d4f402..39136cb1f4 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -135,9 +135,9 @@ private: class HeightfieldBuffer : public BufferData { public: - static const int HEIGHT_BORDER = 1; - static const int SHARED_EDGE = 1; - static const int HEIGHT_EXTENSION = 2 * HEIGHT_BORDER + SHARED_EDGE; + static const int HEIGHT_BORDER; + static const int SHARED_EDGE; + static const int HEIGHT_EXTENSION; HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color); ~HeightfieldBuffer(); diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 7c5e84132b..b7057532fb 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -1101,7 +1101,7 @@ HeightfieldBrushTool::HeightfieldBrushTool(MetavoxelEditor* editor, const QStrin } void HeightfieldBrushTool::render() { - if (Application::getInstance()->isMouseHidden() && false) { + if (Application::getInstance()->isMouseHidden()) { return; } @@ -1115,15 +1115,6 @@ void HeightfieldBrushTool::render() { } Application::getInstance()->getMetavoxels()->renderHeightfieldCursor( _position = origin + distance * direction, _radius->value()); - - glPushMatrix(); - glTranslatef(_position.x, _position.y, _position.z); - - glColor4f(1.0f, 0.0f, 0.0f, 1.0f); - - glutSolidSphere(1.0f, 10, 10); - - glPopMatrix(); } bool HeightfieldBrushTool::eventFilter(QObject* watched, QEvent* event) { From 2f1a56a87c0414c3d2c9a2c74abedf4872e4e08d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 13 Aug 2014 13:48:04 -0700 Subject: [PATCH 365/407] ContactPoint tries to help maintain collisions so that collision events will continue to update the contact --- libraries/shared/src/ContactPoint.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/ContactPoint.cpp b/libraries/shared/src/ContactPoint.cpp index 84a1032565..c69f2ea8f2 100644 --- a/libraries/shared/src/ContactPoint.cpp +++ b/libraries/shared/src/ContactPoint.cpp @@ -13,6 +13,8 @@ #include "Shape.h" #include "SharedUtil.h" +const float CONTACT_PENETRATION_ALLOWANCE = 0.005f; + ContactPoint::ContactPoint() : _lastFrame(0), _shapeA(NULL), _shapeB(NULL), _offsetA(0.0f), _offsetB(0.0f), @@ -42,6 +44,10 @@ ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : pointB = collision._contactPoint; } + // bring the contact points inside the shapes to help maintain collision updates + pointA -= CONTACT_PENETRATION_ALLOWANCE * _normal; + pointB += CONTACT_PENETRATION_ALLOWANCE * _normal; + _offsetA = pointA - _shapeA->getTranslation(); _offsetB = pointB - _shapeB->getTranslation(); @@ -68,13 +74,13 @@ ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : // compute offsets for shapeA for (int i = 0; i < _numPointsA; ++i) { - glm::vec3 offset = _points[i]->_position - collision._contactPoint; + glm::vec3 offset = _points[i]->_position - pointA; _offsets.push_back(offset); _distances.push_back(glm::length(offset)); } // compute offsets for shapeB for (int i = _numPointsA; i < _numPoints; ++i) { - glm::vec3 offset = _points[i]->_position - collision._contactPoint + collision._penetration; + glm::vec3 offset = _points[i]->_position - pointB; _offsets.push_back(offset); _distances.push_back(glm::length(offset)); } @@ -101,9 +107,9 @@ float ContactPoint::enforce() { void ContactPoint::buildConstraints() { glm::vec3 pointA = _shapeA->getTranslation() + _offsetA; glm::vec3 pointB = _shapeB->getTranslation() + _offsetB; - glm::vec3 penetration = pointB - pointA; + glm::vec3 penetration = pointA - pointB; float pDotN = glm::dot(penetration, _normal); - bool constraintViolation = (pDotN < 0.0f); + bool constraintViolation = (pDotN > CONTACT_PENETRATION_ALLOWANCE); // the contact point will be the average of the two points on the shapes _contactPoint = 0.5f * (pointA + pointB); @@ -164,6 +170,10 @@ void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) pointA = pointB; pointB = collision._contactPoint; } + + // bring the contact points inside the shapes to help maintain collision updates + pointA -= CONTACT_PENETRATION_ALLOWANCE * _normal; + pointB += CONTACT_PENETRATION_ALLOWANCE * _normal; // compute relative offsets to per-shape contact points _offsetA = pointA - collision._shapeA->getTranslation(); From b177686f74e455874217a1b2a6e31463402cc4ed Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 13 Aug 2014 14:50:25 -0700 Subject: [PATCH 366/407] minor tweak to how ContactPoint is updated --- libraries/shared/src/ContactPoint.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libraries/shared/src/ContactPoint.cpp b/libraries/shared/src/ContactPoint.cpp index c69f2ea8f2..2d55da9265 100644 --- a/libraries/shared/src/ContactPoint.cpp +++ b/libraries/shared/src/ContactPoint.cpp @@ -133,8 +133,8 @@ void ContactPoint::buildConstraints() { glm::vec3 perpDelta = delta - paraDelta; // use the relative sizes of the components to decide how much perpenducular delta to use - // perpendicular < parallel ==> static friciton ==> perpFactor = 1.0 - // perpendicular > parallel ==> dynamic friciton ==> cap to length of paraDelta ==> perpFactor < 1.0 + // perpendicular < parallel ==> static friction ==> perpFactor = 1.0 + // perpendicular > parallel ==> dynamic friction ==> cap to length of paraDelta ==> perpFactor < 1.0 float paraLength = glm::length(paraDelta); float perpLength = glm::length(perpDelta); float perpFactor = (perpLength > paraLength && perpLength > EPSILON) ? (paraLength / perpLength) : 1.0f; @@ -146,6 +146,10 @@ void ContactPoint::buildConstraints() { _distances[i] = glm::distance(_contactPoint, targetPosition); point->_position += HACK_STRENGTH * delta; } + } else { + for (int i = 0; i < _numPoints; ++i) { + _distances[i] = glm::length(glm::length(_offsets[i])); + } } } @@ -179,9 +183,6 @@ void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) _offsetA = pointA - collision._shapeA->getTranslation(); _offsetB = pointB - collision._shapeB->getTranslation(); - // _contactPoint will be the weighted average of the two - _contactPoint = _relativeMassA * pointA + _relativeMassB * pointB; - // compute offsets for shapeA assert(_offsets.size() == _numPoints); for (int i = 0; i < _numPointsA; ++i) { From 3d107cc7e5f3e5f81dfbedfd047dac8cb8ea0bf6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 13 Aug 2014 14:51:16 -0700 Subject: [PATCH 367/407] less variability in verlet simulation loop count --- interface/src/avatar/MyAvatar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7481aa9ef8..71052bf6ea 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -207,8 +207,8 @@ void MyAvatar::simulate(float deltaTime) { PerformanceTimer perfTimer("ragdoll"); if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { const float minError = 0.00001f; - const float maxIterations = 10; - const quint64 maxUsec = 2000; + const float maxIterations = 3; + const quint64 maxUsec = 4000; _physicsSimulation.setTranslation(_position); _physicsSimulation.stepForward(deltaTime, minError, maxIterations, maxUsec); } else { From f66398d3666b693caef40bf4f54a3ab71221a578 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 13 Aug 2014 15:06:34 -0700 Subject: [PATCH 368/407] adding comment about parameter's purpose --- libraries/shared/src/ContactPoint.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/shared/src/ContactPoint.cpp b/libraries/shared/src/ContactPoint.cpp index 2d55da9265..4c1cf7b842 100644 --- a/libraries/shared/src/ContactPoint.cpp +++ b/libraries/shared/src/ContactPoint.cpp @@ -13,6 +13,8 @@ #include "Shape.h" #include "SharedUtil.h" +// This parameter helps keep the actual point of contact slightly inside each shape +// which allows the collisions to happen almost every frame for more frequent updates. const float CONTACT_PENETRATION_ALLOWANCE = 0.005f; ContactPoint::ContactPoint() : From 62b84edc7f3357f8f6794eea6b6b590597fd9e39 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 13 Aug 2014 15:13:06 -0700 Subject: [PATCH 369/407] Brush fix. --- libraries/metavoxels/src/MetavoxelMessages.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index ad3c36eb03..df6e8172e4 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -361,7 +361,7 @@ int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) { QByteArray contents(pointer->getContents()); int size = glm::sqrt((float)contents.size()); int highest = size - 1; - float heightScale = highest / info.size; + float heightScale = size / info.size; glm::vec3 center = (_edit.position - info.minimum) * heightScale; float scaledRadius = _edit.radius * heightScale; @@ -450,7 +450,7 @@ int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) { const int BYTES_PER_PIXEL = 3; int size = glm::sqrt((float)contents.size() / BYTES_PER_PIXEL); int highest = size - 1; - float heightScale = highest / info.size; + float heightScale = size / info.size; glm::vec3 center = (_edit.position - info.minimum) * heightScale; float scaledRadius = _edit.radius * heightScale; From ec260dbab26767e0591aff5df7db8ef426a157d8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Aug 2014 15:48:03 -0700 Subject: [PATCH 370/407] change both send and receive socket buffers --- libraries/networking/src/LimitedNodeList.cpp | 28 +++++++++++++------- libraries/networking/src/LimitedNodeList.h | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 13dc558687..44e45c359a 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -82,8 +82,8 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short qDebug() << "NodeList DTLS socket is listening on" << _dtlsSocket->localPort(); } - const int LARGER_SNDBUF_SIZE = 1048576; - changeSendSocketBufferSize(LARGER_SNDBUF_SIZE); + const int LARGER_BUFFER_SIZE = 1048576; + changeSocketBufferSizes(LARGER_BUFFER_SIZE); _packetStatTimer.start(); } @@ -129,7 +129,7 @@ QUdpSocket& LimitedNodeList::getDTLSSocket() { return *_dtlsSocket; } -void LimitedNodeList::changeSendSocketBufferSize(int numSendBytes) { +void LimitedNodeList::changeSocketBufferSizes(int numBytes) { // change the socket send buffer size to be 1MB int oldBufferSize = 0; @@ -139,15 +139,23 @@ void LimitedNodeList::changeSendSocketBufferSize(int numSendBytes) { unsigned int sizeOfInt = sizeof(oldBufferSize); #endif - getsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&oldBufferSize), &sizeOfInt); + for (int i = 0; i < 2; i++) { + int bufferOpt = (i == 0) ? SO_SNDBUF : SO_RCVBUF; + + getsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, bufferOpt, reinterpret_cast(&oldBufferSize), &sizeOfInt); + + setsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, bufferOpt, reinterpret_cast(&numBytes), + sizeof(numBytes)); + + int newBufferSize = 0; + getsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, bufferOpt, reinterpret_cast(&newBufferSize), &sizeOfInt); + + QString bufferTypeString = (i == 0) ? "send" : "receive"; + + qDebug() << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to" << newBufferSize << "bytes"; + } - setsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&numSendBytes), - sizeof(numSendBytes)); - int newBufferSize = 0; - getsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&newBufferSize), &sizeOfInt); - - qDebug() << "Changed socket send buffer size from" << oldBufferSize << "to" << newBufferSize << "bytes"; } bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 3e62d4aaab..114d3de910 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -123,7 +123,7 @@ protected: NodeHash::iterator killNodeAtHashIterator(NodeHash::iterator& nodeItemToKill); - void changeSendSocketBufferSize(int numSendBytes); + void changeSocketBufferSizes(int numBytes); QUuid _sessionUUID; NodeHash _nodeHash; From ee0d0a156608edc582af248cb71369902017263c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Aug 2014 09:20:53 -0700 Subject: [PATCH 371/407] remove ragdoll from simulation in dtor --- libraries/shared/src/Ragdoll.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/shared/src/Ragdoll.cpp b/libraries/shared/src/Ragdoll.cpp index e10e1620ae..80e3c27e04 100644 --- a/libraries/shared/src/Ragdoll.cpp +++ b/libraries/shared/src/Ragdoll.cpp @@ -24,6 +24,9 @@ Ragdoll::Ragdoll() : _massScale(1.0f), _ragdollTranslation(0.0f), _translationIn Ragdoll::~Ragdoll() { clearRagdollConstraintsAndPoints(); + if (_ragdollSimulation) { + _ragdollSimulation->removeRagdoll(this); + } } void Ragdoll::stepRagdollForward(float deltaTime) { From ca4a23e5322fd5a7a72ae0ee0bbbd3a2212dbb3c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Aug 2014 09:21:15 -0700 Subject: [PATCH 372/407] use "visible joint positions" for MyAvatar only --- interface/src/avatar/SkeletonModel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 24acd8d2e3..29c4e2cc52 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -432,7 +432,8 @@ bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const { } bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const { - if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { + if (_owningAvatar->isMyAvatar() && + Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { return isActive() && getVisibleJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition); } return isActive() && getJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition); From 64c11ebf8f74103146f0f0d430db6690d3c0f8cd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Aug 2014 10:36:54 -0700 Subject: [PATCH 373/407] don't change the socket buffer sizes if it is already larger --- libraries/networking/src/LimitedNodeList.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 44e45c359a..0548e95c80 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -82,7 +82,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short qDebug() << "NodeList DTLS socket is listening on" << _dtlsSocket->localPort(); } - const int LARGER_BUFFER_SIZE = 1048576; + const int LARGER_BUFFER_SIZE = 2097152; changeSocketBufferSizes(LARGER_BUFFER_SIZE); _packetStatTimer.start(); @@ -147,12 +147,21 @@ void LimitedNodeList::changeSocketBufferSizes(int numBytes) { setsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, bufferOpt, reinterpret_cast(&numBytes), sizeof(numBytes)); - int newBufferSize = 0; - getsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, bufferOpt, reinterpret_cast(&newBufferSize), &sizeOfInt); - QString bufferTypeString = (i == 0) ? "send" : "receive"; - qDebug() << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to" << newBufferSize << "bytes"; + if (oldBufferSize < numBytes) { + int newBufferSize = 0; + getsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, bufferOpt, reinterpret_cast(&newBufferSize), &sizeOfInt); + + qDebug() << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to" + << newBufferSize << "bytes"; + } else { + // don't make the buffer smaller + qDebug() << "Did not change socket" << bufferTypeString << "buffer size from" << oldBufferSize + << "since it is larger than desired size of" << numBytes; + } + + } From db5aeddc0f67dc2c93587fbe5a8979877b333383 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 14 Aug 2014 10:58:00 -0700 Subject: [PATCH 374/407] fix for joints not playing back --- interface/src/avatar/MyAvatar.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1133ac01c3..9e302c45fe 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -916,7 +916,8 @@ const float JOINT_PRIORITY = 2.0f; void MyAvatar::setJointRotations(QVector jointRotations) { for (int i = 0; i < jointRotations.size(); ++i) { if (i < _jointData.size()) { - _skeletonModel.setJointState(i, true, jointRotations[i]); + // TODO change animation priority to proper value + _skeletonModel.setJointState(i, true, jointRotations[i], 100.0f); } } } From 29f4f5b21aaa14e8de2ef1c4162e89878ae1cd2b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 14 Aug 2014 11:18:10 -0700 Subject: [PATCH 375/407] Support FBX files with embedded textures --- examples/editModels.js | 85 +++++++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 26 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index dbae4fd08c..b6552f67f2 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -474,6 +474,7 @@ var modelUploader = (function () { mapping = {}; geometry = {}; geometry.textures = []; + geometry.embedded = []; } function readFile(filename) { @@ -575,7 +576,8 @@ var modelUploader = (function () { var textures, view, index, - EOF; + EOF, + previousNodeFilename; // Reference: // http://code.blender.org/index.php/2013/08/fbx-binary-file-format-specification/ @@ -609,12 +611,19 @@ var modelUploader = (function () { name = view.string(index, nameLength).toLowerCase(); index += nameLength; + if (name === "content" && previousNodeFilename !== "") { + geometry.embedded.push(previousNodeFilename); + } + if (name === "relativefilename") { filename = view.string(index + 5, view.getUint32(index + 1, true)).fileName(); if (!textures.hasOwnProperty(filename)) { textures[filename] = ""; geometry.textures.push(filename); } + previousNodeFilename = filename; + } else { + previousNodeFilename = ""; } index += (propertyListLength); @@ -630,31 +639,49 @@ var modelUploader = (function () { viewLength, charCode, charCodes, - filename; + numCharCodes, + filename, + relativeFilename = "", + MAX_CHAR_CODES = 250; view = new Uint8Array(fbxBuffer.buffer); viewLength = view.byteLength; charCodes = []; + numCharCodes = 0; for (index = 0; index < viewLength; index += 1) { charCode = view[index]; - if (charCode === 10) { // Can ignore EOF - line = String.fromCharCode.apply(String, charCodes).trim(); - if (line.slice(0, 17).toLowerCase() === "relativefilename:") { - filename = line.slice(line.indexOf("\""), line.lastIndexOf("\"") - line.length).fileName(); - if (!textures.hasOwnProperty(filename)) { - textures[filename] = ""; - geometry.textures.push(filename); + if (charCode !== 9 && charCode !== 32) { + if (charCode === 10) { // EOL. Can ignore EOF. + line = String.fromCharCode.apply(String, charCodes).toLowerCase(); + // For embedded textures, "Content:" line immediately follows "RelativeFilename:" line. + if (line.slice(0, 8) === "content:" && relativeFilename !== "") { + geometry.embedded.push(relativeFilename); + } + if (line.slice(0, 17) === "relativefilename:") { + filename = line.slice(line.indexOf("\""), line.lastIndexOf("\"") - line.length).fileName(); + if (!textures.hasOwnProperty(filename)) { + textures[filename] = ""; + geometry.textures.push(filename); + } + relativeFilename = filename; + } else { + relativeFilename = ""; + } + charCodes = []; + numCharCodes = 0; + } else { + if (numCharCodes < MAX_CHAR_CODES) { // Only interested in start of line + charCodes.push(charCode); + numCharCodes += 1; } } - charCodes = []; - } else { - charCodes.push(charCode); } } } if (view.string(0, 18) === "Kaydara FBX Binary") { + previousNodeFilename = ""; index = 27; while (index < view.byteLength - 39 && !EOF) { @@ -800,6 +827,7 @@ var modelUploader = (function () { textureBuffer, textureSourceFormat, textureTargetFormat, + embeddedTextures, i; info("Preparing to send model"); @@ -858,23 +886,28 @@ var modelUploader = (function () { } // Textures + embeddedTextures = "|" + geometry.embedded.join("|") + "|"; for (i = 0; i < geometry.textures.length; i += 1) { - textureBuffer = readFile(modelFile.path() + "\/" - + (mapping[TEXDIR_FIELD] !== "." ? mapping[TEXDIR_FIELD] + "\/" : "") - + geometry.textures[i]); - if (textureBuffer === null) { - return; + if (embeddedTextures.indexOf("|" + geometry.textures[i].fileName() + "|") === -1) { + textureBuffer = readFile(modelFile.path() + "\/" + + (mapping[TEXDIR_FIELD] !== "." ? mapping[TEXDIR_FIELD] + "\/" : "") + + geometry.textures[i]); + if (textureBuffer === null) { + return; + } + + textureSourceFormat = geometry.textures[i].fileType().toLowerCase(); + textureTargetFormat = (textureSourceFormat === "jpg" ? "jpg" : "png"); + textureBuffer.buffer = + textureBuffer.buffer.recodeImage(textureSourceFormat, textureTargetFormat, MAX_TEXTURE_SIZE); + textureBuffer.filename = textureBuffer.filename.slice(0, -textureSourceFormat.length) + textureTargetFormat; + + multiparts.push({ + name: "texture" + i, + buffer: textureBuffer + }); } - textureSourceFormat = geometry.textures[i].fileType().toLowerCase(); - textureTargetFormat = (textureSourceFormat === "jpg" ? "jpg" : "png"); - textureBuffer.buffer = textureBuffer.buffer.recodeImage(textureSourceFormat, textureTargetFormat, MAX_TEXTURE_SIZE); - textureBuffer.filename = textureBuffer.filename.slice(0, -textureSourceFormat.length) + textureTargetFormat; - - multiparts.push({ - name: "texture" + i, - buffer: textureBuffer - }); if (!isProcessing) { return; } } From 029ef962b7cb9e35168df22ab6a685d521b4c7be Mon Sep 17 00:00:00 2001 From: wangyix Date: Thu, 14 Aug 2014 11:31:31 -0700 Subject: [PATCH 376/407] made JitterTester work on windows --- tests/jitter/src/main.cpp | 208 +++++++++++++++++++++----------------- 1 file changed, 118 insertions(+), 90 deletions(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index a33347f9ef..c27a791d5b 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -13,6 +13,7 @@ #include #include #endif +#include #include #include // for MovingMinMaxAvg @@ -58,54 +59,64 @@ int main(int argc, const char * argv[]) { void runSend(const char* addressOption, int port, int gap, int size, int report) { std::cout << "runSend...\n"; +#ifdef _WIN32 + WSADATA wsaData; + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { + printf("WSAStartup failed with error %d\n", WSAGetLastError()); + return; + } +#endif + int sockfd; struct sockaddr_in servaddr; - + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = inet_addr(addressOption); + servaddr.sin_port = htons(port); + + + const int SAMPLES_FOR_30_SECONDS = 30 * 1000000 / gap; + std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n"; + + const int SAMPLES_PER_REPORT = report * MSEC_TO_USEC / gap; + std::cout << "SAMPLES_PER_REPORT:" << SAMPLES_PER_REPORT << "\n"; + + char* outputBuffer = new char[size]; memset(outputBuffer, 0, size); quint16 outgoingSequenceNumber = 0; - - sockfd=socket(AF_INET,SOCK_DGRAM,0); - - memset(&servaddr, 0, sizeof(servaddr)); - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr=inet_addr(addressOption); - servaddr.sin_port=htons(port); - - const int SAMPLES_FOR_30_SECONDS = 30 * 1000000 / gap; - std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n"; - - MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats - - const int SAMPLES_PER_REPORT = report * MSEC_TO_USEC / gap; - - std::cout << "SAMPLES_PER_REPORT:" << SAMPLES_PER_REPORT << "\n"; - + MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); MovingMinMaxAvg timeGapsPerReport(1, SAMPLES_PER_REPORT); StDev stDevReportInterval; StDev stDev30s; StDev stDev; - + quint64 last = usecTimestampNow(); quint64 lastReport = 0; - + while (true) { quint64 now = usecTimestampNow(); int actualGap = now - last; - - + + if (actualGap >= gap) { // pack seq num memcpy(outputBuffer, &outgoingSequenceNumber, sizeof(quint16)); - sendto(sockfd, outputBuffer, size, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); + int n = sendto(sockfd, outputBuffer, size, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); + if (n < 0) { + std::cout << "Send error: " << strerror(errno) << "\n"; + } outgoingSequenceNumber++; - + int gapDifferece = actualGap - gap; timeGaps.update(gapDifferece); timeGapsPerReport.update(gapDifferece); @@ -117,23 +128,23 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) if (now - lastReport >= (report * MSEC_TO_USEC)) { std::cout << "\n" - << "SEND gap Difference From Expected\n" - << "Overall:\n" - << "min: " << timeGaps.getMin() << " usecs, " - << "max: " << timeGaps.getMax() << " usecs, " - << "avg: " << timeGaps.getAverage() << " usecs, " - << "stdev: " << stDev.getStDev() << " usecs\n" - << "Last 30s:\n" - << "min: " << timeGaps.getWindowMin() << " usecs, " - << "max: " << timeGaps.getWindowMax() << " usecs, " - << "avg: " << timeGaps.getWindowAverage() << " usecs, " - << "stdev: " << stDev30s.getStDev() << " usecs\n" - << "Last report interval:\n" - << "min: " << timeGapsPerReport.getWindowMin() << " usecs, " - << "max: " << timeGapsPerReport.getWindowMax() << " usecs, " - << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs, " - << "stdev: " << stDevReportInterval.getStDev() << " usecs\n" - << "\n"; + << "SEND gap Difference From Expected\n" + << "Overall:\n" + << "min: " << timeGaps.getMin() << " usecs, " + << "max: " << timeGaps.getMax() << " usecs, " + << "avg: " << timeGaps.getAverage() << " usecs, " + << "stdev: " << stDev.getStDev() << " usecs\n" + << "Last 30s:\n" + << "min: " << timeGaps.getWindowMin() << " usecs, " + << "max: " << timeGaps.getWindowMax() << " usecs, " + << "avg: " << timeGaps.getWindowAverage() << " usecs, " + << "stdev: " << stDev30s.getStDev() << " usecs\n" + << "Last report interval:\n" + << "min: " << timeGapsPerReport.getWindowMin() << " usecs, " + << "max: " << timeGapsPerReport.getWindowMax() << " usecs, " + << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs, " + << "stdev: " << stDevReportInterval.getStDev() << " usecs\n" + << "\n"; stDevReportInterval.reset(); if (stDev30s.getSamples() > SAMPLES_FOR_30_SECONDS) { @@ -144,62 +155,75 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) } } } + delete[] outputBuffer; + +#ifdef _WIN32 + WSACleanup(); +#endif } void runReceive(const char* addressOption, int port, int gap, int size, int report) { std::cout << "runReceive...\n"; +#ifdef _WIN32 + WSADATA wsaData; + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { + printf("WSAStartup failed with error %d\n", WSAGetLastError()); + return; + } +#endif - int sockfd,n; + int sockfd, n; struct sockaddr_in myaddr; - - char* inputBuffer = new char[size]; - memset(inputBuffer, 0, size); - - sockfd=socket(AF_INET, SOCK_DGRAM, 0); - + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + memset(&myaddr, 0, sizeof(myaddr)); myaddr.sin_family = AF_INET; - myaddr.sin_addr.s_addr=htonl(INADDR_ANY); - myaddr.sin_port=htons(port); + myaddr.sin_addr.s_addr = htonl(INADDR_ANY); + myaddr.sin_port = htons(port); + const int SAMPLES_FOR_30_SECONDS = 30 * 1000000 / gap; - std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n"; - MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats - const int SAMPLES_PER_REPORT = report * MSEC_TO_USEC / gap; - std::cout << "SAMPLES_PER_REPORT:" << SAMPLES_PER_REPORT << "\n"; - - MovingMinMaxAvg timeGapsPerReport(1, SAMPLES_PER_REPORT); const int REPORTS_FOR_30_SECONDS = 30 * MSECS_PER_SECOND / report; - std::cout << "REPORTS_FOR_30_SECONDS:" << REPORTS_FOR_30_SECONDS << "\n"; + + char* inputBuffer = new char[size]; + memset(inputBuffer, 0, size); + + MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); + MovingMinMaxAvg timeGapsPerReport(1, SAMPLES_PER_REPORT); + SequenceNumberStats seqStats(REPORTS_FOR_30_SECONDS); StDev stDevReportInterval; StDev stDev30s; StDev stDev; - + if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { std::cout << "bind failed\n"; return; - } - + } + quint64 last = 0; // first case quint64 lastReport = 0; - + while (true) { n = recvfrom(sockfd, inputBuffer, size, 0, NULL, NULL); // we don't care about where it came from + if (n < 0) { + std::cout << "Receive error: " << strerror(errno) << "\n"; + } // parse seq num quint16 incomingSequenceNumber = *(reinterpret_cast(inputBuffer)); seqStats.sequenceNumberReceived(incomingSequenceNumber); - + if (last == 0) { last = usecTimestampNow(); std::cout << "first packet received\n"; @@ -213,28 +237,28 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo stDev30s.addValue(gapDifferece); stDevReportInterval.addValue(gapDifferece); last = now; - + if (now - lastReport >= (report * MSEC_TO_USEC)) { seqStats.pushStatsToHistory(); std::cout << "RECEIVE gap Difference From Expected\n" - << "Overall:\n" - << "min: " << timeGaps.getMin() << " usecs, " - << "max: " << timeGaps.getMax() << " usecs, " - << "avg: " << timeGaps.getAverage() << " usecs, " - << "stdev: " << stDev.getStDev() << " usecs\n" - << "Last 30s:\n" - << "min: " << timeGaps.getWindowMin() << " usecs, " - << "max: " << timeGaps.getWindowMax() << " usecs, " - << "avg: " << timeGaps.getWindowAverage() << " usecs, " - << "stdev: " << stDev30s.getStDev() << " usecs\n" - << "Last report interval:\n" - << "min: " << timeGapsPerReport.getWindowMin() << " usecs, " - << "max: " << timeGapsPerReport.getWindowMax() << " usecs, " - << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs, " - << "stdev: " << stDevReportInterval.getStDev() << " usecs\n" - << "\n"; + << "Overall:\n" + << "min: " << timeGaps.getMin() << " usecs, " + << "max: " << timeGaps.getMax() << " usecs, " + << "avg: " << timeGaps.getAverage() << " usecs, " + << "stdev: " << stDev.getStDev() << " usecs\n" + << "Last 30s:\n" + << "min: " << timeGaps.getWindowMin() << " usecs, " + << "max: " << timeGaps.getWindowMax() << " usecs, " + << "avg: " << timeGaps.getWindowAverage() << " usecs, " + << "stdev: " << stDev30s.getStDev() << " usecs\n" + << "Last report interval:\n" + << "min: " << timeGapsPerReport.getWindowMin() << " usecs, " + << "max: " << timeGapsPerReport.getWindowMax() << " usecs, " + << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs, " + << "stdev: " << stDevReportInterval.getStDev() << " usecs\n" + << "\n"; stDevReportInterval.reset(); if (stDev30s.getSamples() > SAMPLES_FOR_30_SECONDS) { @@ -245,20 +269,24 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo PacketStreamStats packetStatsLastReportInterval = seqStats.getStatsForLastHistoryInterval(); std::cout << "RECEIVE Packet Stats\n" - << "Overall:\n" - << "lost: " << seqStats.getLost() << ", " - << "lost %: " << seqStats.getStats().getLostRate() * 100.0f << "%\n" - << "Last 30s:\n" - << "lost: " << packetStatsLast30s._lost << ", " - << "lost %: " << packetStatsLast30s.getLostRate() * 100.0f << "%\n" - << "Last report interval:\n" - << "lost: " << packetStatsLastReportInterval._lost << ", " - << "lost %: " << packetStatsLastReportInterval.getLostRate() * 100.0f << "%\n" - << "\n\n"; + << "Overall:\n" + << "lost: " << seqStats.getLost() << ", " + << "lost %: " << seqStats.getStats().getLostRate() * 100.0f << "%\n" + << "Last 30s:\n" + << "lost: " << packetStatsLast30s._lost << ", " + << "lost %: " << packetStatsLast30s.getLostRate() * 100.0f << "%\n" + << "Last report interval:\n" + << "lost: " << packetStatsLastReportInterval._lost << ", " + << "lost %: " << packetStatsLastReportInterval.getLostRate() * 100.0f << "%\n" + << "\n\n"; lastReport = now; } } } -} + delete[] inputBuffer; +#ifdef _WIN32 + WSACleanup(); +#endif +} From cd0f2164197dfa9e8b358d4a966e3f6f84d0527f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 14 Aug 2014 11:39:36 -0700 Subject: [PATCH 377/407] Added Recorder and Player to Audio class --- interface/src/Audio.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 8fae6f3bdd..de87291b55 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -17,6 +17,7 @@ #include "InterfaceConfig.h" #include "AudioStreamStats.h" +#include "Recorder.h" #include "RingBufferHistory.h" #include "MovingMinMaxAvg.h" @@ -101,6 +102,9 @@ public: float getAudioOutputMsecsUnplayed() const; float getAudioOutputAverageMsecsUnplayed() const { return (float)_audioOutputMsecsUnplayedStats.getWindowAverage(); } + + void setRecorder(RecorderPointer recorder) { _recorder = recorder; } + void setPlayer(PlayerPointer player) { _player = player; } public slots: void start(); @@ -297,6 +301,9 @@ private: MovingMinMaxAvg _packetSentTimeGaps; AudioOutputIODevice _audioOutputIODevice; + + WeakRecorderPointer _recorder; + WeakPlayerPointer _player; }; From 1e65a093f23606f9afa0e76f43753e1b39dac1fd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Aug 2014 12:37:57 -0700 Subject: [PATCH 378/407] decouple audio-mixer packet receipt from main thread --- assignment-client/src/audio/AudioMixer.cpp | 80 ++++++++++++------- assignment-client/src/audio/AudioMixer.h | 3 +- .../src/audio/AudioMixerDatagramProcessor.cpp | 51 ++++++++++++ .../src/audio/AudioMixerDatagramProcessor.h | 32 ++++++++ libraries/networking/src/LimitedNodeList.cpp | 4 - .../networking/src/ThreadedAssignment.cpp | 23 +++++- libraries/networking/src/ThreadedAssignment.h | 10 ++- 7 files changed, 164 insertions(+), 39 deletions(-) create mode 100644 assignment-client/src/audio/AudioMixerDatagramProcessor.cpp create mode 100644 assignment-client/src/audio/AudioMixerDatagramProcessor.h diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 914d5ae63b..c315f695cc 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,7 @@ #include "AudioRingBuffer.h" #include "AudioMixerClientData.h" +#include "AudioMixerDatagramProcessor.h" #include "AvatarAudioStream.h" #include "InjectedAudioStream.h" @@ -297,37 +299,31 @@ void AudioMixer::prepareMixForListeningNode(Node* node) { } } -void AudioMixer::readPendingDatagrams() { - QByteArray receivedPacket; - HifiSockAddr senderSockAddr; +void AudioMixer::readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) { NodeList* nodeList = NodeList::getInstance(); - while (readAvailableDatagram(receivedPacket, senderSockAddr)) { - if (nodeList->packetVersionAndHashMatch(receivedPacket)) { - // pull any new audio data from nodes off of the network stack - PacketType mixerPacketType = packetTypeForPacket(receivedPacket); - if (mixerPacketType == PacketTypeMicrophoneAudioNoEcho - || mixerPacketType == PacketTypeMicrophoneAudioWithEcho - || mixerPacketType == PacketTypeInjectAudio - || mixerPacketType == PacketTypeSilentAudioFrame - || mixerPacketType == PacketTypeAudioStreamStats) { - - nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket); - } else if (mixerPacketType == PacketTypeMuteEnvironment) { - QByteArray packet = receivedPacket; - populatePacketHeader(packet, PacketTypeMuteEnvironment); - - 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); + // pull any new audio data from nodes off of the network stack + PacketType mixerPacketType = packetTypeForPacket(receivedPacket); + if (mixerPacketType == PacketTypeMicrophoneAudioNoEcho + || mixerPacketType == PacketTypeMicrophoneAudioWithEcho + || mixerPacketType == PacketTypeInjectAudio + || mixerPacketType == PacketTypeSilentAudioFrame + || mixerPacketType == PacketTypeAudioStreamStats) { + + nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket); + } else if (mixerPacketType == PacketTypeMuteEnvironment) { + QByteArray packet = receivedPacket; + populatePacketHeader(packet, PacketTypeMuteEnvironment); + + 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); } } @@ -392,7 +388,35 @@ void AudioMixer::run() { ThreadedAssignment::commonInit(AUDIO_MIXER_LOGGING_TARGET_NAME, NodeType::AudioMixer); NodeList* nodeList = NodeList::getInstance(); - + + // we do not want this event loop to be the handler for UDP datagrams, so disconnect + disconnect(&nodeList->getNodeSocket(), 0, this, 0); + + // setup a QThread with us as parent that will house the AudioMixerDatagramProcessor + _datagramProcessingThread = new QThread(this); + + // create an AudioMixerDatagramProcessor and move it to that thread + AudioMixerDatagramProcessor* datagramProcessor = new AudioMixerDatagramProcessor(nodeList->getNodeSocket(), thread()); + datagramProcessor->moveToThread(_datagramProcessingThread); + + // remove the NodeList as the parent of the node socket + nodeList->getNodeSocket().setParent(NULL); + nodeList->getNodeSocket().moveToThread(_datagramProcessingThread); + + // let the datagram processor handle readyRead from node socket + connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, + datagramProcessor, &AudioMixerDatagramProcessor::readPendingDatagrams); + + // connect to the datagram processing thread signal that tells us we have to handle a packet + connect(datagramProcessor, &AudioMixerDatagramProcessor::packetRequiresProcessing, this, &AudioMixer::readPendingDatagram); + + // delete the datagram processor and the associated thread when the QThread quits + connect(_datagramProcessingThread, &QThread::finished, datagramProcessor, &QObject::deleteLater); + connect(datagramProcessor, &QObject::destroyed, _datagramProcessingThread, &QThread::deleteLater); + + // start the datagram processing thread + _datagramProcessingThread->start(); + nodeList->addNodeTypeToInterestSet(NodeType::Agent); nodeList->linkedDataCreateCallback = attachNewNodeDataToNode; diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index d11539e22e..2a4b93149c 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -33,7 +33,8 @@ public slots: /// threaded run of assignment void run(); - void readPendingDatagrams(); + void readPendingDatagrams() { }; // this will not be called since our datagram processing thread will handle + void readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr); void sendStatsPacket(); diff --git a/assignment-client/src/audio/AudioMixerDatagramProcessor.cpp b/assignment-client/src/audio/AudioMixerDatagramProcessor.cpp new file mode 100644 index 0000000000..61f42e6f08 --- /dev/null +++ b/assignment-client/src/audio/AudioMixerDatagramProcessor.cpp @@ -0,0 +1,51 @@ +// +// AudioMixerDatagramProcessor.cpp +// assignment-client/src +// +// Created by Stephen Birarda on 2014-08-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 +// + +#include + +#include +#include + +#include "AudioMixerDatagramProcessor.h" + +AudioMixerDatagramProcessor::AudioMixerDatagramProcessor(QUdpSocket& nodeSocket, QThread* previousNodeSocketThread) : + _nodeSocket(nodeSocket), + _previousNodeSocketThread(previousNodeSocketThread) +{ + +} + +AudioMixerDatagramProcessor::~AudioMixerDatagramProcessor() { + // return the node socket to its previous thread + _nodeSocket.moveToThread(_previousNodeSocketThread); +} + +void AudioMixerDatagramProcessor::readPendingDatagrams() { + + HifiSockAddr senderSockAddr; + static QByteArray incomingPacket; + + NodeList* nodeList = NodeList::getInstance(); + + // read everything that is available + while (_nodeSocket.hasPendingDatagrams()) { + incomingPacket.resize(_nodeSocket.pendingDatagramSize()); + + // just get this packet off the stack + _nodeSocket.readDatagram(incomingPacket.data(), incomingPacket.size(), + senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); + + if (nodeList->packetVersionAndHashMatch(incomingPacket)) { + // emit the signal to tell AudioMixer it needs to process a packet + emit packetRequiresProcessing(incomingPacket, senderSockAddr); + } + } +} diff --git a/assignment-client/src/audio/AudioMixerDatagramProcessor.h b/assignment-client/src/audio/AudioMixerDatagramProcessor.h new file mode 100644 index 0000000000..94233a1373 --- /dev/null +++ b/assignment-client/src/audio/AudioMixerDatagramProcessor.h @@ -0,0 +1,32 @@ +// +// AudioMixerDatagramProcessor.h +// assignment-client/src +// +// Created by Stephen Birarda on 2014-08-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 +// + +#ifndef hifi_AudioMixerDatagramProcessor_h +#define hifi_AudioMixerDatagramProcessor_h + +#include +#include + +class AudioMixerDatagramProcessor : public QObject { + Q_OBJECT +public: + AudioMixerDatagramProcessor(QUdpSocket& nodeSocket, QThread* previousNodeSocketThread); + ~AudioMixerDatagramProcessor(); +public slots: + void readPendingDatagrams(); +signals: + void packetRequiresProcessing(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr); +private: + QUdpSocket& _nodeSocket; + QThread* _previousNodeSocketThread; +}; + +#endif // hifi_AudioMixerDatagramProcessor_h \ No newline at end of file diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 0548e95c80..99c8a80bf5 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -160,11 +160,7 @@ void LimitedNodeList::changeSocketBufferSizes(int numBytes) { qDebug() << "Did not change socket" << bufferTypeString << "buffer size from" << oldBufferSize << "since it is larger than desired size of" << numBytes; } - - } - - } bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 4b92f8ba38..cd80c441c1 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include "Logging.h" @@ -18,7 +19,8 @@ ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) : Assignment(packet), - _isFinished(false) + _isFinished(false), + _datagramProcessingThread(NULL) { } @@ -28,10 +30,25 @@ void ThreadedAssignment::setFinished(bool isFinished) { if (_isFinished) { aboutToFinish(); - emit finished(); + + NodeList* nodeList = NodeList::getInstance(); + + // if we have a datagram processing thread, quit it and wait on it to make sure that + // the node socket is back on the same thread as the NodeList + + if (_datagramProcessingThread) { + // tell the datagram processing thread to quit and wait until it is done, then return the node socket to the NodeList + _datagramProcessingThread->quit(); + _datagramProcessingThread->wait(); + + // set node socket parent back to NodeList + nodeList->getNodeSocket().setParent(nodeList); + } // move the NodeList back to the QCoreApplication instance's thread - NodeList::getInstance()->moveToThread(QCoreApplication::instance()->thread()); + nodeList->moveToThread(QCoreApplication::instance()->thread()); + + emit finished(); } } diff --git a/libraries/networking/src/ThreadedAssignment.h b/libraries/networking/src/ThreadedAssignment.h index e9241d0272..454baa85f2 100644 --- a/libraries/networking/src/ThreadedAssignment.h +++ b/libraries/networking/src/ThreadedAssignment.h @@ -20,6 +20,7 @@ class ThreadedAssignment : public Assignment { Q_OBJECT public: ThreadedAssignment(const QByteArray& packet); + void setFinished(bool isFinished); virtual void aboutToFinish() { }; void addPacketStatsAndSendStatsPacket(QJsonObject& statsObject); @@ -29,15 +30,18 @@ public slots: virtual void run() = 0; virtual void readPendingDatagrams() = 0; virtual void sendStatsPacket(); - +signals: + void finished(); + protected: bool readAvailableDatagram(QByteArray& destinationByteArray, HifiSockAddr& senderSockAddr); void commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats = true); bool _isFinished; + QThread* _datagramProcessingThread; + private slots: void checkInWithDomainServerOrExit(); -signals: - void finished(); + }; typedef QSharedPointer SharedAssignmentPointer; From c58bae9021ff028e836dfd63f8d0a544531a184f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Aug 2014 14:27:09 -0700 Subject: [PATCH 379/407] attempt to change buffers to 1MB only --- libraries/networking/src/LimitedNodeList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 99c8a80bf5..f50f7493fb 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -82,7 +82,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short qDebug() << "NodeList DTLS socket is listening on" << _dtlsSocket->localPort(); } - const int LARGER_BUFFER_SIZE = 2097152; + const int LARGER_BUFFER_SIZE = 1048576; changeSocketBufferSizes(LARGER_BUFFER_SIZE); _packetStatTimer.start(); From 46c91052c9edae7be647480c07f36ae1bad189ed Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Aug 2014 14:29:03 -0700 Subject: [PATCH 380/407] split SkeletonModel and Ragdoll classes apart --- interface/src/avatar/MyAvatar.cpp | 11 +- interface/src/avatar/SkeletonModel.cpp | 200 +++++++---------------- interface/src/avatar/SkeletonModel.h | 19 +-- interface/src/avatar/SkeletonRagdoll.cpp | 148 +++++++++++++++++ interface/src/avatar/SkeletonRagdoll.h | 42 +++++ interface/src/renderer/Model.h | 3 + libraries/shared/src/Ragdoll.h | 2 +- 7 files changed, 263 insertions(+), 162 deletions(-) create mode 100644 interface/src/avatar/SkeletonRagdoll.cpp create mode 100644 interface/src/avatar/SkeletonRagdoll.h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c9d19d4bcc..ac44e1884e 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -83,10 +83,11 @@ MyAvatar::MyAvatar() : for (int i = 0; i < MAX_DRIVE_KEYS; i++) { _driveKeys[i] = 0.0f; } - _skeletonModel.setEnableShapes(true); - // The skeleton is both a PhysicsEntity and Ragdoll, so we add it to the simulation once for each type. _physicsSimulation.setEntity(&_skeletonModel); - _physicsSimulation.setRagdoll(&_skeletonModel); + + _skeletonModel.setEnableShapes(true); + Ragdoll* ragdoll = _skeletonModel.buildRagdoll(); + _physicsSimulation.setRagdoll(ragdoll); } MyAvatar::~MyAvatar() { @@ -1604,10 +1605,10 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { if (simulation != &(_physicsSimulation)) { skeleton->setEnableShapes(true); _physicsSimulation.addEntity(skeleton); - _physicsSimulation.addRagdoll(skeleton); + _physicsSimulation.addRagdoll(skeleton->getRagdoll()); } } else if (simulation == &(_physicsSimulation)) { - _physicsSimulation.removeRagdoll(skeleton); + _physicsSimulation.removeRagdoll(skeleton->getRagdoll()); _physicsSimulation.removeEntity(skeleton); skeleton->setEnableShapes(false); } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 29c4e2cc52..90145f0af8 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -23,13 +23,21 @@ #include "Menu.h" #include "MuscleConstraint.h" #include "SkeletonModel.h" +#include "SkeletonRagdoll.h" SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : Model(parent), - Ragdoll(), _owningAvatar(owningAvatar), _boundingShape(), - _boundingShapeLocalOffset(0.0f) { + _boundingShapeLocalOffset(0.0f), + _ragdoll(NULL) { +} + +SkeletonModel::~SkeletonModel() { + if (_ragdoll) { + delete _ragdoll; + _ragdoll = NULL; + } } void SkeletonModel::setJointStates(QVector states) { @@ -155,9 +163,6 @@ void SkeletonModel::getBodyShapes(QVector& shapes) const { void SkeletonModel::renderIKConstraints() { renderJointConstraints(getRightHandJointIndex()); renderJointConstraints(getLeftHandJointIndex()); - //if (isActive() && _owningAvatar->isMyAvatar()) { - // renderRagdoll(); - //} } class IndexValue { @@ -489,21 +494,25 @@ bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& seco } void SkeletonModel::renderRagdoll() { + if (!_ragdoll) { + return; + } + const QVector& points = _ragdoll->getRagdollPoints(); const int BALL_SUBDIVISIONS = 6; glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glPushMatrix(); Application::getInstance()->loadTranslatedViewMatrix(_translation); - int numPoints = _ragdollPoints.size(); + int numPoints = points.size(); float alpha = 0.3f; float radius1 = 0.008f; float radius2 = 0.01f; - glm::vec3 simulationTranslation = getTranslationInSimulationFrame(); + glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame(); for (int i = 0; i < numPoints; ++i) { glPushMatrix(); // NOTE: ragdollPoints are in simulation-frame but we want them to be model-relative - glm::vec3 position = _ragdollPoints[i]._position - simulationTranslation; + glm::vec3 position = points[i]._position - simulationTranslation; glTranslatef(position.x, position.y, position.z); // draw each point as a yellow hexagon with black border glColor4f(0.0f, 0.0f, 0.0f, alpha); @@ -517,109 +526,18 @@ void SkeletonModel::renderRagdoll() { glEnable(GL_LIGHTING); } -// virtual -void SkeletonModel::initRagdollPoints() { - clearRagdollConstraintsAndPoints(); - _muscleConstraints.clear(); - - initRagdollTransform(); - // one point for each joint - int numStates = _jointStates.size(); - _ragdollPoints.fill(VerletPoint(), numStates); - for (int i = 0; i < numStates; ++i) { - const JointState& state = _jointStates.at(i); - // _ragdollPoints start in model-frame - _ragdollPoints[i].initPosition(state.getPosition()); - } -} - -void SkeletonModel::buildRagdollConstraints() { - // NOTE: the length of DistanceConstraints is computed and locked in at this time - // so make sure the ragdoll positions are in a normal configuration before here. - const int numPoints = _ragdollPoints.size(); - assert(numPoints == _jointStates.size()); - - float minBone = FLT_MAX; - float maxBone = -FLT_MAX; - QMultiMap families; - for (int i = 0; i < numPoints; ++i) { - const JointState& state = _jointStates.at(i); - int parentIndex = state.getParentIndex(); - if (parentIndex == -1) { - FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_ragdollPoints[i])); - _fixedConstraints.push_back(anchor); - } else { - DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[i]), &(_ragdollPoints[parentIndex])); - bone->setDistance(state.getDistanceToParent()); - _boneConstraints.push_back(bone); - families.insert(parentIndex, i); - } - float boneLength = glm::length(state.getPositionInParentFrame()); - if (boneLength > maxBone) { - maxBone = boneLength; - } else if (boneLength < minBone) { - minBone = boneLength; - } - } - // Joints that have multiple children effectively have rigid constraints between the children - // in the parent frame, so we add DistanceConstraints between children in the same family. - QMultiMap::iterator itr = families.begin(); - while (itr != families.end()) { - QList children = families.values(itr.key()); - int numChildren = children.size(); - if (numChildren > 1) { - for (int i = 1; i < numChildren; ++i) { - DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[i-1]]), &(_ragdollPoints[children[i]])); - _boneConstraints.push_back(bone); - } - if (numChildren > 2) { - DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[numChildren-1]]), &(_ragdollPoints[children[0]])); - _boneConstraints.push_back(bone); - } - } - ++itr; - } - - float MAX_STRENGTH = 0.6f; - float MIN_STRENGTH = 0.05f; - // each joint gets a MuscleConstraint to its parent - for (int i = 1; i < numPoints; ++i) { - const JointState& state = _jointStates.at(i); - int p = state.getParentIndex(); - if (p == -1) { - continue; - } - MuscleConstraint* constraint = new MuscleConstraint(&(_ragdollPoints[p]), &(_ragdollPoints[i])); - _muscleConstraints.push_back(constraint); - - // Short joints are more susceptible to wiggle so we modulate the strength based on the joint's length: - // long = weak and short = strong. - constraint->setIndices(p, i); - float boneLength = glm::length(state.getPositionInParentFrame()); - - float strength = MIN_STRENGTH + (MAX_STRENGTH - MIN_STRENGTH) * (maxBone - boneLength) / (maxBone - minBone); - if (!families.contains(i)) { - // Although muscles only pull on the children not parents, nevertheless those joints that have - // parents AND children are more stable than joints at the end such as fingers. For such joints we - // bestow maximum strength which helps reduce wiggle. - strength = MAX_MUSCLE_STRENGTH; - } - constraint->setStrength(strength); - } - -} - void SkeletonModel::updateVisibleJointStates() { - if (_showTrueJointTransforms) { + if (_showTrueJointTransforms || !_ragdoll) { // no need to update visible transforms return; } + const QVector& ragdollPoints = _ragdoll->getRagdollPoints(); QVector points; points.reserve(_jointStates.size()); glm::quat invRotation = glm::inverse(_rotation); for (int i = 0; i < _jointStates.size(); i++) { JointState& state = _jointStates[i]; - points.push_back(_ragdollPoints[i]._position); + points.push_back(ragdollPoints[i]._position); // get the parent state (this is the state that we want to rotate) int parentIndex = state.getParentIndex(); @@ -653,15 +571,14 @@ void SkeletonModel::updateVisibleJointStates() { } } -// virtual -void SkeletonModel::stepRagdollForward(float deltaTime) { - setRagdollTransform(_translation, _rotation); - Ragdoll::stepRagdollForward(deltaTime); - updateMuscles(); - int numConstraints = _muscleConstraints.size(); - for (int i = 0; i < numConstraints; ++i) { - _muscleConstraints[i]->enforce(); +SkeletonRagdoll* SkeletonModel::buildRagdoll() { + if (!_ragdoll) { + _ragdoll = new SkeletonRagdoll(this); + if (_enableShapes) { + buildShapes(); + } } + return _ragdoll; } float DENSITY_OF_WATER = 1000.0f; // kg/m^3 @@ -679,8 +596,13 @@ void SkeletonModel::buildShapes() { return; } - initRagdollPoints(); - float massScale = getMassScale(); + if (!_ragdoll) { + _ragdoll = new SkeletonRagdoll(this); + } + _ragdoll->initRagdollPoints(); + QVector& points = _ragdoll->getRagdollPoints(); + + float massScale = _ragdoll->getMassScale(); float uniformScale = extractUniformScale(_scale); const int numStates = _jointStates.size(); @@ -700,14 +622,14 @@ void SkeletonModel::buildShapes() { Shape* shape = NULL; int parentIndex = joint.parentIndex; if (type == Shape::SPHERE_SHAPE) { - shape = new VerletSphereShape(radius, &(_ragdollPoints[i])); + shape = new VerletSphereShape(radius, &(points[i])); shape->setEntity(this); - _ragdollPoints[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); + points[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); } else if (type == Shape::CAPSULE_SHAPE) { assert(parentIndex != -1); - shape = new VerletCapsuleShape(radius, &(_ragdollPoints[parentIndex]), &(_ragdollPoints[i])); + shape = new VerletCapsuleShape(radius, &(points[parentIndex]), &(points[i])); shape->setEntity(this); - _ragdollPoints[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); + points[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); } if (parentIndex != -1) { // always disable collisions between joint and its parent @@ -717,7 +639,7 @@ void SkeletonModel::buildShapes() { } else { // give the base joint a very large mass since it doesn't actually move // in the local-frame simulation (it defines the origin) - _ragdollPoints[i].setMass(VERY_BIG_MASS); + points[i].setMass(VERY_BIG_MASS); } _shapes.push_back(shape); } @@ -729,17 +651,11 @@ void SkeletonModel::buildShapes() { // joints that are currently colliding. disableCurrentSelfCollisions(); - buildRagdollConstraints(); + _ragdoll->buildRagdollConstraints(); // ... then move shapes back to current joint positions - if (_ragdollPoints.size() == numStates) { - int numStates = _jointStates.size(); - for (int i = 0; i < numStates; ++i) { - // ragdollPoints start in model-frame - _ragdollPoints[i].initPosition(_jointStates.at(i).getPosition()); - } - } - enforceRagdollConstraints(); + _ragdoll->slamPointPositions(); + _ragdoll->enforceRagdollConstraints(); } void SkeletonModel::moveShapesTowardJoints(float deltaTime) { @@ -747,8 +663,9 @@ void SkeletonModel::moveShapesTowardJoints(float deltaTime) { // unravel a skelton that has become tangled in its constraints. So let's keep this // around for a while just in case. const int numStates = _jointStates.size(); - assert(_jointStates.size() == _ragdollPoints.size()); - if (_ragdollPoints.size() != numStates) { + QVector& ragdollPoints = _ragdoll->getRagdollPoints(); + assert(_jointStates.size() == ragdollPoints.size()); + if (ragdollPoints.size() != numStates) { return; } @@ -757,32 +674,22 @@ void SkeletonModel::moveShapesTowardJoints(float deltaTime) { float fraction = glm::clamp(deltaTime / RAGDOLL_FOLLOWS_JOINTS_TIMESCALE, 0.0f, 1.0f); float oneMinusFraction = 1.0f - fraction; - glm::vec3 simulationTranslation = getTranslationInSimulationFrame(); + glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame(); for (int i = 0; i < numStates; ++i) { // ragdollPoints are in simulation-frame but jointStates are in model-frame - _ragdollPoints[i].initPosition(oneMinusFraction * _ragdollPoints[i]._position + + ragdollPoints[i].initPosition(oneMinusFraction * ragdollPoints[i]._position + fraction * (simulationTranslation + _rotation * (_jointStates.at(i).getPosition()))); } } -void SkeletonModel::updateMuscles() { - int numConstraints = _muscleConstraints.size(); - for (int i = 0; i < numConstraints; ++i) { - MuscleConstraint* constraint = _muscleConstraints[i]; - int j = constraint->getParentIndex(); - int k = constraint->getChildIndex(); - assert(j != -1 && k != -1); - // ragdollPoints are in simulation-frame but jointStates are in model-frame - constraint->setChildOffset(_rotation * (_jointStates.at(k).getPosition() - _jointStates.at(j).getPosition())); - } -} - void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { // compute default joint transforms int numStates = _jointStates.size(); QVector transforms; transforms.fill(glm::mat4(), numStates); + QVector& ragdollPoints = _ragdoll->getRagdollPoints(); + // compute the default transforms and slam the ragdoll positions accordingly // (which puts the shapes where we want them) for (int i = 0; i < numStates; i++) { @@ -791,7 +698,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { int parentIndex = joint.parentIndex; if (parentIndex == -1) { transforms[i] = _jointStates[i].getTransform(); - _ragdollPoints[i].initPosition(extractTranslation(transforms[i])); + ragdollPoints[i].initPosition(extractTranslation(transforms[i])); continue; } @@ -799,7 +706,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { transforms[i] = transforms[parentIndex] * glm::translate(joint.translation) * joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform; // setting the ragdollPoints here slams the VerletShapes into their default positions - _ragdollPoints[i].initPosition(extractTranslation(transforms[i])); + ragdollPoints[i].initPosition(extractTranslation(transforms[i])); } // compute bounding box that encloses all shapes @@ -918,9 +825,12 @@ const int BALL_SUBDIVISIONS = 10; // virtual void SkeletonModel::renderJointCollisionShapes(float alpha) { + if (!_ragdoll) { + return; + } glPushMatrix(); Application::getInstance()->loadTranslatedViewMatrix(_translation); - glm::vec3 simulationTranslation = getTranslationInSimulationFrame(); + glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame(); for (int i = 0; i < _shapes.size(); i++) { Shape* shape = _shapes[i]; if (!shape) { diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 55fedbcb6b..b0d6ed7325 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -15,18 +15,20 @@ #include "renderer/Model.h" #include -#include +#include "SkeletonRagdoll.h" class Avatar; class MuscleConstraint; +class SkeletonRagdoll; /// A skeleton loaded from a model. -class SkeletonModel : public Model, public Ragdoll { +class SkeletonModel : public Model { Q_OBJECT public: SkeletonModel(Avatar* owningAvatar, QObject* parent = NULL); + ~SkeletonModel(); void setJointStates(QVector states); @@ -96,12 +98,11 @@ public: bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; virtual void updateVisibleJointStates(); - - // virtual overrride from Ragdoll - virtual void stepRagdollForward(float deltaTime); + SkeletonRagdoll* buildRagdoll(); + SkeletonRagdoll* getRagdoll() { return _ragdoll; } + void moveShapesTowardJoints(float fraction); - void updateMuscles(); void computeBoundingShape(const FBXGeometry& geometry); void renderBoundingCollisionShapes(float alpha); @@ -115,10 +116,6 @@ public: protected: - // virtual overrrides from Ragdoll - void initRagdollPoints(); - void buildRagdollConstraints(); - void buildShapes(); /// \param jointIndex index of joint in model @@ -147,7 +144,7 @@ private: CapsuleShape _boundingShape; glm::vec3 _boundingShapeLocalOffset; - QVector _muscleConstraints; + SkeletonRagdoll* _ragdoll; }; #endif // hifi_SkeletonModel_h diff --git a/interface/src/avatar/SkeletonRagdoll.cpp b/interface/src/avatar/SkeletonRagdoll.cpp new file mode 100644 index 0000000000..b63197bd2c --- /dev/null +++ b/interface/src/avatar/SkeletonRagdoll.cpp @@ -0,0 +1,148 @@ +// +// SkeletonRagdoll.cpp +// interface/src/avatar +// +// Created by Andrew Meadows 2014.08.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 +// + +#include +#include + +#include "SkeletonRagdoll.h" +#include "MuscleConstraint.h" +#include "../renderer/Model.h" + +SkeletonRagdoll::SkeletonRagdoll(Model* model) : Ragdoll(), _model(model) { + assert(_model); +} + +SkeletonRagdoll::~SkeletonRagdoll() { +} + +// virtual +void SkeletonRagdoll::stepRagdollForward(float deltaTime) { + setRagdollTransform(_model->getTranslation(), _model->getRotation()); + Ragdoll::stepRagdollForward(deltaTime); + updateMuscles(); + int numConstraints = _muscleConstraints.size(); + for (int i = 0; i < numConstraints; ++i) { + _muscleConstraints[i]->enforce(); + } +} + +void SkeletonRagdoll::slamPointPositions() { + QVector& jointStates = _model->getJointStates(); + int numStates = jointStates.size(); + for (int i = 0; i < numStates; ++i) { + _ragdollPoints[i].initPosition(jointStates.at(i).getPosition()); + } +} + +// virtual +void SkeletonRagdoll::initRagdollPoints() { + clearRagdollConstraintsAndPoints(); + _muscleConstraints.clear(); + + initRagdollTransform(); + // one point for each joint + QVector& jointStates = _model->getJointStates(); + int numStates = jointStates.size(); + _ragdollPoints.fill(VerletPoint(), numStates); + slamPointPositions(); +} + +// virtual +void SkeletonRagdoll::buildRagdollConstraints() { + QVector& jointStates = _model->getJointStates(); + + // NOTE: the length of DistanceConstraints is computed and locked in at this time + // so make sure the ragdoll positions are in a normal configuration before here. + const int numPoints = _ragdollPoints.size(); + assert(numPoints == jointStates.size()); + + float minBone = FLT_MAX; + float maxBone = -FLT_MAX; + QMultiMap families; + for (int i = 0; i < numPoints; ++i) { + const JointState& state = jointStates.at(i); + int parentIndex = state.getParentIndex(); + if (parentIndex == -1) { + FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_ragdollPoints[i])); + _fixedConstraints.push_back(anchor); + } else { + DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[i]), &(_ragdollPoints[parentIndex])); + bone->setDistance(state.getDistanceToParent()); + _boneConstraints.push_back(bone); + families.insert(parentIndex, i); + } + float boneLength = glm::length(state.getPositionInParentFrame()); + if (boneLength > maxBone) { + maxBone = boneLength; + } else if (boneLength < minBone) { + minBone = boneLength; + } + } + // Joints that have multiple children effectively have rigid constraints between the children + // in the parent frame, so we add DistanceConstraints between children in the same family. + QMultiMap::iterator itr = families.begin(); + while (itr != families.end()) { + QList children = families.values(itr.key()); + int numChildren = children.size(); + if (numChildren > 1) { + for (int i = 1; i < numChildren; ++i) { + DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[i-1]]), &(_ragdollPoints[children[i]])); + _boneConstraints.push_back(bone); + } + if (numChildren > 2) { + DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[numChildren-1]]), &(_ragdollPoints[children[0]])); + _boneConstraints.push_back(bone); + } + } + ++itr; + } + + float MAX_STRENGTH = 0.6f; + float MIN_STRENGTH = 0.05f; + // each joint gets a MuscleConstraint to its parent + for (int i = 1; i < numPoints; ++i) { + const JointState& state = jointStates.at(i); + int p = state.getParentIndex(); + if (p == -1) { + continue; + } + MuscleConstraint* constraint = new MuscleConstraint(&(_ragdollPoints[p]), &(_ragdollPoints[i])); + _muscleConstraints.push_back(constraint); + + // Short joints are more susceptible to wiggle so we modulate the strength based on the joint's length: + // long = weak and short = strong. + constraint->setIndices(p, i); + float boneLength = glm::length(state.getPositionInParentFrame()); + + float strength = MIN_STRENGTH + (MAX_STRENGTH - MIN_STRENGTH) * (maxBone - boneLength) / (maxBone - minBone); + if (!families.contains(i)) { + // Although muscles only pull on the children not parents, nevertheless those joints that have + // parents AND children are more stable than joints at the end such as fingers. For such joints we + // bestow maximum strength which helps reduce wiggle. + strength = MAX_MUSCLE_STRENGTH; + } + constraint->setStrength(strength); + } +} + +void SkeletonRagdoll::updateMuscles() { + QVector& jointStates = _model->getJointStates(); + int numConstraints = _muscleConstraints.size(); + glm::quat rotation = _model->getRotation(); + for (int i = 0; i < numConstraints; ++i) { + MuscleConstraint* constraint = _muscleConstraints[i]; + int j = constraint->getParentIndex(); + int k = constraint->getChildIndex(); + assert(j != -1 && k != -1); + // ragdollPoints are in simulation-frame but jointStates are in model-frame + constraint->setChildOffset(rotation * (jointStates.at(k).getPosition() - jointStates.at(j).getPosition())); + } +} diff --git a/interface/src/avatar/SkeletonRagdoll.h b/interface/src/avatar/SkeletonRagdoll.h new file mode 100644 index 0000000000..e9638eafac --- /dev/null +++ b/interface/src/avatar/SkeletonRagdoll.h @@ -0,0 +1,42 @@ +// +// SkeletonkRagdoll.h +// interface/src/avatar +// +// Created by Andrew Meadows 2014.08.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 +// + +#ifndef hifi_SkeletonRagdoll_h +#define hifi_SkeletonRagdoll_h + +#include + +#include + +#include "../renderer/JointState.h" + +class MuscleConstraint; +class Model; + +class SkeletonRagdoll : public Ragdoll { +public: + + SkeletonRagdoll(Model* model); + virtual ~SkeletonRagdoll(); + + void slamPointPositions(); + virtual void stepRagdollForward(float deltaTime); + + virtual void initRagdollPoints(); + virtual void buildRagdollConstraints(); + + void updateMuscles(); +private: + Model* _model; + QVector _muscleConstraints; +}; + +#endif // hifi_SkeletonRagdoll_h diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 7a29b61420..da72d43133 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -164,6 +164,9 @@ public: const QVector& getLocalLights() const { return _localLights; } void setShowTrueJointTransforms(bool show) { _showTrueJointTransforms = show; } + + QVector& getJointStates() { return _jointStates; } + const QVector& getJointStates() const { return _jointStates; } protected: QSharedPointer _geometry; diff --git a/libraries/shared/src/Ragdoll.h b/libraries/shared/src/Ragdoll.h index ec5a561d1a..75f263149e 100644 --- a/libraries/shared/src/Ragdoll.h +++ b/libraries/shared/src/Ragdoll.h @@ -52,11 +52,11 @@ public: void setMassScale(float scale); float getMassScale() const { return _massScale; } -protected: void clearRagdollConstraintsAndPoints(); virtual void initRagdollPoints() = 0; virtual void buildRagdollConstraints() = 0; +protected: float _massScale; glm::vec3 _ragdollTranslation; // world-frame glm::quat _ragdollRotation; // world-frame From 60d411ead50f5701be7f6b88652ccd9ebe9610ba Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Aug 2014 14:41:51 -0700 Subject: [PATCH 381/407] cleanup Ragdoll API (less "ragdoll" qualifiers) --- interface/src/avatar/SkeletonModel.cpp | 16 ++++---- interface/src/avatar/SkeletonRagdoll.cpp | 30 +++++++-------- interface/src/avatar/SkeletonRagdoll.h | 6 +-- libraries/shared/src/PhysicsSimulation.cpp | 28 +++++++------- libraries/shared/src/Ragdoll.cpp | 44 +++++++++++----------- libraries/shared/src/Ragdoll.h | 26 ++++++------- 6 files changed, 75 insertions(+), 75 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 90145f0af8..ffe711b03b 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -497,7 +497,7 @@ void SkeletonModel::renderRagdoll() { if (!_ragdoll) { return; } - const QVector& points = _ragdoll->getRagdollPoints(); + const QVector& points = _ragdoll->getPoints(); const int BALL_SUBDIVISIONS = 6; glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); @@ -531,7 +531,7 @@ void SkeletonModel::updateVisibleJointStates() { // no need to update visible transforms return; } - const QVector& ragdollPoints = _ragdoll->getRagdollPoints(); + const QVector& ragdollPoints = _ragdoll->getPoints(); QVector points; points.reserve(_jointStates.size()); glm::quat invRotation = glm::inverse(_rotation); @@ -599,8 +599,8 @@ void SkeletonModel::buildShapes() { if (!_ragdoll) { _ragdoll = new SkeletonRagdoll(this); } - _ragdoll->initRagdollPoints(); - QVector& points = _ragdoll->getRagdollPoints(); + _ragdoll->initPoints(); + QVector& points = _ragdoll->getPoints(); float massScale = _ragdoll->getMassScale(); @@ -651,11 +651,11 @@ void SkeletonModel::buildShapes() { // joints that are currently colliding. disableCurrentSelfCollisions(); - _ragdoll->buildRagdollConstraints(); + _ragdoll->buildConstraints(); // ... then move shapes back to current joint positions _ragdoll->slamPointPositions(); - _ragdoll->enforceRagdollConstraints(); + _ragdoll->enforceConstraints(); } void SkeletonModel::moveShapesTowardJoints(float deltaTime) { @@ -663,7 +663,7 @@ void SkeletonModel::moveShapesTowardJoints(float deltaTime) { // unravel a skelton that has become tangled in its constraints. So let's keep this // around for a while just in case. const int numStates = _jointStates.size(); - QVector& ragdollPoints = _ragdoll->getRagdollPoints(); + QVector& ragdollPoints = _ragdoll->getPoints(); assert(_jointStates.size() == ragdollPoints.size()); if (ragdollPoints.size() != numStates) { return; @@ -688,7 +688,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { QVector transforms; transforms.fill(glm::mat4(), numStates); - QVector& ragdollPoints = _ragdoll->getRagdollPoints(); + QVector& ragdollPoints = _ragdoll->getPoints(); // compute the default transforms and slam the ragdoll positions accordingly // (which puts the shapes where we want them) diff --git a/interface/src/avatar/SkeletonRagdoll.cpp b/interface/src/avatar/SkeletonRagdoll.cpp index b63197bd2c..503f38f00f 100644 --- a/interface/src/avatar/SkeletonRagdoll.cpp +++ b/interface/src/avatar/SkeletonRagdoll.cpp @@ -24,9 +24,9 @@ SkeletonRagdoll::~SkeletonRagdoll() { } // virtual -void SkeletonRagdoll::stepRagdollForward(float deltaTime) { - setRagdollTransform(_model->getTranslation(), _model->getRotation()); - Ragdoll::stepRagdollForward(deltaTime); +void SkeletonRagdoll::stepForward(float deltaTime) { + setTransform(_model->getTranslation(), _model->getRotation()); + Ragdoll::stepForward(deltaTime); updateMuscles(); int numConstraints = _muscleConstraints.size(); for (int i = 0; i < numConstraints; ++i) { @@ -38,30 +38,30 @@ void SkeletonRagdoll::slamPointPositions() { QVector& jointStates = _model->getJointStates(); int numStates = jointStates.size(); for (int i = 0; i < numStates; ++i) { - _ragdollPoints[i].initPosition(jointStates.at(i).getPosition()); + _points[i].initPosition(jointStates.at(i).getPosition()); } } // virtual -void SkeletonRagdoll::initRagdollPoints() { - clearRagdollConstraintsAndPoints(); +void SkeletonRagdoll::initPoints() { + clearConstraintsAndPoints(); _muscleConstraints.clear(); - initRagdollTransform(); + initTransform(); // one point for each joint QVector& jointStates = _model->getJointStates(); int numStates = jointStates.size(); - _ragdollPoints.fill(VerletPoint(), numStates); + _points.fill(VerletPoint(), numStates); slamPointPositions(); } // virtual -void SkeletonRagdoll::buildRagdollConstraints() { +void SkeletonRagdoll::buildConstraints() { QVector& jointStates = _model->getJointStates(); // NOTE: the length of DistanceConstraints is computed and locked in at this time // so make sure the ragdoll positions are in a normal configuration before here. - const int numPoints = _ragdollPoints.size(); + const int numPoints = _points.size(); assert(numPoints == jointStates.size()); float minBone = FLT_MAX; @@ -71,10 +71,10 @@ void SkeletonRagdoll::buildRagdollConstraints() { const JointState& state = jointStates.at(i); int parentIndex = state.getParentIndex(); if (parentIndex == -1) { - FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_ragdollPoints[i])); + FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_points[i])); _fixedConstraints.push_back(anchor); } else { - DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[i]), &(_ragdollPoints[parentIndex])); + DistanceConstraint* bone = new DistanceConstraint(&(_points[i]), &(_points[parentIndex])); bone->setDistance(state.getDistanceToParent()); _boneConstraints.push_back(bone); families.insert(parentIndex, i); @@ -94,11 +94,11 @@ void SkeletonRagdoll::buildRagdollConstraints() { int numChildren = children.size(); if (numChildren > 1) { for (int i = 1; i < numChildren; ++i) { - DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[i-1]]), &(_ragdollPoints[children[i]])); + DistanceConstraint* bone = new DistanceConstraint(&(_points[children[i-1]]), &(_points[children[i]])); _boneConstraints.push_back(bone); } if (numChildren > 2) { - DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[numChildren-1]]), &(_ragdollPoints[children[0]])); + DistanceConstraint* bone = new DistanceConstraint(&(_points[children[numChildren-1]]), &(_points[children[0]])); _boneConstraints.push_back(bone); } } @@ -114,7 +114,7 @@ void SkeletonRagdoll::buildRagdollConstraints() { if (p == -1) { continue; } - MuscleConstraint* constraint = new MuscleConstraint(&(_ragdollPoints[p]), &(_ragdollPoints[i])); + MuscleConstraint* constraint = new MuscleConstraint(&(_points[p]), &(_points[i])); _muscleConstraints.push_back(constraint); // Short joints are more susceptible to wiggle so we modulate the strength based on the joint's length: diff --git a/interface/src/avatar/SkeletonRagdoll.h b/interface/src/avatar/SkeletonRagdoll.h index e9638eafac..f9f99395ac 100644 --- a/interface/src/avatar/SkeletonRagdoll.h +++ b/interface/src/avatar/SkeletonRagdoll.h @@ -28,10 +28,10 @@ public: virtual ~SkeletonRagdoll(); void slamPointPositions(); - virtual void stepRagdollForward(float deltaTime); + virtual void stepForward(float deltaTime); - virtual void initRagdollPoints(); - virtual void buildRagdollConstraints(); + virtual void initPoints(); + virtual void buildConstraints(); void updateMuscles(); private: diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index 6dcafc6a54..84f8282c9d 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -47,12 +47,12 @@ PhysicsSimulation::~PhysicsSimulation() { void PhysicsSimulation::setRagdoll(Ragdoll* ragdoll) { if (_ragdoll != ragdoll) { if (_ragdoll) { - _ragdoll->_ragdollSimulation = NULL; + _ragdoll->_simulation = NULL; } _ragdoll = ragdoll; if (_ragdoll) { - assert(!(_ragdoll->_ragdollSimulation)); - _ragdoll->_ragdollSimulation = this; + assert(!(_ragdoll->_simulation)); + _ragdoll->_simulation = this; } } } @@ -144,7 +144,7 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { // list is full return false; } - if (doll->_ragdollSimulation == this) { + if (doll->_simulation == this) { for (int i = 0; i < numDolls; ++i) { if (doll == _otherRagdolls[i]) { // already in list @@ -153,8 +153,8 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { } } // add to list - assert(!(doll->_ragdollSimulation)); - doll->_ragdollSimulation = this; + assert(!(doll->_simulation)); + doll->_simulation = this; _otherRagdolls.push_back(doll); // set the massScale of otherRagdolls artificially high @@ -164,7 +164,7 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { int numDolls = _otherRagdolls.size(); - if (doll->_ragdollSimulation != this) { + if (doll->_simulation != this) { return; } for (int i = 0; i < numDolls; ++i) { @@ -178,7 +178,7 @@ void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { _otherRagdolls.pop_back(); _otherRagdolls[i] = lastDoll; } - doll->_ragdollSimulation = NULL; + doll->_simulation = NULL; doll->setMassScale(1.0f); break; } @@ -199,9 +199,9 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter int numDolls = _otherRagdolls.size(); { PerformanceTimer perfTimer("enforce"); - _ragdoll->enforceRagdollConstraints(); + _ragdoll->enforceConstraints(); for (int i = 0; i < numDolls; ++i) { - _otherRagdolls[i]->enforceRagdollConstraints(); + _otherRagdolls[i]->enforceConstraints(); } } @@ -214,9 +214,9 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter { // enforce constraints PerformanceTimer perfTimer("enforce"); - error = _ragdoll->enforceRagdollConstraints(); + error = _ragdoll->enforceConstraints(); for (int i = 0; i < numDolls; ++i) { - error = glm::max(error, _otherRagdolls[i]->enforceRagdollConstraints()); + error = glm::max(error, _otherRagdolls[i]->enforceConstraints()); } } enforceContactConstraints(); @@ -230,10 +230,10 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter void PhysicsSimulation::moveRagdolls(float deltaTime) { PerformanceTimer perfTimer("integrate"); - _ragdoll->stepRagdollForward(deltaTime); + _ragdoll->stepForward(deltaTime); int numDolls = _otherRagdolls.size(); for (int i = 0; i < numDolls; ++i) { - _otherRagdolls[i]->stepRagdollForward(deltaTime); + _otherRagdolls[i]->stepForward(deltaTime); } } diff --git a/libraries/shared/src/Ragdoll.cpp b/libraries/shared/src/Ragdoll.cpp index 80e3c27e04..7eeaf0b609 100644 --- a/libraries/shared/src/Ragdoll.cpp +++ b/libraries/shared/src/Ragdoll.cpp @@ -19,27 +19,27 @@ #include "PhysicsSimulation.h" #include "SharedUtil.h" // for EPSILON -Ragdoll::Ragdoll() : _massScale(1.0f), _ragdollTranslation(0.0f), _translationInSimulationFrame(0.0f), _ragdollSimulation(NULL) { +Ragdoll::Ragdoll() : _massScale(1.0f), _translation(0.0f), _translationInSimulationFrame(0.0f), _simulation(NULL) { } Ragdoll::~Ragdoll() { - clearRagdollConstraintsAndPoints(); - if (_ragdollSimulation) { - _ragdollSimulation->removeRagdoll(this); + clearConstraintsAndPoints(); + if (_simulation) { + _simulation->removeRagdoll(this); } } -void Ragdoll::stepRagdollForward(float deltaTime) { - if (_ragdollSimulation) { - updateSimulationTransforms(_ragdollTranslation - _ragdollSimulation->getTranslation(), _ragdollRotation); +void Ragdoll::stepForward(float deltaTime) { + if (_simulation) { + updateSimulationTransforms(_translation - _simulation->getTranslation(), _rotation); } - int numPoints = _ragdollPoints.size(); + int numPoints = _points.size(); for (int i = 0; i < numPoints; ++i) { - _ragdollPoints[i].integrateForward(); + _points[i].integrateForward(); } } -void Ragdoll::clearRagdollConstraintsAndPoints() { +void Ragdoll::clearConstraintsAndPoints() { int numConstraints = _boneConstraints.size(); for (int i = 0; i < numConstraints; ++i) { delete _boneConstraints[i]; @@ -50,10 +50,10 @@ void Ragdoll::clearRagdollConstraintsAndPoints() { delete _fixedConstraints[i]; } _fixedConstraints.clear(); - _ragdollPoints.clear(); + _points.clear(); } -float Ragdoll::enforceRagdollConstraints() { +float Ragdoll::enforceConstraints() { float maxDistance = 0.0f; // enforce the bone constraints first int numConstraints = _boneConstraints.size(); @@ -68,16 +68,16 @@ float Ragdoll::enforceRagdollConstraints() { return maxDistance; } -void Ragdoll::initRagdollTransform() { - _ragdollTranslation = glm::vec3(0.0f); - _ragdollRotation = glm::quat(); +void Ragdoll::initTransform() { + _translation = glm::vec3(0.0f); + _rotation = glm::quat(); _translationInSimulationFrame = glm::vec3(0.0f); _rotationInSimulationFrame = glm::quat(); } -void Ragdoll::setRagdollTransform(const glm::vec3& translation, const glm::quat& rotation) { - _ragdollTranslation = translation; - _ragdollRotation = rotation; +void Ragdoll::setTransform(const glm::vec3& translation, const glm::quat& rotation) { + _translation = translation; + _rotation = rotation; } void Ragdoll::updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation) { @@ -93,9 +93,9 @@ void Ragdoll::updateSimulationTransforms(const glm::vec3& translation, const glm glm::quat deltaRotation = rotation * glm::inverse(_rotationInSimulationFrame); // apply the deltas to all ragdollPoints - int numPoints = _ragdollPoints.size(); + int numPoints = _points.size(); for (int i = 0; i < numPoints; ++i) { - _ragdollPoints[i].move(deltaPosition, deltaRotation, _translationInSimulationFrame); + _points[i].move(deltaPosition, deltaRotation, _translationInSimulationFrame); } // remember the current transform @@ -109,9 +109,9 @@ void Ragdoll::setMassScale(float scale) { scale = glm::clamp(glm::abs(scale), MIN_SCALE, MAX_SCALE); if (scale != _massScale) { float rescale = scale / _massScale; - int numPoints = _ragdollPoints.size(); + int numPoints = _points.size(); for (int i = 0; i < numPoints; ++i) { - _ragdollPoints[i].setMass(rescale * _ragdollPoints[i].getMass()); + _points[i].setMass(rescale * _points[i].getMass()); } _massScale = scale; } diff --git a/libraries/shared/src/Ragdoll.h b/libraries/shared/src/Ragdoll.h index 75f263149e..c82295d9a5 100644 --- a/libraries/shared/src/Ragdoll.h +++ b/libraries/shared/src/Ragdoll.h @@ -33,44 +33,44 @@ public: Ragdoll(); virtual ~Ragdoll(); - virtual void stepRagdollForward(float deltaTime); + virtual void stepForward(float deltaTime); /// \return max distance of point movement - float enforceRagdollConstraints(); + float enforceConstraints(); // both const and non-const getPoints() - const QVector& getRagdollPoints() const { return _ragdollPoints; } - QVector& getRagdollPoints() { return _ragdollPoints; } + const QVector& getPoints() const { return _points; } + QVector& getPoints() { return _points; } - void initRagdollTransform(); + void initTransform(); /// set the translation and rotation of the Ragdoll and adjust all VerletPoints. - void setRagdollTransform(const glm::vec3& translation, const glm::quat& rotation); + void setTransform(const glm::vec3& translation, const glm::quat& rotation); const glm::vec3& getTranslationInSimulationFrame() const { return _translationInSimulationFrame; } void setMassScale(float scale); float getMassScale() const { return _massScale; } - void clearRagdollConstraintsAndPoints(); - virtual void initRagdollPoints() = 0; - virtual void buildRagdollConstraints() = 0; + void clearConstraintsAndPoints(); + virtual void initPoints() = 0; + virtual void buildConstraints() = 0; protected: float _massScale; - glm::vec3 _ragdollTranslation; // world-frame - glm::quat _ragdollRotation; // world-frame + glm::vec3 _translation; // world-frame + glm::quat _rotation; // world-frame glm::vec3 _translationInSimulationFrame; glm::quat _rotationInSimulationFrame; - QVector _ragdollPoints; + QVector _points; QVector _boneConstraints; QVector _fixedConstraints; private: void updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation); friend class PhysicsSimulation; - PhysicsSimulation* _ragdollSimulation; + PhysicsSimulation* _simulation; }; #endif // hifi_Ragdoll_h From 98d27ad2b53656da0f2b38761f6720d2a0dc45df Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Aug 2014 15:17:03 -0700 Subject: [PATCH 382/407] more correct names for ContactPoint API renamed (and disabled) the useless enforce() to applyFriction() changed the buildConstraints() method to more correct name: enforce() will eventually change how ContactPoint actually works, but later --- libraries/shared/src/ContactPoint.cpp | 39 ++++++++++++---------- libraries/shared/src/ContactPoint.h | 4 +-- libraries/shared/src/PhysicsSimulation.cpp | 24 ++++++------- libraries/shared/src/PhysicsSimulation.h | 4 +-- 4 files changed, 37 insertions(+), 34 deletions(-) diff --git a/libraries/shared/src/ContactPoint.cpp b/libraries/shared/src/ContactPoint.cpp index 4c1cf7b842..4f1cf87da5 100644 --- a/libraries/shared/src/ContactPoint.cpp +++ b/libraries/shared/src/ContactPoint.cpp @@ -88,25 +88,7 @@ ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : } } -// virtual float ContactPoint::enforce() { - for (int i = 0; i < _numPoints; ++i) { - glm::vec3& position = _points[i]->_position; - // TODO: use a fast distance approximation - float newDistance = glm::distance(_contactPoint, position); - float constrainedDistance = _distances[i]; - // NOTE: these "distance" constraints only push OUT, don't pull IN. - if (newDistance > EPSILON && newDistance < constrainedDistance) { - glm::vec3 direction = (_contactPoint - position) / newDistance; - glm::vec3 center = 0.5f * (_contactPoint + position); - _contactPoint = center + (0.5f * constrainedDistance) * direction; - position = center - (0.5f * constrainedDistance) * direction; - } - } - return 0.0f; -} - -void ContactPoint::buildConstraints() { glm::vec3 pointA = _shapeA->getTranslation() + _offsetA; glm::vec3 pointB = _shapeB->getTranslation() + _offsetB; glm::vec3 penetration = pointA - pointB; @@ -153,6 +135,27 @@ void ContactPoint::buildConstraints() { _distances[i] = glm::length(glm::length(_offsets[i])); } } + return 0.0f; +} + +// virtual +void ContactPoint::applyFriction() { + // TODO: Andrew to re-implement this + /* + for (int i = 0; i < _numPoints; ++i) { + glm::vec3& position = _points[i]->_position; + // TODO: use a fast distance approximation + float newDistance = glm::distance(_contactPoint, position); + float constrainedDistance = _distances[i]; + // NOTE: these "distance" constraints only push OUT, don't pull IN. + if (newDistance > EPSILON && newDistance < constrainedDistance) { + glm::vec3 direction = (_contactPoint - position) / newDistance; + glm::vec3 center = 0.5f * (_contactPoint + position); + _contactPoint = center + (0.5f * constrainedDistance) * direction; + position = center - (0.5f * constrainedDistance) * direction; + } + } + */ } void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) { diff --git a/libraries/shared/src/ContactPoint.h b/libraries/shared/src/ContactPoint.h index 5257fabee0..d584945970 100644 --- a/libraries/shared/src/ContactPoint.h +++ b/libraries/shared/src/ContactPoint.h @@ -26,8 +26,8 @@ public: ContactPoint(const CollisionInfo& collision, quint32 frame); virtual float enforce(); - - void buildConstraints(); + + void applyFriction(); void updateContact(const CollisionInfo& collision, quint32 frame); quint32 getLastFrame() const { return _lastFrame; } diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index 84f8282c9d..a62b3816af 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -195,7 +195,7 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter quint64 expiry = startTime + maxUsec; moveRagdolls(deltaTime); - buildContactConstraints(); + enforceContacts(); int numDolls = _otherRagdolls.size(); { PerformanceTimer perfTimer("enforce"); @@ -219,7 +219,7 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter error = glm::max(error, _otherRagdolls[i]->enforceConstraints()); } } - enforceContactConstraints(); + applyContactFriction(); ++iterations; now = usecTimestampNow(); @@ -288,16 +288,7 @@ void PhysicsSimulation::resolveCollisions() { } } -void PhysicsSimulation::buildContactConstraints() { - PerformanceTimer perfTimer("contacts"); - QMap::iterator itr = _contacts.begin(); - while (itr != _contacts.end()) { - itr.value().buildConstraints(); - ++itr; - } -} - -void PhysicsSimulation::enforceContactConstraints() { +void PhysicsSimulation::enforceContacts() { PerformanceTimer perfTimer("contacts"); QMap::iterator itr = _contacts.begin(); while (itr != _contacts.end()) { @@ -306,6 +297,15 @@ void PhysicsSimulation::enforceContactConstraints() { } } +void PhysicsSimulation::applyContactFriction() { + PerformanceTimer perfTimer("contacts"); + QMap::iterator itr = _contacts.begin(); + while (itr != _contacts.end()) { + itr.value().applyFriction(); + ++itr; + } +} + void PhysicsSimulation::updateContacts() { PerformanceTimer perfTimer("contacts"); int numCollisions = _collisions.size(); diff --git a/libraries/shared/src/PhysicsSimulation.h b/libraries/shared/src/PhysicsSimulation.h index 61ab1bf177..881007208b 100644 --- a/libraries/shared/src/PhysicsSimulation.h +++ b/libraries/shared/src/PhysicsSimulation.h @@ -56,8 +56,8 @@ protected: void computeCollisions(); void resolveCollisions(); - void buildContactConstraints(); - void enforceContactConstraints(); + void enforceContacts(); + void applyContactFriction(); void updateContacts(); void pruneContacts(); From 432c14408c05d1f99a7b09bed4c4a619f2d98035 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Aug 2014 15:29:57 -0700 Subject: [PATCH 383/407] removed hackery from ContactPoint enforcement --- libraries/shared/src/ContactPoint.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/libraries/shared/src/ContactPoint.cpp b/libraries/shared/src/ContactPoint.cpp index 4f1cf87da5..27a496d445 100644 --- a/libraries/shared/src/ContactPoint.cpp +++ b/libraries/shared/src/ContactPoint.cpp @@ -98,14 +98,6 @@ float ContactPoint::enforce() { // the contact point will be the average of the two points on the shapes _contactPoint = 0.5f * (pointA + pointB); - // TODO: Andrew to compute more correct lagrangian weights that provide a more realistic response. - // - // HACK: since the weights are naively equal for all points (which is what the above TODO is about) we - // don't want to use the full-strength delta because otherwise there can be annoying oscillations. We - // reduce this problem by in the short-term by attenuating the delta that is applied, the tradeoff is - // that this makes it easier for limbs to tunnel through during collisions. - const float HACK_STRENGTH = 0.5f; - if (constraintViolation) { for (int i = 0; i < _numPoints; ++i) { VerletPoint* point = _points[i]; @@ -128,7 +120,7 @@ float ContactPoint::enforce() { glm::vec3 targetPosition = point->_position + delta; _distances[i] = glm::distance(_contactPoint, targetPosition); - point->_position += HACK_STRENGTH * delta; + point->_position += delta; } } else { for (int i = 0; i < _numPoints; ++i) { @@ -140,7 +132,7 @@ float ContactPoint::enforce() { // virtual void ContactPoint::applyFriction() { - // TODO: Andrew to re-implement this + // TODO: Andrew to re-implement this in a different way /* for (int i = 0; i < _numPoints; ++i) { glm::vec3& position = _points[i]->_position; From e3bab8bdc865c979811b0584b22c89a50a355fd7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Aug 2014 15:47:03 -0700 Subject: [PATCH 384/407] require presence of LibOVR for relative position from OculusManager --- interface/src/devices/OculusManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 7d7375fad5..3582f82820 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -504,7 +504,7 @@ void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { } glm::vec3 OculusManager::getRelativePosition() { -#if defined(__APPLE__) || defined(_WIN32) +#if (defined(__APPLE__) || defined(_WIN32)) && HAVE_LIBOVR ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); ovrVector3f headPosition = trackingState.HeadPose.ThePose.Position; From 05d6b628fa7defff44195163811b0ce309f2f1f8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 14 Aug 2014 17:10:45 -0700 Subject: [PATCH 385/407] Alllmost ready with the big edge sharing rejiggery. --- interface/src/MetavoxelSystem.cpp | 463 +++++++++++------- interface/src/MetavoxelSystem.h | 16 + .../metavoxels/src/AttributeRegistry.cpp | 2 +- libraries/metavoxels/src/MetavoxelUtil.cpp | 5 + libraries/metavoxels/src/MetavoxelUtil.h | 2 + 5 files changed, 304 insertions(+), 184 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index a5f5de5123..40a2ff0097 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -37,6 +37,9 @@ void MetavoxelSystem::init() { _pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new BufferDataAttribute("pointBuffer")); _heightfieldBufferAttribute = AttributeRegistry::getInstance()->registerAttribute( new BufferDataAttribute("heightfieldBuffer")); + + _heightfieldBufferAttribute->setLODThresholdMultiplier( + AttributeRegistry::getInstance()->getHeightfieldAttribute()->getLODThresholdMultiplier()); } MetavoxelLOD MetavoxelSystem::getLOD() { @@ -382,7 +385,7 @@ float MetavoxelSystem::getHeightfieldHeight(const glm::vec3& location) { class HeightfieldCursorRenderVisitor : public MetavoxelVisitor { public: - HeightfieldCursorRenderVisitor(const MetavoxelLOD& lod, const Box& bounds); + HeightfieldCursorRenderVisitor(const Box& bounds); virtual int visit(MetavoxelInfo& info); @@ -391,9 +394,9 @@ private: Box _bounds; }; -HeightfieldCursorRenderVisitor::HeightfieldCursorRenderVisitor(const MetavoxelLOD& lod, const Box& bounds) : +HeightfieldCursorRenderVisitor::HeightfieldCursorRenderVisitor(const Box& bounds) : MetavoxelVisitor(QVector() << - Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector(), lod), + Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute()), _bounds(bounds) { } @@ -433,7 +436,7 @@ void MetavoxelSystem::renderHeightfieldCursor(const glm::vec3& position, float r glActiveTexture(GL_TEXTURE0); glm::vec3 extents(radius, radius, radius); - HeightfieldCursorRenderVisitor visitor(getLOD(), Box(position - extents, position + extents)); + HeightfieldCursorRenderVisitor visitor(Box(position - extents, position + extents)); guideToAugmented(visitor); DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().release(); @@ -601,11 +604,24 @@ HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color) : _translation(translation), _scale(scale), + _heightBounds(translation, translation + glm::vec3(scale, scale, scale)), + _colorBounds(_heightBounds), _height(height), _color(color), _heightTextureID(0), _colorTextureID(0), - _heightSize(glm::sqrt(height.size())) { + _heightSize(glm::sqrt(height.size())), + _heightIncrement(scale / (_heightSize - HEIGHT_EXTENSION)), + _colorSize(glm::sqrt(color.size() / HeightfieldData::COLOR_BYTES)), + _colorIncrement(scale / (_colorSize - SHARED_EDGE)) { + + _heightBounds.minimum.x -= _heightIncrement * HEIGHT_BORDER; + _heightBounds.minimum.z -= _heightIncrement * HEIGHT_BORDER; + _heightBounds.maximum.x += _heightIncrement * (SHARED_EDGE + HEIGHT_BORDER); + _heightBounds.maximum.z += _heightIncrement * (SHARED_EDGE + HEIGHT_BORDER); + + _colorBounds.maximum.x += _colorIncrement * SHARED_EDGE; + _colorBounds.maximum.z += _colorIncrement * SHARED_EDGE; } HeightfieldBuffer::~HeightfieldBuffer() { @@ -807,17 +823,19 @@ BufferDataAttribute::BufferDataAttribute(const QString& name) : } bool BufferDataAttribute::merge(void*& parent, void* children[], bool postRead) const { - BufferDataPointer firstChild = decodeInline(children[0]); - for (int i = 1; i < MERGE_COUNT; i++) { - if (firstChild != decodeInline(children[i])) { - *(BufferDataPointer*)&parent = _defaultValue; + *(BufferDataPointer*)&parent = _defaultValue; + for (int i = 0; i < MERGE_COUNT; i++) { + if (decodeInline(children[i])) { return false; } } - *(BufferDataPointer*)&parent = firstChild; return true; } +AttributeValue BufferDataAttribute::inherit(const AttributeValue& parentValue) const { + return AttributeValue(parentValue.getAttribute()); +} + void DefaultMetavoxelRendererImplementation::init() { if (!_pointProgram.isLinked()) { _pointProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert"); @@ -923,206 +941,279 @@ bool PointAugmentVisitor::postVisit(MetavoxelInfo& info) { return true; } -class HeightfieldAugmentVisitor : public MetavoxelVisitor { -public: - - HeightfieldAugmentVisitor(const MetavoxelLOD& lod); - - virtual int visit(MetavoxelInfo& info); -}; - -HeightfieldAugmentVisitor::HeightfieldAugmentVisitor(const MetavoxelLOD& lod) : - MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getHeightfieldAttribute() << - AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), QVector() << - Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod) { -} - -class BorderFetchVisitor : public MetavoxelVisitor { +class HeightfieldFetchVisitor : public MetavoxelVisitor { public: - BorderFetchVisitor(const MetavoxelLOD& lod, HeightfieldBuffer* buffer); + HeightfieldFetchVisitor(const MetavoxelLOD& lod, const QVector& intersections); + + void init(HeightfieldBuffer* buffer) { _buffer = buffer; } virtual int visit(MetavoxelInfo& info); private: + const QVector& _intersections; HeightfieldBuffer* _buffer; - Box _expandedBounds; - int _heightSize; - float _heightExtension; - int _colorSize; - float _colorExtension; - Box _colorBounds; }; -BorderFetchVisitor::BorderFetchVisitor(const MetavoxelLOD& lod, HeightfieldBuffer* buffer) : +HeightfieldFetchVisitor::HeightfieldFetchVisitor(const MetavoxelLOD& lod, const QVector& intersections) : MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getHeightfieldAttribute() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), QVector(), lod), - _buffer(buffer), - _expandedBounds(_buffer->getTranslation(), _buffer->getTranslation() + - glm::vec3(_buffer->getScale(), _buffer->getScale(), _buffer->getScale())), - _heightSize(glm::sqrt(buffer->getHeight().size())), - _heightExtension(_buffer->getScale() / (_heightSize - HeightfieldBuffer::HEIGHT_EXTENSION)), - _colorSize(glm::sqrt(buffer->getColor().size() / HeightfieldData::COLOR_BYTES)), - _colorBounds(_expandedBounds) { - - _expandedBounds.minimum.x -= _heightExtension * HeightfieldBuffer::HEIGHT_BORDER; - _expandedBounds.minimum.z -= _heightExtension * HeightfieldBuffer::HEIGHT_BORDER; - _expandedBounds.maximum.x += _heightExtension * (HeightfieldBuffer::HEIGHT_BORDER + HeightfieldBuffer::SHARED_EDGE); - _expandedBounds.maximum.z += _heightExtension * (HeightfieldBuffer::HEIGHT_BORDER + HeightfieldBuffer::SHARED_EDGE); - - if (_colorSize > 0) { - _colorExtension = buffer->getScale() / (_colorSize - HeightfieldBuffer::SHARED_EDGE); - _colorBounds.maximum.x += _colorExtension * HeightfieldBuffer::SHARED_EDGE; - _colorBounds.maximum.z += _colorExtension * HeightfieldBuffer::SHARED_EDGE; - } + _intersections(intersections) { } -int BorderFetchVisitor::visit(MetavoxelInfo& info) { +int HeightfieldFetchVisitor::visit(MetavoxelInfo& info) { Box bounds = info.getBounds(); - if (!bounds.intersects(_expandedBounds)) { + const Box& heightBounds = _buffer->getHeightBounds(); + if (!bounds.intersects(heightBounds)) { return STOP_RECURSION; } if (!info.isLeaf && info.size > _buffer->getScale()) { return DEFAULT_ORDER; } - if (_expandedBounds.contains(bounds)) { - return STOP_RECURSION; // this is the principal, which we've already filled in - } HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue(); if (!height) { return STOP_RECURSION; } - Box intersection = bounds.getIntersection(_expandedBounds); - int destX = glm::round((intersection.minimum.x - _expandedBounds.minimum.x) / _heightExtension); - int destY = glm::round((intersection.minimum.z - _expandedBounds.minimum.z) / _heightExtension); - int destWidth = glm::round((intersection.maximum.x - intersection.minimum.x) / _heightExtension); - int destHeight = glm::round((intersection.maximum.z - intersection.minimum.z) / _heightExtension); - char* dest = _buffer->getHeight().data() + destY * _heightSize + destX; - - const QByteArray& srcHeight = height->getContents(); - int srcSize = glm::sqrt(srcHeight.size()); - float srcExtension = info.size / srcSize; - - if (info.size == _buffer->getScale() && srcSize == (_heightSize - HeightfieldBuffer::HEIGHT_EXTENSION)) { - // easy case: same resolution - int srcX = glm::round((intersection.minimum.x - info.minimum.x) / srcExtension); - int srcY = glm::round((intersection.minimum.z - info.minimum.z) / srcExtension); + foreach (const Box& intersection, _intersections) { + Box overlap = intersection.getIntersection(bounds); + if (overlap.isEmpty()) { + continue; + } + float heightIncrement = _buffer->getHeightIncrement(); + int destX = (overlap.minimum.x - heightBounds.minimum.x) / heightIncrement; + int destY = (overlap.minimum.z - heightBounds.minimum.z) / heightIncrement; + int destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / heightIncrement); + int destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / heightIncrement); + int heightSize = _buffer->getHeightSize(); + char* dest = _buffer->getHeight().data() + destY * heightSize + destX; - const char* src = srcHeight.constData() + srcY * srcSize + srcX; - for (int y = 0; y < destHeight; y++, src += srcSize, dest += _heightSize) { - memcpy(dest, src, destWidth); + const QByteArray& srcHeight = height->getContents(); + int srcSize = glm::sqrt(srcHeight.size()); + float srcIncrement = info.size / srcSize; + + if (info.size == _buffer->getScale() && srcSize == (heightSize - HeightfieldBuffer::HEIGHT_EXTENSION)) { + // easy case: same resolution + int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; + int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; + + const char* src = srcHeight.constData() + srcY * srcSize + srcX; + for (int y = 0; y < destHeight; y++, src += srcSize, dest += heightSize) { + memcpy(dest, src, destWidth); + } + } else { + // more difficult: different resolutions + float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; + float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; + float srcAdvance = heightIncrement / srcIncrement; + int shift = 0; + float size = _buffer->getScale(); + while (size < info.size) { + shift++; + size *= 2.0f; + } + const int EIGHT_BIT_MAXIMUM = 255; + int subtract = (_buffer->getTranslation().y - info.minimum.y) * EIGHT_BIT_MAXIMUM / _buffer->getScale(); + for (int y = 0; y < destHeight; y++, dest += heightSize, srcY += srcAdvance) { + const uchar* src = (const uchar*)srcHeight.constData() + (int)srcY * srcSize; + float lineSrcX = srcX; + for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrcX += srcAdvance) { + *lineDest = qMin(qMax(0, (src[(int)lineSrcX] << shift) - subtract), EIGHT_BIT_MAXIMUM); + } + } } - } else { - // more difficult: different resolutions - float srcX = (intersection.minimum.x - info.minimum.x) / srcExtension; - float srcY = (intersection.minimum.z - info.minimum.z) / srcExtension; - float srcIncrement = _heightExtension / srcExtension; - int shift = 0; - float size = _buffer->getScale(); - while (size < info.size) { - shift++; - size *= 2.0f; + + int colorSize = _buffer->getColorSize(); + if (colorSize == 0) { + return STOP_RECURSION; } - const int EIGHT_BIT_MAXIMUM = 255; - int subtract = (_buffer->getTranslation().y - info.minimum.y) * EIGHT_BIT_MAXIMUM / _buffer->getScale(); - for (int y = 0; y < destHeight; y++, dest += _heightSize, srcY += srcIncrement) { - const uchar* src = (const uchar*)srcHeight.constData() + (int)srcY * srcSize; - float lineSrcX = srcX; - for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrcX += srcIncrement) { - *lineDest = qMin(qMax(0, (src[(int)lineSrcX] << shift) - subtract), EIGHT_BIT_MAXIMUM); + HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue(); + if (!color) { + return STOP_RECURSION; + } + const Box& colorBounds = _buffer->getColorBounds(); + overlap = colorBounds.getIntersection(overlap); + float colorIncrement = _buffer->getColorIncrement(); + destX = (overlap.minimum.x - colorBounds.minimum.x) / colorIncrement; + destY = (overlap.minimum.z - colorBounds.minimum.z) / colorIncrement; + destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / colorIncrement); + destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / colorIncrement); + dest = _buffer->getColor().data() + (destY * colorSize + destX) * HeightfieldData::COLOR_BYTES; + int destStride = colorSize * HeightfieldData::COLOR_BYTES; + int destBytes = destWidth * HeightfieldData::COLOR_BYTES; + + const QByteArray& srcColor = color->getContents(); + srcSize = glm::sqrt(srcColor.size() / HeightfieldData::COLOR_BYTES); + int srcStride = srcSize * HeightfieldData::COLOR_BYTES; + srcIncrement = info.size / srcSize; + + if (srcIncrement == colorIncrement) { + // easy case: same resolution + int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; + int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; + + const char* src = srcColor.constData() + (srcY * srcSize + srcX) * HeightfieldData::COLOR_BYTES; + for (int y = 0; y < destHeight; y++, src += srcStride, dest += destStride) { + memcpy(dest, src, destBytes); + } + } else { + // more difficult: different resolutions + float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; + float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; + float srcAdvance = colorIncrement / srcIncrement; + for (int y = 0; y < destHeight; y++, dest += destStride, srcY += srcAdvance) { + const char* src = srcColor.constData() + (int)srcY * srcStride; + float lineSrcX = srcX; + for (char* lineDest = dest, *end = dest + destBytes; lineDest != end; lineDest += HeightfieldData::COLOR_BYTES, + lineSrcX += srcAdvance) { + const char* lineSrc = src + (int)lineSrcX * HeightfieldData::COLOR_BYTES; + lineDest[0] = lineSrc[0]; + lineDest[1] = lineSrc[1]; + lineDest[2] = lineSrc[2]; + } } } } - - if (_colorSize == 0) { - return STOP_RECURSION; - } - HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue(); - if (!color) { - return STOP_RECURSION; - } - intersection = bounds.getIntersection(_colorBounds); - destX = glm::round((intersection.minimum.x - _colorBounds.minimum.x) / _colorExtension); - destY = glm::round((intersection.minimum.z - _colorBounds.minimum.z) / _colorExtension); - destWidth = glm::round((intersection.maximum.x - intersection.minimum.x) / _colorExtension); - destHeight = glm::round((intersection.maximum.z - intersection.minimum.z) / _colorExtension); - dest = _buffer->getColor().data() + (destY * _colorSize + destX) * HeightfieldData::COLOR_BYTES; - int destStride = _colorSize * HeightfieldData::COLOR_BYTES; - int destBytes = destWidth * HeightfieldData::COLOR_BYTES; - - const QByteArray& srcColor = color->getContents(); - srcSize = glm::sqrt(srcColor.size() / HeightfieldData::COLOR_BYTES); - int srcStride = srcSize * HeightfieldData::COLOR_BYTES; - srcExtension = info.size / srcSize; - - if (srcExtension == _colorExtension) { - // easy case: same resolution - int srcX = glm::round((intersection.minimum.x - info.minimum.x) / srcExtension); - int srcY = glm::round((intersection.minimum.z - info.minimum.z) / srcExtension); - - const char* src = srcColor.constData() + (srcY * srcSize + srcX) * HeightfieldData::COLOR_BYTES; - for (int y = 0; y < destHeight; y++, src += srcStride, dest += destStride) { - memcpy(dest, src, destBytes); - } - } else { - // more difficult: different resolutions - float srcX = (intersection.minimum.x - info.minimum.x) / srcExtension; - float srcY = (intersection.minimum.z - info.minimum.z) / srcExtension; - float srcIncrement = _colorExtension / srcExtension; - for (int y = 0; y < destHeight; y++, dest += destStride, srcY += srcIncrement) { - const char* src = srcColor.constData() + (int)srcY * srcStride; - float lineSrcX = srcX; - for (char* lineDest = dest, *end = dest + destBytes; lineDest != end; lineDest += HeightfieldData::COLOR_BYTES, - lineSrcX += srcIncrement) { - const char* lineSrc = src + (int)lineSrcX * HeightfieldData::COLOR_BYTES; - lineDest[0] = lineSrc[0]; - lineDest[1] = lineSrc[1]; - lineDest[2] = lineSrc[2]; - } - } - } - return STOP_RECURSION; } -int HeightfieldAugmentVisitor::visit(MetavoxelInfo& info) { - if (info.isLeaf) { - HeightfieldBuffer* buffer = NULL; - HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue(); - if (height) { - const QByteArray& heightContents = height->getContents(); - int size = glm::sqrt(heightContents.size()); - int extendedSize = size + HeightfieldBuffer::HEIGHT_EXTENSION; - QByteArray extendedHeightContents(extendedSize * extendedSize, 0); - char* dest = extendedHeightContents.data() + (extendedSize + 1) * HeightfieldBuffer::HEIGHT_BORDER; - const char* src = heightContents.constData(); - for (int z = 0; z < size; z++, src += size, dest += extendedSize) { - memcpy(dest, src, size); - } - QByteArray extendedColorContents; - HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue(); - if (color) { - const QByteArray& colorContents = color->getContents(); - int colorSize = glm::sqrt(colorContents.size() / HeightfieldData::COLOR_BYTES); - int extendedColorSize = colorSize + HeightfieldBuffer::SHARED_EDGE; - extendedColorContents = QByteArray(extendedColorSize * extendedColorSize * HeightfieldData::COLOR_BYTES, 0); - char* dest = extendedColorContents.data(); - const char* src = colorContents.constData(); - int srcStride = colorSize * HeightfieldData::COLOR_BYTES; - int destStride = extendedColorSize * HeightfieldData::COLOR_BYTES; - for (int z = 0; z < colorSize; z++, src += srcStride, dest += destStride) { - memcpy(dest, src, srcStride); - } - } - buffer = new HeightfieldBuffer(info.minimum, info.size, extendedHeightContents, extendedColorContents); - BorderFetchVisitor visitor(_lod, buffer); - _data->guide(visitor); +class HeightfieldRegionVisitor : public MetavoxelVisitor { +public: + + QVector regions; + Box regionBounds; + + HeightfieldRegionVisitor(const MetavoxelLOD& lod); + + virtual int visit(MetavoxelInfo& info); + +private: + + void addRegion(const Box& unextended, const Box& extended); + + QVector _intersections; + HeightfieldFetchVisitor _fetchVisitor; +}; + +HeightfieldRegionVisitor::HeightfieldRegionVisitor(const MetavoxelLOD& lod) : + MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getHeightfieldAttribute() << + AttributeRegistry::getInstance()->getHeightfieldColorAttribute() << + Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector() << + Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod), + regionBounds(glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX), glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX)), + _fetchVisitor(lod, _intersections) { +} + +int HeightfieldRegionVisitor::visit(MetavoxelInfo& info) { + if (!info.isLeaf) { + return DEFAULT_ORDER; + } + HeightfieldBuffer* buffer = NULL; + HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue(); + if (height) { + const QByteArray& heightContents = height->getContents(); + int size = glm::sqrt(heightContents.size()); + int extendedSize = size + HeightfieldBuffer::HEIGHT_EXTENSION; + int heightContentsSize = extendedSize * extendedSize; + + HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue(); + int colorContentsSize = 0; + if (color) { + const QByteArray& colorContents = color->getContents(); + int colorSize = glm::sqrt(colorContents.size() / HeightfieldData::COLOR_BYTES); + int extendedColorSize = colorSize + HeightfieldBuffer::SHARED_EDGE; + colorContentsSize = extendedColorSize * extendedColorSize * HeightfieldData::COLOR_BYTES; } - info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer))); + + const HeightfieldBuffer* existingBuffer = static_cast( + info.inputValues.at(2).getInlineValue().data()); + Box bounds = info.getBounds(); + if (existingBuffer && existingBuffer->getHeight().size() == heightContentsSize && + existingBuffer->getColor().size() == colorContentsSize) { + // we already have a buffer of the correct resolution + addRegion(bounds, existingBuffer->getHeightBounds()); + return STOP_RECURSION; + } + // we must create a new buffer and update its borders + buffer = new HeightfieldBuffer(info.minimum, info.size, QByteArray(heightContentsSize, 0), + QByteArray(colorContentsSize, 0)); + const Box& heightBounds = buffer->getHeightBounds(); + addRegion(bounds, heightBounds); + + _intersections.clear(); + _intersections.append(Box(heightBounds.minimum, + glm::vec3(bounds.maximum.x, heightBounds.maximum.y, bounds.minimum.z))); + _intersections.append(Box(glm::vec3(bounds.maximum.x, heightBounds.minimum.y, heightBounds.minimum.z), + glm::vec3(heightBounds.maximum.x, heightBounds.maximum.y, bounds.maximum.z))); + _intersections.append(Box(glm::vec3(bounds.minimum.x, heightBounds.minimum.y, bounds.maximum.z), + heightBounds.maximum)); + _intersections.append(Box(glm::vec3(heightBounds.minimum.x, heightBounds.minimum.y, bounds.minimum.z), + glm::vec3(bounds.minimum.x, heightBounds.maximum.y, heightBounds.maximum.z))); + + _fetchVisitor.init(buffer); + _data->guide(_fetchVisitor); + } + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer))); + return STOP_RECURSION; +} + +void HeightfieldRegionVisitor::addRegion(const Box& unextended, const Box& extended) { + regions.append(unextended); + regionBounds.add(extended); +} + +class HeightfieldUpdateVisitor : public MetavoxelVisitor { +public: + + HeightfieldUpdateVisitor(const MetavoxelLOD& lod, const QVector& regions, const Box& regionBounds); + + virtual int visit(MetavoxelInfo& info); + +private: + + const QVector& _regions; + const Box& _regionBounds; + QVector _intersections; + HeightfieldFetchVisitor _fetchVisitor; +}; + +HeightfieldUpdateVisitor::HeightfieldUpdateVisitor(const MetavoxelLOD& lod, const QVector& regions, + const Box& regionBounds) : + MetavoxelVisitor(QVector() << + Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector() << + Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod), + _regions(regions), + _regionBounds(regionBounds), + _fetchVisitor(lod, _intersections) { +} + +int HeightfieldUpdateVisitor::visit(MetavoxelInfo& info) { + if (!info.getBounds().intersects(_regionBounds)) { return STOP_RECURSION; } - return DEFAULT_ORDER; + if (!info.isLeaf) { + return DEFAULT_ORDER; + } + const HeightfieldBuffer* buffer = static_cast( + info.inputValues.at(0).getInlineValue().data()); + if (!buffer) { + return STOP_RECURSION; + } + _intersections.clear(); + foreach (const Box& region, _regions) { + if (region.intersects(buffer->getHeightBounds())) { + _intersections.append(region.getIntersection(buffer->getHeightBounds())); + } + } + if (_intersections.isEmpty()) { + return STOP_RECURSION; + } + HeightfieldBuffer* newBuffer = new HeightfieldBuffer(info.minimum, info.size, + buffer->getHeight(), buffer->getColor()); + _fetchVisitor.init(newBuffer); + _data->guide(_fetchVisitor); + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(newBuffer))); + return STOP_RECURSION; } void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous, @@ -1149,8 +1240,12 @@ void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const PointAugmentVisitor pointAugmentVisitor(lod); data.guideToDifferent(expandedPrevious, pointAugmentVisitor); - HeightfieldAugmentVisitor heightfieldAugmentVisitor(lod); - data.guideToDifferent(expandedPrevious, heightfieldAugmentVisitor); + HeightfieldRegionVisitor heightfieldRegionVisitor(lod); + data.guideToDifferent(expandedPrevious, heightfieldRegionVisitor); + + HeightfieldUpdateVisitor heightfieldUpdateVisitor(lod, heightfieldRegionVisitor.regions, + heightfieldRegionVisitor.regionBounds); + data.guide(heightfieldUpdateVisitor); } class SpannerSimulateVisitor : public SpannerVisitor { @@ -1222,7 +1317,7 @@ bool SpannerRenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, class BufferRenderVisitor : public MetavoxelVisitor { public: - BufferRenderVisitor(const AttributePointer& attribute, const MetavoxelLOD& lod); + BufferRenderVisitor(const AttributePointer& attribute); virtual int visit(MetavoxelInfo& info); @@ -1232,8 +1327,8 @@ private: int _containmentDepth; }; -BufferRenderVisitor::BufferRenderVisitor(const AttributePointer& attribute, const MetavoxelLOD& lod) : - MetavoxelVisitor(QVector() << attribute, QVector(), lod), +BufferRenderVisitor::BufferRenderVisitor(const AttributePointer& attribute) : + MetavoxelVisitor(QVector() << attribute), _order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())), _containmentDepth(INT_MAX) { } @@ -1247,11 +1342,14 @@ int BufferRenderVisitor::visit(MetavoxelInfo& info) { } _containmentDepth = (intersection == Frustum::CONTAINS_INTERSECTION) ? _depth : INT_MAX; } + if (!info.isLeaf) { + return _order; + } BufferDataPointer buffer = info.inputValues.at(0).getInlineValue(); if (buffer) { buffer->render(); } - return info.isLeaf ? STOP_RECURSION : _order; + return STOP_RECURSION; } void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod) { @@ -1280,7 +1378,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox glDisable(GL_BLEND); - BufferRenderVisitor pointRenderVisitor(Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod); + BufferRenderVisitor pointRenderVisitor(Application::getInstance()->getMetavoxels()->getPointBufferAttribute()); data.guide(pointRenderVisitor); glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); @@ -1300,8 +1398,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox glEnableClientState(GL_TEXTURE_COORD_ARRAY); - BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), - lod); + BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute()); data.guide(heightfieldRenderVisitor); _heightfieldProgram.release(); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 39136cb1f4..051c5da711 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -145,6 +145,9 @@ public: const glm::vec3& getTranslation() const { return _translation; } float getScale() const { return _scale; } + const Box& getHeightBounds() const { return _heightBounds; } + const Box& getColorBounds() const { return _colorBounds; } + QByteArray& getHeight() { return _height; } const QByteArray& getHeight() const { return _height; } @@ -154,17 +157,28 @@ public: QByteArray getUnextendedHeight() const; QByteArray getUnextendedColor() const; + int getHeightSize() const { return _heightSize; } + float getHeightIncrement() const { return _heightIncrement; } + + int getColorSize() const { return _colorSize; } + float getColorIncrement() const { return _colorIncrement; } + virtual void render(bool cursor = false); private: glm::vec3 _translation; float _scale; + Box _heightBounds; + Box _colorBounds; QByteArray _height; QByteArray _color; GLuint _heightTextureID; GLuint _colorTextureID; int _heightSize; + float _heightIncrement; + int _colorSize; + float _colorIncrement; typedef QPair BufferPair; static QHash _bufferPairs; @@ -193,6 +207,8 @@ public: Q_INVOKABLE BufferDataAttribute(const QString& name = QString()); virtual bool merge(void*& parent, void* children[], bool postRead = false) const; + + virtual AttributeValue inherit(const AttributeValue& parentValue) const; }; /// Renders metavoxels as points. diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 0f974b82df..14d05d6e9c 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -55,7 +55,7 @@ AttributeRegistry::AttributeRegistry() : const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 8.0f; _spannersAttribute->setLODThresholdMultiplier(SPANNER_LOD_THRESHOLD_MULTIPLIER); - const float HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER = 32.0f; + const float HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER = 40.0f; _heightfieldAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER); _heightfieldColorAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER); } diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index 4911c0e95f..e6b96e97b0 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -164,6 +164,11 @@ Box::Box(const glm::vec3& minimum, const glm::vec3& maximum) : minimum(minimum), maximum(maximum) { } +void Box::add(const Box& other) { + minimum = glm::min(minimum, other.minimum); + maximum = glm::max(maximum, other.maximum); +} + bool Box::contains(const glm::vec3& point) const { return point.x >= minimum.x && point.x <= maximum.x && point.y >= minimum.y && point.y <= maximum.y && diff --git a/libraries/metavoxels/src/MetavoxelUtil.h b/libraries/metavoxels/src/MetavoxelUtil.h index 2b63b81adc..4228af059f 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.h +++ b/libraries/metavoxels/src/MetavoxelUtil.h @@ -44,6 +44,8 @@ public: explicit Box(const glm::vec3& minimum = glm::vec3(), const glm::vec3& maximum = glm::vec3()); + void add(const Box& other); + bool contains(const glm::vec3& point) const; bool contains(const Box& other) const; From f7addad5acdcc03a330ae7facc78c2e8f39b2e7b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 14 Aug 2014 17:20:00 -0700 Subject: [PATCH 386/407] Update progress background image to use copy on S3 --- examples/editModels.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index b6552f67f2..b15ea58fc6 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -188,8 +188,7 @@ var progressDialog = (function () { cancelHeight = 32, textColor = { red: 255, green: 255, blue: 255 }, textBackground = { red: 52, green: 52, blue: 52 }, - backgroundUrl = "http://ctrlaltstudio.com/hifi/progress-background.svg", // DJRTODO: Update with HiFi location. - //backgroundUrl = "http://public.highfidelity.io/images/tools/progress-background.svg", + backgroundUrl = toolIconUrl + "progress-background.svg", windowDimensions; progressBackground = Overlays.addOverlay("image", { From 67266b41dffdb8312c13fd3f4e41fd3cdba2c81d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 14 Aug 2014 19:21:32 -0700 Subject: [PATCH 387/407] Deflated JPEG encoding for blocks above 16x16. --- .../metavoxels/src/AttributeRegistry.cpp | 104 +++++++++++++----- 1 file changed, 75 insertions(+), 29 deletions(-) diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 14d05d6e9c..1e30aee576 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -55,7 +55,7 @@ AttributeRegistry::AttributeRegistry() : const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 8.0f; _spannersAttribute->setLODThresholdMultiplier(SPANNER_LOD_THRESHOLD_MULTIPLIER); - const float HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER = 40.0f; + const float HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER = 32.0f; _heightfieldAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER); _heightfieldColorAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER); } @@ -493,6 +493,49 @@ HeightfieldData::HeightfieldData(Bitstream& in, int bytes, bool color) { read(in, bytes, color); } +enum HeightfieldImage { NULL_HEIGHTFIELD_IMAGE, NORMAL_HEIGHTFIELD_IMAGE, DEFLATED_HEIGHTFIELD_IMAGE }; + +static QByteArray encodeHeightfieldImage(const QImage& image) { + if (image.isNull()) { + return QByteArray(1, NULL_HEIGHTFIELD_IMAGE); + } + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + const int JPEG_ENCODE_THRESHOLD = 16; + if (image.width() >= JPEG_ENCODE_THRESHOLD && image.height() >= JPEG_ENCODE_THRESHOLD) { + qint32 offsetX = image.offset().x(), offsetY = image.offset().y(); + buffer.write((char*)&offsetX, sizeof(qint32)); + buffer.write((char*)&offsetY, sizeof(qint32)); + image.save(&buffer, "JPG"); + return QByteArray(1, DEFLATED_HEIGHTFIELD_IMAGE) + qCompress(buffer.data()); + + } else { + buffer.putChar(NORMAL_HEIGHTFIELD_IMAGE); + image.save(&buffer, "PNG"); + return buffer.data(); + } +} + +const QImage decodeHeightfieldImage(const QByteArray& data) { + switch (data.at(0)) { + case NULL_HEIGHTFIELD_IMAGE: + default: + return QImage(); + + case NORMAL_HEIGHTFIELD_IMAGE: + return QImage::fromData(QByteArray::fromRawData(data.constData() + 1, data.size() - 1)); + + case DEFLATED_HEIGHTFIELD_IMAGE: { + QByteArray inflated = qUncompress((const uchar*)data.constData() + 1, data.size() - 1); + const int OFFSET_SIZE = sizeof(qint32) * 2; + QImage image = QImage::fromData((const uchar*)inflated.constData() + OFFSET_SIZE, inflated.size() - OFFSET_SIZE); + const qint32* offsets = (const qint32*)inflated.constData(); + image.setOffset(QPoint(offsets[0], offsets[1])); + return image; + } + } +} + HeightfieldData::HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& reference, bool color) { if (!reference) { read(in, bytes, color); @@ -502,7 +545,10 @@ HeightfieldData::HeightfieldData(Bitstream& in, int bytes, const HeightfieldData reference->_encodedDelta = in.readAligned(bytes); reference->_deltaData = this; _contents = reference->_contents; - QImage image = QImage::fromData(reference->_encodedDelta); + QImage image = decodeHeightfieldImage(reference->_encodedDelta); + if (image.isNull()) { + return; + } QPoint offset = image.offset(); image = image.convertToFormat(QImage::Format_RGB888); if (offset.x() == 0) { @@ -550,9 +596,7 @@ void HeightfieldData::write(Bitstream& out, bool color) { *dest++ = *src; } } - QBuffer buffer(&_encoded); - buffer.open(QIODevice::WriteOnly); - image.save(&buffer, "PNG"); + _encoded = encodeHeightfieldImage(image); } out << _encoded.size(); out.writeAligned(_encoded); @@ -588,15 +632,17 @@ void HeightfieldData::writeDelta(Bitstream& out, const HeightfieldDataPointer& r maxY = qMax(maxY, y); } } - int width = qMax(maxX - minX + 1, 0); - int height = qMax(maxY - minY + 1, 0); - image = QImage(width, height, QImage::Format_RGB888); - src = _contents.constData() + (minY * size + minX) * COLOR_BYTES; - int srcStride = size * COLOR_BYTES; - int destStride = width * COLOR_BYTES; - for (int y = 0; y < height; y++) { - memcpy(image.scanLine(y), src, destStride); - src += srcStride; + if (maxX >= minX) { + int width = maxX - minX + 1; + int height = maxY - minY + 1; + image = QImage(width, height, QImage::Format_RGB888); + src = _contents.constData() + (minY * size + minX) * COLOR_BYTES; + int srcStride = size * COLOR_BYTES; + int destStride = width * COLOR_BYTES; + for (int y = 0; y < height; y++) { + memcpy(image.scanLine(y), src, destStride); + src += srcStride; + } } } else { int size = glm::sqrt((float)_contents.size()); @@ -619,24 +665,24 @@ void HeightfieldData::writeDelta(Bitstream& out, const HeightfieldDataPointer& r maxY = qMax(maxY, y); } } - int width = qMax(maxX - minX + 1, 0); - int height = qMax(maxY - minY + 1, 0); - image = QImage(width, height, QImage::Format_RGB888); - const uchar* lineSrc = (const uchar*)_contents.constData() + minY * size + minX; - for (int y = 0; y < height; y++) { - uchar* dest = image.scanLine(y); - for (const uchar* src = lineSrc, *end = src + width; src != end; src++) { - *dest++ = *src; - *dest++ = *src; - *dest++ = *src; + if (maxX >= minX) { + int width = qMax(maxX - minX + 1, 0); + int height = qMax(maxY - minY + 1, 0); + image = QImage(width, height, QImage::Format_RGB888); + const uchar* lineSrc = (const uchar*)_contents.constData() + minY * size + minX; + for (int y = 0; y < height; y++) { + uchar* dest = image.scanLine(y); + for (const uchar* src = lineSrc, *end = src + width; src != end; src++) { + *dest++ = *src; + *dest++ = *src; + *dest++ = *src; + } + lineSrc += size; } - lineSrc += size; } } - QBuffer buffer(&reference->_encodedDelta); - buffer.open(QIODevice::WriteOnly); image.setOffset(QPoint(minX + 1, minY + 1)); - image.save(&buffer, "PNG"); + reference->_encodedDelta = encodeHeightfieldImage(image); reference->_deltaData = this; } out << reference->_encodedDelta.size(); @@ -644,7 +690,7 @@ void HeightfieldData::writeDelta(Bitstream& out, const HeightfieldDataPointer& r } void HeightfieldData::read(Bitstream& in, int bytes, bool color) { - set(QImage::fromData(_encoded = in.readAligned(bytes)).convertToFormat(QImage::Format_RGB888), color); + set(decodeHeightfieldImage(_encoded = in.readAligned(bytes)).convertToFormat(QImage::Format_RGB888), color); } void HeightfieldData::set(const QImage& image, bool color) { From 2e6350832cc65bde0562b937fd3235fbcef43c9f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Aug 2014 09:35:03 -0700 Subject: [PATCH 388/407] perfom packet verification on same thread as NodeList hash --- assignment-client/src/audio/AudioMixer.cpp | 44 ++++++++++--------- .../src/audio/AudioMixerDatagramProcessor.cpp | 8 +--- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index c315f695cc..5f4c3827f2 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -302,29 +302,31 @@ void AudioMixer::prepareMixForListeningNode(Node* node) { void AudioMixer::readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) { NodeList* nodeList = NodeList::getInstance(); - // pull any new audio data from nodes off of the network stack - PacketType mixerPacketType = packetTypeForPacket(receivedPacket); - if (mixerPacketType == PacketTypeMicrophoneAudioNoEcho - || mixerPacketType == PacketTypeMicrophoneAudioWithEcho - || mixerPacketType == PacketTypeInjectAudio - || mixerPacketType == PacketTypeSilentAudioFrame - || mixerPacketType == PacketTypeAudioStreamStats) { - - nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket); - } else if (mixerPacketType == PacketTypeMuteEnvironment) { - QByteArray packet = receivedPacket; - populatePacketHeader(packet, PacketTypeMuteEnvironment); - - 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); + if (nodeList->packetVersionAndHashMatch(receivedPacket)) { + // pull any new audio data from nodes off of the network stack + PacketType mixerPacketType = packetTypeForPacket(receivedPacket); + if (mixerPacketType == PacketTypeMicrophoneAudioNoEcho + || mixerPacketType == PacketTypeMicrophoneAudioWithEcho + || mixerPacketType == PacketTypeInjectAudio + || mixerPacketType == PacketTypeSilentAudioFrame + || mixerPacketType == PacketTypeAudioStreamStats) { + + nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket); + } else if (mixerPacketType == PacketTypeMuteEnvironment) { + QByteArray packet = receivedPacket; + populatePacketHeader(packet, PacketTypeMuteEnvironment); + + 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); } - - } else { - // let processNodeData handle it. - nodeList->processNodeData(senderSockAddr, receivedPacket); - } + } } void AudioMixer::sendStatsPacket() { diff --git a/assignment-client/src/audio/AudioMixerDatagramProcessor.cpp b/assignment-client/src/audio/AudioMixerDatagramProcessor.cpp index 61f42e6f08..73a4e01844 100644 --- a/assignment-client/src/audio/AudioMixerDatagramProcessor.cpp +++ b/assignment-client/src/audio/AudioMixerDatagramProcessor.cpp @@ -33,8 +33,6 @@ void AudioMixerDatagramProcessor::readPendingDatagrams() { HifiSockAddr senderSockAddr; static QByteArray incomingPacket; - NodeList* nodeList = NodeList::getInstance(); - // read everything that is available while (_nodeSocket.hasPendingDatagrams()) { incomingPacket.resize(_nodeSocket.pendingDatagramSize()); @@ -43,9 +41,7 @@ void AudioMixerDatagramProcessor::readPendingDatagrams() { _nodeSocket.readDatagram(incomingPacket.data(), incomingPacket.size(), senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); - if (nodeList->packetVersionAndHashMatch(incomingPacket)) { - // emit the signal to tell AudioMixer it needs to process a packet - emit packetRequiresProcessing(incomingPacket, senderSockAddr); - } + // emit the signal to tell AudioMixer it needs to process a packet + emit packetRequiresProcessing(incomingPacket, senderSockAddr); } } From 6592a6dca28a4f6c47a06fa79d5541370ce3cd56 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 15 Aug 2014 10:28:22 -0700 Subject: [PATCH 389/407] Fix for custom URL schemes --- interface/src/Application.cpp | 3 +-- interface/src/Menu.cpp | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9d49dc6281..efc638a9c2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -814,9 +814,8 @@ bool Application::event(QEvent* event) { QFileOpenEvent* fileEvent = static_cast(event); bool isHifiSchemeURL = !fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME); if (isHifiSchemeURL) { - Menu::getInstance()->goTo(fileEvent->url().toString()); + Menu::getInstance()->goToURL(fileEvent->url().toLocalFile()); } - return false; } return QApplication::event(event); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index e6850aac6d..c21b533695 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1153,8 +1153,8 @@ void Menu::goTo() { } bool Menu::goToURL(QString location) { - if (location.startsWith(CUSTOM_URL_SCHEME + "//")) { - QStringList urlParts = location.remove(0, CUSTOM_URL_SCHEME.length() + 2).split('/', QString::SkipEmptyParts); + if (location.startsWith(CUSTOM_URL_SCHEME + "/")) { + QStringList urlParts = location.remove(0, CUSTOM_URL_SCHEME.length()).split('/', QString::SkipEmptyParts); if (urlParts.count() > 1) { // if url has 2 or more parts, the first one is domain name From 668f6d3cfdc0b2c250bdb4bf0c6a47e9b8a05599 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 15 Aug 2014 16:13:47 -0700 Subject: [PATCH 390/407] Support for shadows on heightmaps. --- .../shaders/metavoxel_heightfield.vert | 15 +++- ...voxel_heightfield_cascaded_shadow_map.frag | 48 ++++++++++++ .../metavoxel_heightfield_shadow_map.frag | 37 +++++++++ interface/src/MetavoxelSystem.cpp | 78 +++++++++++++++++-- interface/src/MetavoxelSystem.h | 17 ++++ interface/src/renderer/Model.cpp | 8 +- 6 files changed, 190 insertions(+), 13 deletions(-) create mode 100644 interface/resources/shaders/metavoxel_heightfield_cascaded_shadow_map.frag create mode 100644 interface/resources/shaders/metavoxel_heightfield_shadow_map.frag diff --git a/interface/resources/shaders/metavoxel_heightfield.vert b/interface/resources/shaders/metavoxel_heightfield.vert index 4932ad1b2b..70cf3f9419 100644 --- a/interface/resources/shaders/metavoxel_heightfield.vert +++ b/interface/resources/shaders/metavoxel_heightfield.vert @@ -20,6 +20,9 @@ uniform float heightScale; // the scale between height and color textures uniform float colorScale; +// the interpolated position +varying vec4 position; + // the interpolated normal varying vec4 normal; @@ -32,13 +35,17 @@ void main(void) { texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r; normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0)); - // pass along the scaled/offset texture coordinates - gl_TexCoord[0] = (gl_MultiTexCoord0 - vec4(heightScale, heightScale, 0.0, 0.0)) * colorScale; - // add the height to the position float height = texture2D(heightMap, heightCoord).r; - gl_Position = gl_ModelViewProjectionMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0)); + position = gl_ModelViewMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0)); + gl_Position = gl_ProjectionMatrix * position; // the zero height should be invisible gl_FrontColor = vec4(1.0, 1.0, 1.0, step(height, 0.0)); + + // pass along the scaled/offset texture coordinates + gl_TexCoord[0] = (gl_MultiTexCoord0 - vec4(heightScale, heightScale, 0.0, 0.0)) * colorScale; + + // and the shadow texture coordinates + gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position), 1.0); } diff --git a/interface/resources/shaders/metavoxel_heightfield_cascaded_shadow_map.frag b/interface/resources/shaders/metavoxel_heightfield_cascaded_shadow_map.frag new file mode 100644 index 0000000000..059a4e0296 --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield_cascaded_shadow_map.frag @@ -0,0 +1,48 @@ +#version 120 + +// +// metavoxel_heightfield.frag +// fragment shader +// +// Created by Andrzej Kapolka on 7/28/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 shadow texture +uniform sampler2DShadow shadowMap; + +// the distances to the cascade sections +uniform vec3 shadowDistances; + +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + +// the interpolated position +varying vec4 position; + +// the interpolated normal +varying vec4 normal; + +void main(void) { + // compute the index of the cascade to use and the corresponding texture coordinates + int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0))); + vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), + dot(gl_EyePlaneR[shadowIndex], position)); + + // compute the base color based on OpenGL lighting model + float diffuse = dot(normalize(normal), gl_LightSource[0].position); + float facingLight = step(0.0, diffuse) * 0.25 * + (shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r); + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st); +} diff --git a/interface/resources/shaders/metavoxel_heightfield_shadow_map.frag b/interface/resources/shaders/metavoxel_heightfield_shadow_map.frag new file mode 100644 index 0000000000..bf319462d3 --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield_shadow_map.frag @@ -0,0 +1,37 @@ +#version 120 + +// +// metavoxel_heightfield.frag +// fragment shader +// +// Created by Andrzej Kapolka on 7/28/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 shadow texture +uniform sampler2DShadow shadowMap; + +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + +// the interpolated normal +varying vec4 normal; + +void main(void) { + // compute the base color based on OpenGL lighting model + float diffuse = dot(normalize(normal), gl_LightSource[0].position); + float facingLight = step(0.0, diffuse) * 0.25 * + (shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r); + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st); +} diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 40a2ff0097..433c8af23e 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -760,10 +760,21 @@ void HeightfieldBuffer::render(bool cursor) { glBindTexture(GL_TEXTURE_2D, _heightTextureID); if (!cursor) { - DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue( - DefaultMetavoxelRendererImplementation::getHeightScaleLocation(), 1.0f / _heightSize); - DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue( - DefaultMetavoxelRendererImplementation::getColorScaleLocation(), (float)_heightSize / innerSize); + int heightScaleLocation = DefaultMetavoxelRendererImplementation::getHeightScaleLocation(); + int colorScaleLocation = DefaultMetavoxelRendererImplementation::getColorScaleLocation(); + ProgramObject* program = &DefaultMetavoxelRendererImplementation::getHeightfieldProgram(); + if (Menu::getInstance()->isOptionChecked(MenuOption::SimpleShadows)) { + heightScaleLocation = DefaultMetavoxelRendererImplementation::getShadowMapHeightScaleLocation(); + colorScaleLocation = DefaultMetavoxelRendererImplementation::getShadowMapColorScaleLocation(); + program = &DefaultMetavoxelRendererImplementation::getShadowMapHeightfieldProgram(); + + } else if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { + heightScaleLocation = DefaultMetavoxelRendererImplementation::getCascadedShadowMapHeightScaleLocation(); + colorScaleLocation = DefaultMetavoxelRendererImplementation::getCascadedShadowMapColorScaleLocation(); + program = &DefaultMetavoxelRendererImplementation::getCascadedShadowMapHeightfieldProgram(); + } + program->setUniformValue(heightScaleLocation, 1.0f / _heightSize); + program->setUniformValue(colorScaleLocation, (float)_heightSize / innerSize); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _colorTextureID); } @@ -858,6 +869,35 @@ void DefaultMetavoxelRendererImplementation::init() { _colorScaleLocation = _heightfieldProgram.uniformLocation("colorScale"); _heightfieldProgram.release(); + _shadowMapHeightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/metavoxel_heightfield.vert"); + _shadowMapHeightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/metavoxel_heightfield_shadow_map.frag"); + _shadowMapHeightfieldProgram.link(); + + _shadowMapHeightfieldProgram.bind(); + _shadowMapHeightfieldProgram.setUniformValue("heightMap", 0); + _shadowMapHeightfieldProgram.setUniformValue("diffuseMap", 1); + _shadowMapHeightfieldProgram.setUniformValue("shadowMap", 2); + _shadowMapHeightScaleLocation = _shadowMapHeightfieldProgram.uniformLocation("heightScale"); + _shadowMapColorScaleLocation = _shadowMapHeightfieldProgram.uniformLocation("colorScale"); + _shadowMapHeightfieldProgram.release(); + + _cascadedShadowMapHeightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/metavoxel_heightfield.vert"); + _cascadedShadowMapHeightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/metavoxel_heightfield_cascaded_shadow_map.frag"); + _cascadedShadowMapHeightfieldProgram.link(); + + _cascadedShadowMapHeightfieldProgram.bind(); + _cascadedShadowMapHeightfieldProgram.setUniformValue("heightMap", 0); + _cascadedShadowMapHeightfieldProgram.setUniformValue("diffuseMap", 1); + _cascadedShadowMapHeightfieldProgram.setUniformValue("shadowMap", 2); + _cascadedShadowMapHeightScaleLocation = _cascadedShadowMapHeightfieldProgram.uniformLocation("heightScale"); + _cascadedShadowMapColorScaleLocation = _cascadedShadowMapHeightfieldProgram.uniformLocation("colorScale"); + _shadowDistancesLocation = _cascadedShadowMapHeightfieldProgram.uniformLocation("shadowDistances"); + _cascadedShadowMapHeightfieldProgram.release(); + _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_heightfield_cursor.vert"); _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + @@ -1394,15 +1434,34 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - _heightfieldProgram.bind(); + ProgramObject* program = &_heightfieldProgram; + if (Menu::getInstance()->getShadowsEnabled()) { + if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { + program = &_cascadedShadowMapHeightfieldProgram; + program->bind(); + program->setUniform(_shadowDistancesLocation, Application::getInstance()->getShadowDistances()); + + } else { + program = &_shadowMapHeightfieldProgram; + } + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID()); + glActiveTexture(GL_TEXTURE0); + } + + program->bind(); glEnableClientState(GL_TEXTURE_COORD_ARRAY); BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute()); data.guide(heightfieldRenderVisitor); - _heightfieldProgram.release(); + program->release(); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); @@ -1416,6 +1475,13 @@ int DefaultMetavoxelRendererImplementation::_pointScaleLocation; ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldProgram; int DefaultMetavoxelRendererImplementation::_heightScaleLocation; int DefaultMetavoxelRendererImplementation::_colorScaleLocation; +ProgramObject DefaultMetavoxelRendererImplementation::_shadowMapHeightfieldProgram; +int DefaultMetavoxelRendererImplementation::_shadowMapHeightScaleLocation; +int DefaultMetavoxelRendererImplementation::_shadowMapColorScaleLocation; +ProgramObject DefaultMetavoxelRendererImplementation::_cascadedShadowMapHeightfieldProgram; +int DefaultMetavoxelRendererImplementation::_cascadedShadowMapHeightScaleLocation; +int DefaultMetavoxelRendererImplementation::_cascadedShadowMapColorScaleLocation; +int DefaultMetavoxelRendererImplementation::_shadowDistancesLocation; ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldCursorProgram; static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 051c5da711..38d67bcaed 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -223,6 +223,14 @@ public: static int getHeightScaleLocation() { return _heightScaleLocation; } static int getColorScaleLocation() { return _colorScaleLocation; } + static ProgramObject& getShadowMapHeightfieldProgram() { return _shadowMapHeightfieldProgram; } + static int getShadowMapHeightScaleLocation() { return _shadowMapHeightScaleLocation; } + static int getShadowMapColorScaleLocation() { return _shadowMapColorScaleLocation; } + + static ProgramObject& getCascadedShadowMapHeightfieldProgram() { return _cascadedShadowMapHeightfieldProgram; } + static int getCascadedShadowMapHeightScaleLocation() { return _cascadedShadowMapHeightScaleLocation; } + static int getCascadedShadowMapColorScaleLocation() { return _cascadedShadowMapColorScaleLocation; } + static ProgramObject& getHeightfieldCursorProgram() { return _heightfieldCursorProgram; } Q_INVOKABLE DefaultMetavoxelRendererImplementation(); @@ -240,6 +248,15 @@ private: static int _heightScaleLocation; static int _colorScaleLocation; + static ProgramObject _shadowMapHeightfieldProgram; + static int _shadowMapHeightScaleLocation; + static int _shadowMapColorScaleLocation; + + static ProgramObject _cascadedShadowMapHeightfieldProgram; + static int _cascadedShadowMapHeightScaleLocation; + static int _cascadedShadowMapColorScaleLocation; + static int _shadowDistancesLocation; + static ProgramObject _heightfieldCursorProgram; }; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index a915406f8e..2ec676de53 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1449,9 +1449,11 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re if (cascadedShadows) { activeProgram->setUniform(activeLocations->shadowDistances, Application::getInstance()->getShadowDistances()); } - activeProgram->setUniformValueArray(activeLocations->localLightDirections, - (const GLfloat*)_localLightDirections, MAX_LOCAL_LIGHTS, 4); - + if (mode != SHADOW_RENDER_MODE) { + activeProgram->setUniformValueArray(activeLocations->localLightDirections, + (const GLfloat*)_localLightDirections, MAX_LOCAL_LIGHTS, 4); + } + if (mesh.blendshapes.isEmpty()) { if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) { activeProgram->setAttributeBuffer(activeLocations->tangent, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3); From cac4e5ba6c5d59dc243ac99c53d6b97dd5b4e7fd Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 17 Aug 2014 14:08:07 -0700 Subject: [PATCH 391/407] improved use of MovingMinMaxAvg<> for better performance, added execution timing stats --- tests/jitter/src/main.cpp | 119 ++++++++++++++++++++++++++++++++------ 1 file changed, 102 insertions(+), 17 deletions(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index c27a791d5b..e70435b543 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -16,12 +16,14 @@ #include #include -#include // for MovingMinMaxAvg +#include #include -#include #include // for usecTimestampNow +#include +#include const quint64 MSEC_TO_USEC = 1000; +const quint64 LARGE_STATS_TIME = 500; // we don't expect stats calculation to take more than this many usecs void runSend(const char* addressOption, int port, int gap, int size, int report); void runReceive(const char* addressOption, int port, int gap, int size, int report); @@ -77,25 +79,37 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) servaddr.sin_addr.s_addr = inet_addr(addressOption); servaddr.sin_port = htons(port); - - const int SAMPLES_FOR_30_SECONDS = 30 * 1000000 / gap; + const int SAMPLES_FOR_SECOND = 1000000 / gap; + std::cout << "SAMPLES_FOR_SECOND:" << SAMPLES_FOR_SECOND << "\n"; + const int INTERVALS_PER_30_SECONDS = 30; + std::cout << "INTERVALS_PER_30_SECONDS:" << INTERVALS_PER_30_SECONDS << "\n"; + const int SAMPLES_FOR_30_SECONDS = 30 * SAMPLES_FOR_SECOND; std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n"; + const int REPORTS_FOR_30_SECONDS = 30 * MSECS_PER_SECOND / report; + std::cout << "REPORTS_FOR_30_SECONDS:" << REPORTS_FOR_30_SECONDS << "\n"; - const int SAMPLES_PER_REPORT = report * MSEC_TO_USEC / gap; - std::cout << "SAMPLES_PER_REPORT:" << SAMPLES_PER_REPORT << "\n"; - + int intervalsPerReport = report / MSEC_TO_USEC; + if (intervalsPerReport < 1) { + intervalsPerReport = 1; + } + std::cout << "intervalsPerReport:" << intervalsPerReport << "\n"; + MovingMinMaxAvg timeGaps(SAMPLES_FOR_SECOND, INTERVALS_PER_30_SECONDS); + MovingMinMaxAvg timeGapsPerReport(SAMPLES_FOR_SECOND, intervalsPerReport); char* outputBuffer = new char[size]; memset(outputBuffer, 0, size); quint16 outgoingSequenceNumber = 0; - MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); - MovingMinMaxAvg timeGapsPerReport(1, SAMPLES_PER_REPORT); StDev stDevReportInterval; StDev stDev30s; StDev stDev; + + SimpleMovingAverage averageNetworkTime(SAMPLES_FOR_30_SECONDS); + SimpleMovingAverage averageStatsCalcultionTime(SAMPLES_FOR_30_SECONDS); + float lastStatsCalculationTime = 0.0f; // we add out stats calculation time in the next calculation window + bool hasStatsCalculationTime = false; quint64 last = usecTimestampNow(); quint64 lastReport = 0; @@ -111,19 +125,37 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) // pack seq num memcpy(outputBuffer, &outgoingSequenceNumber, sizeof(quint16)); + quint64 networkStart = usecTimestampNow(); int n = sendto(sockfd, outputBuffer, size, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); + quint64 networkEnd = usecTimestampNow(); + float networkElapsed = (float)(networkEnd - networkStart); + if (n < 0) { std::cout << "Send error: " << strerror(errno) << "\n"; } outgoingSequenceNumber++; + quint64 statsCalcultionStart = usecTimestampNow(); + int gapDifferece = actualGap - gap; + timeGaps.update(gapDifferece); timeGapsPerReport.update(gapDifferece); stDev.addValue(gapDifferece); stDev30s.addValue(gapDifferece); stDevReportInterval.addValue(gapDifferece); last = now; + + // track out network time and stats calculation times + averageNetworkTime.updateAverage(networkElapsed); + + // for our stats calculation time, we actually delay the updating by one sample. + // we do this so that the calculation of the average timing for the stats calculation + // happen inside of the calculation processing. This ensures that tracking stats on + // stats calculation doesn't side effect the remaining running time. + if (hasStatsCalculationTime) { + averageStatsCalcultionTime.updateAverage(lastStatsCalculationTime); + } if (now - lastReport >= (report * MSEC_TO_USEC)) { @@ -144,6 +176,9 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) << "max: " << timeGapsPerReport.getWindowMax() << " usecs, " << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs, " << "stdev: " << stDevReportInterval.getStDev() << " usecs\n" + << "Average Execution Times Last 30s:\n" + << " network: " << averageNetworkTime.getAverage() << " usecs average\n" + << " stats: " << averageStatsCalcultionTime.getAverage() << " usecs average" << "\n"; stDevReportInterval.reset(); @@ -153,6 +188,14 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) lastReport = now; } + + quint64 statsCalcultionEnd = usecTimestampNow(); + lastStatsCalculationTime = (float)(statsCalcultionEnd - statsCalcultionStart); + if (lastStatsCalculationTime > LARGE_STATS_TIME) { + qDebug() << "WARNING -- unexpectedly large lastStatsCalculationTime=" << lastStatsCalculationTime; + } + hasStatsCalculationTime = true; + } } delete[] outputBuffer; @@ -184,21 +227,26 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo myaddr.sin_port = htons(port); - const int SAMPLES_FOR_30_SECONDS = 30 * 1000000 / gap; + const int SAMPLES_FOR_SECOND = 1000000 / gap; + std::cout << "SAMPLES_FOR_SECOND:" << SAMPLES_FOR_SECOND << "\n"; + const int INTERVALS_PER_30_SECONDS = 30; + std::cout << "INTERVALS_PER_30_SECONDS:" << INTERVALS_PER_30_SECONDS << "\n"; + const int SAMPLES_FOR_30_SECONDS = 30 * SAMPLES_FOR_SECOND; std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n"; - - const int SAMPLES_PER_REPORT = report * MSEC_TO_USEC / gap; - std::cout << "SAMPLES_PER_REPORT:" << SAMPLES_PER_REPORT << "\n"; - const int REPORTS_FOR_30_SECONDS = 30 * MSECS_PER_SECOND / report; std::cout << "REPORTS_FOR_30_SECONDS:" << REPORTS_FOR_30_SECONDS << "\n"; + int intervalsPerReport = report / MSEC_TO_USEC; + if (intervalsPerReport < 1) { + intervalsPerReport = 1; + } + std::cout << "intervalsPerReport:" << intervalsPerReport << "\n"; + MovingMinMaxAvg timeGaps(SAMPLES_FOR_SECOND, INTERVALS_PER_30_SECONDS); + MovingMinMaxAvg timeGapsPerReport(SAMPLES_FOR_SECOND, intervalsPerReport); char* inputBuffer = new char[size]; memset(inputBuffer, 0, size); - MovingMinMaxAvg timeGaps(1, SAMPLES_FOR_30_SECONDS); - MovingMinMaxAvg timeGapsPerReport(1, SAMPLES_PER_REPORT); SequenceNumberStats seqStats(REPORTS_FOR_30_SECONDS); @@ -206,6 +254,11 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo StDev stDev30s; StDev stDev; + SimpleMovingAverage averageNetworkTime(SAMPLES_FOR_30_SECONDS); + SimpleMovingAverage averageStatsCalcultionTime(SAMPLES_FOR_30_SECONDS); + float lastStatsCalculationTime = 0.0f; // we add out stats calculation time in the next calculation window + bool hasStatsCalculationTime = false; + if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { std::cout << "bind failed\n"; return; @@ -213,9 +266,16 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo quint64 last = 0; // first case quint64 lastReport = 0; + + quint64 a,b; while (true) { + + quint64 networkStart = usecTimestampNow(); n = recvfrom(sockfd, inputBuffer, size, 0, NULL, NULL); // we don't care about where it came from + quint64 networkEnd = usecTimestampNow(); + float networkElapsed = (float)(networkEnd - networkStart); + if (n < 0) { std::cout << "Receive error: " << strerror(errno) << "\n"; } @@ -228,8 +288,11 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo last = usecTimestampNow(); std::cout << "first packet received\n"; } else { + + quint64 statsCalcultionStart = usecTimestampNow(); quint64 now = usecTimestampNow(); int actualGap = now - last; + int gapDifferece = actualGap - gap; timeGaps.update(gapDifferece); timeGapsPerReport.update(gapDifferece); @@ -237,6 +300,17 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo stDev30s.addValue(gapDifferece); stDevReportInterval.addValue(gapDifferece); last = now; + + // track out network time and stats calculation times + averageNetworkTime.updateAverage(networkElapsed); + + // for our stats calculation time, we actually delay the updating by one sample. + // we do this so that the calculation of the average timing for the stats calculation + // happen inside of the calculation processing. This ensures that tracking stats on + // stats calculation doesn't side effect the remaining running time. + if (hasStatsCalculationTime) { + averageStatsCalcultionTime.updateAverage(lastStatsCalculationTime); + } if (now - lastReport >= (report * MSEC_TO_USEC)) { @@ -258,9 +332,12 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo << "max: " << timeGapsPerReport.getWindowMax() << " usecs, " << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs, " << "stdev: " << stDevReportInterval.getStDev() << " usecs\n" + << "Average Execution Times Last 30s:\n" + << " network: " << averageNetworkTime.getAverage() << " usecs average\n" + << " stats: " << averageStatsCalcultionTime.getAverage() << " usecs average" << "\n"; - stDevReportInterval.reset(); + if (stDev30s.getSamples() > SAMPLES_FOR_30_SECONDS) { stDev30s.reset(); } @@ -282,6 +359,14 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo lastReport = now; } + + quint64 statsCalcultionEnd = usecTimestampNow(); + + lastStatsCalculationTime = (float)(statsCalcultionEnd - statsCalcultionStart); + if (lastStatsCalculationTime > LARGE_STATS_TIME) { + qDebug() << "WARNING -- unexpectedly large lastStatsCalculationTime=" << lastStatsCalculationTime; + } + hasStatsCalculationTime = true; } } delete[] inputBuffer; From be94f98a9169eb778b71785d94b321f83fb1a1bd Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 17 Aug 2014 14:10:42 -0700 Subject: [PATCH 392/407] fix warning --- tests/jitter/src/main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index e70435b543..8c93b7dbec 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -267,8 +267,6 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo quint64 last = 0; // first case quint64 lastReport = 0; - quint64 a,b; - while (true) { quint64 networkStart = usecTimestampNow(); From 77047b01302b75692a7a751d69ac644c58f8ab0a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 18 Aug 2014 11:25:51 -0700 Subject: [PATCH 393/407] no NULL check on delete SkeletonModel::_ragdoll --- interface/src/avatar/SkeletonModel.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index ffe711b03b..4e954af46b 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -34,10 +34,8 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : } SkeletonModel::~SkeletonModel() { - if (_ragdoll) { - delete _ragdoll; - _ragdoll = NULL; - } + delete _ragdoll; + _ragdoll = NULL; } void SkeletonModel::setJointStates(QVector states) { From 2eb1321cc2f1d207ed3b6cc812212516c45955a4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 18 Aug 2014 12:28:44 -0700 Subject: [PATCH 394/407] Sound and AudioInjector tweaks --- libraries/audio/src/AudioInjectorOptions.h | 4 ++-- libraries/audio/src/Sound.cpp | 11 +++++++++++ libraries/audio/src/Sound.h | 2 ++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/libraries/audio/src/AudioInjectorOptions.h b/libraries/audio/src/AudioInjectorOptions.h index b90deb93f1..35575414d5 100644 --- a/libraries/audio/src/AudioInjectorOptions.h +++ b/libraries/audio/src/AudioInjectorOptions.h @@ -37,8 +37,8 @@ public: float getVolume() const { return _volume; } void setVolume(float volume) { _volume = volume; } - float getLoop() const { return _loop; } - void setLoop(float loop) { _loop = loop; } + bool getLoop() const { return _loop; } + void setLoop(bool loop) { _loop = loop; } const glm::quat& getOrientation() const { return _orientation; } void setOrientation(const glm::quat& orientation) { _orientation = orientation; } diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 03c9f6b8ee..f52f5c04dd 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -82,6 +82,17 @@ Sound::Sound(const QUrl& sampleURL, QObject* parent) : connect(soundDownload, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(replyError(QNetworkReply::NetworkError))); } +Sound::Sound(const QByteArray byteArray, QObject* parent) : + QObject(parent), + _byteArray(byteArray), + _hasDownloaded(true) +{ +} + +void Sound::append(const QByteArray byteArray) { + _byteArray.append(byteArray); +} + void Sound::replyFinished() { QNetworkReply* reply = reinterpret_cast(sender()); diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index c473cdff83..7dae3679f1 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -22,6 +22,8 @@ class Sound : public QObject { public: Sound(const QUrl& sampleURL, QObject* parent = NULL); Sound(float volume, float frequency, float duration, float decay, QObject* parent = NULL); + Sound(const QByteArray byteArray, QObject* parent = NULL); + void append(const QByteArray byteArray); bool hasDownloaded() const { return _hasDownloaded; } From acb55ce65e3054864354551ba4955801afc8e366 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 18 Aug 2014 12:31:44 -0700 Subject: [PATCH 395/407] Switched audio play back to AudioInjector out of Audio --- interface/src/Application.cpp | 2 ++ interface/src/Audio.cpp | 9 +++-- interface/src/Recorder.cpp | 58 +++++++++++++++++++++++++++++---- interface/src/Recorder.h | 19 +++++++++-- interface/src/avatar/Avatar.cpp | 1 - 5 files changed, 77 insertions(+), 12 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dba8174083..2fef2ced8a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1051,12 +1051,14 @@ void Application::keyPressEvent(QKeyEvent* event) { _myAvatar->stopRecording(); } else { _myAvatar->startRecording(); + _audio.setRecorder(_myAvatar->getRecorder()); } } else { if (_myAvatar->isPlaying()) { _myAvatar->stopPlaying(); } else { _myAvatar->startPlaying(); + _audio.setPlayer(_myAvatar->getPlayer()); } } break; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 0484860c65..bb8b79ab59 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -82,7 +82,6 @@ Audio::Audio(QObject* parent) : _noiseGateSampleCounter(0), _noiseGateOpen(false), _noiseGateEnabled(true), - _peqEnabled(false), _toneInjectionEnabled(false), _noiseGateFramesToClose(0), _totalInputAudioSamples(0), @@ -102,6 +101,7 @@ Audio::Audio(QObject* parent) : _scopeOutputOffset(0), _framesPerScope(DEFAULT_FRAMES_PER_SCOPE), _samplesPerScope(NETWORK_SAMPLES_PER_FRAME * _framesPerScope), + _peqEnabled(false), _scopeInput(0), _scopeOutputLeft(0), _scopeOutputRight(0), @@ -475,7 +475,7 @@ void Audio::handleAudioInput() { int16_t* ioBuffer = (int16_t*)inputByteArray.data(); - _peq.render( ioBuffer, ioBuffer, inputByteArray.size() / sizeof(int16_t) ); + _peq.render(ioBuffer, ioBuffer, inputByteArray.size() / sizeof(int16_t)); } if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio) && !_muted && _audioOutput) { @@ -676,6 +676,11 @@ void Audio::handleAudioInput() { NodeList* nodeList = NodeList::getInstance(); SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer); + + if (_recorder && _recorder.data()->isRecording()) { + _recorder.data()->record(reinterpret_cast(networkAudioSamples), numNetworkBytes); + } + if (audioMixer && audioMixer->getActiveSocket()) { MyAvatar* interfaceAvatar = Application::getInstance()->getAvatar(); glm::vec3 headPosition = interfaceAvatar->getHead()->getPosition(); diff --git a/interface/src/Recorder.cpp b/interface/src/Recorder.cpp index de29a887fb..b0698b95cb 100644 --- a/interface/src/Recorder.cpp +++ b/interface/src/Recorder.cpp @@ -45,14 +45,30 @@ void RecordingFrame::setLeanForward(float leanForward) { _leanForward = leanForward; } +Recording::Recording() : _audio(NULL) { +} + +Recording::~Recording() { + delete _audio; +} + void Recording::addFrame(int timestamp, RecordingFrame &frame) { _timestamps << timestamp; _frames << frame; } +void Recording::addAudioPacket(QByteArray byteArray) { + if (!_audio) { + _audio = new Sound(byteArray); + } + _audio->append(byteArray); +} + void Recording::clear() { _timestamps.clear(); _frames.clear(); + delete _audio; + _audio = NULL; } Recorder::Recorder(AvatarData* avatar) : @@ -134,10 +150,19 @@ void Recorder::record() { } } +void Recorder::record(char* samples, int size) { + QByteArray byteArray(samples, size); + _recording->addAudioPacket(byteArray); +} + + Player::Player(AvatarData* avatar) : _recording(new Recording()), - _avatar(avatar) + _avatar(avatar), + _audioThread(NULL) { + _options.setLoop(false); + _options.setVolume(1.0f); } bool Player::isPlaying() const { @@ -276,18 +301,29 @@ float Player::getLeanForward() { return 0.0f; } - +#include void Player::startPlaying() { if (_recording && _recording->getFrameNumber() > 0) { qDebug() << "Recorder::startPlaying()"; - _timer.start(); _currentFrame = 0; + _options.setPosition(_avatar->getPosition()); + _options.setOrientation(_avatar->getOrientation()); + _injector.reset(new AudioInjector(_recording->getAudio(), _options)); + _audioThread = new QThread(); + _injector->moveToThread(_audioThread); + _audioThread->start(); + QMetaObject::invokeMethod(_injector.data(), "injectAudio", Qt::QueuedConnection); + _timer.start(); } } void Player::stopPlaying() { qDebug() << "Recorder::stopPlaying()"; _timer.invalidate(); + _injector->stop(); + _injector.clear(); + _audioThread->exit(); + _audioThread->deleteLater(); } void Player::loadFromFile(QString file) { @@ -311,6 +347,7 @@ void Player::play() { stopPlaying(); return; } + if (_currentFrame == 0) { _avatar->setPosition(_recording->getFrame(_currentFrame).getTranslation()); _avatar->setOrientation(_recording->getFrame(_currentFrame).getRotation()); @@ -318,8 +355,6 @@ void Player::play() { _avatar->setJointRotations(_recording->getFrame(_currentFrame).getJointRotations()); HeadData* head = const_cast(_avatar->getHeadData()); head->setBlendshapeCoefficients(_recording->getFrame(_currentFrame).getBlendshapeCoefficients()); - // TODO - // BODY: Joint Rotations } else { _avatar->setPosition(_recording->getFrame(0).getTranslation() + _recording->getFrame(_currentFrame).getTranslation()); @@ -330,11 +365,20 @@ void Player::play() { _avatar->setJointRotations(_recording->getFrame(_currentFrame).getJointRotations()); HeadData* head = const_cast(_avatar->getHeadData()); head->setBlendshapeCoefficients(_recording->getFrame(_currentFrame).getBlendshapeCoefficients()); - // TODO - // BODY: Joint Rotations } } +void Player::playAudio() { + _options.setPosition(_avatar->getPosition()); + _options.setOrientation(_avatar->getOrientation()); + + qDebug() << "Play"; + if (_injector) { + _injector->injectAudio(); + } + qDebug() << "Played"; +} + void Player::computeCurrentFrame() { if (!isPlaying()) { qDebug() << "Not Playing"; diff --git a/interface/src/Recorder.h b/interface/src/Recorder.h index f2a6f6a1c4..9a412aadbf 100644 --- a/interface/src/Recorder.h +++ b/interface/src/Recorder.h @@ -22,8 +22,10 @@ #include #include +#include #include #include +#include class Recorder; class Recording; @@ -75,28 +77,34 @@ private: /// Stores a recording class Recording { public: + Recording(); + ~Recording(); + bool isEmpty() const { return _timestamps.isEmpty(); } int getLength() const { return _timestamps.last(); } // in ms + int getFrameNumber() const { return _frames.size(); } - qint32 getFrameTimestamp(int i) const { return _timestamps[i]; } const RecordingFrame& getFrame(int i) const { return _frames[i]; } + Sound* getAudio() const { return _audio; } protected: void addFrame(int timestamp, RecordingFrame& frame); + void addAudioPacket(QByteArray byteArray); void clear(); private: QVector _timestamps; QVector _frames; + Sound* _audio; + friend class Recorder; friend class Player; friend void writeRecordingToFile(Recording& recording, QString file); friend RecordingPointer readRecordingFromFile(QString file); }; - /// Records a recording class Recorder { public: @@ -112,6 +120,7 @@ public slots: void stopRecording(); void saveToFile(QString file); void record(); + void record(char* samples, int size); private: QElapsedTimer _timer; @@ -138,12 +147,14 @@ public: float getLeanSideways(); float getLeanForward(); + public slots: void startPlaying(); void stopPlaying(); void loadFromFile(QString file); void loadRecording(RecordingPointer recording); void play(); + void playAudio(); private: void computeCurrentFrame(); @@ -152,7 +163,11 @@ private: RecordingPointer _recording; int _currentFrame; + QSharedPointer _injector; + AudioInjectorOptions _options; + AvatarData* _avatar; + QThread* _audioThread; }; void writeRecordingToFile(Recording& recording, QString file); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index d50e9232ed..498281c98c 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -735,7 +735,6 @@ QVector Avatar::getJointRotations() const { for (int i = 0; i < _skeletonModel.getJointStateCount(); ++i) { _skeletonModel.getJointState(i, jointRotations[i]); } - qDebug() << "Get Joints"; return jointRotations; } From 54851c5ced02f4125d449c18789e16c78bbacad5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 18 Aug 2014 12:49:12 -0700 Subject: [PATCH 396/407] add Ragdoll::_accumulatedMovement --- libraries/shared/src/Ragdoll.cpp | 27 ++++++++++++++++++++++++++- libraries/shared/src/Ragdoll.h | 10 ++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/Ragdoll.cpp b/libraries/shared/src/Ragdoll.cpp index 7eeaf0b609..70ea63930b 100644 --- a/libraries/shared/src/Ragdoll.cpp +++ b/libraries/shared/src/Ragdoll.cpp @@ -19,7 +19,8 @@ #include "PhysicsSimulation.h" #include "SharedUtil.h" // for EPSILON -Ragdoll::Ragdoll() : _massScale(1.0f), _translation(0.0f), _translationInSimulationFrame(0.0f), _simulation(NULL) { +Ragdoll::Ragdoll() : _massScale(1.0f), _translation(0.0f), _translationInSimulationFrame(0.0f), + _accumulatedMovement(0.0f), _simulation(NULL) { } Ragdoll::~Ragdoll() { @@ -116,3 +117,27 @@ void Ragdoll::setMassScale(float scale) { _massScale = scale; } } + +void Ragdoll::removeRootOffset(bool accumulateMovement) { + const int numPoints = _points.size(); + if (numPoints > 0) { + // shift all points so that the root aligns with the the ragdoll's position in the simulation + glm::vec3 offset = _translationInSimulationFrame - _points[0]._position; + float offsetLength = glm::length(offset); + if (offsetLength > EPSILON) { + for (int i = 0; i < numPoints; ++i) { + _points[i].shift(offset); + } + const float MIN_ROOT_OFFSET = 0.02f; + if (accumulateMovement && offsetLength > MIN_ROOT_OFFSET) { + _accumulatedMovement -= (1.0f - MIN_ROOT_OFFSET / offsetLength) * offset; + } + } + } +} + +glm::vec3 Ragdoll::getAndClearAccumulatedMovement() { + glm::vec3 movement = _accumulatedMovement; + _accumulatedMovement = glm::vec3(0.0f); + return movement; +} diff --git a/libraries/shared/src/Ragdoll.h b/libraries/shared/src/Ragdoll.h index c82295d9a5..1ffbdb29ab 100644 --- a/libraries/shared/src/Ragdoll.h +++ b/libraries/shared/src/Ragdoll.h @@ -56,6 +56,10 @@ public: virtual void initPoints() = 0; virtual void buildConstraints() = 0; + void removeRootOffset(bool accumulateMovement); + + glm::vec3 getAndClearAccumulatedMovement(); + protected: float _massScale; glm::vec3 _translation; // world-frame @@ -66,6 +70,12 @@ protected: QVector _points; QVector _boneConstraints; QVector _fixedConstraints; + + // The collisions are typically done in a simulation frame that is slaved to the center of one of the Ragdolls. + // To allow the Ragdoll to provide feedback of its own displacement we store it in _accumulatedMovement. + // The owner of the Ragdoll can harvest this displacement to update the rest of the object positions in the simulation. + glm::vec3 _accumulatedMovement; + private: void updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation); From fe5f9f8fe5a283fcf208f368026e47216baf0eb9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 18 Aug 2014 12:49:47 -0700 Subject: [PATCH 397/407] use relative mass when enforcing ContactPoint --- libraries/shared/src/ContactPoint.cpp | 31 +++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/ContactPoint.cpp b/libraries/shared/src/ContactPoint.cpp index 27a496d445..02cf896594 100644 --- a/libraries/shared/src/ContactPoint.cpp +++ b/libraries/shared/src/ContactPoint.cpp @@ -96,10 +96,10 @@ float ContactPoint::enforce() { bool constraintViolation = (pDotN > CONTACT_PENETRATION_ALLOWANCE); // the contact point will be the average of the two points on the shapes - _contactPoint = 0.5f * (pointA + pointB); + _contactPoint = _relativeMassA * pointA + _relativeMassB * pointB; if (constraintViolation) { - for (int i = 0; i < _numPoints; ++i) { + for (int i = 0; i < _numPointsA; ++i) { VerletPoint* point = _points[i]; glm::vec3 offset = _offsets[i]; @@ -111,8 +111,31 @@ float ContactPoint::enforce() { // use the relative sizes of the components to decide how much perpenducular delta to use // perpendicular < parallel ==> static friction ==> perpFactor = 1.0 // perpendicular > parallel ==> dynamic friction ==> cap to length of paraDelta ==> perpFactor < 1.0 - float paraLength = glm::length(paraDelta); - float perpLength = glm::length(perpDelta); + float paraLength = _relativeMassB * glm::length(paraDelta); + float perpLength = _relativeMassA * glm::length(perpDelta); + float perpFactor = (perpLength > paraLength && perpLength > EPSILON) ? (paraLength / perpLength) : 1.0f; + + // recombine the two components to get the final delta + delta = paraDelta + perpFactor * perpDelta; + + glm::vec3 targetPosition = point->_position + delta; + _distances[i] = glm::distance(_contactPoint, targetPosition); + point->_position += delta; + } + for (int i = _numPointsA; i < _numPoints; ++i) { + VerletPoint* point = _points[i]; + glm::vec3 offset = _offsets[i]; + + // split delta into parallel and perpendicular components + glm::vec3 delta = _contactPoint + offset - point->_position; + glm::vec3 paraDelta = glm::dot(delta, _normal) * _normal; + glm::vec3 perpDelta = delta - paraDelta; + + // use the relative sizes of the components to decide how much perpenducular delta to use + // perpendicular < parallel ==> static friction ==> perpFactor = 1.0 + // perpendicular > parallel ==> dynamic friction ==> cap to length of paraDelta ==> perpFactor < 1.0 + float paraLength = _relativeMassA * glm::length(paraDelta); + float perpLength = _relativeMassB * glm::length(perpDelta); float perpFactor = (perpLength > paraLength && perpLength > EPSILON) ? (paraLength / perpLength) : 1.0f; // recombine the two components to get the final delta From 3e2095332fdf1338fca49a0395e30ddbe6adb4ce Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 18 Aug 2014 12:50:07 -0700 Subject: [PATCH 398/407] make SkeletonRagdoll::updateMuscles() protected --- interface/src/avatar/SkeletonRagdoll.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/avatar/SkeletonRagdoll.h b/interface/src/avatar/SkeletonRagdoll.h index f9f99395ac..ae9bec9116 100644 --- a/interface/src/avatar/SkeletonRagdoll.h +++ b/interface/src/avatar/SkeletonRagdoll.h @@ -33,7 +33,9 @@ public: virtual void initPoints(); virtual void buildConstraints(); +protected: void updateMuscles(); + private: Model* _model; QVector _muscleConstraints; From 7e7978de1a83051160aee4b45606db5df418b523 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 18 Aug 2014 12:53:04 -0700 Subject: [PATCH 399/407] compute and store Ragdoll::_accumulatedMovement --- interface/src/avatar/SkeletonModel.cpp | 23 ++++++++++++---------- interface/src/avatar/SkeletonRagdoll.cpp | 5 +---- libraries/shared/src/PhysicsSimulation.cpp | 21 +++++++++++++++----- libraries/shared/src/PhysicsSimulation.h | 6 ++++-- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index ffe711b03b..536f957143 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -14,14 +14,11 @@ #include #include -#include -#include #include "Application.h" #include "Avatar.h" #include "Hand.h" #include "Menu.h" -#include "MuscleConstraint.h" #include "SkeletonModel.h" #include "SkeletonRagdoll.h" @@ -606,6 +603,7 @@ void SkeletonModel::buildShapes() { float uniformScale = extractUniformScale(_scale); const int numStates = _jointStates.size(); + float totalMass = 0.0f; for (int i = 0; i < numStates; i++) { JointState& state = _jointStates[i]; const FBXJoint& joint = state.getFBXJoint(); @@ -624,26 +622,31 @@ void SkeletonModel::buildShapes() { if (type == Shape::SPHERE_SHAPE) { shape = new VerletSphereShape(radius, &(points[i])); shape->setEntity(this); - points[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); + float mass = massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()); + points[i].setMass(mass); + totalMass += mass; } else if (type == Shape::CAPSULE_SHAPE) { assert(parentIndex != -1); shape = new VerletCapsuleShape(radius, &(points[parentIndex]), &(points[i])); shape->setEntity(this); - points[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); + float mass = massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()); + points[i].setMass(mass); + totalMass += mass; } if (parentIndex != -1) { // always disable collisions between joint and its parent if (shape) { disableCollisions(i, parentIndex); } - } else { - // give the base joint a very large mass since it doesn't actually move - // in the local-frame simulation (it defines the origin) - points[i].setMass(VERY_BIG_MASS); - } + } _shapes.push_back(shape); } + // set the mass of the root + if (numStates > 0) { + points[0].setMass(totalMass); + } + // This method moves the shapes to their default positions in Model frame. computeBoundingShape(geometry); diff --git a/interface/src/avatar/SkeletonRagdoll.cpp b/interface/src/avatar/SkeletonRagdoll.cpp index 503f38f00f..6318323990 100644 --- a/interface/src/avatar/SkeletonRagdoll.cpp +++ b/interface/src/avatar/SkeletonRagdoll.cpp @@ -70,10 +70,7 @@ void SkeletonRagdoll::buildConstraints() { for (int i = 0; i < numPoints; ++i) { const JointState& state = jointStates.at(i); int parentIndex = state.getParentIndex(); - if (parentIndex == -1) { - FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_points[i])); - _fixedConstraints.push_back(anchor); - } else { + if (parentIndex != -1) { DistanceConstraint* bone = new DistanceConstraint(&(_points[i]), &(_points[parentIndex])); bone->setDistance(state.getDistanceToParent()); _boneConstraints.push_back(bone); diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index a62b3816af..6c4901bcd5 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -163,10 +163,10 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { } void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { - int numDolls = _otherRagdolls.size(); - if (doll->_simulation != this) { + if (!doll || doll->_simulation != this) { return; } + int numDolls = _otherRagdolls.size(); for (int i = 0; i < numDolls; ++i) { if (doll == _otherRagdolls[i]) { if (i == numDolls - 1) { @@ -205,10 +205,11 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter } } + bool collidedWithOtherRagdoll = false; int iterations = 0; float error = 0.0f; do { - computeCollisions(); + collidedWithOtherRagdoll = computeCollisions() || collidedWithOtherRagdoll; updateContacts(); resolveCollisions(); @@ -225,6 +226,14 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter now = usecTimestampNow(); } while (_collisions.size() != 0 && (iterations < maxIterations) && (error > minError) && (now < expiry)); + // the collisions may have moved the main ragdoll from the simulation center + // so we remove this offset (potentially storing it as movement of the Ragdoll owner) + _ragdoll->removeRootOffset(collidedWithOtherRagdoll); + + // also remove any offsets from the other ragdolls + for (int i = 0; i < numDolls; ++i) { + _otherRagdolls[i]->removeRootOffset(false); + } pruneContacts(); } @@ -237,7 +246,7 @@ void PhysicsSimulation::moveRagdolls(float deltaTime) { } } -void PhysicsSimulation::computeCollisions() { +bool PhysicsSimulation::computeCollisions() { PerformanceTimer perfTimer("collide"); _collisions.clear(); @@ -258,11 +267,13 @@ void PhysicsSimulation::computeCollisions() { } // collide main ragdoll with others + bool otherCollisions = false; int numEntities = _otherEntities.size(); for (int i = 0; i < numEntities; ++i) { const QVector otherShapes = _otherEntities.at(i)->getShapes(); - ShapeCollider::collideShapesWithShapes(shapes, otherShapes, _collisions); + otherCollisions = ShapeCollider::collideShapesWithShapes(shapes, otherShapes, _collisions) || otherCollisions; } + return otherCollisions; } void PhysicsSimulation::resolveCollisions() { diff --git a/libraries/shared/src/PhysicsSimulation.h b/libraries/shared/src/PhysicsSimulation.h index 881007208b..1db56a46e2 100644 --- a/libraries/shared/src/PhysicsSimulation.h +++ b/libraries/shared/src/PhysicsSimulation.h @@ -53,9 +53,11 @@ public: protected: void moveRagdolls(float deltaTime); - void computeCollisions(); - void resolveCollisions(); + /// \return true if main ragdoll collides with other avatar + bool computeCollisions(); + + void resolveCollisions(); void enforceContacts(); void applyContactFriction(); void updateContacts(); From aa1a7307cc1219a4e965c7490af225bc5890c408 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 18 Aug 2014 12:53:34 -0700 Subject: [PATCH 400/407] use Ragdoll::_accumulatedMovement to move MyAvatar --- interface/src/avatar/MyAvatar.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ac44e1884e..50664d33c9 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -206,12 +206,21 @@ void MyAvatar::simulate(float deltaTime) { { PerformanceTimer perfTimer("ragdoll"); - if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { + Ragdoll* ragdoll = _skeletonModel.getRagdoll(); + if (ragdoll && Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { const float minError = 0.00001f; const float maxIterations = 3; const quint64 maxUsec = 4000; _physicsSimulation.setTranslation(_position); _physicsSimulation.stepForward(deltaTime, minError, maxIterations, maxUsec); + + // harvest any displacement of the Ragdoll that is a result of collisions + glm::vec3 ragdollDisplacement = ragdoll->getAndClearAccumulatedMovement(); + const float MAX_RAGDOLL_DISPLACEMENT_2 = 1.0f; + float length2 = glm::length2(ragdollDisplacement); + if (length2 > EPSILON && length2 < MAX_RAGDOLL_DISPLACEMENT_2) { + setPosition(getPosition() + ragdollDisplacement); + } } else { _skeletonModel.moveShapesTowardJoints(1.0f); } From 543bf5224c118c74a571f26b7123d7c138efdac4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 18 Aug 2014 12:54:26 -0700 Subject: [PATCH 401/407] add VerletPoint::shift() --- libraries/shared/src/VerletPoint.cpp | 5 +++++ libraries/shared/src/VerletPoint.h | 1 + 2 files changed, 6 insertions(+) diff --git a/libraries/shared/src/VerletPoint.cpp b/libraries/shared/src/VerletPoint.cpp index d2dd985587..cf9aeca149 100644 --- a/libraries/shared/src/VerletPoint.cpp +++ b/libraries/shared/src/VerletPoint.cpp @@ -39,6 +39,11 @@ void VerletPoint::move(const glm::vec3& deltaPosition, const glm::quat& deltaRot _lastPosition += deltaPosition + (deltaRotation * arm - arm); } +void VerletPoint::shift(const glm::vec3& deltaPosition) { + _position += deltaPosition; + _lastPosition += deltaPosition; +} + void VerletPoint::setMass(float mass) { const float MIN_MASS = 1.0e-6f; const float MAX_MASS = 1.0e18f; diff --git a/libraries/shared/src/VerletPoint.h b/libraries/shared/src/VerletPoint.h index 6f94656966..3c73e5eb01 100644 --- a/libraries/shared/src/VerletPoint.h +++ b/libraries/shared/src/VerletPoint.h @@ -25,6 +25,7 @@ public: void accumulateDelta(const glm::vec3& delta); void applyAccumulatedDelta(); void move(const glm::vec3& deltaPosition, const glm::quat& deltaRotation, const glm::vec3& oldPivot); + void shift(const glm::vec3& deltaPosition); void setMass(float mass); float getMass() const { return _mass; } From 52640c8482351a0629fc9ba08ab85537d5fa0f34 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 18 Aug 2014 14:23:29 -0700 Subject: [PATCH 402/407] Various tweaks and code cleanup --- interface/src/Application.cpp | 2 ++ interface/src/Recorder.cpp | 29 ++++++++++++++-------------- interface/src/Recorder.h | 13 ++++++------- interface/src/avatar/MyAvatar.cpp | 12 ++++++++++-- interface/src/avatar/MyAvatar.h | 1 + interface/src/renderer/Model.cpp | 8 ++++++++ interface/src/renderer/Model.h | 3 +++ libraries/avatars/src/AvatarData.cpp | 6 ++++++ libraries/avatars/src/AvatarData.h | 4 +++- 9 files changed, 53 insertions(+), 25 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2fef2ced8a..5a689180e5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1047,6 +1047,8 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_R: if (isShifted) { + Menu::getInstance()->triggerOption(MenuOption::FrustumRenderMode); + } else if (isMeta) { if (_myAvatar->isRecording()) { _myAvatar->stopRecording(); } else { diff --git a/interface/src/Recorder.cpp b/interface/src/Recorder.cpp index b0698b95cb..a2101b28b8 100644 --- a/interface/src/Recorder.cpp +++ b/interface/src/Recorder.cpp @@ -75,6 +75,7 @@ Recorder::Recorder(AvatarData* avatar) : _recording(new Recording()), _avatar(avatar) { + _timer.invalidate(); } bool Recorder::isRecording() const { @@ -124,7 +125,7 @@ void Recorder::saveToFile(QString file) { qDebug() << "Cannot save recording to file, recording is empty."; } - writeRecordingToFile(*_recording, file); + writeRecordingToFile(_recording, file); } void Recorder::record() { @@ -161,6 +162,7 @@ Player::Player(AvatarData* avatar) : _avatar(avatar), _audioThread(NULL) { + _timer.invalidate(); _options.setLoop(false); _options.setVolume(1.0f); } @@ -318,8 +320,16 @@ void Player::startPlaying() { } void Player::stopPlaying() { + if (!isPlaying()) { + return; + } + qDebug() << "Recorder::stopPlaying()"; _timer.invalidate(); + + _avatar->clearJointsData(); + + // Cleanup audio thread _injector->stop(); _injector.clear(); _audioThread->exit(); @@ -332,7 +342,7 @@ void Player::loadFromFile(QString file) { } else { _recording = RecordingPointer(new Recording()); } - readRecordingFromFile(*_recording, file); + readRecordingFromFile(_recording, file); } void Player::loadRecording(RecordingPointer recording) { @@ -368,17 +378,6 @@ void Player::play() { } } -void Player::playAudio() { - _options.setPosition(_avatar->getPosition()); - _options.setOrientation(_avatar->getOrientation()); - - qDebug() << "Play"; - if (_injector) { - _injector->injectAudio(); - } - qDebug() << "Played"; -} - void Player::computeCurrentFrame() { if (!isPlaying()) { qDebug() << "Not Playing"; @@ -396,12 +395,12 @@ void Player::computeCurrentFrame() { } } -void writeRecordingToFile(Recording& recording, QString file) { +void writeRecordingToFile(RecordingPointer recording, QString file) { // TODO qDebug() << "Writing recording to " << file; } -Recording& readRecordingFromFile(Recording& recording, QString file) { +RecordingPointer readRecordingFromFile(RecordingPointer recording, QString file) { // TODO qDebug() << "Reading recording from " << file; return recording; diff --git a/interface/src/Recorder.h b/interface/src/Recorder.h index 9a412aadbf..e1a1119449 100644 --- a/interface/src/Recorder.h +++ b/interface/src/Recorder.h @@ -70,8 +70,8 @@ private: float _leanForward; friend class Recorder; - friend void writeRecordingToFile(Recording& recording, QString file); - friend RecordingPointer readRecordingFromFile(QString file); + friend void writeRecordingToFile(RecordingPointer recording, QString file); + friend RecordingPointer readRecordingFromFile(RecordingPointer recording, QString file); }; /// Stores a recording @@ -101,8 +101,8 @@ private: friend class Recorder; friend class Player; - friend void writeRecordingToFile(Recording& recording, QString file); - friend RecordingPointer readRecordingFromFile(QString file); + friend void writeRecordingToFile(RecordingPointer recording, QString file); + friend RecordingPointer readRecordingFromFile(RecordingPointer recording, QString file); }; /// Records a recording @@ -154,7 +154,6 @@ public slots: void loadFromFile(QString file); void loadRecording(RecordingPointer recording); void play(); - void playAudio(); private: void computeCurrentFrame(); @@ -170,7 +169,7 @@ private: QThread* _audioThread; }; -void writeRecordingToFile(Recording& recording, QString file); -Recording& readRecordingFromFile(Recording& recording, QString file); +void writeRecordingToFile(RecordingPointer recording, QString file); +RecordingPointer readRecordingFromFile(RecordingPointer recording, QString file); #endif // hifi_Recorder_h \ No newline at end of file diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9ff60dd610..5ed2e3c011 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -922,8 +922,7 @@ const float JOINT_PRIORITY = 2.0f; void MyAvatar::setJointRotations(QVector jointRotations) { for (int i = 0; i < jointRotations.size(); ++i) { if (i < _jointData.size()) { - // TODO change animation priority to proper value - _skeletonModel.setJointState(i, true, jointRotations[i], 100.0f); + _skeletonModel.setJointState(i, true, jointRotations[i], JOINT_PRIORITY + 1.0f); } } } @@ -942,6 +941,15 @@ void MyAvatar::clearJointData(int index) { } } +void MyAvatar::clearJointsData() { + for (int i = 0; i < _jointData.size(); ++i) { + Avatar::clearJointData(i); + if (QThread::currentThread() == thread()) { + _skeletonModel.clearJointState(i); + } + } +} + void MyAvatar::setFaceModelURL(const QUrl& faceModelURL) { Avatar::setFaceModelURL(faceModelURL); _billboardValid = false; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index bf57bf2367..67d19b87eb 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -115,6 +115,7 @@ public: virtual void setJointRotations(QVector jointRotations); virtual void setJointData(int index, const glm::quat& rotation); virtual void clearJointData(int index); + virtual void clearJointsData(); virtual void setFaceModelURL(const QUrl& faceModelURL); virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); virtual void setAttachmentData(const QVector& attachmentData); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 2ec676de53..290f9b5c6f 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -692,6 +692,14 @@ bool Model::getVisibleJointState(int index, glm::quat& rotation) const { return !state.rotationIsDefault(rotation); } +void Model::clearJointState(int index) { + if (index != -1 && index < _jointStates.size()) { + JointState& state = _jointStates[index]; + state.setRotationInConstrainedFrame(glm::quat()); + state._animationPriority = 0.0f; + } +} + void Model::setJointState(int index, bool valid, const glm::quat& rotation, float priority) { if (index != -1 && index < _jointStates.size()) { JointState& state = _jointStates[index]; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 7a29b61420..e45b8091d3 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -118,6 +118,9 @@ public: /// \return whether or not the joint state is "valid" (that is, non-default) bool getVisibleJointState(int index, glm::quat& rotation) const; + /// Clear the joint states + void clearJointState(int index); + /// Sets the joint state at the specified index. void setJointState(int index, bool valid, const glm::quat& rotation = glm::quat(), float priority = 1.0f); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 569e099c2c..9653999555 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -712,6 +712,12 @@ void AvatarData::setJointRotations(QVector jointRotations) { } } +void AvatarData::clearJointsData() { + for (int i = 0; i < _jointData.size(); ++i) { + clearJointData(i); + } +} + bool AvatarData::hasIdentityChangedAfterParsing(const QByteArray &packet) { QDataStream packetStream(packet); packetStream.skipRawData(numBytesForPacketHeader(packet)); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 7dec55b7e9..fa884c0229 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -213,7 +213,9 @@ public: Q_INVOKABLE virtual QVector getJointRotations() const; Q_INVOKABLE virtual void setJointRotations(QVector jointRotations); - + + Q_INVOKABLE virtual void clearJointsData(); + /// Returns the index of the joint with the specified name, or -1 if not found/unknown. Q_INVOKABLE virtual int getJointIndex(const QString& name) const { return _jointIndices.value(name) - 1; } From 698699dea8cf608564f7919ee62e6a2a4a6f3838 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 18 Aug 2014 15:56:27 -0700 Subject: [PATCH 403/407] CR --- interface/src/Recorder.cpp | 143 +++++++------------------------------ interface/src/Recorder.h | 7 +- 2 files changed, 26 insertions(+), 124 deletions(-) diff --git a/interface/src/Recorder.cpp b/interface/src/Recorder.cpp index a2101b28b8..b782112778 100644 --- a/interface/src/Recorder.cpp +++ b/interface/src/Recorder.cpp @@ -11,6 +11,8 @@ #include +#include + #include "Recorder.h" void RecordingFrame::setBlendshapeCoefficients(QVector blendshapeCoefficients) { @@ -179,131 +181,37 @@ qint64 Player::elapsed() const { } } -QVector Player::getBlendshapeCoefficients() { - computeCurrentFrame(); - if (_currentFrame >= 0 && _currentFrame <= _recording->getFrameNumber()) { - if (_currentFrame == _recording->getFrameNumber()) { - return _recording->getFrame(_currentFrame - 1).getBlendshapeCoefficients(); - } - - return _recording->getFrame(_currentFrame).getBlendshapeCoefficients(); - } - qWarning() << "Incorrect use of Player::getBlendshapeCoefficients()"; - return QVector(); -} - -QVector Player::getJointRotations() { - computeCurrentFrame(); - if (_currentFrame >= 0 && _currentFrame <= _recording->getFrameNumber()) { - if (_currentFrame == _recording->getFrameNumber()) { - return _recording->getFrame(_currentFrame - 1).getJointRotations(); - } - - return _recording->getFrame(_currentFrame).getJointRotations(); - } - qWarning() << "Incorrect use of Player::getJointRotations()"; - return QVector(); -} - -glm::vec3 Player::getPosition() { - computeCurrentFrame(); - if (_currentFrame >= 0 && _currentFrame <= _recording->getFrameNumber()) { - if (_currentFrame == _recording->getFrameNumber()) { - return _recording->getFrame(0).getTranslation() + - _recording->getFrame(_currentFrame - 1).getTranslation(); - } - if (_currentFrame == 0) { - return _recording->getFrame(_currentFrame).getTranslation(); - } - - return _recording->getFrame(0).getTranslation() + - _recording->getFrame(_currentFrame).getTranslation(); - } - qWarning() << "Incorrect use of Player::getTranslation()"; - return glm::vec3(); -} - -glm::quat Player::getRotation() { - computeCurrentFrame(); - if (_currentFrame >= 0 && _currentFrame <= _recording->getFrameNumber()) { - if (_currentFrame == _recording->getFrameNumber()) { - return _recording->getFrame(0).getRotation() * - _recording->getFrame(_currentFrame - 1).getRotation(); - } - if (_currentFrame == 0) { - return _recording->getFrame(_currentFrame).getRotation(); - } - - return _recording->getFrame(0).getRotation() * - _recording->getFrame(_currentFrame).getRotation(); - } - qWarning() << "Incorrect use of Player::getRotation()"; - return glm::quat(); -} - -float Player::getScale() { - computeCurrentFrame(); - if (_currentFrame >= 0 && _currentFrame <= _recording->getFrameNumber()) { - if (_currentFrame == _recording->getFrameNumber()) { - return _recording->getFrame(0).getScale() * - _recording->getFrame(_currentFrame - 1).getScale(); - } - if (_currentFrame == 0) { - return _recording->getFrame(_currentFrame).getScale(); - } - - return _recording->getFrame(0).getScale() * - _recording->getFrame(_currentFrame).getScale(); - } - qWarning() << "Incorrect use of Player::getScale()"; - return 1.0f; -} - glm::quat Player::getHeadRotation() { - computeCurrentFrame(); - if (_currentFrame >= 0 && _currentFrame <= _recording->getFrameNumber()) { - if (_currentFrame == _recording->getFrameNumber()) { - return _recording->getFrame(0).getHeadRotation() * - _recording->getFrame(_currentFrame - 1).getHeadRotation(); - } - if (_currentFrame == 0) { - return _recording->getFrame(_currentFrame).getHeadRotation(); - } - - return _recording->getFrame(0).getHeadRotation() * - _recording->getFrame(_currentFrame).getHeadRotation(); + if (computeCurrentFrame()) { + qWarning() << "Incorrect use of Player::getHeadRotation()"; + return glm::quat(); } - qWarning() << "Incorrect use of Player::getHeadRotation()"; - return glm::quat(); + + if (_currentFrame == 0) { + return _recording->getFrame(_currentFrame).getHeadRotation(); + } + return _recording->getFrame(0).getHeadRotation() * + _recording->getFrame(_currentFrame).getHeadRotation(); } float Player::getLeanSideways() { - computeCurrentFrame(); - if (_currentFrame >= 0 && _currentFrame <= _recording->getFrameNumber()) { - if (_currentFrame == _recording->getFrameNumber()) { - return _recording->getFrame(_currentFrame - 1).getLeanSideways(); - } - - return _recording->getFrame(_currentFrame).getLeanSideways(); + if (computeCurrentFrame()) { + qWarning() << "Incorrect use of Player::getLeanSideways()"; + return 0.0f; } - qWarning() << "Incorrect use of Player::getLeanSideways()"; - return 0.0f; + + return _recording->getFrame(_currentFrame).getLeanSideways(); } float Player::getLeanForward() { - computeCurrentFrame(); - if (_currentFrame >= 0 && _currentFrame <= _recording->getFrameNumber()) { - if (_currentFrame == _recording->getFrameNumber()) { - return _recording->getFrame(_currentFrame - 1).getLeanForward(); - } - - return _recording->getFrame(_currentFrame).getLeanForward(); + if (computeCurrentFrame()) { + qWarning() << "Incorrect use of Player::getLeanForward()"; + return 0.0f; } - qWarning() << "Incorrect use of Player::getLeanForward()"; - return 0.0f; + + return _recording->getFrame(_currentFrame).getLeanForward(); } -#include void Player::startPlaying() { if (_recording && _recording->getFrameNumber() > 0) { qDebug() << "Recorder::startPlaying()"; @@ -350,7 +258,6 @@ void Player::loadRecording(RecordingPointer recording) { } void Player::play() { - qDebug() << "Playing " << _timer.elapsed() / 1000.0f; computeCurrentFrame(); if (_currentFrame < 0 || _currentFrame >= _recording->getFrameNumber()) { // If it's the end of the recording, stop playing @@ -378,14 +285,12 @@ void Player::play() { } } -void Player::computeCurrentFrame() { +bool Player::computeCurrentFrame() { if (!isPlaying()) { - qDebug() << "Not Playing"; _currentFrame = -1; - return; + return false; } if (_currentFrame < 0) { - qDebug() << "Reset to 0"; _currentFrame = 0; } @@ -393,6 +298,8 @@ void Player::computeCurrentFrame() { _recording->getFrameTimestamp(_currentFrame) < _timer.elapsed()) { ++_currentFrame; } + + return true; } void writeRecordingToFile(RecordingPointer recording, QString file) { diff --git a/interface/src/Recorder.h b/interface/src/Recorder.h index e1a1119449..9f7eb66ec6 100644 --- a/interface/src/Recorder.h +++ b/interface/src/Recorder.h @@ -138,11 +138,6 @@ public: qint64 elapsed() const; // Those should only be called if isPlaying() returns true - QVector getBlendshapeCoefficients(); - QVector getJointRotations(); - glm::vec3 getPosition(); - glm::quat getRotation(); - float getScale(); glm::quat getHeadRotation(); float getLeanSideways(); float getLeanForward(); @@ -156,7 +151,7 @@ public slots: void play(); private: - void computeCurrentFrame(); + bool computeCurrentFrame(); QElapsedTimer _timer; RecordingPointer _recording; From c113dd350eabb6f2c18911d660d70355a8437dcf Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 18 Aug 2014 16:25:38 -0700 Subject: [PATCH 404/407] Moved members to MyAvatar --- interface/src/avatar/Avatar.cpp | 1 - interface/src/avatar/Avatar.h | 3 --- interface/src/avatar/MyAvatar.h | 3 +++ 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 498281c98c..41912afd09 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -64,7 +64,6 @@ Avatar::Avatar() : _mouseRayDirection(0.0f, 0.0f, 0.0f), _moving(false), _collisionGroups(0), - _player(NULL), _initialized(false), _shouldRenderBillboard(true) { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 35dec3b8d0..c8ecb23913 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -188,9 +188,6 @@ protected: bool _moving; ///< set when position is changing quint32 _collisionGroups; - - RecorderPointer _recorder; - PlayerPointer _player; // protected methods... glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 67d19b87eb..2c1695a499 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -205,6 +205,9 @@ private: QList _animationHandles; PhysicsSimulation _physicsSimulation; + RecorderPointer _recorder; + PlayerPointer _player; + // private methods float computeDistanceToFloor(const glm::vec3& startPoint); void updateOrientation(float deltaTime); From 45ccb012972989fcb8baa04bc676bc1ad19f8345 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 18 Aug 2014 21:05:03 -0700 Subject: [PATCH 405/407] Update options position and orientation correctly in the AudioInjector --- libraries/audio/src/AudioInjector.cpp | 14 ++++++++++++-- libraries/audio/src/AudioInjector.h | 1 + libraries/audio/src/AudioInjectorOptions.cpp | 9 ++++++++- libraries/audio/src/AudioInjectorOptions.h | 1 + 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index e5c1230832..114ab1c95c 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -27,7 +27,6 @@ AudioInjector::AudioInjector(QObject* parent) : _options(), _shouldStop(false) { - } AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions) : @@ -35,7 +34,10 @@ AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorO _options(injectorOptions), _shouldStop(false) { - +} + +void AudioInjector::setOptions(AudioInjectorOptions& options) { + _options = options; } const uchar MAX_INJECTOR_VOLUME = 0xFF; @@ -73,9 +75,11 @@ void AudioInjector::injectAudio() { packetStream << loopbackFlag; // pack the position for injected audio + int positionOptionOffset = injectAudioPacket.size(); packetStream.writeRawData(reinterpret_cast(&_options.getPosition()), sizeof(_options.getPosition())); // pack our orientation for injected audio + int orientationOptionOffset = injectAudioPacket.size(); packetStream.writeRawData(reinterpret_cast(&_options.getOrientation()), sizeof(_options.getOrientation())); // pack zero for radius @@ -101,6 +105,12 @@ void AudioInjector::injectAudio() { int bytesToCopy = std::min(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, soundByteArray.size() - currentSendPosition); + memcpy(injectAudioPacket.data() + positionOptionOffset, + &_options.getPosition(), + sizeof(_options.getPosition())); + memcpy(injectAudioPacket.data() + orientationOptionOffset, + &_options.getOrientation(), + sizeof(_options.getOrientation())); // resize the QByteArray to the right size injectAudioPacket.resize(numPreAudioDataBytes + bytesToCopy); diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 08fe544255..966a4dd1cf 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -29,6 +29,7 @@ public: public slots: void injectAudio(); void stop() { _shouldStop = true; } + void setOptions(AudioInjectorOptions& options); signals: void finished(); private: diff --git a/libraries/audio/src/AudioInjectorOptions.cpp b/libraries/audio/src/AudioInjectorOptions.cpp index 49f1571c98..01aa43a0cd 100644 --- a/libraries/audio/src/AudioInjectorOptions.cpp +++ b/libraries/audio/src/AudioInjectorOptions.cpp @@ -19,7 +19,6 @@ AudioInjectorOptions::AudioInjectorOptions(QObject* parent) : _orientation(glm::vec3(0.0f, 0.0f, 0.0f)), _loopbackAudioInterface(NULL) { - } AudioInjectorOptions::AudioInjectorOptions(const AudioInjectorOptions& other) { @@ -29,3 +28,11 @@ AudioInjectorOptions::AudioInjectorOptions(const AudioInjectorOptions& other) { _orientation = other._orientation; _loopbackAudioInterface = other._loopbackAudioInterface; } + +void AudioInjectorOptions::operator=(const AudioInjectorOptions& other) { + _position = other._position; + _volume = other._volume; + _loop = other._loop; + _orientation = other._orientation; + _loopbackAudioInterface = other._loopbackAudioInterface; +} \ No newline at end of file diff --git a/libraries/audio/src/AudioInjectorOptions.h b/libraries/audio/src/AudioInjectorOptions.h index 35575414d5..64936e4bc9 100644 --- a/libraries/audio/src/AudioInjectorOptions.h +++ b/libraries/audio/src/AudioInjectorOptions.h @@ -30,6 +30,7 @@ class AudioInjectorOptions : public QObject { public: AudioInjectorOptions(QObject* parent = 0); AudioInjectorOptions(const AudioInjectorOptions& other); + void operator=(const AudioInjectorOptions& other); const glm::vec3& getPosition() const { return _position; } void setPosition(const glm::vec3& position) { _position = position; } From 29830916bafd60414ffd150e6f47142f46a2ca3b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 18 Aug 2014 21:06:32 -0700 Subject: [PATCH 406/407] Fix bug introduced in CR --- interface/src/Recorder.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/interface/src/Recorder.cpp b/interface/src/Recorder.cpp index b782112778..30b14ac589 100644 --- a/interface/src/Recorder.cpp +++ b/interface/src/Recorder.cpp @@ -182,7 +182,7 @@ qint64 Player::elapsed() const { } glm::quat Player::getHeadRotation() { - if (computeCurrentFrame()) { + if (!computeCurrentFrame()) { qWarning() << "Incorrect use of Player::getHeadRotation()"; return glm::quat(); } @@ -195,7 +195,7 @@ glm::quat Player::getHeadRotation() { } float Player::getLeanSideways() { - if (computeCurrentFrame()) { + if (!computeCurrentFrame()) { qWarning() << "Incorrect use of Player::getLeanSideways()"; return 0.0f; } @@ -204,7 +204,7 @@ float Player::getLeanSideways() { } float Player::getLeanForward() { - if (computeCurrentFrame()) { + if (!computeCurrentFrame()) { qWarning() << "Incorrect use of Player::getLeanForward()"; return 0.0f; } @@ -216,13 +216,16 @@ void Player::startPlaying() { if (_recording && _recording->getFrameNumber() > 0) { qDebug() << "Recorder::startPlaying()"; _currentFrame = 0; + + // Setup audio thread + _audioThread = new QThread(); _options.setPosition(_avatar->getPosition()); _options.setOrientation(_avatar->getOrientation()); - _injector.reset(new AudioInjector(_recording->getAudio(), _options)); - _audioThread = new QThread(); + _injector.reset(new AudioInjector(_recording->getAudio(), _options), &QObject::deleteLater); _injector->moveToThread(_audioThread); _audioThread->start(); QMetaObject::invokeMethod(_injector.data(), "injectAudio", Qt::QueuedConnection); + _timer.start(); } } @@ -232,7 +235,6 @@ void Player::stopPlaying() { return; } - qDebug() << "Recorder::stopPlaying()"; _timer.invalidate(); _avatar->clearJointsData(); @@ -242,6 +244,7 @@ void Player::stopPlaying() { _injector.clear(); _audioThread->exit(); _audioThread->deleteLater(); + qDebug() << "Recorder::stopPlaying()"; } void Player::loadFromFile(QString file) { @@ -259,7 +262,7 @@ void Player::loadRecording(RecordingPointer recording) { void Player::play() { computeCurrentFrame(); - if (_currentFrame < 0 || _currentFrame >= _recording->getFrameNumber()) { + if (_currentFrame < 0 || _currentFrame >= _recording->getFrameNumber() - 1) { // If it's the end of the recording, stop playing stopPlaying(); return; @@ -283,6 +286,10 @@ void Player::play() { HeadData* head = const_cast(_avatar->getHeadData()); head->setBlendshapeCoefficients(_recording->getFrame(_currentFrame).getBlendshapeCoefficients()); } + + _options.setPosition(_avatar->getPosition()); + _options.setOrientation(_avatar->getOrientation()); + _injector->setOptions(_options); } bool Player::computeCurrentFrame() { @@ -294,7 +301,7 @@ bool Player::computeCurrentFrame() { _currentFrame = 0; } - while (_currentFrame < _recording->getFrameNumber() && + while (_currentFrame < _recording->getFrameNumber() - 1 && _recording->getFrameTimestamp(_currentFrame) < _timer.elapsed()) { ++_currentFrame; } From 1a80bd98f0c14548213b9df163c314473bb3ff5d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 19 Aug 2014 10:25:18 -0700 Subject: [PATCH 407/407] Ignore empty "embedded" textures Blender 2.71 exporter "embeds" external textures as empty binary blobs --- examples/editModels.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/editModels.js b/examples/editModels.js index b15ea58fc6..411431791c 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -611,7 +611,10 @@ var modelUploader = (function () { index += nameLength; if (name === "content" && previousNodeFilename !== "") { - geometry.embedded.push(previousNodeFilename); + // Blender 2.71 exporter "embeds" external textures as empty binary blobs so ignore these + if (propertyListLength > 5) { + geometry.embedded.push(previousNodeFilename); + } } if (name === "relativefilename") {