diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 2fb7342b0c..681cc58cb3 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -62,6 +62,7 @@ #include "AudioMixer.h" const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f; +const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.18; const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer"; @@ -82,6 +83,7 @@ AudioMixer::AudioMixer(const QByteArray& packet) : _trailingSleepRatio(1.0f), _minAudibilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2.0f), _performanceThrottlingRatio(0.0f), + _attenuationPerDoublingInDistance(DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE), _numStatFrames(0), _sumListeners(0), _sumMixes(0), @@ -104,7 +106,6 @@ AudioMixer::~AudioMixer() { } const float ATTENUATION_BEGINS_AT_DISTANCE = 1.0f; -const float ATTENUATION_AMOUNT_PER_DOUBLING_IN_DISTANCE = 0.18f; const float RADIUS_OF_HEAD = 0.076f; int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* listenerNodeData, @@ -210,7 +211,7 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l if (shouldDistanceAttenuate && (distanceBetween >= ATTENUATION_BEGINS_AT_DISTANCE)) { // calculate the distance coefficient using the distance to this node float distanceCoefficient = 1 - (logf(distanceBetween / ATTENUATION_BEGINS_AT_DISTANCE) / logf(2.0f) - * ATTENUATION_AMOUNT_PER_DOUBLING_IN_DISTANCE); + * _attenuationPerDoublingInDistance); if (distanceCoefficient < 0) { distanceCoefficient = 0; @@ -740,6 +741,16 @@ void AudioMixer::run() { qDebug() << "Buffers inside this zone will not be attenuated inside a box with center at" << QString("%1, %2, %3").arg(destinationCenter.x).arg(destinationCenter.y).arg(destinationCenter.z); } + + const QString ATTENATION_PER_DOULING_IN_DISTANCE = "attenuation_per_doubling_in_distance"; + if (audioGroupObject[ATTENATION_PER_DOULING_IN_DISTANCE].isString()) { + bool ok = false; + float attenuation = audioGroupObject[ATTENATION_PER_DOULING_IN_DISTANCE].toString().toFloat(&ok); + if (ok) { + _attenuationPerDoublingInDistance = attenuation; + qDebug() << "Attenuation per doubling in distance changed to" << _attenuationPerDoublingInDistance; + } + } } int nextFrame = 0; diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 6c25fe21d9..4d08d480f8 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -69,6 +69,7 @@ private: float _trailingSleepRatio; float _minAudibilityThreshold; float _performanceThrottlingRatio; + float _attenuationPerDoublingInDistance; int _numStatFrames; int _sumListeners; int _sumMixes; diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index fbcbcd41a8..e1d478753c 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -72,6 +72,14 @@ "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)", "placeholder": "no zone" }, + { + "name": "attenuation_per_doubling_in_distance", + "label": "Attenuattion per doubling in distance", + "help": "Factor between 0.0 and 1.0 (0.0: No attenuation, 1.0: extreme attenuation)", + "placeholder": "0.18", + "default": "0.18", + "advanced": true + }, { "name": "dynamic_jitter_buffer", "type": "checkbox", diff --git a/domain-server/resources/web/assignment/index.shtml b/domain-server/resources/web/assignment/index.shtml index 27c84be985..b8f4fbb637 100644 --- a/domain-server/resources/web/assignment/index.shtml +++ b/domain-server/resources/web/assignment/index.shtml @@ -6,7 +6,7 @@
- +
diff --git a/domain-server/resources/web/footer.html b/domain-server/resources/web/footer.html index 199a835cf1..4ab3ed0b31 100644 --- a/domain-server/resources/web/footer.html +++ b/domain-server/resources/web/footer.html @@ -1,4 +1,4 @@
- + \ No newline at end of file diff --git a/domain-server/resources/web/js/jquery-2.1.1.min.js b/domain-server/resources/web/js/jquery.min.js similarity index 100% rename from domain-server/resources/web/js/jquery-2.1.1.min.js rename to domain-server/resources/web/js/jquery.min.js diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js index 4c5c118fef..48b3b15e8f 100644 --- a/domain-server/resources/web/js/settings.js +++ b/domain-server/resources/web/js/settings.js @@ -158,6 +158,8 @@ $('body').on('click', '.save-button', function(e){ // grab a JSON representation of the form via form2js var formJSON = form2js('settings-form', ".", false, cleanupFormValues, true); + console.log(formJSON); + // re-enable all inputs $("input").each(function(){ $(this).prop('disabled', false); @@ -237,7 +239,7 @@ function showRestartModal() { function cleanupFormValues(node) { if (node.type && node.type === 'checkbox') { - return { name: node.id, value: node.checked ? true : false }; + return { name: node.name, value: node.checked ? true : false }; } else { return false; } diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 130bb101dc..d6069cac64 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -81,6 +81,11 @@ DomainServer::DomainServer(int argc, char* argv[]) : void DomainServer::restart() { qDebug() << "domain-server is restarting."; + + // make sure all static instances are reset + LimitedNodeList::getInstance()->reset(); + AccountManager::getInstance(true); + exit(DomainServer::EXIT_CODE_REBOOT); } diff --git a/examples/editModels.js b/examples/editModels.js index c47c497a78..5c426c9fb3 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -2745,7 +2745,7 @@ function setupModelMenus() { } Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." }); - + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List", afterItem: "Models" }); 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" }); @@ -2796,6 +2796,128 @@ var dimensionY; var dimensionZ; var rescalePercentage; +function showPropertiesForm() { + propertiesForEditedEntity = Entities.getEntityProperties(editModelID); + var properties = propertiesForEditedEntity; + + var array = new Array(); + var index = 0; + var decimals = 3; + if (properties.type == "Model") { + array.push({ label: "Model URL:", value: properties.modelURL }); + index++; + array.push({ label: "Animation URL:", value: properties.animationURL }); + index++; + array.push({ label: "Animation is playing:", value: properties.animationIsPlaying }); + index++; + array.push({ label: "Animation FPS:", value: properties.animationFPS }); + index++; + array.push({ label: "Animation Frame:", value: properties.animationFrameIndex }); + index++; + } + array.push({ label: "Position:", type: "header" }); + index++; + array.push({ label: "X:", value: properties.position.x.toFixed(decimals) }); + index++; + array.push({ label: "Y:", value: properties.position.y.toFixed(decimals) }); + index++; + array.push({ label: "Z:", value: properties.position.z.toFixed(decimals) }); + index++; + + array.push({ label: "Registration X:", value: properties.registrationPoint.x.toFixed(decimals) }); + index++; + array.push({ label: "Registration Y:", value: properties.registrationPoint.y.toFixed(decimals) }); + index++; + array.push({ label: "Registration Z:", value: properties.registrationPoint.z.toFixed(decimals) }); + index++; + + array.push({ label: "Rotation:", type: "header" }); + index++; + var angles = Quat.safeEulerAngles(properties.rotation); + array.push({ label: "Pitch:", value: angles.x.toFixed(decimals) }); + index++; + array.push({ label: "Yaw:", value: angles.y.toFixed(decimals) }); + index++; + array.push({ label: "Roll:", value: angles.z.toFixed(decimals) }); + index++; + + array.push({ label: "Dimensions:", type: "header" }); + index++; + array.push({ label: "Width:", value: properties.dimensions.x.toFixed(decimals) }); + dimensionX = index; + index++; + array.push({ label: "Height:", value: properties.dimensions.y.toFixed(decimals) }); + dimensionY = index; + index++; + array.push({ label: "Depth:", value: properties.dimensions.z.toFixed(decimals) }); + dimensionZ = index; + index++; + array.push({ label: "", type: "inlineButton", buttonLabel: "Reset to Natural Dimensions", name: "resetDimensions" }); + index++; + array.push({ label: "Rescale Percentage:", value: 100 }); + rescalePercentage = index; + index++; + array.push({ label: "", type: "inlineButton", buttonLabel: "Rescale", name: "rescaleDimensions" }); + index++; + + array.push({ label: "Velocity:", type: "header" }); + index++; + array.push({ label: "Linear X:", value: properties.velocity.x.toFixed(decimals) }); + index++; + array.push({ label: "Linear Y:", value: properties.velocity.y.toFixed(decimals) }); + index++; + array.push({ label: "Linear Z:", value: properties.velocity.z.toFixed(decimals) }); + index++; + array.push({ label: "Linear Damping:", value: properties.damping.toFixed(decimals) }); + index++; + array.push({ label: "Angular Pitch:", value: properties.angularVelocity.x.toFixed(decimals) }); + index++; + array.push({ label: "Angular Yaw:", value: properties.angularVelocity.y.toFixed(decimals) }); + index++; + array.push({ label: "Angular Roll:", value: properties.angularVelocity.z.toFixed(decimals) }); + index++; + array.push({ label: "Angular Damping:", value: properties.angularDamping.toFixed(decimals) }); + index++; + + array.push({ label: "Gravity X:", value: properties.gravity.x.toFixed(decimals) }); + index++; + array.push({ label: "Gravity Y:", value: properties.gravity.y.toFixed(decimals) }); + index++; + array.push({ label: "Gravity Z:", value: properties.gravity.z.toFixed(decimals) }); + index++; + + array.push({ label: "Collisions:", type: "header" }); + index++; + array.push({ label: "Mass:", value: properties.mass.toFixed(decimals) }); + index++; + array.push({ label: "Ignore for Collisions:", value: properties.ignoreForCollisions }); + index++; + array.push({ label: "Collisions Will Move:", value: properties.collisionsWillMove }); + index++; + + array.push({ label: "Lifetime:", value: properties.lifetime.toFixed(decimals) }); + index++; + + array.push({ label: "Visible:", value: properties.visible }); + index++; + + if (properties.type == "Box" || properties.type == "Sphere") { + array.push({ label: "Color:", type: "header" }); + index++; + array.push({ label: "Red:", value: properties.color.red }); + index++; + array.push({ label: "Green:", value: properties.color.green }); + index++; + array.push({ label: "Blue:", value: properties.color.blue }); + index++; + } + array.push({ button: "Cancel" }); + index++; + + editEntityFormArray = array; + Window.nonBlockingForm("Edit Properties", array); +} + function handeMenuEvent(menuItem) { print("menuItemEvent() in JS... menuItem=" + menuItem); if (menuItem == "Delete") { @@ -2823,6 +2945,33 @@ function handeMenuEvent(menuItem) { } else { print(" Delete Entity.... not holding..."); } + } else if (menuItem == "Model List") { + var models = new Array(); + models = Entities.findEntities(MyAvatar.position, Number.MAX_VALUE); + for (var i = 0; i < models.length; i++) { + models[i].properties = Entities.getEntityProperties(models[i]); + models[i].toString = function() { + var modelname = decodeURIComponent( + this.properties.modelURL.indexOf("/") != -1 ? + this.properties.modelURL.substring(this.properties.modelURL.lastIndexOf("/") + 1) : + this.properties.modelURL); + return "[" + this.properties.type + "] " + modelname; + }; + } + var form = [{label: "Model: ", options: models}]; + form.push({label: "Action: ", options: ["Properties", "Delete", "Teleport"]}); + form.push({ button: "Cancel" }); + if (Window.form("Model List", form)) { + var selectedModel = form[0].value; + if (form[1].value == "Properties") { + editModelID = selectedModel; + showPropertiesForm(); + } else if (form[1].value == "Delete") { + Entities.deleteEntity(selectedModel); + } else if (form[1].value == "Teleport") { + MyAvatar.position = selectedModel.properties.position; + } + } } else if (menuItem == "Edit Properties...") { editModelID = -1; if (leftController.grabbing) { @@ -2839,126 +2988,7 @@ function handeMenuEvent(menuItem) { } if (editModelID != -1) { print(" Edit Properties.... about to edit properties..."); - - propertiesForEditedEntity = Entities.getEntityProperties(editModelID); - var properties = propertiesForEditedEntity; - - var array = new Array(); - var index = 0; - var decimals = 3; - if (properties.type == "Model") { - array.push({ label: "Model URL:", value: properties.modelURL }); - index++; - array.push({ label: "Animation URL:", value: properties.animationURL }); - index++; - array.push({ label: "Animation is playing:", value: properties.animationIsPlaying }); - index++; - array.push({ label: "Animation FPS:", value: properties.animationFPS }); - index++; - array.push({ label: "Animation Frame:", value: properties.animationFrameIndex }); - index++; - } - array.push({ label: "Position:", type: "header" }); - index++; - array.push({ label: "X:", value: properties.position.x.toFixed(decimals) }); - index++; - array.push({ label: "Y:", value: properties.position.y.toFixed(decimals) }); - index++; - array.push({ label: "Z:", value: properties.position.z.toFixed(decimals) }); - index++; - - array.push({ label: "Registration X:", value: properties.registrationPoint.x.toFixed(decimals) }); - index++; - array.push({ label: "Registration Y:", value: properties.registrationPoint.y.toFixed(decimals) }); - index++; - array.push({ label: "Registration Z:", value: properties.registrationPoint.z.toFixed(decimals) }); - index++; - - array.push({ label: "Rotation:", type: "header" }); - index++; - var angles = Quat.safeEulerAngles(properties.rotation); - array.push({ label: "Pitch:", value: angles.x.toFixed(decimals) }); - index++; - array.push({ label: "Yaw:", value: angles.y.toFixed(decimals) }); - index++; - array.push({ label: "Roll:", value: angles.z.toFixed(decimals) }); - index++; - - array.push({ label: "Dimensions:", type: "header" }); - index++; - array.push({ label: "Width:", value: properties.dimensions.x.toFixed(decimals) }); - dimensionX = index; - index++; - array.push({ label: "Height:", value: properties.dimensions.y.toFixed(decimals) }); - dimensionY = index; - index++; - array.push({ label: "Depth:", value: properties.dimensions.z.toFixed(decimals) }); - dimensionZ = index; - index++; - array.push({ label: "", type: "inlineButton", buttonLabel: "Reset to Natural Dimensions", name: "resetDimensions" }); - index++; - array.push({ label: "Rescale Percentage:", value: 100 }); - rescalePercentage = index; - index++; - array.push({ label: "", type: "inlineButton", buttonLabel: "Rescale", name: "rescaleDimensions" }); - index++; - - array.push({ label: "Velocity:", type: "header" }); - index++; - array.push({ label: "Linear X:", value: properties.velocity.x.toFixed(decimals) }); - index++; - array.push({ label: "Linear Y:", value: properties.velocity.y.toFixed(decimals) }); - index++; - array.push({ label: "Linear Z:", value: properties.velocity.z.toFixed(decimals) }); - index++; - array.push({ label: "Linear Damping:", value: properties.damping.toFixed(decimals) }); - index++; - array.push({ label: "Angular Pitch:", value: properties.angularVelocity.x.toFixed(decimals) }); - index++; - array.push({ label: "Angular Yaw:", value: properties.angularVelocity.y.toFixed(decimals) }); - index++; - array.push({ label: "Angular Roll:", value: properties.angularVelocity.z.toFixed(decimals) }); - index++; - array.push({ label: "Angular Damping:", value: properties.angularDamping.toFixed(decimals) }); - index++; - - array.push({ label: "Gravity X:", value: properties.gravity.x.toFixed(decimals) }); - index++; - array.push({ label: "Gravity Y:", value: properties.gravity.y.toFixed(decimals) }); - index++; - array.push({ label: "Gravity Z:", value: properties.gravity.z.toFixed(decimals) }); - index++; - - array.push({ label: "Collisions:", type: "header" }); - index++; - array.push({ label: "Mass:", value: properties.mass.toFixed(decimals) }); - index++; - array.push({ label: "Ignore for Collisions:", value: properties.ignoreForCollisions }); - index++; - array.push({ label: "Collisions Will Move:", value: properties.collisionsWillMove }); - index++; - - array.push({ label: "Lifetime:", value: properties.lifetime.toFixed(decimals) }); - index++; - - array.push({ label: "Visible:", value: properties.visible }); - index++; - - if (properties.type == "Box" || properties.type == "Sphere") { - array.push({ label: "Color:", type: "header" }); - index++; - array.push({ label: "Red:", value: properties.color.red }); - index++; - array.push({ label: "Green:", value: properties.color.green }); - index++; - array.push({ label: "Blue:", value: properties.color.blue }); - index++; - } - array.push({ button: "Cancel" }); - index++; - - editEntityFormArray = array; - Window.nonBlockingForm("Edit Properties", array); + showPropertiesForm(editModelID); } } else if (menuItem == "Paste Models") { modelImporter.paste(); diff --git a/examples/leapHands.js b/examples/leapHands.js index 95d3969a08..cc50a328f8 100644 --- a/examples/leapHands.js +++ b/examples/leapHands.js @@ -13,7 +13,10 @@ var leapHands = (function () { - var hands, + var isOnHMD, + LEAP_OFFSET = 0.019, // Thickness of Leap Motion plus HMD clip + HMD_OFFSET = 0.100, // Eyeballs to front surface of Oculus DK2 TODO: Confirm and make depend on device and eye relief + hands, wrists, NUM_HANDS = 2, // 0 = left; 1 = right fingers, @@ -188,8 +191,6 @@ var leapHands = (function () { function setUp() { - calibrationStatus = UNCALIBRATED; - // TODO: Leap Motion controller joint naming doesn't match up with skeleton joint naming; numbers are out by 1. hands = [ @@ -265,6 +266,20 @@ var leapHands = (function () { { jointName: "RightHandPinky3", controller: Controller.createInputController("Spatial", "joint_R_pinky4") } ] ]; + + isOnHMD = Menu.isOptionChecked("Leap Motion on HMD"); + if (isOnHMD) { + print("Leap Motion is on HMD"); + + // Offset of Leap Motion origin from physical eye position + hands[0].zeroPosition = { x: 0.0, y: 0.0, z: HMD_OFFSET + LEAP_OFFSET }; + hands[1].zeroPosition = { x: 0.0, y: 0.0, z: HMD_OFFSET + LEAP_OFFSET }; + + calibrationStatus = CALIBRATED; + } else { + print("Leap Motion is on desk"); + calibrationStatus = UNCALIBRATED; + } } function moveHands() { @@ -278,7 +293,9 @@ var leapHands = (function () { handYaw, handRotation, wristAbsRotation, - locRotation; + locRotation, + cameraOrientation, + inverseAvatarOrientation; for (h = 0; h < NUM_HANDS; h += 1) { side = h === 0 ? -1.0 : 1.0; @@ -291,35 +308,82 @@ var leapHands = (function () { } // Hand position ... - handOffset = hands[h].controller.getAbsTranslation(); - handOffset = { - x: -handOffset.x, - y: hands[h].zeroPosition.y + handOffset.y, - z: hands[h].zeroPosition.z - handOffset.z - }; + if (isOnHMD) { - // TODO: 2.0* scale factor should not be necessary; Leap Motion controller code needs investigating. - handRoll = 2.0 * -hands[h].controller.getAbsRotation().z; - wristAbsRotation = wrists[h].controller.getAbsRotation(); - handPitch = 2.0 * -wristAbsRotation.x; - handYaw = 2.0 * wristAbsRotation.y; + // Hand offset in camera coordinates ... + handOffset = hands[h].controller.getAbsTranslation(); + handOffset = { + x: hands[h].zeroPosition.x - handOffset.x, + y: hands[h].zeroPosition.y - handOffset.z, + z: hands[h].zeroPosition.z + handOffset.y + }; + handOffset.z = -handOffset.z; - // TODO: Leap Motion controller's right-hand roll calculation only works if physical hand is upside down. - // Approximate fix is to add a fudge factor. - if (h === 1 && isWindows) { - handRoll = handRoll + 0.6 * PI; - } + // Hand offset in world coordinates ... + cameraOrientation = Camera.getOrientation(); + handOffset = Vec3.sum(Camera.getPosition(), Vec3.multiplyQbyV(cameraOrientation, handOffset)); - // Hand position and orientation ... - if (h === 0) { - handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), - Quat.fromVec3Radians({ x: handRoll, y: handYaw, z: -handPitch })); + // Hand offset in avatar coordinates ... + inverseAvatarOrientation = Quat.inverse(MyAvatar.orientation); + handOffset = Vec3.subtract(handOffset, MyAvatar.position); + handOffset = Vec3.multiplyQbyV(inverseAvatarOrientation, handOffset); + handOffset.z = -handOffset.z; + handOffset.x = -handOffset.x; + // Hand rotation in camera coordinates ... + // TODO: 2.0* scale factors should not be necessary; Leap Motion controller code needs investigating. + handRoll = 2.0 * -hands[h].controller.getAbsRotation().z; + wristAbsRotation = wrists[h].controller.getAbsRotation(); + handPitch = 2.0 * wristAbsRotation.x - PI / 2.0; + handYaw = 2.0 * -wristAbsRotation.y; + // TODO: Roll values only work if hand is upside down; Leap Motion controller code needs investigating. + handRoll = PI + handRoll; + + if (h === 0) { + handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), + Quat.fromVec3Radians({ x: handRoll, y: handYaw, z: -handPitch })); + } else { + handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }), + Quat.fromVec3Radians({ x: -handRoll, y: handYaw, z: handPitch })); + } + + // Hand rotation in avatar coordinates ... + cameraOrientation.x = -cameraOrientation.x; + cameraOrientation.z = -cameraOrientation.z; + handRotation = Quat.multiply(cameraOrientation, handRotation); + handRotation = Quat.multiply(inverseAvatarOrientation, handRotation); } else { - handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }), - Quat.fromVec3Radians({ x: -handRoll, y: handYaw, z: handPitch })); + + handOffset = hands[h].controller.getAbsTranslation(); + handOffset = { + x: -handOffset.x, + y: hands[h].zeroPosition.y + handOffset.y, + z: hands[h].zeroPosition.z - handOffset.z + }; + + // TODO: 2.0* scale factors should not be necessary; Leap Motion controller code needs investigating. + handRoll = 2.0 * -hands[h].controller.getAbsRotation().z; + wristAbsRotation = wrists[h].controller.getAbsRotation(); + handPitch = 2.0 * -wristAbsRotation.x; + handYaw = 2.0 * wristAbsRotation.y; + + // TODO: Leap Motion controller's right-hand roll calculation only works if physical hand is upside down. + // Approximate fix is to add a fudge factor. + if (h === 1 && isWindows) { + handRoll = handRoll + 0.6 * PI; + } + + // Hand position and orientation ... + if (h === 0) { + handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), + Quat.fromVec3Radians({ x: handRoll, y: handYaw, z: -handPitch })); + } else { + handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }), + Quat.fromVec3Radians({ x: -handRoll, y: handYaw, z: handPitch })); + } } + MyAvatar.setJointModelPositionAndOrientation(hands[h].jointName, handOffset, handRotation, true); // Finger joints ... diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0e63c3dfb2..ec40056299 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -599,8 +599,11 @@ 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()->getEyePosition()); - _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation()); + if (!OculusManager::isConnected()) { + _myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition()); + _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation()); + } + // OculusManager::display() updates camera position and rotation a bit further on. } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { //Note, the camera distance is set in Camera::setMode() so we dont have to do it here. @@ -630,7 +633,9 @@ void Application::paintGL() { } // Update camera position - _myCamera.update( 1.f/_fps ); + if (!OculusManager::isConnected()) { + _myCamera.update(1.f / _fps); + } // Note: whichCamera is used to pick between the normal camera myCamera for our // main camera, vs, an alternate camera. The alternate camera we support right now @@ -640,7 +645,7 @@ void Application::paintGL() { // Why have two cameras? Well, one reason is that because in the case of the renderViewFrustum() // code, we want to keep the state of "myCamera" intact, so we can render what the view frustum of // myCamera is. But we also want to do meaningful camera transforms on OpenGL for the offset camera - Camera whichCamera = _myCamera; + Camera* whichCamera = &_myCamera; if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum)) { @@ -654,7 +659,7 @@ void Application::paintGL() { _viewFrustumOffsetCamera.setDistance(viewFrustumOffset.distance); _viewFrustumOffsetCamera.initialize(); // force immediate snap to ideal position and orientation _viewFrustumOffsetCamera.update(1.f/_fps); - whichCamera = _viewFrustumOffsetCamera; + whichCamera = &_viewFrustumOffsetCamera; } if (Menu::getInstance()->getShadowsEnabled()) { @@ -667,15 +672,16 @@ void Application::paintGL() { glClear(GL_COLOR_BUFFER_BIT); //When in mirror mode, use camera rotation. Otherwise, use body rotation - if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { - OculusManager::display(whichCamera.getRotation(), whichCamera.getPosition(), whichCamera); + if (whichCamera->getMode() == CAMERA_MODE_MIRROR) { + OculusManager::display(whichCamera->getRotation(), whichCamera->getPosition(), *whichCamera); } else { - OculusManager::display(_myAvatar->getWorldAlignedOrientation(), _myAvatar->getDefaultEyePosition(), whichCamera); + OculusManager::display(_myAvatar->getWorldAlignedOrientation(), _myAvatar->getDefaultEyePosition(), *whichCamera); } + _myCamera.update(1.f / _fps); } else if (TV3DManager::isConnected()) { - TV3DManager::display(whichCamera); + TV3DManager::display(*whichCamera); } else { _glowEffect.prepare(); @@ -683,7 +689,7 @@ void Application::paintGL() { glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); - displaySide(whichCamera); + displaySide(*whichCamera); glPopMatrix(); if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d2ae9160ad..94af1ad80a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -453,6 +453,9 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseMouseInput, 0, true); addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseLasers, 0, false); + QMenu* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion"); + addCheckableActionToQMenuAndActionHash(leapOptionsMenu, MenuOption::LeapMotionOnHMD, 0, false); + QMenu* networkMenu = developerMenu->addMenu("Network"); addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::DisableNackPackets, 0, false); addCheckableActionToQMenuAndActionHash(networkMenu, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index c47c04e177..2402090213 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -403,6 +403,7 @@ namespace MenuOption { const QString IncreaseAvatarSize = "Increase Avatar Size"; const QString IncreaseVoxelSize = "Increase Voxel Size"; const QString KeyboardMotorControl = "Enable Keyboard Motor Control"; + const QString LeapMotionOnHMD = "Leap Motion on HMD"; const QString LoadScript = "Open and Run Script File..."; const QString LoadScriptURL = "Open and Run Script from URL..."; const QString LodTools = "LOD Tools"; diff --git a/interface/src/devices/Leapmotion.cpp b/interface/src/devices/Leapmotion.cpp index 7060c5c5e9..a3794123ce 100644 --- a/interface/src/devices/Leapmotion.cpp +++ b/interface/src/devices/Leapmotion.cpp @@ -8,8 +8,9 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "SharedUtil.h" #include "Leapmotion.h" +#include "Menu.h" +#include "SharedUtil.h" const int PALMROOT_NUM_JOINTS = 3; const int FINGER_NUM_JOINTS = 4; @@ -101,6 +102,12 @@ Leapmotion::Leapmotion() : } } } + +#ifdef HAVE_LEAPMOTION + if (Menu::getInstance()->isOptionChecked(MenuOption::LeapMotionOnHMD)) { + _controller.setPolicyFlags(Leap::Controller::POLICY_OPTIMIZE_HMD); + } +#endif } Leapmotion::~Leapmotion() { diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 27590d9a72..65518b839c 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -412,6 +412,10 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p glBindTexture(GL_TEXTURE_2D, 0); + // Update camera for use by rest of Interface. + whichCamera.setTargetPosition((_leftEyePosition + _rightEyePosition) / 2.f); + whichCamera.setTargetRotation(_camera->getTargetRotation()); + #endif } diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 28b125b6da..c3d694d06c 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -45,7 +45,7 @@ SixenseManager& SixenseManager::getInstance() { } SixenseManager::SixenseManager() : -#ifdef __APPLE__ +#if defined(HAVE_SIXENSE) && defined(__APPLE__) _sixenseLibrary(NULL), #endif _isInitialized(false), diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 913655195d..ed6f0cf600 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -265,7 +265,11 @@ QScriptValue WindowScriptingInterface::doPeekNonBlockingFormResult(QScriptValue _form.setProperty(i, item); } else if (item.property("options").isArray()) { c += 1; - item.setProperty("value", _combos.at(c)->currentText()); + item.setProperty("value", + _combos.at(c)->currentIndex() < item.property("options").property("length").toInt32() ? + item.property("options").property(_combos.at(c)->currentIndex()) : + array.engine()->undefinedValue() + ); _form.setProperty(i, item); } else { e += 1; @@ -318,7 +322,11 @@ QScriptValue WindowScriptingInterface::doGetNonBlockingFormResult(QScriptValue a _form.setProperty(i, item); } else if (item.property("options").isArray()) { c += 1; - item.setProperty("value", _combos.at(c)->currentText()); + item.setProperty("value", + _combos.at(c)->currentIndex() < item.property("options").property("length").toInt32() ? + item.property("options").property(_combos.at(c)->currentIndex()) : + array.engine()->undefinedValue() + ); _form.setProperty(i, item); } else { e += 1; @@ -349,6 +357,7 @@ QScriptValue WindowScriptingInterface::doGetNonBlockingFormResult(QScriptValue a _form = QScriptValue(); _edits.clear(); _directories.clear(); + _combos.clear(); array = _form; return (_formResult == QDialog::Accepted); @@ -391,8 +400,12 @@ QScriptValue WindowScriptingInterface::showForm(const QString& title, QScriptVal form.setProperty(i, item); } else if (item.property("options").isArray()) { c += 1; - item.setProperty("value", _combos.at(c)->currentText()); - _form.setProperty(i, item); + item.setProperty("value", + _combos.at(c)->currentIndex() < item.property("options").property("length").toInt32() ? + item.property("options").property(_combos.at(c)->currentIndex()) : + form.engine()->undefinedValue() + ); + form.setProperty(i, item); } else { e += 1; bool ok = true; @@ -418,6 +431,7 @@ QScriptValue WindowScriptingInterface::showForm(const QString& title, QScriptVal } delete editDialog; + _combos.clear(); _edits.clear(); _directories.clear(); return (result == QDialog::Accepted); @@ -498,9 +512,9 @@ QDialog* WindowScriptingInterface::createForm(const QString& title, QScriptValue } else if (item.property("options").isArray()) { QComboBox* combo = new QComboBox(); combo->setMinimumWidth(200); - QStringList options = item.property("options").toVariant().toStringList(); - for (QStringList::const_iterator it = options.begin(); it != options.end(); it += 1) { - combo->addItem(*it); + qint32 options_count = item.property("options").property("length").toInt32(); + for (qint32 i = 0; i < options_count; i++) { + combo->addItem(item.property("options").property(i).toString()); } _combos.push_back(combo); formLayout->addRow(new QLabel(item.property("label").toString()), combo); diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index d5e1c59d7a..31c135fd58 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -96,6 +96,7 @@ void AudioInjector::injectAudio() { packetStream << radius; // pack 255 for attenuation byte + int volumeOptionOffset = injectAudioPacket.size(); quint8 volume = MAX_INJECTOR_VOLUME * _options.getVolume(); packetStream << volume; @@ -118,6 +119,8 @@ void AudioInjector::injectAudio() { memcpy(injectAudioPacket.data() + orientationOptionOffset, &_options.getOrientation(), sizeof(_options.getOrientation())); + volume = MAX_INJECTOR_VOLUME * _options.getVolume(); + memcpy(injectAudioPacket.data() + volumeOptionOffset, &volume, sizeof(volume)); // resize the QByteArray to the right size injectAudioPacket.resize(numPreAudioDataBytes + bytesToCopy); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 126da654ae..ef7083e3bf 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -652,13 +652,25 @@ void AvatarData::startPlaying() { _player->startPlaying(); } -void AvatarData::setPlayerFrame(int frame) { +void AvatarData::setPlayerVolume(float volume) { + if (_player) { + _player->setVolume(volume); + } +} + +void AvatarData::setPlayerAudioOffset(int audioOffset) { + if (_player) { + _player->setAudioOffset(audioOffset); + } +} + +void AvatarData::setPlayerFrame(unsigned int frame) { if (_player) { _player->setCurrentFrame(frame); } } -void AvatarData::setPlayerTime(qint64 time) { +void AvatarData::setPlayerTime(unsigned int time) { if (_player) { _player->setCurrentTime(time); } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 9b28fdc258..1fd4052974 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -100,8 +100,6 @@ enum KeyState { DELETE_KEY_DOWN }; -const glm::vec3 vec3Zero(0.0f); - class QDataStream; class AttachmentData; @@ -304,8 +302,10 @@ public slots: void loadRecording(QString filename); void startPlaying(); - void setPlayerFrame(int frame); - void setPlayerTime(qint64 time); + void setPlayerVolume(float volume); + void setPlayerAudioOffset(int audioOffset); + void setPlayerFrame(unsigned int frame); + void setPlayerTime(unsigned int time); void setPlayFromCurrentLocation(bool playFromCurrentLocation); void setPlayerLoop(bool loop); void setPlayerUseDisplayName(bool useDisplayName); diff --git a/libraries/avatars/src/Player.cpp b/libraries/avatars/src/Player.cpp index 2540d7d004..35a822f11b 100644 --- a/libraries/avatars/src/Player.cpp +++ b/libraries/avatars/src/Player.cpp @@ -17,13 +17,16 @@ #include "AvatarData.h" #include "Player.h" +static const int INVALID_FRAME = -1; + Player::Player(AvatarData* avatar) : - _recording(new Recording()), - _currentFrame(-1), - _frameInterpolationFactor(0.0f), - _pausedFrame(-1), - _timerOffset(0), _avatar(avatar), + _recording(new Recording()), + _currentFrame(INVALID_FRAME), + _frameInterpolationFactor(0.0f), + _pausedFrame(INVALID_FRAME), + _timerOffset(0), + _audioOffset(0), _audioThread(NULL), _playFromCurrentPosition(true), _loop(false), @@ -33,8 +36,6 @@ Player::Player(AvatarData* avatar) : _useSkeletonURL(true) { _timer.invalidate(); - _options.setLoop(false); - _options.setVolume(1.0f); } bool Player::isPlaying() const { @@ -42,7 +43,7 @@ bool Player::isPlaying() const { } bool Player::isPaused() const { - return (_pausedFrame != -1); + return (_pausedFrame != INVALID_FRAME); } qint64 Player::elapsed() const { @@ -122,7 +123,7 @@ void Player::startPlaying() { _timer.start(); setCurrentFrame(_pausedFrame); - _pausedFrame = -1; + _pausedFrame = INVALID_FRAME; } } @@ -130,7 +131,7 @@ void Player::stopPlaying() { if (!isPlaying()) { return; } - _pausedFrame = -1; + _pausedFrame = INVALID_FRAME; _timer.invalidate(); cleanupAudioThread(); _avatar->clearJointsData(); @@ -201,12 +202,12 @@ void Player::loadFromFile(const QString& file) { } readRecordingFromFile(_recording, file); - _pausedFrame = -1; + _pausedFrame = INVALID_FRAME; } void Player::loadRecording(RecordingPointer recording) { _recording = recording; - _pausedFrame = -1; + _pausedFrame = INVALID_FRAME; } void Player::play() { @@ -253,6 +254,9 @@ void Player::play() { HeadData* head = const_cast(_avatar->getHeadData()); if (head) { + // Make sure fake faceshift connection doesn't get turned off + _avatar->setForceFaceshiftConnected(true); + QVector blendCoef(currentFrame.getBlendshapeCoefficients().size()); for (int i = 0; i < currentFrame.getBlendshapeCoefficients().size(); ++i) { blendCoef[i] = glm::mix(currentFrame.getBlendshapeCoefficients()[i], @@ -293,8 +297,8 @@ void Player::play() { _injector->setOptions(_options); } -void Player::setCurrentFrame(int currentFrame) { - if (_recording && (currentFrame < 0 || currentFrame >= _recording->getFrameNumber())) { +void Player::setCurrentFrame(unsigned int currentFrame) { + if (_recording && currentFrame >= _recording->getFrameNumber()) { stopPlaying(); return; } @@ -306,12 +310,12 @@ void Player::setCurrentFrame(int currentFrame) { _timer.start(); setAudionInjectorPosition(); } else { - _pausedFrame = currentFrame; + _pausedFrame = _currentFrame; } } -void Player::setCurrentTime(qint64 currentTime) { - if (currentTime < 0 || currentTime >= _recording->getLength()) { +void Player::setCurrentTime(unsigned int currentTime) { + if (currentTime >= _recording->getLength()) { stopPlaying(); return; } @@ -355,6 +359,18 @@ void Player::setCurrentTime(qint64 currentTime) { } } +void Player::setVolume(float volume) { + _options.setVolume(volume); + if (_injector) { + _injector->setOptions(_options); + } + qDebug() << "New volume: " << volume; +} + +void Player::setAudioOffset(int audioOffset) { + _audioOffset = audioOffset; +} + void Player::setAudionInjectorPosition() { int MSEC_PER_SEC = 1000; int SAMPLE_SIZE = 2; // 16 bits @@ -370,14 +386,19 @@ void Player::setPlayFromCurrentLocation(bool playFromCurrentLocation) { bool Player::computeCurrentFrame() { if (!isPlaying()) { - _currentFrame = -1; + _currentFrame = INVALID_FRAME; return false; } if (_currentFrame < 0) { _currentFrame = 0; } - qint64 elapsed = Player::elapsed(); + quint64 elapsed = glm::clamp(Player::elapsed() - _audioOffset, (qint64)0, (qint64)_recording->getLength()); + while(_currentFrame >= 0 && + _recording->getFrameTimestamp(_currentFrame) > elapsed) { + --_currentFrame; + } + while (_currentFrame < _recording->getFrameNumber() && _recording->getFrameTimestamp(_currentFrame) < elapsed) { ++_currentFrame; diff --git a/libraries/avatars/src/Player.h b/libraries/avatars/src/Player.h index 5db56d725a..043fcc4a25 100644 --- a/libraries/avatars/src/Player.h +++ b/libraries/avatars/src/Player.h @@ -44,8 +44,11 @@ public slots: void loadRecording(RecordingPointer recording); void play(); - void setCurrentFrame(int currentFrame); - void setCurrentTime(qint64 currentTime); + void setCurrentFrame(unsigned int currentFrame); + void setCurrentTime(unsigned int currentTime); + + void setVolume(float volume); + void setAudioOffset(int audioOffset); void setPlayFromCurrentLocation(bool playFromCurrentPosition); void setLoop(bool loop) { _loop = loop; } @@ -61,19 +64,20 @@ private: void setAudionInjectorPosition(); bool computeCurrentFrame(); - QElapsedTimer _timer; + AvatarData* _avatar; RecordingPointer _recording; int _currentFrame; float _frameInterpolationFactor; int _pausedFrame; - qint64 _timerOffset; + + QElapsedTimer _timer; + int _timerOffset; + int _audioOffset; + QThread* _audioThread; QSharedPointer _injector; AudioInjectorOptions _options; - AvatarData* _avatar; - QThread* _audioThread; - RecordingContext _currentContext; bool _playFromCurrentPosition; bool _loop; diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index d8de09e2cb..595e4cbb60 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include #include #include @@ -25,9 +27,14 @@ const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false; -AccountManager& AccountManager::getInstance() { - static AccountManager sharedInstance; - return sharedInstance; +AccountManager& AccountManager::getInstance(bool forceReset) { + static std::auto_ptr sharedInstance(new AccountManager()); + + if (forceReset) { + sharedInstance.reset(new AccountManager()); + } + + return *sharedInstance; } Q_DECLARE_METATYPE(OAuthAccessToken) diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index 46c71dd476..3628b5a865 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -42,7 +42,7 @@ const QByteArray ACCESS_TOKEN_AUTHORIZATION_HEADER = "Authorization"; class AccountManager : public QObject { Q_OBJECT public: - static AccountManager& getInstance(); + static AccountManager& getInstance(bool forceReset = false); void authenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation, diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index d42cab6210..2c8e968375 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -35,29 +35,32 @@ const char SOLO_NODE_TYPES[2] = { const QUrl DEFAULT_NODE_AUTH_URL = QUrl("https://data.highfidelity.io"); -LimitedNodeList* LimitedNodeList::_sharedInstance = NULL; +std::auto_ptr LimitedNodeList::_sharedInstance; LimitedNodeList* LimitedNodeList::createInstance(unsigned short socketListenPort, unsigned short dtlsPort) { - if (!_sharedInstance) { - NodeType::init(); + NodeType::init(); + + if (_sharedInstance.get()) { + qDebug() << "LimitedNodeList called with existing instance." << + "Releasing auto_ptr, deleting existing instance and creating a new one."; - _sharedInstance = new LimitedNodeList(socketListenPort, dtlsPort); - - // register the SharedNodePointer meta-type for signals/slots - qRegisterMetaType(); - } else { - qDebug("LimitedNodeList createInstance called with existing instance."); + delete _sharedInstance.release(); } + + _sharedInstance = std::auto_ptr(new LimitedNodeList(socketListenPort, dtlsPort)); + + // register the SharedNodePointer meta-type for signals/slots + qRegisterMetaType(); - return _sharedInstance; + return _sharedInstance.get(); } LimitedNodeList* LimitedNodeList::getInstance() { - if (!_sharedInstance) { + if (!_sharedInstance.get()) { qDebug("LimitedNodeList getInstance called before call to createInstance. Returning NULL pointer."); } - return _sharedInstance; + return _sharedInstance.get(); } diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 337d66616e..b34845719c 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -14,6 +14,7 @@ #include #include +#include #ifndef _WIN32 #include // not on windows, not needed for mac or windows @@ -118,7 +119,7 @@ signals: void nodeKilled(SharedNodePointer); void publicSockAddrChanged(const HifiSockAddr& publicSockAddr); protected: - static LimitedNodeList* _sharedInstance; + static std::auto_ptr _sharedInstance; LimitedNodeList(unsigned short socketListenPort, unsigned short dtlsListenPort); LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 7ae9f9ba00..3a1ed79f77 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -24,30 +24,31 @@ #include "SharedUtil.h" #include "UUID.h" -NodeList* NodeList::_sharedInstance = NULL; - NodeList* NodeList::createInstance(char ownerType, unsigned short socketListenPort, unsigned short dtlsPort) { - if (!_sharedInstance) { - NodeType::init(); + + NodeType::init(); + + if (_sharedInstance.get()) { + qDebug() << "NodeList called with existing instance." << + "Releasing auto_ptr, deleting existing instance and creating a new one."; - _sharedInstance = new NodeList(ownerType, socketListenPort, dtlsPort); - LimitedNodeList::_sharedInstance = _sharedInstance; - - // register the SharedNodePointer meta-type for signals/slots - qRegisterMetaType(); - } else { - qDebug("NodeList createInstance called with existing instance."); + delete _sharedInstance.release(); } - - return _sharedInstance; + + _sharedInstance = std::auto_ptr(new NodeList(ownerType, socketListenPort, dtlsPort)); + + // register the SharedNodePointer meta-type for signals/slots + qRegisterMetaType(); + + return static_cast(_sharedInstance.get()); } NodeList* NodeList::getInstance() { - if (!_sharedInstance) { + if (!_sharedInstance.get()) { qDebug("NodeList getInstance called before call to createInstance. Returning NULL pointer."); } - return _sharedInstance; + return static_cast(_sharedInstance.get()); } NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned short dtlsListenPort) : diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index d17e56fd48..8293d0a05a 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -84,8 +84,6 @@ public slots: signals: void limitOfSilentDomainCheckInsReached(); private: - static NodeList* _sharedInstance; - NodeList(char ownerType, unsigned short socketListenPort, unsigned short dtlsListenPort); NodeList(NodeList const&); // Don't implement, needed to avoid copies of singleton void operator=(NodeList const&); // Don't implement, needed to avoid copies of singleton