From 24c779e551dc500d3de7806bba311fc108fee604 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 18 Mar 2014 22:05:51 -0700 Subject: [PATCH 01/84] Fix bug in extrusion deleting first voxel made --- examples/editVoxels.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 31d483d798..62990e1d70 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -1271,7 +1271,6 @@ function mouseMoveEvent(event) { var dy = event.y - mouseY; if (Math.sqrt(dx*dx + dy*dy) > PIXELS_PER_EXTRUDE_VOXEL) { lastVoxelPosition = Vec3.sum(lastVoxelPosition, extrudeDirection); - Voxels.eraseVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s); Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, extrudeScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); mouseX = event.x; From 83026fa2ca830c802a99103010e3a02a79410600 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 18 Mar 2014 22:22:40 -0700 Subject: [PATCH 02/84] added skeet to gun, display joint names to log in crazy legs --- examples/crazylegs.js | 4 ++ examples/gun.js | 44 +++++++++++--- examples/voxelBird.js | 133 ------------------------------------------ 3 files changed, 40 insertions(+), 141 deletions(-) delete mode 100644 examples/voxelBird.js diff --git a/examples/crazylegs.js b/examples/crazylegs.js index c098758a38..099387e000 100644 --- a/examples/crazylegs.js +++ b/examples/crazylegs.js @@ -12,6 +12,10 @@ var AMPLITUDE = 45.0; var cumulativeTime = 0.0; +print("Joint List:"); +var jointList = MyAvatar.getJointNames(); +print(jointList); + Script.update.connect(function(deltaTime) { cumulativeTime += deltaTime; MyAvatar.setJointData("joint_R_hip", Quat.fromPitchYawRollDegrees(0.0, 0.0, AMPLITUDE * Math.sin(cumulativeTime * FREQUENCY))); diff --git a/examples/gun.js b/examples/gun.js index 29b60a94ad..94f3fd4ee3 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -12,6 +12,11 @@ // // + +function getRandomFloat(min, max) { + return Math.random() * (max - min) + min; +} + var lastX = 0; var lastY = 0; var yawFromMouse = 0; @@ -19,17 +24,22 @@ var pitchFromMouse = 0; var isMouseDown = false; var BULLET_VELOCITY = 5.0; +var MIN_THROWER_DELAY = 1000; +var MAX_THROWER_DELAY = 1000; var LEFT_BUTTON_3 = 3; // Load some sound to use for loading and firing var fireSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guns/GUN-SHOT2.raw"); var loadSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guns/Gun_Reload_Weapon22.raw"); var impactSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guns/BulletImpact2.raw"); -var targetLaunchSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guns/GUN-SHOT2.raw"); +var targetHitSound = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Space%20Invaders/hit.raw"); +var targetLaunchSound = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Space%20Invaders/shoot.raw"); var audioOptions = new AudioInjectionOptions(); audioOptions.volume = 0.9; +var shotTime = new Date(); + // initialize our triggers var triggerPulled = new Array(); var numberOfTriggers = Controller.getNumberOfTriggers(); @@ -94,7 +104,9 @@ function shootTarget() { var DISTANCE_TO_LAUNCH_FROM = 3.0; var camera = Camera.getPosition(); //printVector("camera", camera); - var forwardVector = Quat.getFront(Camera.getOrientation()); + var targetDirection = Quat.angleAxis(getRandomFloat(-20.0, 20.0), { x:0, y:1, z:0 }); + targetDirection = Quat.multiply(Camera.getOrientation(), targetDirection); + var forwardVector = Quat.getFront(targetDirection); //printVector("forwardVector", forwardVector); var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_TO_LAUNCH_FROM)); //printVector("newPosition", newPosition); @@ -111,6 +123,9 @@ function shootTarget() { lifetime: 1000.0, damping: 0.99 }); + // Record start time + shotTime = new Date(); + // Play target shoot sound audioOptions.position = newPosition; Audio.playSound(targetLaunchSound, audioOptions); @@ -119,31 +134,43 @@ function shootTarget() { function particleCollisionWithVoxel(particle, voxel, penetration) { - Vec3.print('particleCollisionWithVoxel() ... penetration=', penetration); - var HOLE_SIZE = 0.125; var particleProperties = Particles.getParticleProperties(particle); var position = particleProperties.position; Particles.deleteParticle(particle); // Make a hole in this voxel + Vec3.print("penetration", penetration); + Vec3.print("position", position); + var pointOfEntry = Vec3.subtract(position, penetration); + Vec3.print("pointOfEntry", pointOfEntry); + Voxels.eraseVoxel(pointOfEntry.x, pointOfEntry.y, pointOfEntry.z, HOLE_SIZE); Voxels.eraseVoxel(position.x, position.y, position.z, HOLE_SIZE); //audioOptions.position = position; audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); - Audio.playSound(impactSound, audioOptions); + Audio.playSound(targetHitSound, audioOptions); } function particleCollisionWithParticle(particle1, particle2) { - print("Particle/Particle!"); score++; Overlays.editOverlay(text, { text: "Score: " + score } ); + // Sort out which particle is which + + // Record shot time + var endTime = new Date(); + var msecs = endTime.valueOf() - shotTime.valueOf(); + print("hit, msecs = " + msecs); Particles.deleteParticle(particle1); Particles.deleteParticle(particle2); + audioOptions.position = newPosition; + audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); + Audio.playSound(targetHitSound, audioOptions); } function keyPressEvent(event) { // if our tools are off, then don't do anything if (event.text == "t") { - shootTarget(); + var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY; + Script.setTimeout(shootTarget, time); } } @@ -164,7 +191,8 @@ function update(deltaTime) { // Check hydra controller for launch button press if (!isLaunchButtonPressed && Controller.isButtonPressed(LEFT_BUTTON_3)) { isLaunchButtonPressed = true; - shootTarget(); + var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY; + Script.setTimeout(shootTarget, time); } else if (isLaunchButtonPressed && !Controller.isButtonPressed(LEFT_BUTTON_3)) { isLaunchButtonPressed = false; diff --git a/examples/voxelBird.js b/examples/voxelBird.js deleted file mode 100644 index 1e33851ff6..0000000000 --- a/examples/voxelBird.js +++ /dev/null @@ -1,133 +0,0 @@ -// -// This sample script moves a voxel around like a bird and sometimes makes tweeting noises -// - -function vLength(v) { - return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); -} - -function printVector(v) { - print(v.x + ", " + v.y + ", " + v.z + "\n"); -} - -// Create a random vector with individual lengths between a,b -function randVector(a, b) { - var rval = { x: a + Math.random() * (b - a), y: a + Math.random() * (b - a), z: a + Math.random() * (b - a) }; - return rval; -} - -function vMinus(a, b) { - var rval = { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z }; - return rval; -} - -function vPlus(a, b) { - var rval = { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z }; - return rval; -} - -function vCopy(a, b) { - a.x = b.x; - a.y = b.y; - a.z = b.z; - return; -} - -// Returns a vector which is fraction of the way between a and b -function vInterpolate(a, b, fraction) { - var rval = { x: a.x + (b.x - a.x) * fraction, y: a.y + (b.y - a.y) * fraction, z: a.z + (b.z - a.z) * fraction }; - return rval; -} - -// Decide what kind of bird we are -var tweet; - -var which = Math.random(); -if (which < 0.2) { - tweet = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/bushtit_1.raw"); -} else if (which < 0.4) { - tweet = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/rosyfacedlovebird.raw"); -} else if (which < 0.6) { - tweet = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/saysphoebe.raw"); -} else if (which < 0.8) { - tweet = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/mexicanWhipoorwill.raw"); -} else { - tweet = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/westernscreechowl.raw"); -} - -var position = { x: 0, y: 0, z: 0 }; -var lastPosition = { x: 0, y: 0, z: 0 }; -var oldPosition = { x: 0, y: 0, z:0 }; -var targetPosition = { x: 0, y: 0, z: 0 }; - -var size = 0.125; -var range = 50.0; // Over what distance in meters do you want your bird to fly around -var color = { r: 100, g: 50, b: 150 }; -var colorEdge = { r:255, g:250, b:175 }; -var frame = 0; -var thisColor = color; -var moving = false; -var tweeting = 0; -var moved = true; - -var CHANCE_OF_MOVING = 0.05; -var CHANCE_OF_TWEETING = 0.05; - -function moveBird(deltaTime) { - frame++; - if (frame % 3 == 0) { - // Tweeting behavior - if (tweeting == 0) { - if (Math.random() < CHANCE_OF_TWEETING) { - //print("tweet!" + "\n"); - var options = new AudioInjectionOptions();
 - options.position = position; - options.volume = 0.75; - Audio.playSound(tweet, options); - tweeting = 10; - } - } else { - tweeting -= 1; - } - // Moving behavior - if (moving == false) { - if (Math.random() < CHANCE_OF_MOVING) { - targetPosition = randVector(0, range); - //printVector(position); - moving = true; - } - } - if (moving) { - position = vInterpolate(position, targetPosition, 0.5); - if (vLength(vMinus(position, targetPosition)) < (size / 2.0)) { - moved = false; - moving = false; - } else { - moved = true; - } - } - - if (tweeting > 0) { - // Change color of voxel to blinky red a bit while playing the sound - var blinkColor = { r: Math.random() * 255, g: 0, b: 0 }; - Voxels.setVoxel(position.x, - position.y, - position.z, - size, - blinkColor.r, blinkColor.g, blinkColor.b); - } - if (moved) { - Voxels.setVoxel(position.x, position.y, position.z, size, thisColor.r, thisColor.g, thisColor.b); - // delete old voxel - - Voxels.eraseVoxel(oldPosition.x, oldPosition.y, oldPosition.z, size); - // Copy old location to new - vCopy(oldPosition, position); - moved = false; - } - } -} - -Voxels.setPacketsPerSecond(10000); -// Connect a call back that happens every frame -Script.update.connect(moveBird); \ No newline at end of file From 9c8a4828f2ca6337562ec5f61c2797c950b62e85 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 18 Mar 2014 22:41:09 -0700 Subject: [PATCH 03/84] remove unused variable, function --- interface/src/avatar/MyAvatar.cpp | 5 ----- libraries/avatars/src/HandData.cpp | 3 --- 2 files changed, 8 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6c51026097..fb0d704c6a 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -424,11 +424,6 @@ void MyAvatar::updateFromGyros(float deltaTime) { } } -static TextRenderer* textRenderer() { - static TextRenderer* renderer = new TextRenderer(SANS_FONT_FAMILY, 24, -1, false, TextRenderer::SHADOW_EFFECT); - return renderer; -} - void MyAvatar::renderDebugBodyPoints() { glm::vec3 torsoPosition(getPosition()); glm::vec3 headPosition(getHead()->getEyePosition()); diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index c84ed77dae..3334dbb41d 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -14,9 +14,6 @@ #include -// When converting between fixed and float, use this as the radix. -const int fingerVectorRadix = 4; - HandData::HandData(AvatarData* owningAvatar) : _owningAvatarData(owningAvatar) { From 69a83ee94d7e8479df945178a9a7bed6074559fb Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 19 Mar 2014 16:27:27 -0700 Subject: [PATCH 04/84] add bots able to see voxels --- examples/bot.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/examples/bot.js b/examples/bot.js index 8485a2b993..d6f9f8344c 100644 --- a/examples/bot.js +++ b/examples/bot.js @@ -28,7 +28,9 @@ var CHANCE_OF_HEAD_TURNING = 0.05; var CHANCE_OF_BIG_MOVE = 0.1; var CHANCE_OF_WAVING = 0.000; // Currently this isn't working -var shouldReceiveVoxels = false; +var shouldReceiveVoxels = true; +var VOXEL_FPS = 60.0; +var lastVoxelQueryTime = 0.0; var isMoving = false; var isTurningHead = false; @@ -130,6 +132,17 @@ function updateBehavior(deltaTime) { cumulativeTime += deltaTime; + if (shouldReceiveVoxels && ((cumulativeTime - lastVoxelQueryTime) > (1.0 / VOXEL_FPS))) { + VoxelViewer.setPosition(Avatar.position); + VoxelViewer.setOrientation(Avatar.orientation); + VoxelViewer.queryOctree(); + lastVoxelQueryTime = cumulativeTime; + /* + if (Math.random() < (1.0 / VOXEL_FPS)) { + print("Voxels in view = " + VoxelViewer.getOctreeElementsCount()); + }*/ + } + if (!isWaving && (Math.random() < CHANCE_OF_WAVING)) { isWaving = true; waveFrequency = 1.0 + Math.random() * 5.0; From 3ab0288c4f133a9841452540e4240f1ff1803d9b Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 20 Mar 2014 08:54:12 -0700 Subject: [PATCH 05/84] testing numbered joint movement --- examples/bot.js | 8 ++------ libraries/avatars/src/HandData.cpp | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/examples/bot.js b/examples/bot.js index 201a629a92..f2cc3e23a1 100644 --- a/examples/bot.js +++ b/examples/bot.js @@ -26,7 +26,7 @@ var CHANCE_OF_MOVING = 0.005; var CHANCE_OF_SOUND = 0.005; var CHANCE_OF_HEAD_TURNING = 0.05; var CHANCE_OF_BIG_MOVE = 0.1; -var CHANCE_OF_WAVING = 0.000; // Currently this isn't working +var CHANCE_OF_WAVING = 0.005; // Currently this isn't working var shouldReceiveVoxels = true; var VOXEL_FPS = 60.0; @@ -141,17 +141,13 @@ function updateBehavior(deltaTime) { waveAmplitude = 5.0 + Math.random() * 60.0; Script.setTimeout(stopWaving, 1000 + Math.random() * 2000); } else if (isWaving) { - Avatar.setJointData("joint_L_shoulder", Quat.fromPitchYawRollDegrees(0.0, 0.0, waveAmplitude * Math.sin(cumulativeTime * waveFrequency))); + Avatar.setJointData(15, Quat.fromPitchYawRollDegrees(0.0, 0.0, waveAmplitude * Math.sin(cumulativeTime * waveFrequency))); } if (Math.random() < CHANCE_OF_SOUND) { playRandomSound(); } - if (Agent.isPlayingAvatarSound) { - Avatar.handPosition = Vec3.sum(Avatar.position, Quat.getFront(Avatar.orientation)); - } - if (!isTurningHead && (Math.random() < CHANCE_OF_HEAD_TURNING)) { targetHeadPitch = getRandomFloat(-PITCH_RANGE, PITCH_RANGE); isTurningHead = true; diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index e983c0e705..78ebf4b921 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -11,7 +11,7 @@ #include #include -#include "AvatarData.h" +#include "AvatarData.h" #include "HandData.h" From a30c4268da49b27a69ddeda135d318cd36ad6bd4 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 20 Mar 2014 15:47:42 -0700 Subject: [PATCH 06/84] wave work for bot --- examples/bot.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/examples/bot.js b/examples/bot.js index 808830b30d..ea78f40de9 100644 --- a/examples/bot.js +++ b/examples/bot.js @@ -44,6 +44,7 @@ var X_MAX = 5.0; var Z_MIN = 0.0; var Z_MAX = 5.0; var Y_PELVIS = 2.5; +var SHOULDER_JOINT_NUMBER = 15; var MOVE_RANGE_SMALL = 0.5; var MOVE_RANGE_BIG = Math.max(X_MAX - X_MIN, Z_MAX - Z_MIN) / 2.0; @@ -107,17 +108,13 @@ Avatar.billboardURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/me Agent.isAvatar = true; Agent.isListeningToAudioStream = true; -print("Joint List:"); -var jointList = Avatar.getJointNames(); -print(jointList); - // change the avatar's position to the random one Avatar.position = firstPosition; printVector("New bot, position = ", Avatar.position); function stopWaving() { isWaving = false; - Avatar.clearJointData("joint_L_shoulder"); + Avatar.clearJointData(SHOULDER_JOINT_NUMBER); } function updateBehavior(deltaTime) { @@ -141,7 +138,7 @@ function updateBehavior(deltaTime) { waveAmplitude = 5.0 + Math.random() * 60.0; Script.setTimeout(stopWaving, 1000 + Math.random() * 2000); } else if (isWaving) { - Avatar.setJointData(15, Quat.fromPitchYawRollDegrees(0.0, 0.0, waveAmplitude * Math.sin(cumulativeTime * waveFrequency))); + Avatar.setJointData(SHOULDER_JOINT_NUMBER, Quat.fromPitchYawRollDegrees(0.0, 0.0, waveAmplitude * Math.sin(cumulativeTime * waveFrequency))); } if (Math.random() < CHANCE_OF_SOUND) { From 22aa9b075dbad703ccbb0093b2b061f307a37684 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 20 Mar 2014 16:52:40 -0700 Subject: [PATCH 07/84] datalength sanity checking for AvatarData packet --- interface/src/avatar/Avatar.h | 2 +- interface/src/avatar/MyAvatar.cpp | 8 + interface/src/avatar/MyAvatar.h | 2 + libraries/avatars/src/AvatarData.cpp | 285 ++++++++++++++++++--------- libraries/avatars/src/AvatarData.h | 4 +- 5 files changed, 209 insertions(+), 92 deletions(-) diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 30073c54d4..638bff6e32 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -133,7 +133,7 @@ public: void setShowDisplayName(bool showDisplayName); - int parseDataAtOffset(const QByteArray& packet, int offset); + virtual int parseDataAtOffset(const QByteArray& packet, int offset); static void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index fb0d704c6a..e21c179b5b 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -551,6 +551,14 @@ void MyAvatar::loadData(QSettings* settings) { settings->endGroup(); } +int MyAvatar::parseDataAtOffset(const QByteArray& packet, int offset) { + qDebug() << "Error: ignoring update packet for MyAvatar" + << " packetLength = " << packet.size() + << " offset = " << offset; + // this packet is just bad, so we pretend that we unpacked it ALL + return packet.size() - offset; +} + void MyAvatar::sendKillAvatar() { QByteArray killPacket = byteArrayWithPopulatedHeader(PacketTypeKillAvatar); NodeList::getInstance()->broadcastToNodes(killPacket, NodeSet() << NodeType::AvatarMixer); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 3544fb1a61..2363ee26e1 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -71,6 +71,8 @@ public: void jump() { _shouldJump = true; }; bool isMyAvatar() { return true; } + + virtual int parseDataAtOffset(const QByteArray& packet, int offset); static void sendKillAvatar(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 4e57e311eb..35e9938dc7 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -24,6 +25,8 @@ #include "AvatarData.h" +quint64 DEFAULT_FILTERED_LOG_EXPIRY = 20 * USECS_PER_SECOND; + using namespace std; QNetworkAccessManager* AvatarData::networkAccessManager = NULL; @@ -42,7 +45,8 @@ AvatarData::AvatarData() : _displayNameBoundingRect(), _displayNameTargetAlpha(0.0f), _displayNameAlpha(0.0f), - _billboard() + _billboard(), + _debugLogExpiry(0) { } @@ -176,7 +180,6 @@ QByteArray AvatarData::toByteArray() { // read data in packet starting at byte offset and return number of bytes parsed int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { - // lazily allocate memory for HeadData in case we're not an Avatar instance if (!_headData) { _headData = new HeadData(this); @@ -189,102 +192,204 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { const unsigned char* startPosition = reinterpret_cast(packet.data()) + offset; const unsigned char* sourceBuffer = startPosition; + + // 50 bytes of "plain old data" (POD) + // 1 byte for messageSize (0) + // 1 byte for pupilSize + // 1 byte for numJoints (0) + int minPossibleSize = 53; - // Body world position - memcpy(&_position, sourceBuffer, sizeof(float) * 3); - sourceBuffer += sizeof(float) * 3; - - // Body rotation (NOTE: This needs to become a quaternion to save two bytes) - sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_bodyYaw); - sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_bodyPitch); - sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_bodyRoll); - - // Body scale - sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, _targetScale); - - // Head rotation (NOTE: This needs to become a quaternion to save two bytes) - float headYaw, headPitch, headRoll; - sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headYaw); - sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headPitch); - sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headRoll); - _headData->setYaw(headYaw); - _headData->setPitch(headPitch); - _headData->setRoll(headRoll); - - // Head position relative to pelvis - memcpy(&_headData->_leanSideways, sourceBuffer, sizeof(_headData->_leanSideways)); - sourceBuffer += sizeof(float); - memcpy(&_headData->_leanForward, sourceBuffer, sizeof(_headData->_leanForward)); - sourceBuffer += sizeof(_headData->_leanForward); - - // Lookat Position - memcpy(&_headData->_lookAtPosition, sourceBuffer, sizeof(_headData->_lookAtPosition)); - sourceBuffer += sizeof(_headData->_lookAtPosition); - - // Instantaneous audio loudness (used to drive facial animation) - memcpy(&_headData->_audioLoudness, sourceBuffer, sizeof(float)); - sourceBuffer += sizeof(float); - - // the rest is a chat message - int chatMessageSize = *sourceBuffer++; - _chatMessage = string((char*)sourceBuffer, chatMessageSize); - sourceBuffer += chatMessageSize * sizeof(char); - - // voxel sending features... - unsigned char bitItems = 0; - bitItems = (unsigned char)*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); - - // If it is connected, pack up the data - if (_headData->_isFaceshiftConnected) { - memcpy(&_headData->_leftEyeBlink, sourceBuffer, sizeof(float)); - sourceBuffer += sizeof(float); - - memcpy(&_headData->_rightEyeBlink, sourceBuffer, sizeof(float)); - sourceBuffer += sizeof(float); - - memcpy(&_headData->_averageLoudness, sourceBuffer, sizeof(float)); - sourceBuffer += sizeof(float); - - memcpy(&_headData->_browAudioLift, sourceBuffer, sizeof(float)); - sourceBuffer += sizeof(float); - - _headData->_blendshapeCoefficients.resize(*sourceBuffer++); - memcpy(_headData->_blendshapeCoefficients.data(), sourceBuffer, - _headData->_blendshapeCoefficients.size() * sizeof(float)); - sourceBuffer += _headData->_blendshapeCoefficients.size() * sizeof(float); + int maxAvailableSize = packet.size() - offset; + if (minPossibleSize > maxAvailableSize) { + // this packet is malformed so we pretend to read to the end + quint64 now = usecTimestampNow(); + if (now > _debugLogExpiry) { + qDebug() << "Malformed AvatarData packet at the start: minPossibleSize = " << minPossibleSize + << " but maxAvailableSize = " << maxAvailableSize; + _debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY; + } + return maxAvailableSize; } + + { // Body world position, rotation, and scale + // position + memcpy(&_position, sourceBuffer, sizeof(float) * 3); + sourceBuffer += sizeof(float) * 3; + + // rotation (NOTE: This needs to become a quaternion to save two bytes) + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_bodyYaw); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_bodyPitch); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_bodyRoll); + + // scale + sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, _targetScale); + } // 20 bytes - // pupil dilation - sourceBuffer += unpackFloatFromByte(sourceBuffer, _headData->_pupilDilation, 1.0f); + { // Head rotation + //(NOTE: This needs to become a quaternion to save two bytes) + float headYaw, headPitch, headRoll; + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headYaw); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headPitch); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headRoll); + _headData->setYaw(headYaw); + _headData->setPitch(headPitch); + _headData->setRoll(headRoll); + } // 6 bytes + + // Head lean (relative to pelvis) + { + memcpy(&_headData->_leanSideways, sourceBuffer, sizeof(_headData->_leanSideways)); + sourceBuffer += sizeof(float); + memcpy(&_headData->_leanForward, sourceBuffer, sizeof(_headData->_leanForward)); + sourceBuffer += sizeof(float); + } // 8 bytes + + { // Lookat Position + memcpy(&_headData->_lookAtPosition, sourceBuffer, sizeof(_headData->_lookAtPosition)); + sourceBuffer += sizeof(_headData->_lookAtPosition); + } // 12 bytes + + { // AudioLoudness + // Instantaneous audio loudness (used to drive facial animation) + memcpy(&_headData->_audioLoudness, sourceBuffer, sizeof(float)); + sourceBuffer += sizeof(float); + } // 4 bytes + + // chat + int chatMessageSize = *sourceBuffer++; + minPossibleSize += chatMessageSize; + if (minPossibleSize > maxAvailableSize) { + // this packet is malformed so we pretend to read to the end + quint64 now = usecTimestampNow(); + if (now > _debugLogExpiry) { + qDebug() << "Malformed AvatarData packet before ChatMessage: minPossibleSize = " << minPossibleSize + << " but maxAvailableSize = " << maxAvailableSize; + _debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY; + } + return maxAvailableSize; + } + { // chat payload + _chatMessage = string((char*)sourceBuffer, chatMessageSize); + sourceBuffer += chatMessageSize * sizeof(char); + } // 1 + chatMessageSize bytes + + { // bitFlags and face data + unsigned char bitItems = 0; + bitItems = (unsigned char)*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); + + if (_headData->_isFaceshiftConnected) { + minPossibleSize += 4 * sizeof(float) + 1; // four floats + one byte for blendDataSize + if (minPossibleSize > maxAvailableSize) { + // this packet is malformed so we pretend to read to the end + quint64 now = usecTimestampNow(); + if (now > _debugLogExpiry) { + qDebug() << "Malformed AvatarData packet after BitItems: minPossibleSize = " << minPossibleSize + << " but maxAvailableSize = " << maxAvailableSize; + _debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY; + } + return maxAvailableSize; + } + // unpack face data + memcpy(&_headData->_leftEyeBlink, sourceBuffer, sizeof(float)); + sourceBuffer += sizeof(float); + + memcpy(&_headData->_rightEyeBlink, sourceBuffer, sizeof(float)); + sourceBuffer += sizeof(float); + + memcpy(&_headData->_averageLoudness, sourceBuffer, sizeof(float)); + sourceBuffer += sizeof(float); + + memcpy(&_headData->_browAudioLift, sourceBuffer, sizeof(float)); + sourceBuffer += sizeof(float); + + int numCoefficients = (int)(*sourceBuffer++); + int blendDataSize = numCoefficients * sizeof(float); + minPossibleSize += blendDataSize; + if (minPossibleSize > maxAvailableSize) { + // this packet is malformed so we pretend to read to the end + quint64 now = usecTimestampNow(); + if (now > _debugLogExpiry) { + qDebug() << "Malformed AvatarData packet after Blendshapes: minPossibleSize = " << minPossibleSize + << " but maxAvailableSize = " << maxAvailableSize; + _debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY; + } + return maxAvailableSize; + } + + _headData->_blendshapeCoefficients.resize(numCoefficients); + memcpy(_headData->_blendshapeCoefficients.data(), sourceBuffer, blendDataSize); + sourceBuffer += numCoefficients * sizeof(float); + + //bitItemsDataSize = 4 * sizeof(float) + 1 + blendDataSize; + } + } // 1 + bitItemsDataSize bytes + + { // pupil dilation + sourceBuffer += unpackFloatFromByte(sourceBuffer, _headData->_pupilDilation, 1.0f); + } // 1 byte // joint data - int jointCount = *sourceBuffer++; - _jointData.resize(jointCount); - unsigned char validity = 0; - int validityBit = 0; - for (int i = 0; i < jointCount; i++) { - if (validityBit == 0) { - validity = *sourceBuffer++; - } - _jointData[i].valid = (bool)(validity & (1 << validityBit)); - validityBit = (validityBit + 1) % BITS_IN_BYTE; + int numJoints = *sourceBuffer++; + int bytesOfValidity = (int)ceil((float)numJoints / 8.f); + minPossibleSize += bytesOfValidity; + if (minPossibleSize > maxAvailableSize) { + // this packet is malformed so we pretend to read to the end + quint64 now = usecTimestampNow(); + if (now > _debugLogExpiry) { + qDebug() << "Malformed AvatarData packet after JointValidityBits: minPossibleSize = " << minPossibleSize + << " but maxAvailableSize = " << maxAvailableSize; + _debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY; + } + return maxAvailableSize; } - for (int i = 0; i < jointCount; i++) { - JointData& data = _jointData[i]; - if (data.valid) { - sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, data.rotation); + int numValidJoints = 0; + _jointData.resize(numJoints); + { // validity bits + unsigned char validity = 0; + int validityBit = 0; + for (int i = 0; i < numJoints; i++) { + if (validityBit == 0) { + validity = *sourceBuffer++; + } + bool valid = (bool)(validity & (1 << validityBit)); + if (valid) { + ++numValidJoints; + } + _jointData[i].valid = valid; + validityBit = (validityBit + 1) % BITS_IN_BYTE; } } + // 1 + bytesOfValidity bytes + + minPossibleSize += numValidJoints * 8; // 8 bytes per quaternion + if (minPossibleSize > maxAvailableSize) { + // this packet is malformed so we pretend to read to the end + quint64 now = usecTimestampNow(); + if (now > _debugLogExpiry) { + qDebug() << "Malformed AvatarData packet after JointData: minPossibleSize = " << minPossibleSize + << " but maxAvailableSize = " << maxAvailableSize; + _debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY; + } + return maxAvailableSize; + } + + { // joint data + for (int i = 0; i < numJoints; i++) { + JointData& data = _jointData[i]; + if (data.valid) { + sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, data.rotation); + } + } + } // numJoints * 8 bytes return sourceBuffer - startPosition; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index c7a93daef5..4048b9bebe 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -33,10 +33,10 @@ typedef unsigned long long quint64; #include #include #include -#include #include #include #include +#include #include #include @@ -256,6 +256,8 @@ protected: static QNetworkAccessManager* networkAccessManager; + quint64 _debugLogExpiry; + private: // privatize the copy constructor and assignment operator so they cannot be called AvatarData(const AvatarData&); From 1214794f050e5acf19c437448a41b468767230ad Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 20 Mar 2014 17:03:28 -0700 Subject: [PATCH 08/84] QMap is not used by AvatarData --- libraries/avatars/src/AvatarData.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 4048b9bebe..bcf32ec8e2 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -36,7 +36,6 @@ typedef unsigned long long quint64; #include #include #include -#include #include #include From 939265356ba43f5ec69bdb509a9698645e2abbfc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 21 Mar 2014 10:03:01 -0700 Subject: [PATCH 09/84] fix editVoxels.js mouse clicking --- examples/editVoxels.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 43bc485274..ac0b67407b 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -33,7 +33,7 @@ var zFightingSizeAdjust = 0.002; // used to adjust preview voxels to prevent z f var previewLineWidth = 1.5; var oldMode = Camera.getMode(); - +var trackAsOrbitOrPan = false; var isAdding = false; var isExtruding = false; var extrudeDirection = { x: 0, y: 0, z: 0 }; @@ -792,7 +792,6 @@ function mousePressEvent(event) { if (!trackAsOrbitOrPan) { var clickedOnSomething = false; var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - // If the user clicked on the thumb, handle the slider logic if (clickedOverlay == thumb) { From 0105029d9cfc185ffb01a5138f770c7df3f15b4c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 10:10:25 -0700 Subject: [PATCH 10/84] output number of no reply domain checkins when finished --- assignment-client/src/audio/AudioMixer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index f5bed48a86..4a064087f1 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -393,6 +393,7 @@ void AudioMixer::run() { QCoreApplication::processEvents(); if (_isFinished) { + qDebug() << "NRDC:" << NodeList::getInstance()->getNumNoReplyDomainCheckIns(); break; } From 6f37bb54f889ff4f9c5ed4bb49bf29f3eb204719 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 10:19:17 -0700 Subject: [PATCH 11/84] suppress useless audio debug --- libraries/audio/src/PositionalAudioRingBuffer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index ccbe5d3f23..8fb3d64e7d 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -80,13 +80,11 @@ int PositionalAudioRingBuffer::parsePositionalData(const QByteArray& positionalB bool PositionalAudioRingBuffer::shouldBeAddedToMix(int numJitterBufferSamples) { if (!isNotStarvedOrHasMinimumSamples(NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL + numJitterBufferSamples)) { if (_shouldOutputStarveDebug) { - qDebug() << "Starved and do not have minimum samples to start. Buffer held back."; _shouldOutputStarveDebug = false; } return false; } else if (samplesAvailable() < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL) { - qDebug() << "Do not have number of samples needed for interval. Buffer starved."; _isStarved = true; // reset our _shouldOutputStarveDebug to true so the next is printed From c1cbc7980705bd02a83565042c3c2d356f1d9902 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 10:26:09 -0700 Subject: [PATCH 12/84] move debug for no reply domain checkins to ThreadedAssignment --- assignment-client/src/audio/AudioMixer.cpp | 1 - libraries/shared/src/ThreadedAssignment.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 4a064087f1..f5bed48a86 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -393,7 +393,6 @@ void AudioMixer::run() { QCoreApplication::processEvents(); if (_isFinished) { - qDebug() << "NRDC:" << NodeList::getInstance()->getNumNoReplyDomainCheckIns(); break; } diff --git a/libraries/shared/src/ThreadedAssignment.cpp b/libraries/shared/src/ThreadedAssignment.cpp index c4282028ae..b3a54b1488 100644 --- a/libraries/shared/src/ThreadedAssignment.cpp +++ b/libraries/shared/src/ThreadedAssignment.cpp @@ -56,6 +56,7 @@ void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeTy void ThreadedAssignment::checkInWithDomainServerOrExit() { if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { + qDebug() << "NRDC:" << NodeList::getInstance()->getNumNoReplyDomainCheckIns(); setFinished(true); } else { NodeList::getInstance()->sendDomainServerCheckIn(); From 5b3340ce49edbbadd002db3d8b7b19dea64205d7 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 21 Mar 2014 10:38:29 -0700 Subject: [PATCH 13/84] Add Ryan's updated smoothing factors. --- interface/resources/visage/tracker.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/visage/tracker.cfg b/interface/resources/visage/tracker.cfg index 10744da6e5..2efb7f3463 100644 --- a/interface/resources/visage/tracker.cfg +++ b/interface/resources/visage/tracker.cfg @@ -40,7 +40,7 @@ detect_strip_roi_width 2 detect_strip_roi_height 4 smoothing_factors - 150 5 -2 100 -1 50 50 0 + 5 25 -2 100 -1 50 25 0 #translation rotation action_units eyebrows mouth gaze eye_closure other process_eyes 1 From 5a6456c29f699f132920a550063d3bfaf77f517b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 11:29:16 -0700 Subject: [PATCH 14/84] use an epsilon value to drop average loudness to zero --- libraries/audio/src/AudioRingBuffer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index cf35b6a20f..3b36d4cf4b 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -70,8 +70,13 @@ void AudioRingBuffer::updateAverageLoudnessForBoundarySamples(int numSamples) { const int TRAILING_AVERAGE_FRAMES = 100; const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; const float PREVIOUS_FRAMES_RATIO = 1 - CURRENT_FRAME_RATIO; + const float LOUDNESS_EPSILON = 0.05; _averageLoudness = (_averageLoudness * PREVIOUS_FRAMES_RATIO) + (CURRENT_FRAME_RATIO * nextLoudness); + + if (_averageLoudness < LOUDNESS_EPSILON) { + _averageLoudness = 0; + } } qint64 AudioRingBuffer::readSamples(int16_t* destination, qint64 maxSamples) { From 1580896ec4bf7137a3b7d97823c8a824c51e6941 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 11:42:02 -0700 Subject: [PATCH 15/84] don't use a trailing average for loudness --- libraries/audio/src/AudioRingBuffer.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index 3b36d4cf4b..800f4f64ee 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -66,17 +66,8 @@ void AudioRingBuffer::updateAverageLoudnessForBoundarySamples(int numSamples) { nextLoudness /= numSamples; nextLoudness /= MAX_SAMPLE_VALUE; - - const int TRAILING_AVERAGE_FRAMES = 100; - const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; - const float PREVIOUS_FRAMES_RATIO = 1 - CURRENT_FRAME_RATIO; - const float LOUDNESS_EPSILON = 0.05; - _averageLoudness = (_averageLoudness * PREVIOUS_FRAMES_RATIO) + (CURRENT_FRAME_RATIO * nextLoudness); - - if (_averageLoudness < LOUDNESS_EPSILON) { - _averageLoudness = 0; - } + _averageLoudness = nextLoudness; } qint64 AudioRingBuffer::readSamples(int16_t* destination, qint64 maxSamples) { From 3cb3cb81c40e3d08d177cfcd7ae27bf9e57dabb7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 21 Mar 2014 14:15:02 -0700 Subject: [PATCH 16/84] fixes to voxel server crashes on client shutdown --- .../src/octree/OctreeQueryNode.cpp | 8 +++++ .../src/octree/OctreeQueryNode.h | 1 + .../src/octree/OctreeSendThread.cpp | 35 +++++++++++-------- .../src/octree/OctreeSendThread.h | 4 +++ libraries/shared/src/NodeList.cpp | 18 ++++++++-- libraries/shared/src/NodeList.h | 3 +- 6 files changed, 50 insertions(+), 19 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 2ceb9e1040..e0ff29effd 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -67,6 +67,14 @@ OctreeQueryNode::~OctreeQueryNode() { } +void OctreeQueryNode::deleteLater() { + _isShuttingDown = true; + if (_octreeSendThread) { + _octreeSendThread->setIsShuttingDown(); + } + OctreeQuery::deleteLater(); +} + void OctreeQueryNode::initializeOctreeSendThread(OctreeServer* octreeServer, const QUuid& nodeUUID) { // Create octree sending thread... diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index eab8cb5d0a..b7e68e805d 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -27,6 +27,7 @@ class OctreeQueryNode : public OctreeQuery { public: OctreeQueryNode(); virtual ~OctreeQueryNode(); + virtual void deleteLater(); void init(); // called after creation to set up some virtual items virtual PacketType getMyPacketType() const = 0; diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 9c04c4a1ad..a215d9b3c3 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -5,6 +5,8 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // +#include + #include #include #include @@ -21,7 +23,9 @@ OctreeSendThread::OctreeSendThread(const QUuid& nodeUUID, OctreeServer* myServer _nodeUUID(nodeUUID), _myServer(myServer), _packetData(), - _nodeMissingCount(0) + _nodeMissingCount(0), + _processLock(), + _isShuttingDown(false) { QString safeServerName("Octree"); if (_myServer) { @@ -43,8 +47,19 @@ OctreeSendThread::~OctreeSendThread() { OctreeServer::clientDisconnected(); } +void OctreeSendThread::setIsShuttingDown() { + QMutexLocker locker(&_processLock); // this will cause us to wait till the process loop is complete + _isShuttingDown = true; +} + bool OctreeSendThread::process() { + QMutexLocker locker(&_processLock); + + if (_isShuttingDown) { + return false; // exit early if we're shutting down + } + const int MAX_NODE_MISSING_CHECKS = 10; if (_nodeMissingCount > MAX_NODE_MISSING_CHECKS) { qDebug() << "our target node:" << _nodeUUID << "has been missing the last" << _nodeMissingCount @@ -56,7 +71,10 @@ bool OctreeSendThread::process() { // don't do any send processing until the initial load of the octree is complete... if (_myServer->isInitialLoadComplete()) { - SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(_nodeUUID); + + // see if we can get access to our node, but don't wait on the lock, if the nodeList is busy + // it might not return a node that is known, but that's ok we can handle that case. + SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(_nodeUUID, false); if (node) { _nodeMissingCount = 0; @@ -113,19 +131,6 @@ int OctreeSendThread::handlePacketSend(const SharedNodePointer& node, bool packetSent = false; // did we send a packet? int packetsSent = 0; - // double check that the node has an active socket, otherwise, don't send... - - quint64 lockWaitStart = usecTimestampNow(); - QMutexLocker locker(&node->getMutex()); - quint64 lockWaitEnd = usecTimestampNow(); - float lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); - OctreeServer::trackNodeWaitTime(lockWaitElapsedUsec); - - const HifiSockAddr* nodeAddress = node->getActiveSocket(); - if (!nodeAddress) { - return packetsSent; // without sending... - } - // Here's where we check to see if this packet is a duplicate of the last packet. If it is, we will silently // obscure the packet and not send it. This allows the callers and upper level logic to not need to know about // this rate control savings. diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index 39c27911b0..ab88121ee8 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -23,6 +23,8 @@ class OctreeSendThread : public GenericThread { public: OctreeSendThread(const QUuid& nodeUUID, OctreeServer* myServer); virtual ~OctreeSendThread(); + + void setIsShuttingDown(); static quint64 _totalBytes; static quint64 _totalWastedBytes; @@ -45,6 +47,8 @@ private: OctreePacketData _packetData; int _nodeMissingCount; + QMutex _processLock; // don't allow us to have our nodeData, or our thread to be deleted while we're processing + bool _isShuttingDown; }; #endif // __octree_server__OctreeSendThread__ diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 6d699322de..797e90fa51 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -308,9 +308,21 @@ int NodeList::findNodeAndUpdateWithDataFromPacket(const QByteArray& packet) { return 0; } -SharedNodePointer NodeList::nodeWithUUID(const QUuid& nodeUUID) { - QMutexLocker locker(&_nodeHashMutex); - return _nodeHash.value(nodeUUID); +SharedNodePointer NodeList::nodeWithUUID(const QUuid& nodeUUID, bool blockingLock) { + SharedNodePointer node; + // if caller wants us to block and guarantee the correct answer, then honor that request + if (blockingLock) { + // this will block till we can get access + QMutexLocker locker(&_nodeHashMutex); + node = _nodeHash.value(nodeUUID); + } else { + // some callers are willing to get wrong answers but not block + if (_nodeHashMutex.tryLock()) { + node = _nodeHash.value(nodeUUID); + _nodeHashMutex.unlock(); + } + } + return node; } SharedNodePointer NodeList::sendingNodeForPacket(const QByteArray& packet) { diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 590a2ce83f..d6328a1303 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -101,7 +101,8 @@ public: QByteArray constructPingReplyPacket(const QByteArray& pingPacket); void pingPublicAndLocalSocketsForInactiveNode(const SharedNodePointer& node); - SharedNodePointer nodeWithUUID(const QUuid& nodeUUID); + /// passing false for blockingLock, will tryLock, and may return NULL when a node with the UUID actually does exist + SharedNodePointer nodeWithUUID(const QUuid& nodeUUID, bool blockingLock = true); SharedNodePointer sendingNodeForPacket(const QByteArray& packet); SharedNodePointer addOrUpdateNode(const QUuid& uuid, char nodeType, From 9f96129fb17eeac1347dea772e4fa24c40f887a5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 21 Mar 2014 14:22:26 -0700 Subject: [PATCH 17/84] Fixed #2379 --- examples/editVoxels.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index ac0b67407b..34635d6e7d 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -742,6 +742,7 @@ function trackKeyReleaseEvent(event) { if (event.text == "TAB") { editToolsOn = !editToolsOn; moveTools(); + showPreviewGuides(); Audio.playSound(clickSound, audioOptions); } From c10d78c3975869477c8dc2c682990cda9ca053c1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 21 Mar 2014 14:29:19 -0700 Subject: [PATCH 18/84] Fixed bug when mouse leaves window. --- examples/inspect.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/inspect.js b/examples/inspect.js index 9292450784..8ff759c127 100644 --- a/examples/inspect.js +++ b/examples/inspect.js @@ -165,7 +165,7 @@ function keyReleaseEvent(event) { } function mousePressEvent(event) { - if (alt) { + if (alt && !isActive) { isActive = true; mouseLastX = event.x; mouseLastY = event.y; From 2575b33662c62f1dc65576ba0ccaeb38df6418c9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 14:29:57 -0700 Subject: [PATCH 19/84] reinstate a cutoff when the audio-mixer is struggling --- assignment-client/src/audio/AudioMixer.cpp | 73 +++++++++++++++---- assignment-client/src/audio/AudioMixer.h | 5 +- .../src/audio/AudioMixerClientData.cpp | 6 +- .../src/audio/AudioMixerClientData.h | 2 +- 4 files changed, 63 insertions(+), 23 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index f5bed48a86..ba659d8379 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -53,6 +53,8 @@ const short JITTER_BUFFER_MSECS = 12; const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_MSECS * (SAMPLE_RATE / 1000.0); +const float LOUDNESS_TO_DISTANCE_RATIO = 0.00305f; + const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer"; void attachNewBufferToNode(Node *newNode) { @@ -64,10 +66,7 @@ void attachNewBufferToNode(Node *newNode) { AudioMixer::AudioMixer(const QByteArray& packet) : ThreadedAssignment(packet), _trailingSleepRatio(1.0f), - _minSourceLoudnessInFrame(1.0f), - _maxSourceLoudnessInFrame(0.0f), - _loudnessCutoffRatio(0.0f), - _minRequiredLoudness(0.0f) + _minAudabilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2) { } @@ -83,8 +82,15 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf // if the two buffer pointers do not match then these are different buffers glm::vec3 relativePosition = bufferToAdd->getPosition() - listeningNodeBuffer->getPosition(); + + if (bufferToAdd->getAverageLoudness() / glm::length(relativePosition) <= _minAudabilityThreshold) { + // according to mixer performance we have decided this does not get to be mixed in + // bail out + return; + } + glm::quat inverseOrientation = glm::inverse(listeningNodeBuffer->getOrientation()); - + float distanceSquareToSource = glm::dot(relativePosition, relativePosition); float radius = 0.0f; @@ -305,8 +311,7 @@ void AudioMixer::prepareMixForListeningNode(Node* node) { if ((*otherNode != *node || otherNodeBuffer->shouldLoopbackForNode()) - && otherNodeBuffer->willBeAddedToMix() - && otherNodeBuffer->getAverageLoudness() > _minRequiredLoudness) { + && otherNodeBuffer->willBeAddedToMix()) { addBufferToMixForListeningNodeWithBuffer(otherNodeBuffer, nodeRingBuffer); } } @@ -357,19 +362,61 @@ void AudioMixer::run() { + numBytesForPacketHeaderGivenPacketType(PacketTypeMixedAudio)]; int usecToSleep = BUFFER_SEND_INTERVAL_USECS; + float audabilityCutoffRatio = 0; while (!_isFinished) { - - _minSourceLoudnessInFrame = 1.0f; - _maxSourceLoudnessInFrame = 0.0f; foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { if (node->getLinkedData()) { - ((AudioMixerClientData*) node->getLinkedData())->checkBuffersBeforeFrameSend(JITTER_BUFFER_SAMPLES, - _minSourceLoudnessInFrame, - _maxSourceLoudnessInFrame); + ((AudioMixerClientData*) node->getLinkedData())->checkBuffersBeforeFrameSend(JITTER_BUFFER_SAMPLES); } } + + const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10; + const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.30; + const float CUTOFF_EPSILON = 0.0001; + + const int TRAILING_AVERAGE_FRAMES = 100; + const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; + const float PREVIOUS_FRAMES_RATIO = 1 - CURRENT_FRAME_RATIO; + + if (usecToSleep < 0) { + usecToSleep = 0; + } + + _trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio) + + (usecToSleep * CURRENT_FRAME_RATIO / (float) BUFFER_SEND_INTERVAL_USECS); + + float lastCutoffRatio = audabilityCutoffRatio; + bool hasRatioChanged = false; + + if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { + // we're struggling - change our min required loudness to reduce some load + audabilityCutoffRatio += (1 - audabilityCutoffRatio) / 2; + + qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" + << lastCutoffRatio << "and is now" << audabilityCutoffRatio; + hasRatioChanged = true; + } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && audabilityCutoffRatio != 0) { + // we've recovered and can back off the required loudness + audabilityCutoffRatio -= audabilityCutoffRatio / 2; + + if (audabilityCutoffRatio < CUTOFF_EPSILON) { + audabilityCutoffRatio = 0; + } + + qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" + << lastCutoffRatio << "and is now" << audabilityCutoffRatio; + hasRatioChanged = true; + } + + + + if (hasRatioChanged) { + // set out min required loudness from the new ratio + _minAudabilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2 * (1 - audabilityCutoffRatio)); + qDebug() << "Minimum loudness required to be mixed is now" << _minAudabilityThreshold; + } foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 4ba8cdebd3..93656aabff 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -41,10 +41,7 @@ private: int16_t _clientSamples[NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (SAMPLE_PHASE_DELAY_AT_90 * 2)]; float _trailingSleepRatio; - float _minSourceLoudnessInFrame; - float _maxSourceLoudnessInFrame; - float _loudnessCutoffRatio; - float _minRequiredLoudness; + float _minAudabilityThreshold; }; #endif /* defined(__hifi__AudioMixer__) */ diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index f370a1509f..381c80cb09 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -83,20 +83,16 @@ int AudioMixerClientData::parseData(const QByteArray& packet) { return 0; } -void AudioMixerClientData::checkBuffersBeforeFrameSend(int jitterBufferLengthSamples, - float& currentMinLoudness, - float& currentMaxLoudness) { +void AudioMixerClientData::checkBuffersBeforeFrameSend(int jitterBufferLengthSamples) { for (unsigned int i = 0; i < _ringBuffers.size(); i++) { if (_ringBuffers[i]->shouldBeAddedToMix(jitterBufferLengthSamples)) { // this is a ring buffer that is ready to go // set its flag so we know to push its buffer when all is said and done _ringBuffers[i]->setWillBeAddedToMix(true); - // calculate the average loudness for the next NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL // that would be mixed in _ringBuffers[i]->updateAverageLoudnessForBoundarySamples(NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL); - } } } diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index d41563bbca..7f44390ec5 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -25,7 +25,7 @@ public: AvatarAudioRingBuffer* getAvatarAudioRingBuffer() const; int parseData(const QByteArray& packet); - void checkBuffersBeforeFrameSend(int jitterBufferLengthSamples, float& currentMinLoudness, float& currentMaxLoudness); + void checkBuffersBeforeFrameSend(int jitterBufferLengthSamples); void pushBuffersAfterFrameSend(); private: std::vector _ringBuffers; From 3721ce8e438c06381803c3bef54a57b98f09fae6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 21 Mar 2014 14:30:12 -0700 Subject: [PATCH 20/84] Added boundaries to altitude and changed radius rate --- examples/inspect.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/examples/inspect.js b/examples/inspect.js index 8ff759c127..2443eadf9b 100644 --- a/examples/inspect.js +++ b/examples/inspect.js @@ -14,9 +14,11 @@ // Dragging the mouse will move your camera according to the mode you are in. // +var PI = 3.14 // No need for something more precise + var AZIMUTH_RATE = 90.0; var ALTITUDE_RATE = 200.0; -var RADIUS_RATE = 20.0; +var RADIUS_RATE = 1.0 / 100.0; var PAN_RATE = 50.0; var alt = false; @@ -46,7 +48,7 @@ var altitude = 0.0; function handleRadialMode(dx, dy) { azimuth += dx / AZIMUTH_RATE; - radius += radius * dy / RADIUS_RATE; + radius += radius * dy * RADIUS_RATE; if (radius < 1) { radius = 1; } @@ -61,6 +63,12 @@ function handleRadialMode(dx, dy) { function handleOrbitMode(dx, dy) { azimuth += dx / AZIMUTH_RATE; altitude += dy / ALTITUDE_RATE; + if (altitude > PI / 2.0) { + altitude = PI / 2.0; + } + if (altitude < -PI / 2.0) { + altitude = -PI / 2.0; + } vector = { x:(Math.cos(altitude) * Math.cos(azimuth)) * radius, y:Math.sin(altitude) * radius, From 53eaea6a2215835f578e8b6a8a8b9c4fa84df2bf Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 21 Mar 2014 14:30:57 -0700 Subject: [PATCH 21/84] Removed rest of orbit/pan code in editVoxels.js --- examples/editVoxels.js | 136 +++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 73 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 34635d6e7d..a66d82f9ba 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -32,8 +32,6 @@ var MIN_PASTE_VOXEL_SCALE = .256; var zFightingSizeAdjust = 0.002; // used to adjust preview voxels to prevent z fighting var previewLineWidth = 1.5; -var oldMode = Camera.getMode(); -var trackAsOrbitOrPan = false; var isAdding = false; var isExtruding = false; var extrudeDirection = { x: 0, y: 0, z: 0 }; @@ -614,8 +612,6 @@ function showPreviewVoxel() { var guidePosition; if (trackAsRecolor || recolorToolSelected || trackAsEyedropper || eyedropperToolSelected) { Overlays.editOverlay(voxelPreview, { visible: true }); - } else if (trackAsOrbitOrPan) { - Overlays.editOverlay(voxelPreview, { visible: false }); } else if (voxelToolSelected && !isExtruding) { Overlays.editOverlay(voxelPreview, { visible: true }); } else if (isExtruding) { @@ -706,15 +702,12 @@ function showPreviewGuides() { } function trackMouseEvent(event) { - if (!trackAsOrbitOrPan) { - trackLastMouseX = event.x; - trackLastMouseY = event.y; - trackAsDelete = event.isControl; - trackAsRecolor = event.isShifted; - trackAsEyedropper = event.isMeta; - trackAsOrbitOrPan = event.isAlt; // TODO: double check this...?? - showPreviewGuides(); - } + trackLastMouseX = event.x; + trackLastMouseY = event.y; + trackAsDelete = event.isControl; + trackAsRecolor = event.isShifted; + trackAsEyedropper = event.isMeta; + showPreviewGuides(); } function trackKeyPressEvent(event) { @@ -789,67 +782,64 @@ function mousePressEvent(event) { return; } - // no clicking on overlays while in panning mode - if (!trackAsOrbitOrPan) { - var clickedOnSomething = false; - var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - - // If the user clicked on the thumb, handle the slider logic - if (clickedOverlay == thumb) { - isMovingSlider = true; - thumbClickOffsetX = event.x - (sliderX + thumbX); // this should be the position of the mouse relative to the thumb - clickedOnSomething = true; - - Overlays.editOverlay(thumb, { imageURL: toolIconUrl + "voxel-size-slider-handle.svg", }); - - } else if (clickedOverlay == voxelTool) { - voxelToolSelected = true; - recolorToolSelected = false; - eyedropperToolSelected = false; - moveTools(); - clickedOnSomething = true; - } else if (clickedOverlay == recolorTool) { - voxelToolSelected = false; - recolorToolSelected = true; - eyedropperToolSelected = false; - moveTools(); - clickedOnSomething = true; - } else if (clickedOverlay == eyedropperTool) { - voxelToolSelected = false; - recolorToolSelected = false; - eyedropperToolSelected = true; - moveTools(); - clickedOnSomething = true; - } else if (clickedOverlay == slider) { - - if (event.x < sliderX + minThumbX) { - thumbX -= thumbDeltaPerStep; - calcScaleFromThumb(thumbX); - } - - if (event.x > sliderX + maxThumbX) { - thumbX += thumbDeltaPerStep; - calcScaleFromThumb(thumbX); - } - - moveTools(); - clickedOnSomething = true; - } else { - // if the user clicked on one of the color swatches, update the selectedSwatch - for (s = 0; s < numColors; s++) { - if (clickedOverlay == swatches[s]) { - whichColor = s; - moveTools(); - clickedOnSomething = true; - break; - } - } + var clickedOnSomething = false; + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + + // If the user clicked on the thumb, handle the slider logic + if (clickedOverlay == thumb) { + isMovingSlider = true; + thumbClickOffsetX = event.x - (sliderX + thumbX); // this should be the position of the mouse relative to the thumb + clickedOnSomething = true; + + Overlays.editOverlay(thumb, { imageURL: toolIconUrl + "voxel-size-slider-handle.svg", }); + + } else if (clickedOverlay == voxelTool) { + voxelToolSelected = true; + recolorToolSelected = false; + eyedropperToolSelected = false; + moveTools(); + clickedOnSomething = true; + } else if (clickedOverlay == recolorTool) { + voxelToolSelected = false; + recolorToolSelected = true; + eyedropperToolSelected = false; + moveTools(); + clickedOnSomething = true; + } else if (clickedOverlay == eyedropperTool) { + voxelToolSelected = false; + recolorToolSelected = false; + eyedropperToolSelected = true; + moveTools(); + clickedOnSomething = true; + } else if (clickedOverlay == slider) { + + if (event.x < sliderX + minThumbX) { + thumbX -= thumbDeltaPerStep; + calcScaleFromThumb(thumbX); } - if (clickedOnSomething) { - return; // no further processing + + if (event.x > sliderX + maxThumbX) { + thumbX += thumbDeltaPerStep; + calcScaleFromThumb(thumbX); + } + + moveTools(); + clickedOnSomething = true; + } else { + // if the user clicked on one of the color swatches, update the selectedSwatch + for (s = 0; s < numColors; s++) { + if (clickedOverlay == swatches[s]) { + whichColor = s; + moveTools(); + clickedOnSomething = true; + break; + } } } - + if (clickedOnSomething) { + return; // no further processing + } + // TODO: does any of this stuff need to execute if we're panning or orbiting? trackMouseEvent(event); // used by preview support mouseX = event.x; @@ -1072,7 +1062,7 @@ function mouseMoveEvent(event) { } - if (!trackAsOrbitOrPan && isMovingSlider) { + if (isMovingSlider) { thumbX = (event.x - thumbClickOffsetX) - sliderX; if (thumbX < minThumbX) { thumbX = minThumbX; @@ -1082,7 +1072,7 @@ function mouseMoveEvent(event) { } calcScaleFromThumb(thumbX); - } else if (!trackAsOrbitOrPan && isAdding) { + } else if (isAdding) { // Watch the drag direction to tell which way to 'extrude' this voxel if (!isExtruding) { var pickRay = Camera.computePickRay(event.x, event.y); From 18e563797636cfc29bfec3a4d2441d0c0d83db4c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 14:33:11 -0700 Subject: [PATCH 22/84] remove some extra spaces --- assignment-client/src/audio/AudioMixer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index ba659d8379..8c504be763 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -410,8 +410,6 @@ void AudioMixer::run() { hasRatioChanged = true; } - - if (hasRatioChanged) { // set out min required loudness from the new ratio _minAudabilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2 * (1 - audabilityCutoffRatio)); From 3d9aa6cc9f7275f8bc6cf6185b53a7b288930965 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 14:36:44 -0700 Subject: [PATCH 23/84] fix a spelling mistake and convert some ints to floats --- assignment-client/src/audio/AudioMixer.cpp | 22 +++++++++++----------- assignment-client/src/audio/AudioMixer.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 8c504be763..5b889b979c 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -66,7 +66,7 @@ void attachNewBufferToNode(Node *newNode) { AudioMixer::AudioMixer(const QByteArray& packet) : ThreadedAssignment(packet), _trailingSleepRatio(1.0f), - _minAudabilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2) + _minAudibilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2) { } @@ -83,7 +83,7 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf glm::vec3 relativePosition = bufferToAdd->getPosition() - listeningNodeBuffer->getPosition(); - if (bufferToAdd->getAverageLoudness() / glm::length(relativePosition) <= _minAudabilityThreshold) { + if (bufferToAdd->getAverageLoudness() / glm::length(relativePosition) <= _minAudibilityThreshold) { // according to mixer performance we have decided this does not get to be mixed in // bail out return; @@ -372,13 +372,13 @@ void AudioMixer::run() { } } - const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10; - const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.30; - const float CUTOFF_EPSILON = 0.0001; + const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; + const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.30f; + const float CUTOFF_EPSILON = 0.0001f; const int TRAILING_AVERAGE_FRAMES = 100; const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; - const float PREVIOUS_FRAMES_RATIO = 1 - CURRENT_FRAME_RATIO; + const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; if (usecToSleep < 0) { usecToSleep = 0; @@ -392,17 +392,17 @@ void AudioMixer::run() { if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { // we're struggling - change our min required loudness to reduce some load - audabilityCutoffRatio += (1 - audabilityCutoffRatio) / 2; + audabilityCutoffRatio += (1.0f - audabilityCutoffRatio) / 2.0f; qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" << lastCutoffRatio << "and is now" << audabilityCutoffRatio; hasRatioChanged = true; } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && audabilityCutoffRatio != 0) { // we've recovered and can back off the required loudness - audabilityCutoffRatio -= audabilityCutoffRatio / 2; + audabilityCutoffRatio -= audabilityCutoffRatio / 2.0f; if (audabilityCutoffRatio < CUTOFF_EPSILON) { - audabilityCutoffRatio = 0; + audabilityCutoffRatio = 0.0f; } qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" @@ -412,8 +412,8 @@ void AudioMixer::run() { if (hasRatioChanged) { // set out min required loudness from the new ratio - _minAudabilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2 * (1 - audabilityCutoffRatio)); - qDebug() << "Minimum loudness required to be mixed is now" << _minAudabilityThreshold; + _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - audabilityCutoffRatio)); + qDebug() << "Minimum loudness required to be mixed is now" << _minAudibilityThreshold; } foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 93656aabff..9d731a5c9c 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -41,7 +41,7 @@ private: int16_t _clientSamples[NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (SAMPLE_PHASE_DELAY_AT_90 * 2)]; float _trailingSleepRatio; - float _minAudabilityThreshold; + float _minAudibilityThreshold; }; #endif /* defined(__hifi__AudioMixer__) */ From 98f014d13d1c7251a2b092b31283c1c6076d0adb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 14:37:31 -0700 Subject: [PATCH 24/84] add another check to avoid any mixing for a silent frame --- assignment-client/src/audio/AudioMixer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 5b889b979c..a63fad4cd1 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -311,7 +311,8 @@ void AudioMixer::prepareMixForListeningNode(Node* node) { if ((*otherNode != *node || otherNodeBuffer->shouldLoopbackForNode()) - && otherNodeBuffer->willBeAddedToMix()) { + && otherNodeBuffer->willBeAddedToMix() + && otherNodeBuffer->getAverageLoudness() > 0) { addBufferToMixForListeningNodeWithBuffer(otherNodeBuffer, nodeRingBuffer); } } From c99f5a4ae6cb1ffac8b9e2b033fcd41584dd1861 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 14:38:01 -0700 Subject: [PATCH 25/84] int to float conversion in the constructor --- 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 a63fad4cd1..15e1b864eb 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -66,7 +66,7 @@ void attachNewBufferToNode(Node *newNode) { AudioMixer::AudioMixer(const QByteArray& packet) : ThreadedAssignment(packet), _trailingSleepRatio(1.0f), - _minAudibilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2) + _minAudibilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2.0f) { } From 2c8c43094faa9166de5ba233229736524fc3e6a2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 21 Mar 2014 14:46:46 -0700 Subject: [PATCH 26/84] CR feedback --- libraries/shared/src/NodeList.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 797e90fa51..2b131ab7ff 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -315,12 +315,9 @@ SharedNodePointer NodeList::nodeWithUUID(const QUuid& nodeUUID, bool blockingLoc // this will block till we can get access QMutexLocker locker(&_nodeHashMutex); node = _nodeHash.value(nodeUUID); - } else { - // some callers are willing to get wrong answers but not block - if (_nodeHashMutex.tryLock()) { - node = _nodeHash.value(nodeUUID); - _nodeHashMutex.unlock(); - } + } else if (_nodeHashMutex.tryLock()) { // some callers are willing to get wrong answers but not block + node = _nodeHash.value(nodeUUID); + _nodeHashMutex.unlock(); } return node; } From 4661553acb865d1d887e5256cac870d5298320e2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 15:40:08 -0700 Subject: [PATCH 27/84] check for cutoff change only every TRAILING_AVERAGE_FRAMES --- assignment-client/src/audio/AudioMixer.cpp | 54 +++++++++++++--------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 15e1b864eb..cab7af5fd0 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -364,6 +364,9 @@ void AudioMixer::run() { int usecToSleep = BUFFER_SEND_INTERVAL_USECS; float audabilityCutoffRatio = 0; + + const int TRAILING_AVERAGE_FRAMES = 100; + int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; while (!_isFinished) { @@ -374,10 +377,9 @@ void AudioMixer::run() { } const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; - const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.30f; + const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; const float CUTOFF_EPSILON = 0.0001f; - const int TRAILING_AVERAGE_FRAMES = 100; const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; @@ -391,30 +393,36 @@ void AudioMixer::run() { float lastCutoffRatio = audabilityCutoffRatio; bool hasRatioChanged = false; - if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { - // we're struggling - change our min required loudness to reduce some load - audabilityCutoffRatio += (1.0f - audabilityCutoffRatio) / 2.0f; - - qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" + if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { + if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { + // we're struggling - change our min required loudness to reduce some load + audabilityCutoffRatio += (1.0f - audabilityCutoffRatio) / 2.0f; + + qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" << lastCutoffRatio << "and is now" << audabilityCutoffRatio; - hasRatioChanged = true; - } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && audabilityCutoffRatio != 0) { - // we've recovered and can back off the required loudness - audabilityCutoffRatio -= audabilityCutoffRatio / 2.0f; - - if (audabilityCutoffRatio < CUTOFF_EPSILON) { - audabilityCutoffRatio = 0.0f; + hasRatioChanged = true; + } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && audabilityCutoffRatio != 0) { + // we've recovered and can back off the required loudness + audabilityCutoffRatio -= audabilityCutoffRatio / 2.0f; + + if (audabilityCutoffRatio < CUTOFF_EPSILON) { + audabilityCutoffRatio = 0.0f; + } + + qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" + << lastCutoffRatio << "and is now" << audabilityCutoffRatio; + hasRatioChanged = true; } - qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" - << lastCutoffRatio << "and is now" << audabilityCutoffRatio; - hasRatioChanged = true; - } - - if (hasRatioChanged) { - // set out min required loudness from the new ratio - _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - audabilityCutoffRatio)); - qDebug() << "Minimum loudness required to be mixed is now" << _minAudibilityThreshold; + if (hasRatioChanged) { + // set out min required loudness from the new ratio + _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - audabilityCutoffRatio)); + qDebug() << "Minimum loudness required to be mixed is now" << _minAudibilityThreshold; + + framesSinceCutoffEvent = 0; + } + } else { + framesSinceCutoffEvent++; } foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { From 75bc64010434f4b8b61dc18ebf9f7884fa30eae4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 15:42:58 -0700 Subject: [PATCH 28/84] fix some indentation is audio mixer cutoff code --- assignment-client/src/audio/AudioMixer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index cab7af5fd0..fd7e5e360d 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -399,7 +399,7 @@ void AudioMixer::run() { audabilityCutoffRatio += (1.0f - audabilityCutoffRatio) / 2.0f; qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" - << lastCutoffRatio << "and is now" << audabilityCutoffRatio; + << lastCutoffRatio << "and is now" << audabilityCutoffRatio; hasRatioChanged = true; } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && audabilityCutoffRatio != 0) { // we've recovered and can back off the required loudness @@ -410,7 +410,7 @@ void AudioMixer::run() { } qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" - << lastCutoffRatio << "and is now" << audabilityCutoffRatio; + << lastCutoffRatio << "and is now" << audabilityCutoffRatio; hasRatioChanged = true; } From 50007d7f4b8918839bfa2a410b53d9c3281ef775 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 15:43:39 -0700 Subject: [PATCH 29/84] fix a debug message for audability threshold --- assignment-client/src/audio/AudioMixer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index fd7e5e360d..dc066f8857 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -415,9 +415,9 @@ void AudioMixer::run() { } if (hasRatioChanged) { - // set out min required loudness from the new ratio + // set out min audability threshold from the new ratio _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - audabilityCutoffRatio)); - qDebug() << "Minimum loudness required to be mixed is now" << _minAudibilityThreshold; + qDebug() << "Minimum audability required to be mixed is now" << _minAudibilityThreshold; framesSinceCutoffEvent = 0; } From 438e5bd235ccc01f9be457e388c0e482d686c424 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 21 Mar 2014 15:46:06 -0700 Subject: [PATCH 30/84] fix crash on domain restart in Agent, also have Agent properly shutdown on call to Script.stop() --- assignment-client/src/Agent.cpp | 5 +++++ assignment-client/src/Agent.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 4eb6b17260..d32d6a3fd7 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -189,4 +189,9 @@ void Agent::run() { _scriptEngine.setScriptContents(scriptContents); _scriptEngine.run(); + setFinished(true); +} + +void Agent::aboutToFinish() { + _scriptEngine.stop(); } diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index b638c39356..0a61bd73f7 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -41,6 +41,8 @@ public: bool isListeningToAudioStream() const { return _scriptEngine.isListeningToAudioStream(); } void setIsListeningToAudioStream(bool isListeningToAudioStream) { _scriptEngine.setIsListeningToAudioStream(isListeningToAudioStream); } + + virtual void aboutToFinish(); public slots: void run(); From dc2d050187568c8606a01c6aedc9b2af23d36da0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 15:47:21 -0700 Subject: [PATCH 31/84] remove sleep time debug now that the audio-mixer reports struggle --- assignment-client/src/audio/AudioMixer.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index dc066f8857..6754b1eee7 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -454,10 +454,7 @@ void AudioMixer::run() { if (usecToSleep > 0) { usleep(usecToSleep); - } else { - qDebug() << "AudioMixer loop took" << -usecToSleep << "of extra time. Not sleeping."; } - } delete[] clientMixBuffer; From bad209bf09f1b315ede15fe758bdd324ef0fa4a9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 15:53:00 -0700 Subject: [PATCH 32/84] use a trailing average for a quieter loudness --- libraries/audio/src/AudioRingBuffer.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index 800f4f64ee..efe62de515 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -67,7 +67,15 @@ void AudioRingBuffer::updateAverageLoudnessForBoundarySamples(int numSamples) { nextLoudness /= numSamples; nextLoudness /= MAX_SAMPLE_VALUE; - _averageLoudness = nextLoudness; + const int TRAILING_AVERAGE_FRAMES = 100; + const float CURRENT_FRAME_RATIO = 1 / TRAILING_AVERAGE_FRAMES; + const float PREVIOUS_FRAMES_RATIO = 1 - CURRENT_FRAME_RATIO; + + if (nextLoudness >= _averageLoudness) { + _averageLoudness = nextLoudness; + } else { + _averageLoudness = (_averageLoudness * PREVIOUS_FRAMES_RATIO) + (CURRENT_FRAME_RATIO * nextLoudness); + } } qint64 AudioRingBuffer::readSamples(int16_t* destination, qint64 maxSamples) { From 34f90759803f61eaa2ccfaca9d8fd6c140879711 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 16:47:41 -0700 Subject: [PATCH 33/84] use a linear change to audability ratio --- assignment-client/src/audio/AudioMixer.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 6754b1eee7..f2c766460a 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -379,6 +379,7 @@ void AudioMixer::run() { const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; const float CUTOFF_EPSILON = 0.0001f; + const float CUTOFF_DELTA = 0.05; const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; @@ -396,17 +397,21 @@ void AudioMixer::run() { if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { // we're struggling - change our min required loudness to reduce some load - audabilityCutoffRatio += (1.0f - audabilityCutoffRatio) / 2.0f; + audabilityCutoffRatio += CUTOFF_DELTA; + + if (audabilityCutoffRatio > 1) { + audabilityCutoffRatio = 1; + } qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" << lastCutoffRatio << "and is now" << audabilityCutoffRatio; hasRatioChanged = true; } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && audabilityCutoffRatio != 0) { // we've recovered and can back off the required loudness - audabilityCutoffRatio -= audabilityCutoffRatio / 2.0f; + audabilityCutoffRatio -= CUTOFF_DELTA; - if (audabilityCutoffRatio < CUTOFF_EPSILON) { - audabilityCutoffRatio = 0.0f; + if (audabilityCutoffRatio < 0) { + audabilityCutoffRatio = 0; } qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" From 8ecd9aa0c04d024506ea7c6631b0fa92fde05251 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 17:16:54 -0700 Subject: [PATCH 34/84] change audibility delta to 2%, don't hit 1.0 --- assignment-client/src/audio/AudioMixer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index f2c766460a..e95dcb0ec3 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -379,7 +379,7 @@ void AudioMixer::run() { const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; const float CUTOFF_EPSILON = 0.0001f; - const float CUTOFF_DELTA = 0.05; + const float CUTOFF_DELTA = 0.02; const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; @@ -399,8 +399,8 @@ void AudioMixer::run() { // we're struggling - change our min required loudness to reduce some load audabilityCutoffRatio += CUTOFF_DELTA; - if (audabilityCutoffRatio > 1) { - audabilityCutoffRatio = 1; + if (audabilityCutoffRatio >= 1) { + audabilityCutoffRatio = 1 - CUTOFF_DELTA; } qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" From 88b91b9eb70673c219c6297b5ff9a11fa5f1ceaa Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 17:17:11 -0700 Subject: [PATCH 35/84] change an int to a float --- 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 e95dcb0ec3..bb60abacc0 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -379,7 +379,7 @@ void AudioMixer::run() { const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; const float CUTOFF_EPSILON = 0.0001f; - const float CUTOFF_DELTA = 0.02; + const float CUTOFF_DELTA = 0.02f; const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; From c70bbda10a1249f40464384ba070d335bf4e7cb0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 21 Mar 2014 18:16:28 -0700 Subject: [PATCH 36/84] kill local voxels on domain change --- interface/src/Application.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 030e3bc6fd..9563cbf3b4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3252,6 +3252,9 @@ void Application::domainChanged(const QString& domainHostname) { // reset the particle renderer _particles.clear(); + + // reset the voxels renderer + _voxels.killLocalVoxels(); } void Application::connectedToDomain(const QString& hostname) { From 88348b12d2158104fcfc5c7283584b2960aa30b0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 18:16:47 -0700 Subject: [PATCH 37/84] fix a divide by zero and output number of clients mixed in last frame --- assignment-client/src/audio/AudioMixer.cpp | 17 ++++++++++++++--- assignment-client/src/audio/AudioMixer.h | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index bb60abacc0..d2a498eef1 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -66,7 +66,8 @@ void attachNewBufferToNode(Node *newNode) { AudioMixer::AudioMixer(const QByteArray& packet) : ThreadedAssignment(packet), _trailingSleepRatio(1.0f), - _minAudibilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2.0f) + _minAudibilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2.0f), + _numClientsMixedInFrame(0) { } @@ -80,15 +81,22 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf if (bufferToAdd != listeningNodeBuffer) { // if the two buffer pointers do not match then these are different buffers - glm::vec3 relativePosition = bufferToAdd->getPosition() - listeningNodeBuffer->getPosition(); - if (bufferToAdd->getAverageLoudness() / glm::length(relativePosition) <= _minAudibilityThreshold) { + float distanceBetween = glm::length(relativePosition); + + if (distanceBetween < EPSILON) { + distanceBetween = EPSILON; + } + + if (bufferToAdd->getAverageLoudness() / distanceBetween <= _minAudibilityThreshold) { // according to mixer performance we have decided this does not get to be mixed in // bail out return; } + ++_numClientsMixedInFrame; + glm::quat inverseOrientation = glm::inverse(listeningNodeBuffer->getOrientation()); float distanceSquareToSource = glm::dot(relativePosition, relativePosition); @@ -441,6 +449,9 @@ void AudioMixer::run() { nodeList->writeDatagram(clientMixBuffer, NETWORK_BUFFER_LENGTH_BYTES_STEREO + numBytesPacketHeader, node); } } + + qDebug() << "There were" << _numClientsMixedInFrame << "clients mixed in the last frame"; + _numClientsMixedInFrame = 0; // push forward the next output pointers for any audio buffers we used foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 9d731a5c9c..d8f1a8eb85 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -42,6 +42,7 @@ private: float _trailingSleepRatio; float _minAudibilityThreshold; + int _numClientsMixedInFrame; }; #endif /* defined(__hifi__AudioMixer__) */ From abd6c8a747cfdcbdfc22b5fd6bb472388d5807ef Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 18:28:12 -0700 Subject: [PATCH 38/84] fix trailing average on ring buffer, remove unused constant --- assignment-client/src/audio/AudioMixer.cpp | 1 - libraries/audio/src/AudioRingBuffer.cpp | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index d2a498eef1..94fdbcea9d 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -386,7 +386,6 @@ void AudioMixer::run() { const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; - const float CUTOFF_EPSILON = 0.0001f; const float CUTOFF_DELTA = 0.02f; const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index efe62de515..4f0df744ee 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -70,11 +70,16 @@ void AudioRingBuffer::updateAverageLoudnessForBoundarySamples(int numSamples) { const int TRAILING_AVERAGE_FRAMES = 100; const float CURRENT_FRAME_RATIO = 1 / TRAILING_AVERAGE_FRAMES; const float PREVIOUS_FRAMES_RATIO = 1 - CURRENT_FRAME_RATIO; + const float LOUDNESS_EPSILON = 0.001; if (nextLoudness >= _averageLoudness) { _averageLoudness = nextLoudness; } else { _averageLoudness = (_averageLoudness * PREVIOUS_FRAMES_RATIO) + (CURRENT_FRAME_RATIO * nextLoudness); + + if (_averageLoudness < LOUDNESS_EPSILON) { + _averageLoudness = 0; + } } } From af4fb2603135dbbffa28e85a798d7d62b43f88b6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 18:44:59 -0700 Subject: [PATCH 39/84] floats are important --- assignment-client/src/audio/AudioMixer.cpp | 1 - libraries/audio/src/AudioRingBuffer.cpp | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 94fdbcea9d..ba17847773 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -449,7 +449,6 @@ void AudioMixer::run() { } } - qDebug() << "There were" << _numClientsMixedInFrame << "clients mixed in the last frame"; _numClientsMixedInFrame = 0; // push forward the next output pointers for any audio buffers we used diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index 4f0df744ee..4732cc77d1 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -68,9 +68,9 @@ void AudioRingBuffer::updateAverageLoudnessForBoundarySamples(int numSamples) { nextLoudness /= MAX_SAMPLE_VALUE; const int TRAILING_AVERAGE_FRAMES = 100; - const float CURRENT_FRAME_RATIO = 1 / TRAILING_AVERAGE_FRAMES; - const float PREVIOUS_FRAMES_RATIO = 1 - CURRENT_FRAME_RATIO; - const float LOUDNESS_EPSILON = 0.001; + const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; + const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; + const float LOUDNESS_EPSILON = 0.01f; if (nextLoudness >= _averageLoudness) { _averageLoudness = nextLoudness; From c5b0288c12030c81200d3076cac5de6b757fdbaf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 21 Mar 2014 18:49:46 -0700 Subject: [PATCH 40/84] remove numClientsMixedInFrame since it is no longer used --- assignment-client/src/audio/AudioMixer.cpp | 7 +------ assignment-client/src/audio/AudioMixer.h | 1 - 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index ba17847773..f3b623bac2 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -66,8 +66,7 @@ void attachNewBufferToNode(Node *newNode) { AudioMixer::AudioMixer(const QByteArray& packet) : ThreadedAssignment(packet), _trailingSleepRatio(1.0f), - _minAudibilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2.0f), - _numClientsMixedInFrame(0) + _minAudibilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2.0f) { } @@ -95,8 +94,6 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf return; } - ++_numClientsMixedInFrame; - glm::quat inverseOrientation = glm::inverse(listeningNodeBuffer->getOrientation()); float distanceSquareToSource = glm::dot(relativePosition, relativePosition); @@ -448,8 +445,6 @@ void AudioMixer::run() { nodeList->writeDatagram(clientMixBuffer, NETWORK_BUFFER_LENGTH_BYTES_STEREO + numBytesPacketHeader, node); } } - - _numClientsMixedInFrame = 0; // push forward the next output pointers for any audio buffers we used foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index d8f1a8eb85..9d731a5c9c 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -42,7 +42,6 @@ private: float _trailingSleepRatio; float _minAudibilityThreshold; - int _numClientsMixedInFrame; }; #endif /* defined(__hifi__AudioMixer__) */ From 98041b11564a6e092ffaa3d23ac4e17a9a8cde24 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Fri, 21 Mar 2014 22:05:56 -0600 Subject: [PATCH 41/84] Trivial commit - testing build on new server --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c374901d2..f8a6725ed8 100644 --- a/README.md +++ b/README.md @@ -63,4 +63,5 @@ To test things out you'll want to run the Interface client. To access your local domain in Interface, open your Preferences -- on OS X this is available in the Interface menu, on Linux you'll find it in the File menu. Enter "localhost" in the "Domain server" field. -If everything worked you should see that you are connected to at least one server. Nice work! +If everything worked you should see that you are connected to at least one server. +Nice work! From a56b7e341d2fbdda8ec7d1419609ab67c0770db1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 22 Mar 2014 20:22:05 -0700 Subject: [PATCH 42/84] reorganize files in interface directory --- interface/CMakeLists.txt | 2 +- interface/src/Application.cpp | 10 ++++++---- interface/src/Application.h | 10 +++++----- interface/src/Audio.h | 2 +- interface/src/Menu.cpp | 6 +++--- interface/src/VoxelImporter.h | 7 ++++--- .../{ => scripting}/ClipboardScriptingInterface.cpp | 0 .../src/{ => scripting}/ClipboardScriptingInterface.h | 0 .../{ => scripting}/ControllerScriptingInterface.cpp | 0 .../src/{ => scripting}/ControllerScriptingInterface.h | 0 .../src/{ => scripting}/MenuScriptingInterface.cpp | 0 interface/src/{ => scripting}/MenuScriptingInterface.h | 0 interface/src/{ => ui}/BandwidthMeter.cpp | 0 interface/src/{ => ui}/BandwidthMeter.h | 0 interface/src/{ => ui}/ImportDialog.cpp | 0 interface/src/{ => ui}/ImportDialog.h | 0 interface/src/{ => ui}/InfoView.cpp | 0 interface/src/{ => ui}/InfoView.h | 0 interface/src/{ => ui}/ModelBrowser.cpp | 0 interface/src/{ => ui}/ModelBrowser.h | 0 interface/src/{ => ui}/Oscilloscope.cpp | 0 interface/src/{ => ui}/Oscilloscope.h | 0 interface/src/ui/{ => overlays}/Base3DOverlay.cpp | 1 - interface/src/ui/{ => overlays}/Base3DOverlay.h | 0 interface/src/ui/{ => overlays}/Cube3DOverlay.cpp | 0 interface/src/ui/{ => overlays}/Cube3DOverlay.h | 0 interface/src/ui/{ => overlays}/ImageOverlay.cpp | 0 interface/src/ui/{ => overlays}/ImageOverlay.h | 0 interface/src/ui/{ => overlays}/Line3DOverlay.cpp | 0 interface/src/ui/{ => overlays}/Line3DOverlay.h | 0 interface/src/ui/{ => overlays}/LocalVoxelsOverlay.cpp | 0 interface/src/ui/{ => overlays}/LocalVoxelsOverlay.h | 0 interface/src/ui/{ => overlays}/Overlay.cpp | 0 interface/src/ui/{ => overlays}/Overlay.h | 0 interface/src/ui/{ => overlays}/Overlay2D.cpp | 0 interface/src/ui/{ => overlays}/Overlay2D.h | 0 interface/src/ui/{ => overlays}/Overlays.cpp | 0 interface/src/ui/{ => overlays}/Overlays.h | 0 interface/src/ui/{ => overlays}/Sphere3DOverlay.cpp | 0 interface/src/ui/{ => overlays}/Sphere3DOverlay.h | 0 interface/src/ui/{ => overlays}/TextOverlay.cpp | 2 +- interface/src/ui/{ => overlays}/TextOverlay.h | 0 interface/src/ui/{ => overlays}/Volume3DOverlay.cpp | 0 interface/src/ui/{ => overlays}/Volume3DOverlay.h | 0 44 files changed, 21 insertions(+), 19 deletions(-) rename interface/src/{ => scripting}/ClipboardScriptingInterface.cpp (100%) rename interface/src/{ => scripting}/ClipboardScriptingInterface.h (100%) rename interface/src/{ => scripting}/ControllerScriptingInterface.cpp (100%) rename interface/src/{ => scripting}/ControllerScriptingInterface.h (100%) rename interface/src/{ => scripting}/MenuScriptingInterface.cpp (100%) rename interface/src/{ => scripting}/MenuScriptingInterface.h (100%) rename interface/src/{ => ui}/BandwidthMeter.cpp (100%) rename interface/src/{ => ui}/BandwidthMeter.h (100%) rename interface/src/{ => ui}/ImportDialog.cpp (100%) rename interface/src/{ => ui}/ImportDialog.h (100%) rename interface/src/{ => ui}/InfoView.cpp (100%) rename interface/src/{ => ui}/InfoView.h (100%) rename interface/src/{ => ui}/ModelBrowser.cpp (100%) rename interface/src/{ => ui}/ModelBrowser.h (100%) rename interface/src/{ => ui}/Oscilloscope.cpp (100%) rename interface/src/{ => ui}/Oscilloscope.h (100%) rename interface/src/ui/{ => overlays}/Base3DOverlay.cpp (98%) rename interface/src/ui/{ => overlays}/Base3DOverlay.h (100%) rename interface/src/ui/{ => overlays}/Cube3DOverlay.cpp (100%) rename interface/src/ui/{ => overlays}/Cube3DOverlay.h (100%) rename interface/src/ui/{ => overlays}/ImageOverlay.cpp (100%) rename interface/src/ui/{ => overlays}/ImageOverlay.h (100%) rename interface/src/ui/{ => overlays}/Line3DOverlay.cpp (100%) rename interface/src/ui/{ => overlays}/Line3DOverlay.h (100%) rename interface/src/ui/{ => overlays}/LocalVoxelsOverlay.cpp (100%) rename interface/src/ui/{ => overlays}/LocalVoxelsOverlay.h (100%) rename interface/src/ui/{ => overlays}/Overlay.cpp (100%) rename interface/src/ui/{ => overlays}/Overlay.h (100%) rename interface/src/ui/{ => overlays}/Overlay2D.cpp (100%) rename interface/src/ui/{ => overlays}/Overlay2D.h (100%) rename interface/src/ui/{ => overlays}/Overlays.cpp (100%) rename interface/src/ui/{ => overlays}/Overlays.h (100%) rename interface/src/ui/{ => overlays}/Sphere3DOverlay.cpp (100%) rename interface/src/ui/{ => overlays}/Sphere3DOverlay.h (100%) rename interface/src/ui/{ => overlays}/TextOverlay.cpp (98%) rename interface/src/ui/{ => overlays}/TextOverlay.h (100%) rename interface/src/ui/{ => overlays}/Volume3DOverlay.cpp (100%) rename interface/src/ui/{ => overlays}/Volume3DOverlay.h (100%) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 7126e8929f..3751c4c857 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -48,7 +48,7 @@ configure_file(InterfaceVersion.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceVe # grab the implementation and header files from src dirs file(GLOB INTERFACE_SRCS src/*.cpp src/*.h) -foreach(SUBDIR avatar devices renderer ui starfield location) +foreach(SUBDIR avatar devices renderer ui starfield location scripting) file(GLOB_RECURSE SUBDIR_SRCS src/${SUBDIR}/*.cpp src/${SUBDIR}/*.h) set(INTERFACE_SRCS ${INTERFACE_SRCS} "${SUBDIR_SRCS}") endforeach(SUBDIR) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9563cbf3b4..91509386e4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -65,17 +65,19 @@ #include #include "Application.h" -#include "ClipboardScriptingInterface.h" #include "InterfaceVersion.h" #include "Menu.h" -#include "MenuScriptingInterface.h" #include "Util.h" #include "devices/OculusManager.h" #include "devices/TV3DManager.h" #include "renderer/ProgramObject.h" -#include "ui/TextRenderer.h" -#include "InfoView.h" + +#include "scripting/ClipboardScriptingInterface.h" +#include "scripting/MenuScriptingInterface.h" + +#include "ui/InfoView.h" #include "ui/Snapshot.h" +#include "ui/TextRenderer.h" using namespace std; diff --git a/interface/src/Application.h b/interface/src/Application.h index 28060113a9..38a8f87904 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -29,12 +29,12 @@ #include #include #include +#include +#include #include "Audio.h" -#include "BandwidthMeter.h" #include "BuckyBalls.h" #include "Camera.h" -#include "ControllerScriptingInterface.h" #include "DatagramProcessor.h" #include "Environment.h" #include "FileLogger.h" @@ -44,9 +44,7 @@ #include "PacketHeaders.h" #include "ParticleTreeRenderer.h" #include "Stars.h" -#include "ViewFrustum.h" #include "VoxelFade.h" -#include "VoxelEditPacketSender.h" #include "VoxelHideShowThread.h" #include "VoxelPacketProcessor.h" #include "VoxelSystem.h" @@ -63,13 +61,15 @@ #include "renderer/PointShader.h" #include "renderer/TextureCache.h" #include "renderer/VoxelShader.h" +#include "scripting/ControllerScriptingInterface.h" #include "ui/BandwidthDialog.h" +#include "ui/BandwidthMeter.h" #include "ui/OctreeStatsDialog.h" #include "ui/RearMirrorTools.h" #include "ui/LodToolsDialog.h" #include "ui/LogDialog.h" #include "ui/UpdateDialog.h" -#include "ui/Overlays.h" +#include "ui/overlays/Overlays.h" class QAction; diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 880391d7f3..6c2fbab204 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -27,7 +27,7 @@ #include #include -#include "Oscilloscope.h" +#include "ui/Oscilloscope.h" #include diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index e62c7e1102..e0ed6aa055 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -33,11 +33,11 @@ #include "Application.h" #include "Menu.h" -#include "MenuScriptingInterface.h" +#include "scripting/MenuScriptingInterface.h" #include "Util.h" -#include "InfoView.h" +#include "ui/InfoView.h" #include "ui/MetavoxelEditor.h" -#include "ModelBrowser.h" +#include "ui/ModelBrowser.h" Menu* Menu::_instance = NULL; diff --git a/interface/src/VoxelImporter.h b/interface/src/VoxelImporter.h index e77abaf18d..e3e5a1370c 100644 --- a/interface/src/VoxelImporter.h +++ b/interface/src/VoxelImporter.h @@ -9,12 +9,13 @@ #ifndef __hifi__VoxelImporter__ #define __hifi__VoxelImporter__ -#include -#include - #include #include +#include + +#include "ui/ImportDialog.h" + class ImportTask; class VoxelImporter : public QObject { diff --git a/interface/src/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp similarity index 100% rename from interface/src/ClipboardScriptingInterface.cpp rename to interface/src/scripting/ClipboardScriptingInterface.cpp diff --git a/interface/src/ClipboardScriptingInterface.h b/interface/src/scripting/ClipboardScriptingInterface.h similarity index 100% rename from interface/src/ClipboardScriptingInterface.h rename to interface/src/scripting/ClipboardScriptingInterface.h diff --git a/interface/src/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp similarity index 100% rename from interface/src/ControllerScriptingInterface.cpp rename to interface/src/scripting/ControllerScriptingInterface.cpp diff --git a/interface/src/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h similarity index 100% rename from interface/src/ControllerScriptingInterface.h rename to interface/src/scripting/ControllerScriptingInterface.h diff --git a/interface/src/MenuScriptingInterface.cpp b/interface/src/scripting/MenuScriptingInterface.cpp similarity index 100% rename from interface/src/MenuScriptingInterface.cpp rename to interface/src/scripting/MenuScriptingInterface.cpp diff --git a/interface/src/MenuScriptingInterface.h b/interface/src/scripting/MenuScriptingInterface.h similarity index 100% rename from interface/src/MenuScriptingInterface.h rename to interface/src/scripting/MenuScriptingInterface.h diff --git a/interface/src/BandwidthMeter.cpp b/interface/src/ui/BandwidthMeter.cpp similarity index 100% rename from interface/src/BandwidthMeter.cpp rename to interface/src/ui/BandwidthMeter.cpp diff --git a/interface/src/BandwidthMeter.h b/interface/src/ui/BandwidthMeter.h similarity index 100% rename from interface/src/BandwidthMeter.h rename to interface/src/ui/BandwidthMeter.h diff --git a/interface/src/ImportDialog.cpp b/interface/src/ui/ImportDialog.cpp similarity index 100% rename from interface/src/ImportDialog.cpp rename to interface/src/ui/ImportDialog.cpp diff --git a/interface/src/ImportDialog.h b/interface/src/ui/ImportDialog.h similarity index 100% rename from interface/src/ImportDialog.h rename to interface/src/ui/ImportDialog.h diff --git a/interface/src/InfoView.cpp b/interface/src/ui/InfoView.cpp similarity index 100% rename from interface/src/InfoView.cpp rename to interface/src/ui/InfoView.cpp diff --git a/interface/src/InfoView.h b/interface/src/ui/InfoView.h similarity index 100% rename from interface/src/InfoView.h rename to interface/src/ui/InfoView.h diff --git a/interface/src/ModelBrowser.cpp b/interface/src/ui/ModelBrowser.cpp similarity index 100% rename from interface/src/ModelBrowser.cpp rename to interface/src/ui/ModelBrowser.cpp diff --git a/interface/src/ModelBrowser.h b/interface/src/ui/ModelBrowser.h similarity index 100% rename from interface/src/ModelBrowser.h rename to interface/src/ui/ModelBrowser.h diff --git a/interface/src/Oscilloscope.cpp b/interface/src/ui/Oscilloscope.cpp similarity index 100% rename from interface/src/Oscilloscope.cpp rename to interface/src/ui/Oscilloscope.cpp diff --git a/interface/src/Oscilloscope.h b/interface/src/ui/Oscilloscope.h similarity index 100% rename from interface/src/Oscilloscope.h rename to interface/src/ui/Oscilloscope.h diff --git a/interface/src/ui/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp similarity index 98% rename from interface/src/ui/Base3DOverlay.cpp rename to interface/src/ui/overlays/Base3DOverlay.cpp index 67e7ea25f2..bcd2ca1cd2 100644 --- a/interface/src/ui/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -12,7 +12,6 @@ #include #include "Base3DOverlay.h" -#include "TextRenderer.h" const glm::vec3 DEFAULT_POSITION = glm::vec3(0.0f, 0.0f, 0.0f); const float DEFAULT_LINE_WIDTH = 1.0f; diff --git a/interface/src/ui/Base3DOverlay.h b/interface/src/ui/overlays/Base3DOverlay.h similarity index 100% rename from interface/src/ui/Base3DOverlay.h rename to interface/src/ui/overlays/Base3DOverlay.h diff --git a/interface/src/ui/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp similarity index 100% rename from interface/src/ui/Cube3DOverlay.cpp rename to interface/src/ui/overlays/Cube3DOverlay.cpp diff --git a/interface/src/ui/Cube3DOverlay.h b/interface/src/ui/overlays/Cube3DOverlay.h similarity index 100% rename from interface/src/ui/Cube3DOverlay.h rename to interface/src/ui/overlays/Cube3DOverlay.h diff --git a/interface/src/ui/ImageOverlay.cpp b/interface/src/ui/overlays/ImageOverlay.cpp similarity index 100% rename from interface/src/ui/ImageOverlay.cpp rename to interface/src/ui/overlays/ImageOverlay.cpp diff --git a/interface/src/ui/ImageOverlay.h b/interface/src/ui/overlays/ImageOverlay.h similarity index 100% rename from interface/src/ui/ImageOverlay.h rename to interface/src/ui/overlays/ImageOverlay.h diff --git a/interface/src/ui/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp similarity index 100% rename from interface/src/ui/Line3DOverlay.cpp rename to interface/src/ui/overlays/Line3DOverlay.cpp diff --git a/interface/src/ui/Line3DOverlay.h b/interface/src/ui/overlays/Line3DOverlay.h similarity index 100% rename from interface/src/ui/Line3DOverlay.h rename to interface/src/ui/overlays/Line3DOverlay.h diff --git a/interface/src/ui/LocalVoxelsOverlay.cpp b/interface/src/ui/overlays/LocalVoxelsOverlay.cpp similarity index 100% rename from interface/src/ui/LocalVoxelsOverlay.cpp rename to interface/src/ui/overlays/LocalVoxelsOverlay.cpp diff --git a/interface/src/ui/LocalVoxelsOverlay.h b/interface/src/ui/overlays/LocalVoxelsOverlay.h similarity index 100% rename from interface/src/ui/LocalVoxelsOverlay.h rename to interface/src/ui/overlays/LocalVoxelsOverlay.h diff --git a/interface/src/ui/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp similarity index 100% rename from interface/src/ui/Overlay.cpp rename to interface/src/ui/overlays/Overlay.cpp diff --git a/interface/src/ui/Overlay.h b/interface/src/ui/overlays/Overlay.h similarity index 100% rename from interface/src/ui/Overlay.h rename to interface/src/ui/overlays/Overlay.h diff --git a/interface/src/ui/Overlay2D.cpp b/interface/src/ui/overlays/Overlay2D.cpp similarity index 100% rename from interface/src/ui/Overlay2D.cpp rename to interface/src/ui/overlays/Overlay2D.cpp diff --git a/interface/src/ui/Overlay2D.h b/interface/src/ui/overlays/Overlay2D.h similarity index 100% rename from interface/src/ui/Overlay2D.h rename to interface/src/ui/overlays/Overlay2D.h diff --git a/interface/src/ui/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp similarity index 100% rename from interface/src/ui/Overlays.cpp rename to interface/src/ui/overlays/Overlays.cpp diff --git a/interface/src/ui/Overlays.h b/interface/src/ui/overlays/Overlays.h similarity index 100% rename from interface/src/ui/Overlays.h rename to interface/src/ui/overlays/Overlays.h diff --git a/interface/src/ui/Sphere3DOverlay.cpp b/interface/src/ui/overlays/Sphere3DOverlay.cpp similarity index 100% rename from interface/src/ui/Sphere3DOverlay.cpp rename to interface/src/ui/overlays/Sphere3DOverlay.cpp diff --git a/interface/src/ui/Sphere3DOverlay.h b/interface/src/ui/overlays/Sphere3DOverlay.h similarity index 100% rename from interface/src/ui/Sphere3DOverlay.h rename to interface/src/ui/overlays/Sphere3DOverlay.h diff --git a/interface/src/ui/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp similarity index 98% rename from interface/src/ui/TextOverlay.cpp rename to interface/src/ui/overlays/TextOverlay.cpp index edaec6849a..1a6edb3ea2 100644 --- a/interface/src/ui/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -12,7 +12,7 @@ #include #include "TextOverlay.h" -#include "TextRenderer.h" +#include "ui/TextRenderer.h" TextOverlay::TextOverlay() : _leftMargin(DEFAULT_MARGIN), diff --git a/interface/src/ui/TextOverlay.h b/interface/src/ui/overlays/TextOverlay.h similarity index 100% rename from interface/src/ui/TextOverlay.h rename to interface/src/ui/overlays/TextOverlay.h diff --git a/interface/src/ui/Volume3DOverlay.cpp b/interface/src/ui/overlays/Volume3DOverlay.cpp similarity index 100% rename from interface/src/ui/Volume3DOverlay.cpp rename to interface/src/ui/overlays/Volume3DOverlay.cpp diff --git a/interface/src/ui/Volume3DOverlay.h b/interface/src/ui/overlays/Volume3DOverlay.h similarity index 100% rename from interface/src/ui/Volume3DOverlay.h rename to interface/src/ui/overlays/Volume3DOverlay.h From b7243b0bfec82ec5fd8fad5c9c7b969156d55c70 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 22 Mar 2014 20:42:34 -0700 Subject: [PATCH 43/84] more cleanup --- interface/CMakeLists.txt | 2 +- interface/src/Application.h | 10 ++--- interface/src/avatar/Hand.cpp | 44 +------------------ interface/src/avatar/Hand.h | 10 ----- interface/src/avatar/MyAvatar.cpp | 1 - .../src/ui/overlays/LocalVoxelsOverlay.cpp | 2 +- .../src/{ => voxels}/PrimitiveRenderer.cpp | 0 .../src/{ => voxels}/PrimitiveRenderer.h | 0 interface/src/{ => voxels}/VoxelFade.cpp | 0 interface/src/{ => voxels}/VoxelFade.h | 0 .../src/{ => voxels}/VoxelHideShowThread.cpp | 0 .../src/{ => voxels}/VoxelHideShowThread.h | 0 interface/src/{ => voxels}/VoxelImporter.cpp | 10 +++-- interface/src/{ => voxels}/VoxelImporter.h | 3 +- .../src/{ => voxels}/VoxelPacketProcessor.cpp | 0 .../src/{ => voxels}/VoxelPacketProcessor.h | 0 interface/src/{ => voxels}/VoxelSystem.cpp | 0 interface/src/{ => voxels}/VoxelSystem.h | 0 18 files changed, 16 insertions(+), 66 deletions(-) rename interface/src/{ => voxels}/PrimitiveRenderer.cpp (100%) rename interface/src/{ => voxels}/PrimitiveRenderer.h (100%) rename interface/src/{ => voxels}/VoxelFade.cpp (100%) rename interface/src/{ => voxels}/VoxelFade.h (100%) rename interface/src/{ => voxels}/VoxelHideShowThread.cpp (100%) rename interface/src/{ => voxels}/VoxelHideShowThread.h (100%) rename interface/src/{ => voxels}/VoxelImporter.cpp (97%) rename interface/src/{ => voxels}/VoxelImporter.h (96%) rename interface/src/{ => voxels}/VoxelPacketProcessor.cpp (100%) rename interface/src/{ => voxels}/VoxelPacketProcessor.h (100%) rename interface/src/{ => voxels}/VoxelSystem.cpp (100%) rename interface/src/{ => voxels}/VoxelSystem.h (100%) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 3751c4c857..f991212a6e 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -48,7 +48,7 @@ configure_file(InterfaceVersion.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceVe # grab the implementation and header files from src dirs file(GLOB INTERFACE_SRCS src/*.cpp src/*.h) -foreach(SUBDIR avatar devices renderer ui starfield location scripting) +foreach(SUBDIR avatar devices renderer ui starfield location scripting voxels) file(GLOB_RECURSE SUBDIR_SRCS src/${SUBDIR}/*.cpp src/${SUBDIR}/*.h) set(INTERFACE_SRCS ${INTERFACE_SRCS} "${SUBDIR_SRCS}") endforeach(SUBDIR) diff --git a/interface/src/Application.h b/interface/src/Application.h index 38a8f87904..a796a700bb 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -44,11 +44,6 @@ #include "PacketHeaders.h" #include "ParticleTreeRenderer.h" #include "Stars.h" -#include "VoxelFade.h" -#include "VoxelHideShowThread.h" -#include "VoxelPacketProcessor.h" -#include "VoxelSystem.h" -#include "VoxelImporter.h" #include "avatar/Avatar.h" #include "avatar/AvatarManager.h" #include "avatar/MyAvatar.h" @@ -70,6 +65,11 @@ #include "ui/LogDialog.h" #include "ui/UpdateDialog.h" #include "ui/overlays/Overlays.h" +#include "voxels/VoxelFade.h" +#include "voxels/VoxelHideShowThread.h" +#include "voxels/VoxelImporter.h" +#include "voxels/VoxelPacketProcessor.h" +#include "voxels/VoxelSystem.h" class QAction; diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 43a1787d13..77586dd7ae 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -27,10 +27,7 @@ Hand::Hand(Avatar* owningAvatar) : HandData((AvatarData*)owningAvatar), _owningAvatar(owningAvatar), - _renderAlpha(1.0), - _collisionCenter(0,0,0), - _collisionAge(0), - _collisionDuration(0) + _renderAlpha(1.0) { } @@ -42,10 +39,6 @@ void Hand::reset() { void Hand::simulate(float deltaTime, bool isMine) { - if (_collisionAge > 0.f) { - _collisionAge += deltaTime; - } - calculateGeometry(); if (isMine) { @@ -222,26 +215,6 @@ void Hand::collideAgainstOurself() { } } -void Hand::handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelTreeElement* voxel, float deltaTime) { - // Collision between finger and a voxel plays sound - const float LOWEST_FREQUENCY = 100.f; - const float HERTZ_PER_RGB = 3.f; - const float DECAY_PER_SAMPLE = 0.0005f; - const float DURATION_MAX = 2.0f; - const float MIN_VOLUME = 0.1f; - float volume = MIN_VOLUME + glm::clamp(glm::length(palm->getRawVelocity()), 0.f, (1.f - MIN_VOLUME)); - float duration = volume; - _collisionCenter = fingerTipPosition; - _collisionAge = deltaTime; - _collisionDuration = duration; - int voxelBrightness = voxel->getColor()[0] + voxel->getColor()[1] + voxel->getColor()[2]; - float frequency = LOWEST_FREQUENCY + (voxelBrightness * HERTZ_PER_RGB); - Application::getInstance()->getAudio()->startDrumSound(volume, - frequency, - DURATION_MAX, - DECAY_PER_SAMPLE); -} - void Hand::calculateGeometry() { // generate finger tip balls.... _leapFingerTipBalls.clear(); @@ -312,21 +285,6 @@ void Hand::render(bool isMine) { renderLeapHands(isMine); } - if (isMine) { - // If hand/voxel collision has happened, render a little expanding sphere - if (_collisionAge > 0.f) { - float opacity = glm::clamp(1.f - (_collisionAge / _collisionDuration), 0.f, 1.f); - glColor4f(1, 0, 0, 0.5 * opacity); - glPushMatrix(); - glTranslatef(_collisionCenter.x, _collisionCenter.y, _collisionCenter.z); - glutSolidSphere(_collisionAge * 0.25f, 20, 20); - glPopMatrix(); - if (_collisionAge > _collisionDuration) { - _collisionAge = 0.f; - } - } - } - glEnable(GL_DEPTH_TEST); glEnable(GL_RESCALE_NORMAL); diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index a1b1875424..f6ee5b281f 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -22,7 +22,6 @@ #include "InterfaceConfig.h" #include "world.h" -#include "VoxelSystem.h" class Avatar; @@ -72,13 +71,6 @@ private: std::vector _leapFingerTipBalls; std::vector _leapFingerRootBalls; - glm::vec3 _lastFingerAddVoxel, _lastFingerDeleteVoxel; - VoxelDetail _collidingVoxel; - - glm::vec3 _collisionCenter; - float _collisionAge; - float _collisionDuration; - // private methods void setLeapHands(const std::vector& handPositions, const std::vector& handNormals); @@ -88,8 +80,6 @@ private: void calculateGeometry(); - void handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelTreeElement* voxel, float deltaTime); - void playSlaps(PalmData& palm, Avatar* avatar); }; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index a6a7f22896..5a1cefaa87 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -26,7 +26,6 @@ #include "Menu.h" #include "MyAvatar.h" #include "Physics.h" -#include "VoxelSystem.h" #include "devices/Faceshift.h" #include "devices/OculusManager.h" #include "ui/TextRenderer.h" diff --git a/interface/src/ui/overlays/LocalVoxelsOverlay.cpp b/interface/src/ui/overlays/LocalVoxelsOverlay.cpp index 7eaf9ed5c5..460f4eadb6 100644 --- a/interface/src/ui/overlays/LocalVoxelsOverlay.cpp +++ b/interface/src/ui/overlays/LocalVoxelsOverlay.cpp @@ -12,10 +12,10 @@ #include #include -#include #include #include "LocalVoxelsOverlay.h" +#include "voxels/VoxelSystem.h" QMap LocalVoxelsOverlay::_voxelSystemMap; diff --git a/interface/src/PrimitiveRenderer.cpp b/interface/src/voxels/PrimitiveRenderer.cpp similarity index 100% rename from interface/src/PrimitiveRenderer.cpp rename to interface/src/voxels/PrimitiveRenderer.cpp diff --git a/interface/src/PrimitiveRenderer.h b/interface/src/voxels/PrimitiveRenderer.h similarity index 100% rename from interface/src/PrimitiveRenderer.h rename to interface/src/voxels/PrimitiveRenderer.h diff --git a/interface/src/VoxelFade.cpp b/interface/src/voxels/VoxelFade.cpp similarity index 100% rename from interface/src/VoxelFade.cpp rename to interface/src/voxels/VoxelFade.cpp diff --git a/interface/src/VoxelFade.h b/interface/src/voxels/VoxelFade.h similarity index 100% rename from interface/src/VoxelFade.h rename to interface/src/voxels/VoxelFade.h diff --git a/interface/src/VoxelHideShowThread.cpp b/interface/src/voxels/VoxelHideShowThread.cpp similarity index 100% rename from interface/src/VoxelHideShowThread.cpp rename to interface/src/voxels/VoxelHideShowThread.cpp diff --git a/interface/src/VoxelHideShowThread.h b/interface/src/voxels/VoxelHideShowThread.h similarity index 100% rename from interface/src/VoxelHideShowThread.h rename to interface/src/voxels/VoxelHideShowThread.h diff --git a/interface/src/VoxelImporter.cpp b/interface/src/voxels/VoxelImporter.cpp similarity index 97% rename from interface/src/VoxelImporter.cpp rename to interface/src/voxels/VoxelImporter.cpp index 9d8b8ad811..d3c1b259ae 100644 --- a/interface/src/VoxelImporter.cpp +++ b/interface/src/voxels/VoxelImporter.cpp @@ -6,13 +6,17 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -#include -#include -#include +// include this before QGLWidget, which includes an earlier version of OpenGL +#include "InterfaceConfig.h" #include #include +#include +#include + +#include "voxels/VoxelImporter.h" + const QString SETTINGS_GROUP_NAME = "VoxelImport"; const QString IMPORT_DIALOG_SETTINGS_KEY = "ImportDialogSettings"; diff --git a/interface/src/VoxelImporter.h b/interface/src/voxels/VoxelImporter.h similarity index 96% rename from interface/src/VoxelImporter.h rename to interface/src/voxels/VoxelImporter.h index e3e5a1370c..9ebfc2eef2 100644 --- a/interface/src/VoxelImporter.h +++ b/interface/src/voxels/VoxelImporter.h @@ -12,9 +12,8 @@ #include #include -#include - #include "ui/ImportDialog.h" +#include "voxels/VoxelSystem.h" class ImportTask; diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/voxels/VoxelPacketProcessor.cpp similarity index 100% rename from interface/src/VoxelPacketProcessor.cpp rename to interface/src/voxels/VoxelPacketProcessor.cpp diff --git a/interface/src/VoxelPacketProcessor.h b/interface/src/voxels/VoxelPacketProcessor.h similarity index 100% rename from interface/src/VoxelPacketProcessor.h rename to interface/src/voxels/VoxelPacketProcessor.h diff --git a/interface/src/VoxelSystem.cpp b/interface/src/voxels/VoxelSystem.cpp similarity index 100% rename from interface/src/VoxelSystem.cpp rename to interface/src/voxels/VoxelSystem.cpp diff --git a/interface/src/VoxelSystem.h b/interface/src/voxels/VoxelSystem.h similarity index 100% rename from interface/src/VoxelSystem.h rename to interface/src/voxels/VoxelSystem.h From 938959a9f631f2b41e3c4a08a1cdfde410319201 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 22 Mar 2014 21:20:35 -0700 Subject: [PATCH 44/84] expose application settings to JS --- interface/src/Application.cpp | 2 ++ interface/src/Application.h | 7 +++- interface/src/Menu.cpp | 15 ++++++-- .../scripting/SettingsScriptingInterface.cpp | 36 +++++++++++++++++++ .../scripting/SettingsScriptingInterface.h | 30 ++++++++++++++++ interface/src/ui/InfoView.cpp | 11 +++--- 6 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 interface/src/scripting/SettingsScriptingInterface.cpp create mode 100644 interface/src/scripting/SettingsScriptingInterface.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 91509386e4..8a8a1961ec 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -74,6 +74,7 @@ #include "scripting/ClipboardScriptingInterface.h" #include "scripting/MenuScriptingInterface.h" +#include "scripting/SettingsScriptingInterface.h" #include "ui/InfoView.h" #include "ui/Snapshot.h" @@ -3550,6 +3551,7 @@ void Application::loadScript(const QString& fileNameString) { scriptEngine->registerGlobalObject("Overlays", &_overlays); scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance()); + scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance()); QThread* workerThread = new QThread(this); diff --git a/interface/src/Application.h b/interface/src/Application.h index a796a700bb..10a7a6375b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -171,7 +171,11 @@ public: Visage* getVisage() { return &_visage; } SixenseManager* getSixenseManager() { return &_sixenseManager; } BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; } - QSettings* getSettings() { return _settings; } + + /// if you need to access the application settings, use lockSettings()/unlockSettings() + QSettings* lockSettings() { _settingsMutex.lock(); return _settings; } + void unlockSettings() { _settingsMutex.unlock(); } + QMainWindow* getWindow() { return _window; } NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; } void lockOctreeSceneStats() { _octreeSceneStatsLock.lockForRead(); } @@ -352,6 +356,7 @@ private: DatagramProcessor _datagramProcessor; QNetworkAccessManager* _networkAccessManager; + QMutex _settingsMutex; QSettings* _settings; glm::vec3 _gravity; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index e0ed6aa055..6eb03021b3 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -374,8 +374,10 @@ Menu::~Menu() { } void Menu::loadSettings(QSettings* settings) { + bool lockedSettings = false; if (!settings) { - settings = Application::getInstance()->getSettings(); + settings = Application::getInstance()->lockSettings(); + lockedSettings = true; } _audioJitterBufferSamples = loadSetting(settings, "audioJitterBufferSamples", 0); @@ -404,11 +406,17 @@ void Menu::loadSettings(QSettings* settings) { // TODO: cache more settings in MyAvatar that are checked with very high frequency. MyAvatar* myAvatar = Application::getInstance()->getAvatar(); myAvatar->updateCollisionFlags(); + + if (lockedSettings) { + Application::getInstance()->unlockSettings(); + } } void Menu::saveSettings(QSettings* settings) { + bool lockedSettings = false; if (!settings) { - settings = Application::getInstance()->getSettings(); + settings = Application::getInstance()->lockSettings(); + lockedSettings = true; } settings->setValue("audioJitterBufferSamples", _audioJitterBufferSamples); @@ -430,6 +438,9 @@ void Menu::saveSettings(QSettings* settings) { Application::getInstance()->getAvatar()->saveData(settings); NodeList::getInstance()->saveData(settings); + if (lockedSettings) { + Application::getInstance()->unlockSettings(); + } } void Menu::importSettings() { diff --git a/interface/src/scripting/SettingsScriptingInterface.cpp b/interface/src/scripting/SettingsScriptingInterface.cpp new file mode 100644 index 0000000000..2a788c2776 --- /dev/null +++ b/interface/src/scripting/SettingsScriptingInterface.cpp @@ -0,0 +1,36 @@ +// +// SettingsScriptingInterface.cpp +// hifi +// +// Created by Brad Hefta-Gaub on 2/25/14 +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// + +#include "Application.h" +#include "SettingsScriptingInterface.h" + + +SettingsScriptingInterface* SettingsScriptingInterface::getInstance() { + static SettingsScriptingInterface sharedInstance; + return &sharedInstance; +} + +QVariant SettingsScriptingInterface::getValue(const QString& setting) { + QSettings* settings = Application::getInstance()->lockSettings(); + QVariant value = settings->value(setting); + Application::getInstance()->unlockSettings(); + return value; +} + +QVariant SettingsScriptingInterface::getValue(const QString& setting, const QVariant& defaultValue) { + QSettings* settings = Application::getInstance()->lockSettings(); + QVariant value = settings->value(setting, defaultValue); + Application::getInstance()->unlockSettings(); + return value; +} + +void SettingsScriptingInterface::setValue(const QString& setting, const QVariant& value) { + QSettings* settings = Application::getInstance()->lockSettings(); + settings->setValue(setting, value); + Application::getInstance()->unlockSettings(); +} diff --git a/interface/src/scripting/SettingsScriptingInterface.h b/interface/src/scripting/SettingsScriptingInterface.h new file mode 100644 index 0000000000..12bda2173f --- /dev/null +++ b/interface/src/scripting/SettingsScriptingInterface.h @@ -0,0 +1,30 @@ +// +// SettingsScriptingInterface.h +// hifi +// +// Created by Brad Hefta-Gaub on 3/22/14 +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// + +#ifndef __hifi__SettingsScriptingInterface__ +#define __hifi__SettingsScriptingInterface__ + +#include +#include +#include + +#include "Application.h" + +class SettingsScriptingInterface : public QObject { + Q_OBJECT + SettingsScriptingInterface() { }; +public: + static SettingsScriptingInterface* getInstance(); + +public slots: + QVariant getValue(const QString& setting); + QVariant getValue(const QString& setting, const QVariant& defaultValue); + void setValue(const QString& setting, const QVariant& value); +}; + +#endif /* defined(__hifi__SettingsScriptingInterface__) */ diff --git a/interface/src/ui/InfoView.cpp b/interface/src/ui/InfoView.cpp index fbf63666d8..8ed4da254c 100644 --- a/interface/src/ui/InfoView.cpp +++ b/interface/src/ui/InfoView.cpp @@ -38,11 +38,12 @@ void InfoView::forcedShow() { } bool InfoView::shouldShow() { + bool shouldShow = false; if (_forced) { return true; } - QSettings* settings = Application::getInstance()->getSettings(); + QSettings* settings = Application::getInstance()->lockSettings(); QString lastVersion = settings->value(SETTINGS_VERSION_KEY).toString(); @@ -51,10 +52,12 @@ bool InfoView::shouldShow() { if (version != QString::null && (lastVersion == QString::null || lastVersion != version)) { settings->setValue(SETTINGS_VERSION_KEY, version); - return true; + shouldShow = true; } else { - return false; - } + shouldShow = false; + } + Application::getInstance()->unlockSettings(); + return shouldShow; } void InfoView::loaded(bool ok) { From 82d620b1d9b6cc9c97d200c4d75de92950e49de1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 23 Mar 2014 11:26:27 -0700 Subject: [PATCH 45/84] add support for AudioDevice scripting interface, and switching audio input/output device on the fly --- interface/src/Application.cpp | 2 + interface/src/Audio.cpp | 123 ++++++++++++++---- interface/src/Audio.h | 13 +- .../AudioDeviceScriptingInterface.cpp | 44 +++++++ .../scripting/AudioDeviceScriptingInterface.h | 31 +++++ 5 files changed, 190 insertions(+), 23 deletions(-) create mode 100644 interface/src/scripting/AudioDeviceScriptingInterface.cpp create mode 100644 interface/src/scripting/AudioDeviceScriptingInterface.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8a8a1961ec..966f4eb2ea 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -72,6 +72,7 @@ #include "devices/TV3DManager.h" #include "renderer/ProgramObject.h" +#include "scripting/AudioDeviceScriptingInterface.h" #include "scripting/ClipboardScriptingInterface.h" #include "scripting/MenuScriptingInterface.h" #include "scripting/SettingsScriptingInterface.h" @@ -3552,6 +3553,7 @@ void Application::loadScript(const QString& fileNameString) { scriptEngine->registerGlobalObject("Overlays", &_overlays); scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance()); + scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance()); QThread* workerThread = new QThread(this); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index b684cec46e..44432fcc94 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -92,6 +92,16 @@ void Audio::reset() { _ringBuffer.reset(); } +QAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& deviceName) { + QAudioDeviceInfo result; + foreach(QAudioDeviceInfo audioDevice, QAudioDeviceInfo::availableDevices(mode)) { + if (audioDevice.deviceName().trimmed() == deviceName.trimmed()) { + result = audioDevice; + } + } + return result; +} + QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { #ifdef __APPLE__ if (QAudioDeviceInfo::availableDevices(mode).size() > 1) { @@ -249,27 +259,92 @@ void Audio::start() { _desiredOutputFormat.setChannelCount(2); QAudioDeviceInfo inputDeviceInfo = defaultAudioDeviceForMode(QAudio::AudioInput); - qDebug() << "The audio input device is" << inputDeviceInfo.deviceName(); + qDebug() << "The default audio input device is" << inputDeviceInfo.deviceName(); + bool inputFormatSupported = switchInputToAudioDevice(inputDeviceInfo.deviceName()); + + QAudioDeviceInfo outputDeviceInfo = defaultAudioDeviceForMode(QAudio::AudioOutput); + qDebug() << "The default audio output device is" << outputDeviceInfo.deviceName(); + bool outputFormatSupported = switchOutputToAudioDevice(outputDeviceInfo.deviceName()); - if (adjustedFormatForAudioDevice(inputDeviceInfo, _desiredInputFormat, _inputFormat)) { - qDebug() << "The format to be used for audio input is" << _inputFormat; + if (!inputFormatSupported || !outputFormatSupported) { + qDebug() << "Unable to set up audio I/O because of a problem with input or output formats."; + } +} + +bool Audio::switchInputToAudioDevice(const QString& inputDeviceName) { + bool supportedFormat = false; + + // cleanup any previously initialized device + if (_audioInput) { + _audioInput->stop(); + disconnect(_inputDevice, 0, 0, 0); + _inputDevice = NULL; + + delete _audioInput; + _audioInput = NULL; + _numInputCallbackBytes = 0; + + _inputAudioDeviceName = ""; + } + + QAudioDeviceInfo inputDeviceInfo = getNamedAudioDeviceForMode(QAudio::AudioInput, inputDeviceName); + + if (!inputDeviceInfo.isNull()) { + qDebug() << "The audio input device " << inputDeviceInfo.deviceName() << "is available."; + _inputAudioDeviceName = inputDeviceInfo.deviceName().trimmed(); + + if (adjustedFormatForAudioDevice(inputDeviceInfo, _desiredInputFormat, _inputFormat)) { + qDebug() << "The format to be used for audio input is" << _inputFormat; - _audioInput = new QAudioInput(inputDeviceInfo, _inputFormat, this); - _numInputCallbackBytes = NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL * _inputFormat.channelCount() - * (_inputFormat.sampleRate() / SAMPLE_RATE) - / CALLBACK_ACCELERATOR_RATIO; - _audioInput->setBufferSize(_numInputCallbackBytes); + _audioInput = new QAudioInput(inputDeviceInfo, _inputFormat, this); + _numInputCallbackBytes = NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL * _inputFormat.channelCount() + * (_inputFormat.sampleRate() / SAMPLE_RATE) + / CALLBACK_ACCELERATOR_RATIO; + _audioInput->setBufferSize(_numInputCallbackBytes); - QAudioDeviceInfo outputDeviceInfo = defaultAudioDeviceForMode(QAudio::AudioOutput); - qDebug() << "The audio output device is" << outputDeviceInfo.deviceName(); - - if (adjustedFormatForAudioDevice(outputDeviceInfo, _desiredOutputFormat, _outputFormat)) { - qDebug() << "The format to be used for audio output is" << _outputFormat; - + // how do we want to handle input working, but output not working? _inputRingBuffer.resizeForFrameSize(_numInputCallbackBytes * CALLBACK_ACCELERATOR_RATIO / sizeof(int16_t)); _inputDevice = _audioInput->start(); connect(_inputDevice, SIGNAL(readyRead()), this, SLOT(handleAudioInput())); + supportedFormat = true; + } + } + return supportedFormat; +} + +bool Audio::switchOutputToAudioDevice(const QString& outputDeviceName) { + bool supportedFormat = false; + + // cleanup any previously initialized device + if (_audioOutput) { + _audioOutput->stop(); + disconnect(_outputDevice, 0, 0, 0); + _outputDevice = NULL; + + delete _audioOutput; + _audioOutput = NULL; + _numInputCallbackBytes = 0; + + _loopbackOutputDevice = NULL; + delete _loopbackAudioOutput; + _loopbackAudioOutput = NULL; + + _proceduralOutputDevice = NULL; + delete _proceduralAudioOutput; + _proceduralAudioOutput = NULL; + _outputAudioDeviceName = ""; + } + + QAudioDeviceInfo outputDeviceInfo = getNamedAudioDeviceForMode(QAudio::AudioOutput, outputDeviceName); + + if (!outputDeviceInfo.isNull()) { + qDebug() << "The audio output device " << outputDeviceInfo.deviceName() << "is available."; + _outputAudioDeviceName = outputDeviceInfo.deviceName().trimmed(); + + if (adjustedFormatForAudioDevice(outputDeviceInfo, _desiredOutputFormat, _outputFormat)) { + qDebug() << "The format to be used for audio output is" << _outputFormat; + // setup our general output device for audio-mixer audio _audioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this); _audioOutput->setBufferSize(_ringBuffer.getSampleCapacity() * sizeof(int16_t)); @@ -278,17 +353,15 @@ void Audio::start() { // setup a loopback audio output device _loopbackAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this); - + // setup a procedural audio output device _proceduralAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this); gettimeofday(&_lastReceiveTime, NULL); + supportedFormat = true; } - - return; } - - qDebug() << "Unable to set up audio I/O because of a problem with input or output formats."; + return supportedFormat; } void Audio::handleAudioInput() { @@ -315,7 +388,9 @@ void Audio::handleAudioInput() { } if (_inputFormat == _outputFormat) { - _loopbackOutputDevice->write(inputByteArray); + if (_loopbackOutputDevice) { + _loopbackOutputDevice->write(inputByteArray); + } } else { static float loopbackOutputToInputRatio = (_outputFormat.sampleRate() / (float) _inputFormat.sampleRate()) * (_outputFormat.channelCount() / _inputFormat.channelCount()); @@ -326,7 +401,9 @@ void Audio::handleAudioInput() { inputByteArray.size() / sizeof(int16_t), loopBackByteArray.size() / sizeof(int16_t), _inputFormat, _outputFormat); - _loopbackOutputDevice->write(loopBackByteArray); + if (_loopbackOutputDevice) { + _loopbackOutputDevice->write(loopBackByteArray); + } } } @@ -469,7 +546,9 @@ void Audio::handleAudioInput() { NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 4, _desiredInputFormat, _outputFormat); - _proceduralOutputDevice->write(proceduralOutput); + if (_proceduralOutputDevice) { + _proceduralOutputDevice->write(proceduralOutput); + } NodeList* nodeList = NodeList::getInstance(); SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 6c2fbab204..0b986cc935 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -72,7 +72,7 @@ public: int getNetworkSampleRate() { return SAMPLE_RATE; } int getNetworkBufferLengthSamplesPerChannel() { return NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; } - + public slots: void start(); void addReceivedAudioToBuffer(const QByteArray& audioByteArray); @@ -83,10 +83,18 @@ public slots: virtual void handleAudioByteArray(const QByteArray& audioByteArray); + bool switchInputToAudioDevice(const QString& inputDeviceName); + bool switchOutputToAudioDevice(const QString& outputDeviceName); + + QString getInputAudioDeviceName() const { return _inputAudioDeviceName; } + QString getOutputAudioDeviceName() const { return _outputAudioDeviceName; } + + signals: bool muteToggled(); private: + QByteArray firstInputFrame; QAudioInput* _audioInput; QAudioFormat _desiredInputFormat; @@ -105,6 +113,9 @@ private: QIODevice* _proceduralOutputDevice; AudioRingBuffer _inputRingBuffer; AudioRingBuffer _ringBuffer; + + QString _inputAudioDeviceName; + QString _outputAudioDeviceName; Oscilloscope* _scope; StDev _stdev; diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.cpp b/interface/src/scripting/AudioDeviceScriptingInterface.cpp new file mode 100644 index 0000000000..1d147a4a0c --- /dev/null +++ b/interface/src/scripting/AudioDeviceScriptingInterface.cpp @@ -0,0 +1,44 @@ +// +// AudioDeviceScriptingInterface.cpp +// hifi +// +// Created by Brad Hefta-Gaub on 3/23/14 +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// + +#include "Application.h" +#include "AudioDeviceScriptingInterface.h" + + +AudioDeviceScriptingInterface* AudioDeviceScriptingInterface::getInstance() { + static AudioDeviceScriptingInterface sharedInstance; + return &sharedInstance; +} + +bool AudioDeviceScriptingInterface::setInputDevice(const QString& deviceName) { + bool result; + QMetaObject::invokeMethod(Application::getInstance()->getAudio(), "switchInputToAudioDevice", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, result), + Q_ARG(const QString&, deviceName)); + + return result; +} + +bool AudioDeviceScriptingInterface::setOutputDevice(const QString& deviceName) { + bool result; + QMetaObject::invokeMethod(Application::getInstance()->getAudio(), "switchOutputToAudioDevice", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, result), + Q_ARG(const QString&, deviceName)); + + return result; +} + +QString AudioDeviceScriptingInterface::getInputDevice() { + return Application::getInstance()->getAudio()->getInputAudioDeviceName(); +} + +QString AudioDeviceScriptingInterface::getOutputDevice() { + return Application::getInstance()->getAudio()->getOutputAudioDeviceName(); +} diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.h b/interface/src/scripting/AudioDeviceScriptingInterface.h new file mode 100644 index 0000000000..a4352d9758 --- /dev/null +++ b/interface/src/scripting/AudioDeviceScriptingInterface.h @@ -0,0 +1,31 @@ +// +// AudioDeviceScriptingInterface.h +// hifi +// +// Created by Brad Hefta-Gaub on 3/22/14 +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// + +#ifndef __hifi__AudioDeviceScriptingInterface__ +#define __hifi__AudioDeviceScriptingInterface__ + +#include +#include +#include + +#include "Application.h" + +class AudioDeviceScriptingInterface : public QObject { + Q_OBJECT + AudioDeviceScriptingInterface() { }; +public: + static AudioDeviceScriptingInterface* getInstance(); + +public slots: + bool setInputDevice(const QString& deviceName); + bool setOutputDevice(const QString& deviceName); + QString getInputDevice(); + QString getOutputDevice(); +}; + +#endif /* defined(__hifi__AudioDeviceScriptingInterface__) */ From 55b844ed6a9ed0ebff4c178abe6eb61e5c93c064 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 23 Mar 2014 11:27:06 -0700 Subject: [PATCH 46/84] add sample scripts --- examples/audioDeviceExample.js | 22 ++++++++++++++++++++++ examples/settingsExample.js | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 examples/audioDeviceExample.js create mode 100644 examples/settingsExample.js diff --git a/examples/audioDeviceExample.js b/examples/audioDeviceExample.js new file mode 100644 index 0000000000..2565e17524 --- /dev/null +++ b/examples/audioDeviceExample.js @@ -0,0 +1,22 @@ +// +// audioDeviceExample.js +// hifi +// +// Created by Brad Hefta-Gaub on 3/22/14 +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// +// This is an example script that demonstrates use of the Menu object +// + + + + +print("Audio Input Device: " + AudioDevice.getInputDevice()); +AudioDevice.setInputDevice("Shure Digital"); +print("Audio Input Device: " + AudioDevice.getInputDevice()); + +print("Audio Output Device: " + AudioDevice.getOutputDevice()); +AudioDevice.setOutputDevice("Shure Digital"); +print("Audio Output Device: " + AudioDevice.getOutputDevice()); + +Script.stop(); \ No newline at end of file diff --git a/examples/settingsExample.js b/examples/settingsExample.js new file mode 100644 index 0000000000..0dcc5482b6 --- /dev/null +++ b/examples/settingsExample.js @@ -0,0 +1,18 @@ +// +// settingsExample.js +// hifi +// +// Created by Brad Hefta-Gaub on 3/22/14 +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// +// This is an example script that demonstrates use of the Menu object +// + + + + +print("mySetting: " + Settings.getValue("mySetting")); +Settings.setValue("mySetting", "spam"); +print("mySetting: " + Settings.getValue("mySetting")); + +Script.stop(); \ No newline at end of file From 9c7ffffbaefdfbe198b999cd246544995d668985 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 20 Mar 2014 21:55:08 -0700 Subject: [PATCH 47/84] fix some windows issues Conflicts: assignment-client/src/audio/AudioMixer.cpp --- assignment-client/src/audio/AudioMixer.cpp | 4 ++-- assignment-client/src/main.cpp | 4 +++- assignment-client/src/octree/OctreeServer.cpp | 2 ++ domain-server/src/main.cpp | 10 ++++++---- libraries/shared/src/Logging.cpp | 3 ++- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index f3b623bac2..769eb29342 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -382,8 +382,8 @@ void AudioMixer::run() { } const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; - const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; - const float CUTOFF_DELTA = 0.02f; + const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.30f; + const float CUTOFF_EPSILON = 0.0001f; const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 7ee0ea9e14..0151f93319 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -15,8 +15,10 @@ int main(int argc, char* argv[]) { +#ifndef WIN32 setvbuf(stdout, NULL, _IOLBF, 0); - +#endif + // use the verbose message handler in Logging qInstallMessageHandler(Logging::verboseMessageHandler); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 496f9af1a0..d4dfa80724 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -880,7 +880,9 @@ void OctreeServer::run() { // we need to ask the DS about agents so we can ping/reply with them nodeList->addNodeTypeToInterestSet(NodeType::Agent); +#ifndef WIN32 setvbuf(stdout, NULL, _IOLBF, 0); +#endif nodeList->linkedDataCreateCallback = &OctreeServer::attachQueryNodeToNode; diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 1d9f554237..f18bb05c64 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -20,11 +20,13 @@ int main(int argc, char* argv[]) { +#ifndef WIN32 setvbuf(stdout, NULL, _IOLBF, 0); - - qInstallMessageHandler(Logging::verboseMessageHandler); - - DomainServer domainServer(argc, argv); +#endif + + qInstallMessageHandler(Logging::verboseMessageHandler); + + DomainServer domainServer(argc, argv); return domainServer.exec(); } diff --git a/libraries/shared/src/Logging.cpp b/libraries/shared/src/Logging.cpp index 1713382fcf..1fa4052569 100644 --- a/libraries/shared/src/Logging.cpp +++ b/libraries/shared/src/Logging.cpp @@ -86,7 +86,8 @@ const char* stringForLogType(QtMsgType msgType) { } // the following will produce 2000-10-02 13:55:36 -0700 -const char DATE_STRING_FORMAT[] = "%F %H:%M:%S %z"; +const char DATE_STRING_FORMAT[] = "%Y-%m-%d %H:%M:%S %z"; +//const char DATE_STRING_FORMAT[] = "%F %H:%M:%S %z"; void Logging::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { if (message.isEmpty()) { From d962387c75e9fba84e54332e731f7e99d896b50d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 23 Mar 2014 18:11:40 -0700 Subject: [PATCH 48/84] revert --- assignment-client/src/audio/AudioMixer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 769eb29342..d73a730b01 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -382,8 +382,8 @@ void AudioMixer::run() { } const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; - const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.30f; - const float CUTOFF_EPSILON = 0.0001f; + const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; + const float CUTOFF_EPSILON = 0.02f; const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; From d63acfc46f2ece206233fa6a5cf9199068e8de19 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 23 Mar 2014 18:12:02 -0700 Subject: [PATCH 49/84] revert --- 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 d73a730b01..f3b623bac2 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -383,7 +383,7 @@ void AudioMixer::run() { const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; - const float CUTOFF_EPSILON = 0.02f; + const float CUTOFF_DELTA = 0.02f; const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; From bde2146b1b2b5c2696857a0868b1921b472d2f56 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 23 Mar 2014 18:14:36 -0700 Subject: [PATCH 50/84] whitespace cleanup --- domain-server/src/main.cpp | 5 ++--- libraries/shared/src/Logging.cpp | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index f18bb05c64..970d1dad70 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -24,9 +24,8 @@ int main(int argc, char* argv[]) { setvbuf(stdout, NULL, _IOLBF, 0); #endif - qInstallMessageHandler(Logging::verboseMessageHandler); - - DomainServer domainServer(argc, argv); + qInstallMessageHandler(Logging::verboseMessageHandler); + DomainServer domainServer(argc, argv); return domainServer.exec(); } diff --git a/libraries/shared/src/Logging.cpp b/libraries/shared/src/Logging.cpp index 1fa4052569..f0dcd7b67b 100644 --- a/libraries/shared/src/Logging.cpp +++ b/libraries/shared/src/Logging.cpp @@ -87,7 +87,6 @@ const char* stringForLogType(QtMsgType msgType) { // the following will produce 2000-10-02 13:55:36 -0700 const char DATE_STRING_FORMAT[] = "%Y-%m-%d %H:%M:%S %z"; -//const char DATE_STRING_FORMAT[] = "%F %H:%M:%S %z"; void Logging::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { if (message.isEmpty()) { From 7ef1fe3a7453859f651e88988021f0782d7e1902 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 24 Mar 2014 09:15:03 -0700 Subject: [PATCH 51/84] add support for listing all audio devices and default device in JS --- examples/audioDeviceExample.js | 21 +++++++++++++++++++ interface/src/Audio.cpp | 13 ++++++++++++ interface/src/Audio.h | 12 ++++++----- .../AudioDeviceScriptingInterface.cpp | 20 ++++++++++++++++-- .../scripting/AudioDeviceScriptingInterface.h | 7 +++++++ libraries/script-engine/src/ScriptEngine.cpp | 1 + 6 files changed, 67 insertions(+), 7 deletions(-) diff --git a/examples/audioDeviceExample.js b/examples/audioDeviceExample.js index 2565e17524..99dee8a29a 100644 --- a/examples/audioDeviceExample.js +++ b/examples/audioDeviceExample.js @@ -10,6 +10,27 @@ +var inputDevices = AudioDevice.getInputDevices(); +var defaultInputDevice = AudioDevice.getDefaultInputDevice(); +print("Input Devices:"); +for(var i = 0; i < inputDevices.length; i++) { + if (inputDevices[i] == defaultInputDevice) { + print(" " + inputDevices[i] + " << default"); + } else { + print(" " + inputDevices[i]); + } +} + +var outputDevices = AudioDevice.getInputDevices(); +var defaultOutputDevice = AudioDevice.getDefaultInputDevice(); +print("Output Devices:"); +for(var i = 0; i < outputDevices.length; i++) { + if (outputDevices[i] == defaultOutputDevice) { + print(" " + outputDevices[i] + " << default"); + } else { + print(" " + outputDevices[i]); + } +} print("Audio Input Device: " + AudioDevice.getInputDevice()); AudioDevice.setInputDevice("Shure Digital"); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 44432fcc94..f460b46951 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -271,6 +271,19 @@ void Audio::start() { } } +QString Audio::getDefaultDeviceName(QAudio::Mode mode) { + QAudioDeviceInfo deviceInfo = defaultAudioDeviceForMode(mode); + return deviceInfo.deviceName(); +} + +QVector Audio::getDeviceNames(QAudio::Mode mode) { + QVector deviceNames; + foreach(QAudioDeviceInfo audioDevice, QAudioDeviceInfo::availableDevices(mode)) { + deviceNames << audioDevice.deviceName().trimmed(); + } + return deviceNames; +} + bool Audio::switchInputToAudioDevice(const QString& inputDeviceName) { bool supportedFormat = false; diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 0b986cc935..6bd83d1c9c 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -19,9 +19,12 @@ #include "InterfaceConfig.h" +#include +#include #include #include #include +#include #include #include @@ -29,7 +32,6 @@ #include "ui/Oscilloscope.h" -#include static const int NUM_AUDIO_CHANNELS = 2; @@ -85,10 +87,10 @@ public slots: bool switchInputToAudioDevice(const QString& inputDeviceName); bool switchOutputToAudioDevice(const QString& outputDeviceName); - - QString getInputAudioDeviceName() const { return _inputAudioDeviceName; } - QString getOutputAudioDeviceName() const { return _outputAudioDeviceName; } - + QString getDeviceName(QAudio::Mode mode) const { return (mode == QAudio::AudioInput) ? + _inputAudioDeviceName : _outputAudioDeviceName; } + QString getDefaultDeviceName(QAudio::Mode mode); + QVector getDeviceNames(QAudio::Mode mode); signals: bool muteToggled(); diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.cpp b/interface/src/scripting/AudioDeviceScriptingInterface.cpp index 1d147a4a0c..dda0043241 100644 --- a/interface/src/scripting/AudioDeviceScriptingInterface.cpp +++ b/interface/src/scripting/AudioDeviceScriptingInterface.cpp @@ -36,9 +36,25 @@ bool AudioDeviceScriptingInterface::setOutputDevice(const QString& deviceName) { } QString AudioDeviceScriptingInterface::getInputDevice() { - return Application::getInstance()->getAudio()->getInputAudioDeviceName(); + return Application::getInstance()->getAudio()->getDeviceName(QAudio::AudioInput); } QString AudioDeviceScriptingInterface::getOutputDevice() { - return Application::getInstance()->getAudio()->getOutputAudioDeviceName(); + return Application::getInstance()->getAudio()->getDeviceName(QAudio::AudioOutput); +} + +QString AudioDeviceScriptingInterface::getDefaultInputDevice() { + return Application::getInstance()->getAudio()->getDefaultDeviceName(QAudio::AudioInput); +} + +QString AudioDeviceScriptingInterface::getDefaultOutputDevice() { + return Application::getInstance()->getAudio()->getDefaultDeviceName(QAudio::AudioOutput); +} + +QVector AudioDeviceScriptingInterface::getInputDevices() { + return Application::getInstance()->getAudio()->getDeviceNames(QAudio::AudioInput); +} + +QVector AudioDeviceScriptingInterface::getOutputDevices() { + return Application::getInstance()->getAudio()->getDeviceNames(QAudio::AudioOutput); } diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.h b/interface/src/scripting/AudioDeviceScriptingInterface.h index a4352d9758..faa48a198a 100644 --- a/interface/src/scripting/AudioDeviceScriptingInterface.h +++ b/interface/src/scripting/AudioDeviceScriptingInterface.h @@ -24,8 +24,15 @@ public: public slots: bool setInputDevice(const QString& deviceName); bool setOutputDevice(const QString& deviceName); + QString getInputDevice(); QString getOutputDevice(); + + QString getDefaultInputDevice(); + QString getDefaultOutputDevice(); + + QVector getInputDevices(); + QVector getOutputDevices(); }; #endif /* defined(__hifi__AudioDeviceScriptingInterface__) */ diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index c820347cab..38948071ff 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -144,6 +144,7 @@ void ScriptEngine::init() { qScriptRegisterMetaType(&_engine, ParticleIDtoScriptValue, ParticleIDfromScriptValue); qScriptRegisterSequenceMetaType >(&_engine); qScriptRegisterSequenceMetaType >(&_engine); + qScriptRegisterSequenceMetaType >(&_engine); QScriptValue soundConstructorValue = _engine.newFunction(soundConstructor); QScriptValue soundMetaObject = _engine.newQMetaObject(&Sound::staticMetaObject, soundConstructorValue); From 5567d9acb9157af0692e9d1f705aabd7874654b5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 09:24:13 -0700 Subject: [PATCH 52/84] change audio-mixer struggle behaviour --- assignment-client/src/audio/AudioMixer.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index f3b623bac2..9a7b96fa51 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -383,7 +383,6 @@ void AudioMixer::run() { const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; - const float CUTOFF_DELTA = 0.02f; const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; @@ -401,18 +400,14 @@ void AudioMixer::run() { if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { // we're struggling - change our min required loudness to reduce some load - audabilityCutoffRatio += CUTOFF_DELTA; - - if (audabilityCutoffRatio >= 1) { - audabilityCutoffRatio = 1 - CUTOFF_DELTA; - } + audabilityCutoffRatio = audabilityCutoffRatio + (0.5f * (1.0f - audabilityCutoffRatio)); qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" << lastCutoffRatio << "and is now" << audabilityCutoffRatio; hasRatioChanged = true; } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && audabilityCutoffRatio != 0) { // we've recovered and can back off the required loudness - audabilityCutoffRatio -= CUTOFF_DELTA; + audabilityCutoffRatio = audabilityCutoffRatio - (1.0f - audabilityCutoffRatio); if (audabilityCutoffRatio < 0) { audabilityCutoffRatio = 0; From d0fbf4953aa417bcd79c88b50b7f223fb6811167 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 10:27:46 -0700 Subject: [PATCH 53/84] change back off strategy, output trailing sleep --- assignment-client/src/audio/AudioMixer.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 9a7b96fa51..c8cb7a78c0 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -384,6 +384,8 @@ void AudioMixer::run() { const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; + const float RATIO_BACK_OFF = 0.02f; + const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; @@ -398,6 +400,10 @@ void AudioMixer::run() { bool hasRatioChanged = false; if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { + if (framesSinceCutoffEvent % TRAILING_AVERAGE_FRAMES == 0) { + qDebug() << "Current trailing sleep ratio:" << _trailingSleepRatio; + } + if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { // we're struggling - change our min required loudness to reduce some load audabilityCutoffRatio = audabilityCutoffRatio + (0.5f * (1.0f - audabilityCutoffRatio)); @@ -407,7 +413,7 @@ void AudioMixer::run() { hasRatioChanged = true; } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && audabilityCutoffRatio != 0) { // we've recovered and can back off the required loudness - audabilityCutoffRatio = audabilityCutoffRatio - (1.0f - audabilityCutoffRatio); + audabilityCutoffRatio = audabilityCutoffRatio - RATIO_BACK_OFF; if (audabilityCutoffRatio < 0) { audabilityCutoffRatio = 0; From c0da215a603b12fd56d83e0b04027ca87dc8d054 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 10:39:10 -0700 Subject: [PATCH 54/84] correctly output trailing sleep time --- assignment-client/src/audio/AudioMixer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index c8cb7a78c0..d6e82a3889 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -431,8 +431,10 @@ void AudioMixer::run() { framesSinceCutoffEvent = 0; } - } else { - framesSinceCutoffEvent++; + } + + if (!hasRatioChanged) { + ++framesSinceCutoffEvent; } foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { From 949f7b2fc15e45ff70d095ab946361a9dc518315 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 11:21:39 -0700 Subject: [PATCH 55/84] add a json stats packet type --- libraries/shared/src/PacketHeaders.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h index c6ce6bdd6b..a9bc5d3763 100644 --- a/libraries/shared/src/PacketHeaders.h +++ b/libraries/shared/src/PacketHeaders.h @@ -58,7 +58,8 @@ enum PacketType { PacketTypeAvatarIdentity, PacketTypeAvatarBillboard, PacketTypeDomainConnectRequest, - PacketTypeDomainServerAuthRequest + PacketTypeDomainServerAuthRequest, + PacketTypeNodeJsonStats }; typedef char PacketVersion; From ec10e61b8cc42257802f14a64d27823b5559573d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 11:42:04 -0700 Subject: [PATCH 56/84] add logic to domain-server to parse JSON stats --- domain-server/src/DomainServer.cpp | 5 ++++ domain-server/src/DomainServerNodeData.cpp | 35 +++++++++++++++++++++- domain-server/src/DomainServerNodeData.h | 5 ++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 216d249858..86bc557a74 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -603,6 +603,11 @@ void DomainServer::readAvailableDatagrams() { if (noisyMessage) { lastNoisyMessage = timeNow; } + } else if (requestType == PacketTypeNodeJsonStats) { + SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket); + if (matchingNode) { + reinterpret_cast(matchingNode->getLinkedData())->parseJSONStatsPacket(receivedPacket); + } } } } diff --git a/domain-server/src/DomainServerNodeData.cpp b/domain-server/src/DomainServerNodeData.cpp index 2e32903712..4f943c85db 100644 --- a/domain-server/src/DomainServerNodeData.cpp +++ b/domain-server/src/DomainServerNodeData.cpp @@ -6,11 +6,44 @@ // Copyright (c) 2014 HighFidelity, Inc. All rights reserved. // +#include +#include +#include + +#include + #include "DomainServerNodeData.h" DomainServerNodeData::DomainServerNodeData() : _sessionSecretHash(), - _staticAssignmentUUID() + _staticAssignmentUUID(), + _statsJSONObject() { +} + +void DomainServerNodeData::parseJSONStatsPacket(const QByteArray& statsPacket) { + // push past the packet header + QDataStream packetStream(statsPacket); + packetStream.skipRawData(numBytesForPacketHeader(statsPacket)); + + QVariantMap unpackedVariantMap; + + packetStream >> unpackedVariantMap; + + QJsonObject unpackedStatsJSON = QJsonObject::fromVariantMap(unpackedVariantMap); + _statsJSONObject = mergeJSONStatsFromNewObject(unpackedStatsJSON, _statsJSONObject); +} + + +QJsonObject DomainServerNodeData::mergeJSONStatsFromNewObject(const QJsonObject& newObject, QJsonObject destinationObject) { + foreach(const QString& key, newObject.keys()) { + if (newObject[key].isObject() && destinationObject.contains(key)) { + destinationObject[key] = mergeJSONStatsFromNewObject(newObject[key].toObject(), destinationObject[key].toObject()); + } else { + destinationObject[key] = newObject[key]; + } + } + + return destinationObject; } \ No newline at end of file diff --git a/domain-server/src/DomainServerNodeData.h b/domain-server/src/DomainServerNodeData.h index 6686b9120f..8035147bef 100644 --- a/domain-server/src/DomainServerNodeData.h +++ b/domain-server/src/DomainServerNodeData.h @@ -19,13 +19,18 @@ public: DomainServerNodeData(); int parseData(const QByteArray& packet) { return 0; } + void parseJSONStatsPacket(const QByteArray& statsPacket); + void setStaticAssignmentUUID(const QUuid& staticAssignmentUUID) { _staticAssignmentUUID = staticAssignmentUUID; } const QUuid& getStaticAssignmentUUID() const { return _staticAssignmentUUID; } QHash& getSessionSecretHash() { return _sessionSecretHash; } private: + QJsonObject mergeJSONStatsFromNewObject(const QJsonObject& newObject, QJsonObject destinationObject); + QHash _sessionSecretHash; QUuid _staticAssignmentUUID; + QJsonObject _statsJSONObject; }; #endif /* defined(__hifi__DomainServerNodeData__) */ From 8f403609e7cb2bbf5234ef069fd156577fbf6d68 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 11:56:16 -0700 Subject: [PATCH 57/84] hook JSON stats sending from domain-server --- assignment-client/src/audio/AudioMixer.cpp | 20 ++++++++++++++++++++ assignment-client/src/audio/AudioMixer.h | 2 ++ domain-server/src/DomainServerNodeData.cpp | 1 - libraries/shared/src/NodeList.cpp | 4 ++++ libraries/shared/src/NodeList.h | 1 + 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index d6e82a3889..8412295bae 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -349,11 +350,30 @@ void AudioMixer::readPendingDatagrams() { } } +void AudioMixer::sendStatsPacket() { + static QJsonObject statsObject; + statsObject["trailing_sleep"] = _trailingSleepRatio; + statsObject["min_audability_threshold"] = _minAudibilityThreshold; + + QByteArray statsPacket = byteArrayWithPopulatedHeader(PacketTypeNodeJsonStats); + QDataStream statsPacketStream(&statsPacket, QIODevice::Append); + + statsPacketStream << statsObject.toVariantMap(); + + NodeList* nodeList = NodeList::getInstance(); + nodeList->sendDatagramToDomainServer(statsPacket); +} + void AudioMixer::run() { commonInit(AUDIO_MIXER_LOGGING_TARGET_NAME, NodeType::AudioMixer); NodeList* nodeList = NodeList::getInstance(); + + // send a stats packet every 1 second + QTimer* statsTimer = new QTimer(this); + connect(statsTimer, SIGNAL(timeout()), this, SLOT(sendStatsPacket())); + statsTimer->start(1000); nodeList->addNodeTypeToInterestSet(NodeType::Agent); diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 9d731a5c9c..0f88701303 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -28,6 +28,8 @@ public slots: void run(); void readPendingDatagrams(); + + void sendStatsPacket(); private: /// adds one buffer to the mix for a listening node void addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuffer* bufferToAdd, diff --git a/domain-server/src/DomainServerNodeData.cpp b/domain-server/src/DomainServerNodeData.cpp index 4f943c85db..f1e08e3bc4 100644 --- a/domain-server/src/DomainServerNodeData.cpp +++ b/domain-server/src/DomainServerNodeData.cpp @@ -35,7 +35,6 @@ void DomainServerNodeData::parseJSONStatsPacket(const QByteArray& statsPacket) { _statsJSONObject = mergeJSONStatsFromNewObject(unpackedStatsJSON, _statsJSONObject); } - QJsonObject DomainServerNodeData::mergeJSONStatsFromNewObject(const QJsonObject& newObject, QJsonObject destinationObject) { foreach(const QString& key, newObject.keys()) { if (newObject[key].isObject() && destinationObject.contains(key)) { diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 2b131ab7ff..7bbe1ce29b 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -193,6 +193,10 @@ qint64 NodeList::writeDatagram(const char* data, qint64 size, const SharedNodePo return writeDatagram(QByteArray(data, size), destinationNode, overridenSockAddr); } +qint64 NodeList::sendDatagramToDomainServer(const QByteArray &datagram) { + return writeDatagram(datagram, _domainInfo.getSockAddr(), _domainInfo.getConnectionSecret()); +} + void NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode) { QDataStream packetStream(packet); packetStream.skipRawData(numBytesForPacketHeader(packet)); diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index d6328a1303..d479e72ee7 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -78,6 +78,7 @@ public: const HifiSockAddr& overridenSockAddr = HifiSockAddr()); qint64 writeDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr = HifiSockAddr()); + qint64 sendDatagramToDomainServer(const QByteArray& datagram); void(*linkedDataCreateCallback)(Node *); From 55bc9c059d8aca31c35692c6bff75805f5b4a29f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 12:15:36 -0700 Subject: [PATCH 58/84] show stats for node at /nodes/UUID --- domain-server/resources/web/js/tables.js | 2 +- domain-server/src/DomainServer.cpp | 36 ++++++++++++++++++++---- domain-server/src/DomainServerNodeData.h | 2 ++ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/domain-server/resources/web/js/tables.js b/domain-server/resources/web/js/tables.js index d0855d7967..5080087692 100644 --- a/domain-server/resources/web/js/tables.js +++ b/domain-server/resources/web/js/tables.js @@ -42,7 +42,7 @@ $(document).ready(function(){ $(document.body).on('click', '.glyphicon-remove', function(){ // fire off a delete for this node $.ajax({ - url: "/node/" + $(this).data('uuid'), + url: "/nodes/" + $(this).data('uuid'), type: 'DELETE', success: function(result) { console.log("Succesful request to delete node."); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 86bc557a74..1b867501d2 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -655,7 +655,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& const QString JSON_MIME_TYPE = "application/json"; const QString URI_ASSIGNMENT = "/assignment"; - const QString URI_NODE = "/node"; + const QString URI_NODES = "/nodes"; if (connection->requestOperation() == QNetworkAccessManager::GetOperation) { if (path == "/assignments.json") { @@ -702,7 +702,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& // we've processed this request return true; - } else if (path == "/nodes.json") { + } else if (path == QString("%1.json").arg(URI_NODES)) { // setup the JSON QJsonObject rootJSON; QJsonObject nodesJSON; @@ -723,14 +723,36 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& // send the response connection->respond(HTTPConnection::StatusCode200, nodesDocument.toJson(), qPrintable(JSON_MIME_TYPE)); + + return true; + } else { + const QString NODE_REGEX_STRING = + QString("\\%1\\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\/?$").arg(URI_NODES); + QRegExp nodeShowRegex(NODE_REGEX_STRING); + + if (nodeShowRegex.indexIn(path) != -1) { + QUuid matchingUUID = QUuid(nodeShowRegex.cap(1)); + + // see if we have a node that matches this ID + SharedNodePointer matchingNode = NodeList::getInstance()->nodeWithUUID(matchingUUID); + if (matchingNode) { + // create a QJsonDocument with the stats QJsonObject + QJsonDocument statsDocument(reinterpret_cast(matchingNode->getLinkedData()) + ->getStatsJSONObject()); + + // send the resposne + connection->respond(HTTPConnection::StatusCode200, statsDocument.toJson(), qPrintable(JSON_MIME_TYPE)); + + // tell the caller we processed the request + return true; + } + } } } else if (connection->requestOperation() == QNetworkAccessManager::PostOperation) { if (path == URI_ASSIGNMENT) { // this is a script upload - ask the HTTPConnection to parse the form data QList formData = connection->parseFormData(); - - // check how many instances of this assignment the user wants by checking the ASSIGNMENT-INSTANCES header const QString ASSIGNMENT_INSTANCES_HEADER = "ASSIGNMENT-INSTANCES"; @@ -770,13 +792,15 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& // respond with a 200 code for successful upload connection->respond(HTTPConnection::StatusCode200); + + return true; } } else if (connection->requestOperation() == QNetworkAccessManager::DeleteOperation) { - if (path.startsWith(URI_NODE)) { + if (path.startsWith(URI_NODES)) { // this is a request to DELETE a node by UUID // pull the UUID from the url - QUuid deleteUUID = QUuid(path.mid(URI_NODE.size() + sizeof('/'))); + QUuid deleteUUID = QUuid(path.mid(URI_NODES.size() + sizeof('/'))); if (!deleteUUID.isNull()) { SharedNodePointer nodeToKill = NodeList::getInstance()->nodeWithUUID(deleteUUID); diff --git a/domain-server/src/DomainServerNodeData.h b/domain-server/src/DomainServerNodeData.h index 8035147bef..20531839f4 100644 --- a/domain-server/src/DomainServerNodeData.h +++ b/domain-server/src/DomainServerNodeData.h @@ -19,6 +19,8 @@ public: DomainServerNodeData(); int parseData(const QByteArray& packet) { return 0; } + const QJsonObject& getStatsJSONObject() const { return _statsJSONObject; } + void parseJSONStatsPacket(const QByteArray& statsPacket); void setStaticAssignmentUUID(const QUuid& staticAssignmentUUID) { _staticAssignmentUUID = staticAssignmentUUID; } From fc76103fa0e4736036d7fedc226af8cad4d6aa9d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 12:18:42 -0700 Subject: [PATCH 59/84] link to node stats page from table --- domain-server/resources/web/js/tables.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/web/js/tables.js b/domain-server/resources/web/js/tables.js index 5080087692..e32f78a63e 100644 --- a/domain-server/resources/web/js/tables.js +++ b/domain-server/resources/web/js/tables.js @@ -7,7 +7,7 @@ $(document).ready(function(){ $.each(json.nodes, function (uuid, data) { nodesTableBody += ""; nodesTableBody += "" + data.type + ""; - nodesTableBody += "" + uuid + ""; + nodesTableBody += "" + uuid + ""; nodesTableBody += "" + (data.pool ? data.pool : "") + ""; nodesTableBody += "" + data.public.ip + ":" + data.public.port + ""; nodesTableBody += "" + data.local.ip + ":" + data.local.port + ""; From 5f93e44ff7477ac3e5dce57faed954d5f263df9a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 12:33:00 -0700 Subject: [PATCH 60/84] abstract stats packet sending to NodeList --- assignment-client/src/audio/AudioMixer.cpp | 8 +------- libraries/shared/src/NodeList.cpp | 9 +++++++-- libraries/shared/src/NodeList.h | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 8412295bae..f7953cdf41 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -355,13 +355,7 @@ void AudioMixer::sendStatsPacket() { statsObject["trailing_sleep"] = _trailingSleepRatio; statsObject["min_audability_threshold"] = _minAudibilityThreshold; - QByteArray statsPacket = byteArrayWithPopulatedHeader(PacketTypeNodeJsonStats); - QDataStream statsPacketStream(&statsPacket, QIODevice::Append); - - statsPacketStream << statsObject.toVariantMap(); - - NodeList* nodeList = NodeList::getInstance(); - nodeList->sendDatagramToDomainServer(statsPacket); + NodeList::getInstance()->sendStatsToDomainServer(statsObject); } void AudioMixer::run() { diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 7bbe1ce29b..fe1466d5d1 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -193,8 +193,13 @@ qint64 NodeList::writeDatagram(const char* data, qint64 size, const SharedNodePo return writeDatagram(QByteArray(data, size), destinationNode, overridenSockAddr); } -qint64 NodeList::sendDatagramToDomainServer(const QByteArray &datagram) { - return writeDatagram(datagram, _domainInfo.getSockAddr(), _domainInfo.getConnectionSecret()); +qint64 NodeList::sendStatsToDomainServer(const QJsonObject& statsObject) { + QByteArray statsPacket = byteArrayWithPopulatedHeader(PacketTypeNodeJsonStats); + QDataStream statsPacketStream(&statsPacket, QIODevice::Append); + + statsPacketStream << statsObject.toVariantMap(); + + return writeDatagram(statsPacket, _domainInfo.getSockAddr(), _domainInfo.getConnectionSecret()); } void NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode) { diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index d479e72ee7..379db70412 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -78,7 +78,7 @@ public: const HifiSockAddr& overridenSockAddr = HifiSockAddr()); qint64 writeDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr = HifiSockAddr()); - qint64 sendDatagramToDomainServer(const QByteArray& datagram); + qint64 sendStatsToDomainServer(const QJsonObject& statsObject); void(*linkedDataCreateCallback)(Node *); From da763671faf80bc356fee252b11c4342bab6e6e3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 24 Mar 2014 12:52:34 -0700 Subject: [PATCH 61/84] fix crash when no output audio device selected, add get/set volume support for input devices --- interface/src/Audio.cpp | 6 +++--- interface/src/Audio.h | 4 ++++ .../src/scripting/AudioDeviceScriptingInterface.cpp | 9 +++++++++ interface/src/scripting/AudioDeviceScriptingInterface.h | 3 +++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index f460b46951..734b5345fb 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -395,7 +395,7 @@ void Audio::handleAudioInput() { if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio) && !_muted) { // if this person wants local loopback add that to the locally injected audio - if (!_loopbackOutputDevice) { + if (!_loopbackOutputDevice && _loopbackAudioOutput) { // we didn't have the loopback output device going so set that up now _loopbackOutputDevice = _loopbackAudioOutput->start(); } @@ -545,7 +545,7 @@ void Audio::handleAudioInput() { addProceduralSounds(monoAudioSamples, NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL); - if (!_proceduralOutputDevice) { + if (!_proceduralOutputDevice && _proceduralAudioOutput) { _proceduralOutputDevice = _proceduralAudioOutput->start(); } @@ -645,7 +645,7 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { static float networkOutputToOutputRatio = (_desiredOutputFormat.sampleRate() / (float) _outputFormat.sampleRate()) * (_desiredOutputFormat.channelCount() / (float) _outputFormat.channelCount()); - if (!_ringBuffer.isStarved() && _audioOutput->bytesFree() == _audioOutput->bufferSize()) { + if (!_ringBuffer.isStarved() && _audioOutput && _audioOutput->bytesFree() == _audioOutput->bufferSize()) { // we don't have any audio data left in the output buffer // we just starved //qDebug() << "Audio output just starved."; diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 6bd83d1c9c..7aa1ef5afe 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -20,6 +20,7 @@ #include "InterfaceConfig.h" #include +#include #include #include #include @@ -92,6 +93,9 @@ public slots: QString getDefaultDeviceName(QAudio::Mode mode); QVector getDeviceNames(QAudio::Mode mode); + float getInputVolume() const { return (_audioInput) ? _audioInput->volume() : 0.0f; } + void setInputVolume(float volume) { if (_audioInput) _audioInput->setVolume(volume); } + signals: bool muteToggled(); diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.cpp b/interface/src/scripting/AudioDeviceScriptingInterface.cpp index dda0043241..a184e8a2f6 100644 --- a/interface/src/scripting/AudioDeviceScriptingInterface.cpp +++ b/interface/src/scripting/AudioDeviceScriptingInterface.cpp @@ -58,3 +58,12 @@ QVector AudioDeviceScriptingInterface::getInputDevices() { QVector AudioDeviceScriptingInterface::getOutputDevices() { return Application::getInstance()->getAudio()->getDeviceNames(QAudio::AudioOutput); } + + +float AudioDeviceScriptingInterface::getInputVolume() { + return Application::getInstance()->getAudio()->getInputVolume(); +} + +void AudioDeviceScriptingInterface::setInputVolume(float volume) { + Application::getInstance()->getAudio()->setInputVolume(volume); +} diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.h b/interface/src/scripting/AudioDeviceScriptingInterface.h index faa48a198a..adc86cb15c 100644 --- a/interface/src/scripting/AudioDeviceScriptingInterface.h +++ b/interface/src/scripting/AudioDeviceScriptingInterface.h @@ -33,6 +33,9 @@ public slots: QVector getInputDevices(); QVector getOutputDevices(); + + float getInputVolume(); + void setInputVolume(float volume); }; #endif /* defined(__hifi__AudioDeviceScriptingInterface__) */ From c623d8e9ac28878cd1d2c43d82287d97f131bb6e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 24 Mar 2014 13:07:42 -0700 Subject: [PATCH 62/84] tweak example script --- examples/audioDeviceExample.js | 41 +++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/examples/audioDeviceExample.js b/examples/audioDeviceExample.js index 99dee8a29a..1ee00a1582 100644 --- a/examples/audioDeviceExample.js +++ b/examples/audioDeviceExample.js @@ -9,8 +9,26 @@ // +var outputDevices = AudioDevice.getOutputDevices(); +var defaultOutputDevice = AudioDevice.getDefaultOutputDevice(); +var selectOutputDevice = outputDevices[0]; +print("Output Devices:"); +for(var i = 0; i < outputDevices.length; i++) { + if (outputDevices[i] == defaultOutputDevice) { + print(" " + outputDevices[i] + " << default"); + } else { + print(" " + outputDevices[i]); + } +} + +print("Default Output Device:" + defaultOutputDevice); +print("Selected Output Device:" + selectOutputDevice); +print("Current Audio Output Device: " + AudioDevice.getOutputDevice()); +AudioDevice.setOutputDevice(selectOutputDevice); +print("Audio Output Device: " + AudioDevice.getOutputDevice()); var inputDevices = AudioDevice.getInputDevices(); +var selectInputDevice = inputDevices[0]; var defaultInputDevice = AudioDevice.getDefaultInputDevice(); print("Input Devices:"); for(var i = 0; i < inputDevices.length; i++) { @@ -21,23 +39,14 @@ for(var i = 0; i < inputDevices.length; i++) { } } -var outputDevices = AudioDevice.getInputDevices(); -var defaultOutputDevice = AudioDevice.getDefaultInputDevice(); -print("Output Devices:"); -for(var i = 0; i < outputDevices.length; i++) { - if (outputDevices[i] == defaultOutputDevice) { - print(" " + outputDevices[i] + " << default"); - } else { - print(" " + outputDevices[i]); - } -} - -print("Audio Input Device: " + AudioDevice.getInputDevice()); -AudioDevice.setInputDevice("Shure Digital"); +print("Default Input Device:" + defaultInputDevice); +print("Selected Input Device:" + selectInputDevice); +print("Current Audio Input Device: " + AudioDevice.getInputDevice()); +AudioDevice.setInputDevice(selectInputDevice); print("Audio Input Device: " + AudioDevice.getInputDevice()); -print("Audio Output Device: " + AudioDevice.getOutputDevice()); -AudioDevice.setOutputDevice("Shure Digital"); -print("Audio Output Device: " + AudioDevice.getOutputDevice()); +print("Audio Input Device Level: " + AudioDevice.getInputVolume()); +AudioDevice.setInputVolume(AudioDevice.getInputVolume() * 2); // twice as loud! +print("Audio Input Device Level: " + AudioDevice.getInputVolume()); Script.stop(); \ No newline at end of file From 1fffda674a8fb65b8ef315f2a4815e61d5c31a6c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 13:14:19 -0700 Subject: [PATCH 63/84] send extra stats from audio-mixer to domain-server --- assignment-client/src/audio/AudioMixer.cpp | 42 +++++++++++++++------- assignment-client/src/audio/AudioMixer.h | 4 +++ 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index f7953cdf41..ca95fd190a 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -67,7 +67,11 @@ void attachNewBufferToNode(Node *newNode) { AudioMixer::AudioMixer(const QByteArray& packet) : ThreadedAssignment(packet), _trailingSleepRatio(1.0f), - _minAudibilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2.0f) + _minAudibilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2.0f), + _performanceThrottling(0.0f), + _numStatFrames(0), + _sumListeners(0), + _sumMixes(0) { } @@ -95,6 +99,8 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf return; } + ++_sumMixes; + glm::quat inverseOrientation = glm::inverse(listeningNodeBuffer->getOrientation()); float distanceSquareToSource = glm::dot(relativePosition, relativePosition); @@ -352,8 +358,15 @@ void AudioMixer::readPendingDatagrams() { void AudioMixer::sendStatsPacket() { static QJsonObject statsObject; - statsObject["trailing_sleep"] = _trailingSleepRatio; - statsObject["min_audability_threshold"] = _minAudibilityThreshold; + statsObject["trailing_sleep_time"] = _trailingSleepRatio; + statsObject["performance_cutoff"] = _minAudibilityThreshold; + + statsObject["average_listeners_per_frame"] = _sumListeners / (float) _numStatFrames; + statsObject["average_mixes_per_listeners"] = _sumMixes / _sumListeners / _numStatFrames; + + _sumListeners = 0; + _sumMixes = 0; + _numStatFrames = 0; NodeList::getInstance()->sendStatsToDomainServer(statsObject); } @@ -382,7 +395,6 @@ void AudioMixer::run() { + numBytesForPacketHeaderGivenPacketType(PacketTypeMixedAudio)]; int usecToSleep = BUFFER_SEND_INTERVAL_USECS; - float audabilityCutoffRatio = 0; const int TRAILING_AVERAGE_FRAMES = 100; int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; @@ -410,7 +422,7 @@ void AudioMixer::run() { _trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio) + (usecToSleep * CURRENT_FRAME_RATIO / (float) BUFFER_SEND_INTERVAL_USECS); - float lastCutoffRatio = audabilityCutoffRatio; + float lastCutoffRatio = _performanceThrottling; bool hasRatioChanged = false; if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { @@ -420,27 +432,27 @@ void AudioMixer::run() { if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { // we're struggling - change our min required loudness to reduce some load - audabilityCutoffRatio = audabilityCutoffRatio + (0.5f * (1.0f - audabilityCutoffRatio)); + _performanceThrottling = _performanceThrottling + (0.5f * (1.0f - _performanceThrottling)); qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" - << lastCutoffRatio << "and is now" << audabilityCutoffRatio; + << lastCutoffRatio << "and is now" << _performanceThrottling; hasRatioChanged = true; - } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && audabilityCutoffRatio != 0) { + } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && _performanceThrottling != 0) { // we've recovered and can back off the required loudness - audabilityCutoffRatio = audabilityCutoffRatio - RATIO_BACK_OFF; + _performanceThrottling = _performanceThrottling - RATIO_BACK_OFF; - if (audabilityCutoffRatio < 0) { - audabilityCutoffRatio = 0; + if (_performanceThrottling < 0) { + _performanceThrottling = 0; } qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" - << lastCutoffRatio << "and is now" << audabilityCutoffRatio; + << lastCutoffRatio << "and is now" << _performanceThrottling; hasRatioChanged = true; } if (hasRatioChanged) { // set out min audability threshold from the new ratio - _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - audabilityCutoffRatio)); + _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - _performanceThrottling)); qDebug() << "Minimum audability required to be mixed is now" << _minAudibilityThreshold; framesSinceCutoffEvent = 0; @@ -460,6 +472,8 @@ void AudioMixer::run() { memcpy(clientMixBuffer + numBytesPacketHeader, _clientSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO); nodeList->writeDatagram(clientMixBuffer, NETWORK_BUFFER_LENGTH_BYTES_STEREO + numBytesPacketHeader, node); + + ++_sumListeners; } } @@ -470,6 +484,8 @@ void AudioMixer::run() { } } + ++_numStatFrames; + QCoreApplication::processEvents(); if (_isFinished) { diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 0f88701303..0b1de6f069 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -44,6 +44,10 @@ private: float _trailingSleepRatio; float _minAudibilityThreshold; + float _performanceThrottling; + int _numStatFrames; + int _sumListeners; + int _sumMixes; }; #endif /* defined(__hifi__AudioMixer__) */ From 62884f1f4fca9f2e8a9f511d2fb13b036c9816ee Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 24 Mar 2014 13:15:03 -0700 Subject: [PATCH 64/84] Don't use textures/fancy shaders when rendering shadow map. Closes #2270. --- interface/interface_en.ts | 12 +-- interface/resources/shaders/model_shadow.frag | 14 ++++ interface/resources/shaders/model_shadow.vert | 14 ++++ .../resources/shaders/skin_model_shadow.vert | 27 +++++++ interface/src/Application.cpp | 4 +- interface/src/avatar/Avatar.cpp | 27 ++++--- interface/src/avatar/Avatar.h | 7 +- interface/src/avatar/AvatarManager.cpp | 14 ++-- interface/src/avatar/AvatarManager.h | 4 +- interface/src/avatar/FaceModel.cpp | 7 -- interface/src/avatar/FaceModel.h | 1 - interface/src/avatar/Head.cpp | 4 +- interface/src/avatar/Head.h | 2 +- interface/src/avatar/MyAvatar.cpp | 12 +-- interface/src/avatar/MyAvatar.h | 4 +- interface/src/avatar/SkeletonModel.cpp | 11 --- interface/src/avatar/SkeletonModel.h | 1 - interface/src/renderer/Model.cpp | 81 ++++++++++++------- interface/src/renderer/Model.h | 7 +- 19 files changed, 159 insertions(+), 94 deletions(-) create mode 100644 interface/resources/shaders/model_shadow.frag create mode 100644 interface/resources/shaders/model_shadow.vert create mode 100644 interface/resources/shaders/skin_model_shadow.vert diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 34e3614716..74ac030afc 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -14,12 +14,12 @@ - + Open Script - + JavaScript Files (*.js) @@ -113,18 +113,18 @@ Menu - + Open .ini config file - - + + Text files (*.ini) - + Save .ini config file diff --git a/interface/resources/shaders/model_shadow.frag b/interface/resources/shaders/model_shadow.frag new file mode 100644 index 0000000000..bcb597b13c --- /dev/null +++ b/interface/resources/shaders/model_shadow.frag @@ -0,0 +1,14 @@ +#version 120 + +// +// model_shadow.frag +// fragment shader +// +// Created by Andrzej Kapolka on 3/24/14. +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + +void main(void) { + // fixed color for now (we may eventually want to use texture alpha) + gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); +} diff --git a/interface/resources/shaders/model_shadow.vert b/interface/resources/shaders/model_shadow.vert new file mode 100644 index 0000000000..ae7e871887 --- /dev/null +++ b/interface/resources/shaders/model_shadow.vert @@ -0,0 +1,14 @@ +#version 120 + +// +// model_shadow.vert +// vertex shader +// +// Created by Andrzej Kapolka on 3/24/14. +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + +void main(void) { + // just use standard pipeline transform + gl_Position = ftransform(); +} diff --git a/interface/resources/shaders/skin_model_shadow.vert b/interface/resources/shaders/skin_model_shadow.vert new file mode 100644 index 0000000000..b9ef05ad8a --- /dev/null +++ b/interface/resources/shaders/skin_model_shadow.vert @@ -0,0 +1,27 @@ +#version 120 + +// +// skin_model_shadow.vert +// vertex shader +// +// Created by Andrzej Kapolka on 3/24/14. +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + +const int MAX_CLUSTERS = 128; +const int INDICES_PER_VERTEX = 4; + +uniform mat4 clusterMatrices[MAX_CLUSTERS]; + +attribute vec4 clusterIndices; +attribute vec4 clusterWeights; + +void main(void) { + vec4 position = vec4(0.0, 0.0, 0.0, 0.0); + for (int i = 0; i < INDICES_PER_VERTEX; i++) { + mat4 clusterMatrix = clusterMatrices[int(clusterIndices[i])]; + float clusterWeight = clusterWeights[i]; + position += clusterMatrix * gl_Vertex * clusterWeight; + } + gl_Position = gl_ModelViewProjectionMatrix * position; +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9563cbf3b4..994423b9c4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2210,7 +2210,7 @@ void Application::updateShadowMap() { glTranslatef(translation.x, translation.y, translation.z); - _avatarManager.renderAvatars(true); + _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); _particles.render(); glPopMatrix(); @@ -2388,7 +2388,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } bool mirrorMode = (whichCamera.getInterpolatedMode() == CAMERA_MODE_MIRROR); - _avatarManager.renderAvatars(mirrorMode, selfAvatarOnly); + _avatarManager.renderAvatars(mirrorMode ? Avatar::MIRROR_RENDER_MODE : Avatar::NORMAL_RENDER_MODE, selfAvatarOnly); if (!selfAvatarOnly) { // Render the world box diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 75a8386ea9..2b94947928 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -189,10 +189,11 @@ static TextRenderer* textRenderer(TextRendererType type) { return displayNameRenderer; } -void Avatar::render(const glm::vec3& cameraPosition, bool forShadowMap) { +void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { // simple frustum check float boundingRadius = getBillboardSize(); - if (Application::getInstance()->getViewFrustum()->sphereInFrustum(cameraPosition, boundingRadius) == ViewFrustum::OUTSIDE) { + if (Application::getInstance()->getViewFrustum()->sphereInFrustum( + cameraPosition, boundingRadius) == ViewFrustum::OUTSIDE) { return; } @@ -202,11 +203,11 @@ void Avatar::render(const glm::vec3& cameraPosition, bool forShadowMap) { { // glow when moving far away const float GLOW_DISTANCE = 20.0f; - Glower glower(_moving && distanceToTarget > GLOW_DISTANCE && !forShadowMap ? 1.0f : 0.0f); + Glower glower(_moving && distanceToTarget > GLOW_DISTANCE && renderMode == NORMAL_RENDER_MODE ? 1.0f : 0.0f); // render body if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) { - renderBody(forShadowMap); + renderBody(renderMode); } if (Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionProxies)) { _skeletonModel.renderCollisionProxies(0.7f); @@ -230,7 +231,8 @@ void Avatar::render(const glm::vec3& cameraPosition, bool forShadowMap) { float angle = abs(angleBetween(toTarget + delta, toTarget - delta)); float sphereRadius = getHead()->getAverageLoudness() * SPHERE_LOUDNESS_SCALING; - if (!forShadowMap && (sphereRadius > MIN_SPHERE_SIZE) && (angle < MAX_SPHERE_ANGLE) && (angle > MIN_SPHERE_ANGLE)) { + if (renderMode == NORMAL_RENDER_MODE && (sphereRadius > MIN_SPHERE_SIZE) && + (angle < MAX_SPHERE_ANGLE) && (angle > MIN_SPHERE_ANGLE)) { glColor4f(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.f - angle / MAX_SPHERE_ANGLE); glPushMatrix(); glTranslatef(_position.x, _position.y, _position.z); @@ -242,8 +244,8 @@ void Avatar::render(const glm::vec3& cameraPosition, bool forShadowMap) { } const float DISPLAYNAME_DISTANCE = 10.0f; - setShowDisplayName(!forShadowMap && distanceToTarget < DISPLAYNAME_DISTANCE); - if (forShadowMap) { + setShowDisplayName(renderMode == NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE); + if (renderMode != NORMAL_RENDER_MODE) { return; } renderDisplayName(); @@ -306,17 +308,16 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { return glm::angleAxis(angle * proportion, axis); } -void Avatar::renderBody(bool forShadowMap) { +void Avatar::renderBody(RenderMode renderMode) { if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { // render the billboard until both models are loaded - if (forShadowMap) { - return; + if (renderMode != SHADOW_RENDER_MODE) { + renderBillboard(); } - renderBillboard(); return; } - _skeletonModel.render(1.0f); - getHead()->render(1.0f); + _skeletonModel.render(1.0f, renderMode == SHADOW_RENDER_MODE); + getHead()->render(1.0f, renderMode == SHADOW_RENDER_MODE); getHand()->render(false); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 638bff6e32..25600e0943 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -74,7 +74,10 @@ public: void init(); void simulate(float deltaTime); - virtual void render(const glm::vec3& cameraPosition, bool forShadowMap); + + enum RenderMode { NORMAL_RENDER_MODE, SHADOW_RENDER_MODE, MIRROR_RENDER_MODE }; + + virtual void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE); //setters void setDisplayingLookatVectors(bool displayingLookatVectors) { getHead()->setRenderLookatVectors(displayingLookatVectors); } @@ -181,7 +184,7 @@ protected: float getPelvisToHeadLength() const; void renderDisplayName(); - virtual void renderBody(bool forShadowMap); + virtual void renderBody(RenderMode renderMode); private: diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 29b23e1f5b..9147a08dbd 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -72,7 +72,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { simulateAvatarFades(deltaTime); } -void AvatarManager::renderAvatars(bool forShadowMapOrMirror, bool selfAvatarOnly) { +void AvatarManager::renderAvatars(Avatar::RenderMode renderMode, bool selfAvatarOnly) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::renderAvatars()"); bool renderLookAtVectors = Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors); @@ -85,13 +85,13 @@ void AvatarManager::renderAvatars(bool forShadowMapOrMirror, bool selfAvatarOnly if (!avatar->isInitialized()) { continue; } - avatar->render(cameraPosition, forShadowMapOrMirror); + avatar->render(cameraPosition, renderMode); avatar->setDisplayingLookatVectors(renderLookAtVectors); } - renderAvatarFades(cameraPosition, forShadowMapOrMirror); + renderAvatarFades(cameraPosition, renderMode); } else { // just render myAvatar - _myAvatar->render(cameraPosition, forShadowMapOrMirror); + _myAvatar->render(cameraPosition, renderMode); _myAvatar->setDisplayingLookatVectors(renderLookAtVectors); } } @@ -114,14 +114,14 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { } } -void AvatarManager::renderAvatarFades(const glm::vec3& cameraPosition, bool forShadowMap) { +void AvatarManager::renderAvatarFades(const glm::vec3& cameraPosition, Avatar::RenderMode renderMode) { // render avatar fades - Glower glower(forShadowMap ? 0.0f : 1.0f); + Glower glower(renderMode == Avatar::NORMAL_RENDER_MODE ? 1.0f : 0.0f); foreach(const AvatarSharedPointer& fadingAvatar, _avatarFades) { Avatar* avatar = static_cast(fadingAvatar.data()); if (avatar != static_cast(_myAvatar.data())) { - avatar->render(cameraPosition, forShadowMap); + avatar->render(cameraPosition, renderMode); } } } diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 455153b92a..06494f309c 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -29,7 +29,7 @@ public: MyAvatar* getMyAvatar() { return _myAvatar.data(); } void updateOtherAvatars(float deltaTime); - void renderAvatars(bool forShadowMapOrMirror = false, bool selfAvatarOnly = false); + void renderAvatars(Avatar::RenderMode renderMode, bool selfAvatarOnly = false); void clearOtherAvatars(); @@ -45,7 +45,7 @@ private: void processKillAvatar(const QByteArray& datagram); void simulateAvatarFades(float deltaTime); - void renderAvatarFades(const glm::vec3& cameraPosition, bool forShadowMap); + void renderAvatarFades(const glm::vec3& cameraPosition, Avatar::RenderMode renderMode); // virtual override AvatarHash::iterator erase(const AvatarHash::iterator& iterator); diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index db6c3fe98d..19faa0da42 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -45,13 +45,6 @@ void FaceModel::simulate(float deltaTime) { Model::simulate(deltaTime, true, newJointStates); } -bool FaceModel::render(float alpha) { - if (!Model::render(alpha)) { - return false; - } - return true; -} - void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { // get the rotation axes in joint space and use them to adjust the rotation glm::mat3 axes = glm::mat3_cast(_rotation); diff --git a/interface/src/avatar/FaceModel.h b/interface/src/avatar/FaceModel.h index d0f0f6baef..acf2d2baf4 100644 --- a/interface/src/avatar/FaceModel.h +++ b/interface/src/avatar/FaceModel.h @@ -22,7 +22,6 @@ public: FaceModel(Head* owningHead); void simulate(float deltaTime); - bool render(float alpha); protected: diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 44001a2015..4a81df8b74 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -168,8 +168,8 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { _eyePosition = calculateAverageEyePosition(); } -void Head::render(float alpha) { - if (_faceModel.render(alpha) && _renderLookatVectors) { +void Head::render(float alpha, bool forShadowMap) { + if (_faceModel.render(alpha, forShadowMap) && _renderLookatVectors) { renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition); } } diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index a9ea9b4cc6..60730c8724 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -37,7 +37,7 @@ public: void init(); void reset(); void simulate(float deltaTime, bool isMine, bool billboard = false); - void render(float alpha); + void render(float alpha, bool forShadowMap); void setScale(float scale); void setPosition(glm::vec3 position) { _position = position; } void setGravity(glm::vec3 gravity) { _gravity = gravity; } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index a6a7f22896..711e1d32c3 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -451,12 +451,12 @@ void MyAvatar::renderDebugBodyPoints() { } // virtual -void MyAvatar::render(const glm::vec3& cameraPosition, bool forShadowMapOrMirror) { +void MyAvatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { // don't render if we've been asked to disable local rendering if (!_shouldRender) { return; // exit early } - Avatar::render(cameraPosition, forShadowMapOrMirror); + Avatar::render(cameraPosition, renderMode); } void MyAvatar::renderHeadMouse() const { @@ -639,20 +639,20 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { _billboardValid = false; } -void MyAvatar::renderBody(bool forceRenderHead) { +void MyAvatar::renderBody(RenderMode renderMode) { if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { return; // wait until both models are loaded } // Render the body's voxels and head - _skeletonModel.render(1.0f); + _skeletonModel.render(1.0f, renderMode == SHADOW_RENDER_MODE); // Render head so long as the camera isn't inside it const float RENDER_HEAD_CUTOFF_DISTANCE = 0.40f; Camera* myCamera = Application::getInstance()->getCamera(); - if (forceRenderHead || (glm::length(myCamera->getPosition() - getHead()->calculateAverageEyePosition()) > + if (renderMode != NORMAL_RENDER_MODE || (glm::length(myCamera->getPosition() - getHead()->calculateAverageEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale)) { - getHead()->render(1.0f); + getHead()->render(1.0f, renderMode == SHADOW_RENDER_MODE); } getHand()->render(true); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 241286a721..cbb625aa2f 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -35,8 +35,8 @@ public: void simulate(float deltaTime); void updateFromGyros(float deltaTime); - void render(const glm::vec3& cameraPosition, bool forShadowMapOrMirror = false); - void renderBody(bool forceRenderHead); + void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE); + void renderBody(RenderMode renderMode); void renderDebugBodyPoints(); void renderHeadMouse() const; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 7173cb0b84..9e4740df15 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -62,17 +62,6 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { } } -bool SkeletonModel::render(float alpha) { - - if (_jointStates.isEmpty()) { - return false; - } - - Model::render(alpha); - - return true; -} - void SkeletonModel::getHandShapes(int jointIndex, QVector& shapes) const { if (jointIndex == -1) { return; diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 0bcbcef2ea..514b5daf1c 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -23,7 +23,6 @@ public: SkeletonModel(Avatar* owningAvatar); void simulate(float deltaTime, bool fullUpdate = true); - bool render(float alpha); /// \param jointIndex index of hand joint /// \param shapes[out] list in which is stored pointers to hand shapes diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 16b5c167d9..690b19ee5e 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -43,11 +43,14 @@ Model::~Model() { ProgramObject Model::_program; ProgramObject Model::_normalMapProgram; +ProgramObject Model::_shadowProgram; ProgramObject Model::_skinProgram; ProgramObject Model::_skinNormalMapProgram; +ProgramObject Model::_skinShadowProgram; int Model::_normalMapTangentLocation; Model::SkinLocations Model::_skinLocations; Model::SkinLocations Model::_skinNormalMapLocations; +Model::SkinLocations Model::_skinShadowLocations; void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations) { program.bind(); @@ -93,6 +96,11 @@ void Model::init() { _normalMapTangentLocation = _normalMapProgram.attributeLocation("tangent"); _normalMapProgram.release(); + _shadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_shadow.vert"); + _shadowProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/model_shadow.frag"); + _shadowProgram.link(); + _skinProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() @@ -108,6 +116,14 @@ void Model::init() { _skinNormalMapProgram.link(); initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations); + + _skinShadowProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/skin_model_shadow.vert"); + _skinShadowProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_shadow.frag"); + _skinShadowProgram.link(); + + initSkinProgram(_skinShadowProgram, _skinShadowLocations); } } @@ -167,7 +183,7 @@ void Model::simulate(float deltaTime, bool fullUpdate) { simulate(deltaTime, fullUpdate, updateGeometry()); } -bool Model::render(float alpha) { +bool Model::render(float alpha, bool forShadowMap) { // render the attachments foreach (Model* attachment, _attachments) { attachment->render(alpha); @@ -198,13 +214,13 @@ bool Model::render(float alpha) { glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.5f * alpha); - renderMeshes(alpha, false); + renderMeshes(alpha, forShadowMap, false); glDisable(GL_ALPHA_TEST); // render translucent meshes afterwards, with back face culling - renderMeshes(alpha, true); + renderMeshes(alpha, forShadowMap, true); glDisable(GL_CULL_FACE); @@ -960,7 +976,7 @@ void Model::deleteGeometry() { } } -void Model::renderMeshes(float alpha, bool translucent) { +void Model::renderMeshes(float alpha, bool forShadowMap, bool translucent) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); @@ -985,7 +1001,12 @@ void Model::renderMeshes(float alpha, bool translucent) { ProgramObject* program = &_program; ProgramObject* skinProgram = &_skinProgram; SkinLocations* skinLocations = &_skinLocations; - if (!mesh.tangents.isEmpty()) { + if (forShadowMap) { + program = &_shadowProgram; + skinProgram = &_skinShadowProgram; + skinLocations = &_skinShadowLocations; + + } else if (!mesh.tangents.isEmpty()) { program = &_normalMapProgram; skinProgram = &_skinNormalMapProgram; skinLocations = &_skinNormalMapLocations; @@ -1018,7 +1039,7 @@ void Model::renderMeshes(float alpha, bool translucent) { } if (mesh.blendshapes.isEmpty()) { - if (!mesh.tangents.isEmpty()) { + if (!(mesh.tangents.isEmpty() || forShadowMap)) { activeProgram->setAttributeBuffer(tangentLocation, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3); activeProgram->enableAttributeArray(tangentLocation); } @@ -1028,7 +1049,7 @@ void Model::renderMeshes(float alpha, bool translucent) { (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3))); } else { - if (!mesh.tangents.isEmpty()) { + if (!(mesh.tangents.isEmpty() || forShadowMap)) { activeProgram->setAttributeBuffer(tangentLocation, GL_FLOAT, 0, 3); activeProgram->enableAttributeArray(tangentLocation); } @@ -1057,31 +1078,33 @@ void Model::renderMeshes(float alpha, bool translucent) { continue; } // apply material properties - glm::vec4 diffuse = glm::vec4(part.diffuseColor, alpha); - glm::vec4 specular = glm::vec4(part.specularColor, alpha); - glMaterialfv(GL_FRONT, GL_AMBIENT, (const float*)&diffuse); - glMaterialfv(GL_FRONT, GL_DIFFUSE, (const float*)&diffuse); - glMaterialfv(GL_FRONT, GL_SPECULAR, (const float*)&specular); - glMaterialf(GL_FRONT, GL_SHININESS, part.shininess); - - Texture* diffuseMap = networkPart.diffuseTexture.data(); - if (mesh.isEye) { - if (diffuseMap) { + if (forShadowMap) { + glBindTexture(GL_TEXTURE_2D, 0); + + } else { + glm::vec4 diffuse = glm::vec4(part.diffuseColor, alpha); + glm::vec4 specular = glm::vec4(part.specularColor, alpha); + glMaterialfv(GL_FRONT, GL_AMBIENT, (const float*)&diffuse); + glMaterialfv(GL_FRONT, GL_DIFFUSE, (const float*)&diffuse); + glMaterialfv(GL_FRONT, GL_SPECULAR, (const float*)&specular); + glMaterialf(GL_FRONT, GL_SHININESS, part.shininess); + + Texture* diffuseMap = networkPart.diffuseTexture.data(); + if (mesh.isEye && diffuseMap) { diffuseMap = (_dilatedTextures[i][j] = static_cast(diffuseMap)->getDilatedTexture(_pupilDilation)).data(); } + glBindTexture(GL_TEXTURE_2D, !diffuseMap ? + Application::getInstance()->getTextureCache()->getWhiteTextureID() : diffuseMap->getID()); + + if (!mesh.tangents.isEmpty()) { + glActiveTexture(GL_TEXTURE1); + Texture* normalMap = networkPart.normalTexture.data(); + glBindTexture(GL_TEXTURE_2D, !normalMap ? + Application::getInstance()->getTextureCache()->getBlueTextureID() : normalMap->getID()); + glActiveTexture(GL_TEXTURE0); + } } - glBindTexture(GL_TEXTURE_2D, !diffuseMap ? - Application::getInstance()->getTextureCache()->getWhiteTextureID() : diffuseMap->getID()); - - if (!mesh.tangents.isEmpty()) { - glActiveTexture(GL_TEXTURE1); - Texture* normalMap = networkPart.normalTexture.data(); - glBindTexture(GL_TEXTURE_2D, !normalMap ? - Application::getInstance()->getTextureCache()->getBlueTextureID() : normalMap->getID()); - glActiveTexture(GL_TEXTURE0); - } - glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, part.quadIndices.size(), GL_UNSIGNED_INT, (void*)offset); offset += part.quadIndices.size() * sizeof(int); glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, part.triangleIndices.size(), @@ -1096,7 +1119,7 @@ void Model::renderMeshes(float alpha, bool translucent) { glDisableClientState(GL_TEXTURE_COORD_ARRAY); } - if (!mesh.tangents.isEmpty()) { + if (!(mesh.tangents.isEmpty() || forShadowMap)) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index f08a6b9fc2..b4f71f14d3 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -58,7 +58,7 @@ public: void createCollisionShapes(); void updateShapePositions(); void simulate(float deltaTime, bool fullUpdate = true); - bool render(float alpha); + bool render(float alpha = 1.0f, bool forShadowMap = false); /// Sets the URL of the model to render. /// \param fallback the URL of a fallback model to render if the requested model fails to load @@ -261,7 +261,7 @@ private: void applyNextGeometry(); void deleteGeometry(); - void renderMeshes(float alpha, bool translucent); + void renderMeshes(float alpha, bool forShadowMap, bool translucent); QSharedPointer _baseGeometry; ///< reference required to prevent collection of base QSharedPointer _nextBaseGeometry; @@ -283,8 +283,10 @@ private: static ProgramObject _program; static ProgramObject _normalMapProgram; + static ProgramObject _shadowProgram; static ProgramObject _skinProgram; static ProgramObject _skinNormalMapProgram; + static ProgramObject _skinShadowProgram; static int _normalMapTangentLocation; @@ -298,6 +300,7 @@ private: static SkinLocations _skinLocations; static SkinLocations _skinNormalMapLocations; + static SkinLocations _skinShadowLocations; static void initSkinProgram(ProgramObject& program, SkinLocations& locations); static QVector createJointStates(const FBXGeometry& geometry); From f8279c1f5b1b667607b5dcb673e1c09465652717 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 14:14:26 -0700 Subject: [PATCH 65/84] handle query params in HTTPManager, display stats table from DS --- assignment-client/src/audio/AudioMixer.cpp | 12 +++++-- domain-server/resources/web/footer.html | 4 +-- domain-server/resources/web/header.html | 4 +-- domain-server/resources/web/js/tables.js | 2 +- domain-server/resources/web/stats/index.shtml | 6 ++++ domain-server/resources/web/stats/js/stats.js | 31 +++++++++++++++++++ domain-server/src/DomainServer.cpp | 18 +++++------ domain-server/src/DomainServer.h | 2 +- .../embedded-webserver/src/HTTPConnection.cpp | 2 +- .../embedded-webserver/src/HTTPManager.cpp | 10 ++++-- .../embedded-webserver/src/HTTPManager.h | 4 +-- 11 files changed, 71 insertions(+), 24 deletions(-) create mode 100644 domain-server/resources/web/stats/index.shtml create mode 100644 domain-server/resources/web/stats/js/stats.js diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index ca95fd190a..9e7cf53e2f 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -358,11 +358,17 @@ void AudioMixer::readPendingDatagrams() { void AudioMixer::sendStatsPacket() { static QJsonObject statsObject; - statsObject["trailing_sleep_time"] = _trailingSleepRatio; - statsObject["performance_cutoff"] = _minAudibilityThreshold; + statsObject["trailing_sleep_percentage"] = _trailingSleepRatio * 100.0f; + statsObject["performance_throttling"] = _performanceThrottling; statsObject["average_listeners_per_frame"] = _sumListeners / (float) _numStatFrames; - statsObject["average_mixes_per_listeners"] = _sumMixes / _sumListeners / _numStatFrames; + + if (_sumListeners > 0) { + statsObject["average_mixes_per_listener"] = _sumMixes / (float) _sumListeners; + } else { + statsObject["average_mixes_per_listener"] = 0.0; + } + _sumListeners = 0; _sumMixes = 0; diff --git a/domain-server/resources/web/footer.html b/domain-server/resources/web/footer.html index 08ea9fba66..d1a3fc29e8 100644 --- a/domain-server/resources/web/footer.html +++ b/domain-server/resources/web/footer.html @@ -1,3 +1,3 @@ - - \ 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 83d7ae5c23..2be603b00e 100644 --- a/domain-server/resources/web/header.html +++ b/domain-server/resources/web/header.html @@ -4,8 +4,8 @@ domain-server - - + +
\ No newline at end of file diff --git a/domain-server/resources/web/js/tables.js b/domain-server/resources/web/js/tables.js index e32f78a63e..ae5095592b 100644 --- a/domain-server/resources/web/js/tables.js +++ b/domain-server/resources/web/js/tables.js @@ -7,7 +7,7 @@ $(document).ready(function(){ $.each(json.nodes, function (uuid, data) { nodesTableBody += ""; nodesTableBody += "" + data.type + ""; - nodesTableBody += "" + uuid + ""; + nodesTableBody += "" + uuid + ""; nodesTableBody += "" + (data.pool ? data.pool : "") + ""; nodesTableBody += "" + data.public.ip + ":" + data.public.port + ""; nodesTableBody += "" + data.local.ip + ":" + data.local.port + ""; diff --git a/domain-server/resources/web/stats/index.shtml b/domain-server/resources/web/stats/index.shtml new file mode 100644 index 0000000000..62115d18fe --- /dev/null +++ b/domain-server/resources/web/stats/index.shtml @@ -0,0 +1,6 @@ + +

Stats

+
+ + + \ No newline at end of file diff --git a/domain-server/resources/web/stats/js/stats.js b/domain-server/resources/web/stats/js/stats.js new file mode 100644 index 0000000000..e82668ea9e --- /dev/null +++ b/domain-server/resources/web/stats/js/stats.js @@ -0,0 +1,31 @@ +function qs(key) { + key = key.replace(/[*+?^$.\[\]{}()|\\\/]/g, "\\$&"); // escape RegEx meta chars + var match = location.search.match(new RegExp("[?&]"+key+"=([^&]+)(&|$)")); + return match && decodeURIComponent(match[1].replace(/\+/g, " ")); +} + +$(document).ready(function(){ + // setup a function to grab the nodeStats + function getNodeStats() { + + var uuid = qs("uuid"); + + var statsTableBody = ""; + + $.getJSON("/nodes/" + uuid + ".json", function(json){ + $.each(json, function (key, value) { + statsTableBody += ""; + statsTableBody += "" + key + ""; + statsTableBody += "" + value + ""; + statsTableBody += ""; + }); + + $('#stats-table tbody').html(statsTableBody); + }); + } + + // do the first GET on page load + getNodeStats(); + // grab the new assignments JSON every second + var getNodeStatsInterval = setInterval(getNodeStats, 1000); +}); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 1b867501d2..0a8b70a673 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -651,14 +651,14 @@ QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { return nodeJson; } -bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& path) { +bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url) { const QString JSON_MIME_TYPE = "application/json"; const QString URI_ASSIGNMENT = "/assignment"; const QString URI_NODES = "/nodes"; if (connection->requestOperation() == QNetworkAccessManager::GetOperation) { - if (path == "/assignments.json") { + if (url.path() == "/assignments.json") { // user is asking for json list of assignments // setup the JSON @@ -702,7 +702,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& // we've processed this request return true; - } else if (path == QString("%1.json").arg(URI_NODES)) { + } else if (url.path() == QString("%1.json").arg(URI_NODES)) { // setup the JSON QJsonObject rootJSON; QJsonObject nodesJSON; @@ -727,10 +727,10 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& return true; } else { const QString NODE_REGEX_STRING = - QString("\\%1\\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\/?$").arg(URI_NODES); + QString("\\%1\\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}).json\\/?$").arg(URI_NODES); QRegExp nodeShowRegex(NODE_REGEX_STRING); - if (nodeShowRegex.indexIn(path) != -1) { + if (nodeShowRegex.indexIn(url.path()) != -1) { QUuid matchingUUID = QUuid(nodeShowRegex.cap(1)); // see if we have a node that matches this ID @@ -740,7 +740,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& QJsonDocument statsDocument(reinterpret_cast(matchingNode->getLinkedData()) ->getStatsJSONObject()); - // send the resposne + // send the response connection->respond(HTTPConnection::StatusCode200, statsDocument.toJson(), qPrintable(JSON_MIME_TYPE)); // tell the caller we processed the request @@ -749,7 +749,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& } } } else if (connection->requestOperation() == QNetworkAccessManager::PostOperation) { - if (path == URI_ASSIGNMENT) { + if (url.path() == URI_ASSIGNMENT) { // this is a script upload - ask the HTTPConnection to parse the form data QList formData = connection->parseFormData(); @@ -796,11 +796,11 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& return true; } } else if (connection->requestOperation() == QNetworkAccessManager::DeleteOperation) { - if (path.startsWith(URI_NODES)) { + if (url.path().startsWith(URI_NODES)) { // this is a request to DELETE a node by UUID // pull the UUID from the url - QUuid deleteUUID = QUuid(path.mid(URI_NODES.size() + sizeof('/'))); + QUuid deleteUUID = QUuid(url.path().mid(URI_NODES.size() + sizeof('/'))); if (!deleteUUID.isNull()) { SharedNodePointer nodeToKill = NodeList::getInstance()->nodeWithUUID(deleteUUID); diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 2d253cc41c..597be7f50d 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -30,7 +30,7 @@ public: bool requiresAuthentication() const { return !_nodeAuthenticationURL.isEmpty(); } - bool handleHTTPRequest(HTTPConnection* connection, const QString& path); + bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url); void exit(int retCode = 0); diff --git a/libraries/embedded-webserver/src/HTTPConnection.cpp b/libraries/embedded-webserver/src/HTTPConnection.cpp index 50ce72e0cd..8fc0a25dca 100755 --- a/libraries/embedded-webserver/src/HTTPConnection.cpp +++ b/libraries/embedded-webserver/src/HTTPConnection.cpp @@ -180,7 +180,7 @@ void HTTPConnection::readHeaders() { QByteArray clength = _requestHeaders.value("Content-Length"); if (clength.isEmpty()) { - _parentManager->handleHTTPRequest(this, _requestUrl.path()); + _parentManager->handleHTTPRequest(this, _requestUrl); } else { _requestContent.resize(clength.toInt()); diff --git a/libraries/embedded-webserver/src/HTTPManager.cpp b/libraries/embedded-webserver/src/HTTPManager.cpp index a217555a78..d106b6df59 100755 --- a/libraries/embedded-webserver/src/HTTPManager.cpp +++ b/libraries/embedded-webserver/src/HTTPManager.cpp @@ -15,15 +15,15 @@ #include "HTTPConnection.h" #include "HTTPManager.h" -bool HTTPManager::handleHTTPRequest(HTTPConnection* connection, const QString& path) { - if (_requestHandler && _requestHandler->handleHTTPRequest(connection, path)) { +bool HTTPManager::handleHTTPRequest(HTTPConnection* connection, const QUrl& url) { + if (_requestHandler && _requestHandler->handleHTTPRequest(connection, url)) { // this request was handled by our _requestHandler object // so we don't need to attempt to do so in the document root return true; } // check to see if there is a file to serve from the document root for this path - QString subPath = path; + QString subPath = url.path(); // remove any slash at the beginning of the path if (subPath.startsWith('/')) { @@ -38,6 +38,10 @@ bool HTTPManager::handleHTTPRequest(HTTPConnection* connection, const QString& p // this could be a directory with a trailing slash // send a redirect to the path with a slash so we can QString redirectLocation = '/' + subPath + '/'; + + if (!url.query().isEmpty()) { + redirectLocation += "?" + url.query(); + } QHash redirectHeader; redirectHeader.insert(QByteArray("Location"), redirectLocation.toUtf8()); diff --git a/libraries/embedded-webserver/src/HTTPManager.h b/libraries/embedded-webserver/src/HTTPManager.h index e3b44e7cdc..a8f9d723fa 100755 --- a/libraries/embedded-webserver/src/HTTPManager.h +++ b/libraries/embedded-webserver/src/HTTPManager.h @@ -20,7 +20,7 @@ class HTTPConnection; class HTTPRequestHandler { public: /// Handles an HTTP request. - virtual bool handleHTTPRequest(HTTPConnection* connection, const QString& path) = 0; + virtual bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url) = 0; }; /// Handles HTTP connections @@ -30,7 +30,7 @@ public: /// Initializes the manager. HTTPManager(quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler = NULL, QObject* parent = 0); - bool handleHTTPRequest(HTTPConnection* connection, const QString& path); + bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url); protected slots: /// Accepts all pending connections From 40fa4bfbd2d7b07abc48b9af31037b4d74c3c92a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 14:15:38 -0700 Subject: [PATCH 66/84] fix octree server HTTPRequestHandler for url handling --- assignment-client/src/octree/OctreeServer.cpp | 6 +++--- assignment-client/src/octree/OctreeServer.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index d4dfa80724..4990de2b55 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -236,7 +236,7 @@ void OctreeServer::initHTTPManager(int port) { _httpManager = new HTTPManager(port, documentRoot, this, this); } -bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& path) { +bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url) { #ifdef FORCE_CRASH if (connection->requestOperation() == QNetworkAccessManager::GetOperation @@ -259,9 +259,9 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& bool showStats = false; if (connection->requestOperation() == QNetworkAccessManager::GetOperation) { - if (path == "/") { + if (url.path() == "/") { showStats = true; - } else if (path == "/resetStats") { + } else if (url.path() == "/resetStats") { _octreeInboundPacketProcessor->resetStats(); resetSendingStats(); showStats = true; diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 12091170d9..2664499b6a 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -97,7 +97,7 @@ public: static void trackPacketSendingTime(float time); static float getAveragePacketSendingTime() { return _averagePacketSendingTime.getAverage(); } - bool handleHTTPRequest(HTTPConnection* connection, const QString& path); + bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url); virtual void aboutToFinish(); From 210af25396d0c2ff76501fdde3623a16e033a2c6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 24 Mar 2014 14:52:02 -0700 Subject: [PATCH 67/84] When rendering avatar shadows, check bounds against shadow frustum. Closes --- interface/interface_en.ts | 4 +-- interface/src/Application.cpp | 43 ++++++++++++++--------- interface/src/Application.h | 2 ++ interface/src/avatar/Avatar.cpp | 5 +-- libraries/octree/src/ViewFrustum.cpp | 51 ++++++++++++++++++++++++++++ libraries/octree/src/ViewFrustum.h | 11 ++++++ 6 files changed, 96 insertions(+), 20 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 74ac030afc..c29959f0a6 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -14,12 +14,12 @@ - + Open Script - + JavaScript Files (*.js) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 994423b9c4..e896160b65 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2138,6 +2138,7 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { viewFrustum.setOrientation(rotation); // Also make sure it's got the correct lens details from the camera + viewFrustum.setOrthographic(false); viewFrustum.setAspectRatio(aspectRatio); viewFrustum.setFieldOfView(fov); // degrees viewFrustum.setNearClip(nearClip); @@ -2163,21 +2164,22 @@ void Application::updateShadowMap() { glViewport(0, 0, fbo->width(), fbo->height()); glm::vec3 lightDirection = -getSunDirection(); - glm::quat rotation = glm::inverse(rotationBetween(IDENTITY_FRONT, lightDirection)); - glm::vec3 translation = glm::vec3(); + glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection); + glm::quat inverseRotation = glm::inverse(rotation); float nearScale = 0.0f; const float MAX_SHADOW_DISTANCE = 2.0f; - float farScale = (MAX_SHADOW_DISTANCE - _viewFrustum.getNearClip()) / (_viewFrustum.getFarClip() - _viewFrustum.getNearClip()); + float farScale = (MAX_SHADOW_DISTANCE - _viewFrustum.getNearClip()) / + (_viewFrustum.getFarClip() - _viewFrustum.getNearClip()); loadViewFrustum(_myCamera, _viewFrustum); glm::vec3 points[] = { - rotation * (glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale) + translation), - rotation * (glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale) + translation), - rotation * (glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale) + translation), - rotation * (glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale) + translation), - rotation * (glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale) + translation), - rotation * (glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale) + translation), - rotation * (glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale) + translation), - rotation * (glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale) + translation) }; + inverseRotation * (glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale)), + inverseRotation * (glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale)), + inverseRotation * (glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale)), + inverseRotation * (glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale)), + inverseRotation * (glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale)), + inverseRotation * (glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale)), + inverseRotation * (glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale)), + inverseRotation * (glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale)) }; glm::vec3 minima(FLT_MAX, FLT_MAX, FLT_MAX), maxima(-FLT_MAX, -FLT_MAX, -FLT_MAX); for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) { minima = glm::min(minima, points[i]); @@ -2190,9 +2192,20 @@ void Application::updateShadowMap() { // save the combined matrix for rendering _shadowMatrix = glm::transpose(glm::translate(glm::vec3(0.5f, 0.5f, 0.5f)) * glm::scale(glm::vec3(0.5f, 0.5f, 0.5f)) * - glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) * - glm::mat4_cast(rotation) * glm::translate(translation)); + glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) * glm::mat4_cast(inverseRotation)); + // update the shadow view frustum + _shadowViewFrustum.setPosition(rotation * ((minima + maxima) * 0.5f)); + _shadowViewFrustum.setOrientation(rotation); + _shadowViewFrustum.setOrthographic(true); + _shadowViewFrustum.setWidth(maxima.x - minima.x); + _shadowViewFrustum.setHeight(maxima.y - minima.y); + _shadowViewFrustum.setNearClip(minima.z); + _shadowViewFrustum.setFarClip(maxima.z); + _shadowViewFrustum.setEyeOffsetPosition(glm::vec3()); + _shadowViewFrustum.setEyeOffsetOrientation(glm::quat()); + _shadowViewFrustum.calculate(); + glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); @@ -2206,9 +2219,7 @@ void Application::updateShadowMap() { // store view matrix without translation, which we'll use for precision-sensitive objects glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix); - _viewMatrixTranslation = translation; - - glTranslatef(translation.x, translation.y, translation.z); + _viewMatrixTranslation = glm::vec3(); _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); _particles.render(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 28060113a9..93a5044124 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -155,6 +155,7 @@ public: Audio* getAudio() { return &_audio; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } + ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; } VoxelSystem* getVoxels() { return &_voxels; } VoxelTree* getVoxelTree() { return _voxels.getTree(); } ParticleTreeRenderer* getParticles() { return &_particles; } @@ -385,6 +386,7 @@ private: ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc. ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels, particles) + ViewFrustum _shadowViewFrustum; quint64 _lastQueriedTime; Oscilloscope _audioScope; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 2b94947928..7e5a777484 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -192,8 +192,9 @@ static TextRenderer* textRenderer(TextRendererType type) { void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { // simple frustum check float boundingRadius = getBillboardSize(); - if (Application::getInstance()->getViewFrustum()->sphereInFrustum( - cameraPosition, boundingRadius) == ViewFrustum::OUTSIDE) { + ViewFrustum* frustum = (renderMode == Avatar::SHADOW_RENDER_MODE) ? + Application::getInstance()->getShadowViewFrustum() : Application::getInstance()->getViewFrustum(); + if (frustum->sphereInFrustum(_position, boundingRadius) == ViewFrustum::OUTSIDE) { return; } diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp index da03aad697..fa6873b093 100644 --- a/libraries/octree/src/ViewFrustum.cpp +++ b/libraries/octree/src/ViewFrustum.cpp @@ -30,6 +30,9 @@ ViewFrustum::ViewFrustum() : _direction(IDENTITY_FRONT), _up(IDENTITY_UP), _right(IDENTITY_RIGHT), + _orthographic(false), + _width(1.0f), + _height(1.0f), _fieldOfView(0.0), _aspectRatio(1.0f), _nearClip(0.1f), @@ -62,6 +65,11 @@ void ViewFrustum::setOrientation(const glm::quat& orientationAsQuaternion) { // http://www.lighthouse3d.com/tutorials/view-frustum-culling/view-frustums-shape/ // void ViewFrustum::calculate() { + if (_orthographic) { + calculateOrthographic(); + return; + } + // compute the off-axis frustum parameters as we would for glFrustum float left, right, bottom, top, nearVal, farVal; glm::vec4 nearClipPlane, farClipPlane; @@ -133,6 +141,49 @@ void ViewFrustum::calculate() { _keyholeBoundingBox = AABox(corner,(_keyholeRadius * 2.0f)); } +void ViewFrustum::calculateOrthographic() { + float halfWidth = _width * 0.5f; + float halfHeight = _height * 0.5f; + + // find the corners of the view box in world space + glm::mat4 worldMatrix = glm::translate(_position) * glm::mat4(glm::mat3(_right, _up, -_direction)) * + glm::translate(_eyeOffsetPosition) * glm::mat4_cast(_eyeOffsetOrientation); + _farTopLeft = glm::vec3(worldMatrix * glm::vec4(-halfWidth, halfHeight, -_farClip, 1.0f)); + _farTopRight = glm::vec3(worldMatrix * glm::vec4(halfWidth, halfHeight, -_farClip, 1.0f)); + _farBottomLeft = glm::vec3(worldMatrix * glm::vec4(-halfWidth, -halfHeight, -_farClip, 1.0f)); + _farBottomRight = glm::vec3(worldMatrix * glm::vec4(halfWidth, -halfHeight, -_farClip, 1.0f)); + _nearTopLeft = glm::vec3(worldMatrix * glm::vec4(-halfWidth, halfHeight, -_nearClip, 1.0f)); + _nearTopRight = glm::vec3(worldMatrix * glm::vec4(halfWidth, halfHeight, -_nearClip, 1.0f)); + _nearBottomLeft = glm::vec3(worldMatrix * glm::vec4(-halfWidth, -halfHeight, -_nearClip, 1.0f)); + _nearBottomRight = glm::vec3(worldMatrix * glm::vec4(halfWidth, -halfHeight, -_nearClip, 1.0f)); + + // compute the offset position and axes in world space + _offsetPosition = glm::vec3(worldMatrix * glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); + _offsetDirection = glm::vec3(worldMatrix * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f)); + _offsetUp = glm::vec3(worldMatrix * glm::vec4(0.0f, 1.0f, 0.0f, 0.0f)); + _offsetRight = glm::vec3(worldMatrix * glm::vec4(1.0f, 0.0f, 0.0f, 0.0f)); + + _planes[TOP_PLANE].set3Points(_nearTopRight, _nearTopLeft, _farTopLeft); + _planes[BOTTOM_PLANE].set3Points(_nearBottomLeft, _nearBottomRight, _farBottomRight); + _planes[LEFT_PLANE].set3Points(_nearBottomLeft, _farBottomLeft, _farTopLeft); + _planes[RIGHT_PLANE].set3Points(_farBottomRight, _nearBottomRight, _nearTopRight); + _planes[NEAR_PLANE].set3Points(_nearBottomRight, _nearBottomLeft, _nearTopLeft); + _planes[FAR_PLANE].set3Points(_farBottomLeft, _farBottomRight, _farTopRight); + + // Also calculate our projection matrix in case people want to project points... + // Projection matrix : Field of View, ratio, display range : near to far + glm::mat4 projection = glm::ortho(-halfWidth, halfWidth, -halfHeight, halfHeight, _nearClip, _farClip); + glm::vec3 lookAt = _position + _direction; + glm::mat4 view = glm::lookAt(_position, lookAt, _up); + + // Our ModelViewProjection : multiplication of our 3 matrices (note: model is identity, so we can drop it) + _ourModelViewProjectionMatrix = projection * view; // Remember, matrix multiplication is the other way around + + // Set up our keyhole bounding box... + glm::vec3 corner = _position - _keyholeRadius; + _keyholeBoundingBox = AABox(corner, (_keyholeRadius * 2.0f)); +} + //enum { TOP_PLANE = 0, BOTTOM_PLANE, LEFT_PLANE, RIGHT_PLANE, NEAR_PLANE, FAR_PLANE }; const char* ViewFrustum::debugPlaneName (int plane) const { switch (plane) { diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index a0b3a851aa..7a1c3b49ba 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -41,6 +41,9 @@ public: const glm::vec3& getRight() const { return _right; } // setters for lens attributes + void setOrthographic(bool orthographic) { _orthographic = orthographic; } + void setWidth(float width) { _width = width; } + void setHeight(float height) { _height = height; } void setFieldOfView(float f) { _fieldOfView = f; } void setAspectRatio(float a) { _aspectRatio = a; } void setNearClip(float n) { _nearClip = n; } @@ -50,6 +53,9 @@ public: void setEyeOffsetOrientation(const glm::quat& o) { _eyeOffsetOrientation = o; } // getters for lens attributes + bool isOrthographic() const { return _orthographic; } + float getWidth() const { return _width; } + float getHeight() const { return _height; } float getFieldOfView() const { return _fieldOfView; } float getAspectRatio() const { return _aspectRatio; } float getNearClip() const { return _nearClip; } @@ -114,6 +120,8 @@ private: ViewFrustum::location sphereInKeyhole(const glm::vec3& center, float radius) const; ViewFrustum::location boxInKeyhole(const AABox& box) const; + void calculateOrthographic(); + // camera location/orientation attributes glm::vec3 _position; // the position in TREE_SCALE glm::vec3 _positionVoxelScale; // the position in voxel scale @@ -125,6 +133,9 @@ private: glm::vec3 _right; // Lens attributes + bool _orthographic; + float _width; + float _height; float _fieldOfView; // degrees float _aspectRatio; float _nearClip; From 8dbe4dfddef3fe714a2844574f756a595a271df3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 15:06:53 -0700 Subject: [PATCH 68/84] collect packet rate stats in NodeList --- assignment-client/src/audio/AudioMixer.cpp | 10 ++++++++- libraries/shared/src/NodeList.cpp | 24 ++++++++++++++++++++-- libraries/shared/src/NodeList.h | 12 ++++++++--- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 9e7cf53e2f..c4e09bfe47 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -369,12 +369,20 @@ void AudioMixer::sendStatsPacket() { statsObject["average_mixes_per_listener"] = 0.0; } + NodeList* nodeList = NodeList::getInstance(); + + float packetsPerSecond, bytesPerSecond; + nodeList->getPacketStats(packetsPerSecond, bytesPerSecond); + nodeList->resetPacketStats(); + + statsObject["packets_per_second"] = packetsPerSecond; + statsObject["bytes_per_second"] = bytesPerSecond; _sumListeners = 0; _sumMixes = 0; _numStatFrames = 0; - NodeList::getInstance()->sendStatsToDomainServer(statsObject); + nodeList->sendStatsToDomainServer(statsObject); } void AudioMixer::run() { diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index fe1466d5d1..d4babd4557 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -69,7 +69,10 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) : _assignmentServerSocket(), _publicSockAddr(), _hasCompletedInitialSTUNFailure(false), - _stunRequestsSinceSuccess(0) + _stunRequestsSinceSuccess(0), + _numCollectedPackets(0), + _numCollectedBytes(0), + _packetStatTimer() { _nodeSocket.bind(QHostAddress::AnyIPv4, newSocketListenPort); qDebug() << "NodeList socket is listening on" << _nodeSocket.localPort(); @@ -79,6 +82,8 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) : // clear our NodeList when logout is requested connect(&AccountManager::getInstance(), &AccountManager::logoutComplete , this, &NodeList::reset); + + _packetStatTimer.start(); } bool NodeList::packetVersionAndHashMatch(const QByteArray& packet) { @@ -161,7 +166,11 @@ qint64 NodeList::writeDatagram(const QByteArray& datagram, const HifiSockAddr& d // setup the MD5 hash for source verification in the header replaceHashInPacketGivenConnectionUUID(datagramCopy, connectionSecret); - + + // stat collection for packets + ++_numCollectedPackets; + _numCollectedBytes += datagram.size(); + return _nodeSocket.writeDatagram(datagramCopy, destinationSockAddr.getAddress(), destinationSockAddr.getPort()); } @@ -854,6 +863,17 @@ SharedNodePointer NodeList::soloNodeOfType(char nodeType) { return SharedNodePointer(); } +void NodeList::getPacketStats(float& packetsPerSecond, float& bytesPerSecond) { + packetsPerSecond = _numCollectedPackets / (float) (_packetStatTimer.elapsed() / 1000.0f); + bytesPerSecond = _numCollectedBytes / (float) (_packetStatTimer.elapsed() / 1000.0f); +} + +void NodeList::resetPacketStats() { + _numCollectedPackets = 0; + _numCollectedBytes = 0; + _packetStatTimer.restart(); +} + void NodeList::removeSilentNodes() { _nodeHashMutex.lock(); diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 379db70412..d892223f75 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -21,6 +21,7 @@ #include // not on windows, not needed for mac or windows #endif +#include #include #include #include @@ -120,6 +121,9 @@ public: unsigned broadcastToNodes(const QByteArray& packet, const NodeSet& destinationNodeTypes); SharedNodePointer soloNodeOfType(char nodeType); + void getPacketStats(float &packetsPerSecond, float &bytesPerSecond); + void resetPacketStats(); + void loadData(QSettings* settings); void saveData(QSettings* settings); public slots: @@ -155,6 +159,8 @@ private: void processDomainServerAuthRequest(const QByteArray& packet); void requestAuthForDomainServer(); + void activateSocketFromNodeCommunication(const QByteArray& packet, const SharedNodePointer& sendingNode); + void timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode); NodeHash _nodeHash; QMutex _nodeHashMutex; @@ -168,9 +174,9 @@ private: HifiSockAddr _publicSockAddr; bool _hasCompletedInitialSTUNFailure; unsigned int _stunRequestsSinceSuccess; - - void activateSocketFromNodeCommunication(const QByteArray& packet, const SharedNodePointer& sendingNode); - void timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode); + int _numCollectedPackets; + int _numCollectedBytes; + QElapsedTimer _packetStatTimer; }; #endif /* defined(__hifi__NodeList__) */ From 7bc0c8eff08ce82c82c239d8c73a8f934a8a0f3e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 24 Mar 2014 15:07:57 -0700 Subject: [PATCH 69/84] Missed a spot. --- interface/src/Application.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c36e9a77db..2ca4ef74cd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2142,7 +2142,6 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { viewFrustum.setOrientation(rotation); // Also make sure it's got the correct lens details from the camera - viewFrustum.setOrthographic(false); viewFrustum.setAspectRatio(aspectRatio); viewFrustum.setFieldOfView(fov); // degrees viewFrustum.setNearClip(nearClip); @@ -2218,8 +2217,8 @@ void Application::updateShadowMap() { glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); - glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + glm::vec3 axis = glm::axis(inverseRotation); + glRotatef(glm::degrees(glm::angle(inverseRotation)), axis.x, axis.y, axis.z); // store view matrix without translation, which we'll use for precision-sensitive objects glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix); From d3618aa8390b2cf7a0eb285a62b73287c1bfce2d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 24 Mar 2014 15:11:14 -0700 Subject: [PATCH 70/84] Yeesh, another translation update. --- interface/interface_en.ts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index c29959f0a6..beada5df43 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -4,22 +4,22 @@ Application - + Export Voxels - + Sparse Voxel Octree Files (*.svo) - + Open Script - + JavaScript Files (*.js) @@ -113,18 +113,18 @@ Menu - + Open .ini config file - - + + Text files (*.ini) - + Save .ini config file @@ -132,28 +132,28 @@ QObject - - + + Import Voxels - + Loading ... - + Place voxels - + <b>Import</b> %1 as voxels - + Cancel From 638e9eae48cf5ce0b1690f6acfaee2d84c732550 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 15:38:01 -0700 Subject: [PATCH 71/84] add some basic stat collection to avatar-mixer --- assignment-client/src/audio/AudioMixer.cpp | 2 +- assignment-client/src/avatars/AvatarMixer.cpp | 34 +++++++++++++++++-- assignment-client/src/avatars/AvatarMixer.h | 8 +++++ 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index c4e09bfe47..608362e0d4 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -393,7 +393,7 @@ void AudioMixer::run() { // send a stats packet every 1 second QTimer* statsTimer = new QTimer(this); - connect(statsTimer, SIGNAL(timeout()), this, SLOT(sendStatsPacket())); + connect(statsTimer, &QTimer::timeout, this, &AudioMixer::sendStatsPacket); statsTimer->start(1000); nodeList->addNodeTypeToInterestSet(NodeType::Agent); diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 47f7084f64..d243894ea1 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -29,7 +30,9 @@ const QString AVATAR_MIXER_LOGGING_NAME = "avatar-mixer"; const unsigned int AVATAR_DATA_SEND_INTERVAL_USECS = (1 / 60.0) * 1000 * 1000; AvatarMixer::AvatarMixer(const QByteArray& packet) : - ThreadedAssignment(packet) + ThreadedAssignment(packet), + _sumListeners(0), + _numStatFrames(0) { // make sure we hear about node kills so we can tell the other nodes connect(NodeList::getInstance(), &NodeList::nodeKilled, this, &AvatarMixer::nodeKilled); @@ -48,7 +51,7 @@ void attachAvatarDataToNode(Node* newNode) { // 3) if we need to rate limit the amount of data we send, we can use a distance weighted "semi-random" function to // determine which avatars are included in the packet stream // 4) we should optimize the avatar data format to be more compact (100 bytes is pretty wasteful). -void broadcastAvatarData() { +void AvatarMixer::broadcastAvatarData() { static QByteArray mixedAvatarByteArray; int numPacketHeaderBytes = populatePacketHeader(mixedAvatarByteArray, PacketTypeBulkAvatarData); @@ -57,6 +60,7 @@ void broadcastAvatarData() { foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { if (node->getLinkedData() && node->getType() == NodeType::Agent && node->getActiveSocket()) { + ++_sumListeners; // reset packet pointers for this node mixedAvatarByteArray.resize(numPacketHeaderBytes); @@ -241,6 +245,25 @@ void AvatarMixer::readPendingDatagrams() { } } +void AvatarMixer::sendStatsPacket() { + QJsonObject statsObject; + statsObject["average_listeners_last_second"] = _sumListeners / (float) _numStatFrames; + + NodeList* nodeList = NodeList::getInstance(); + + float packetsPerSecond, bytesPerSecond; + nodeList->getPacketStats(packetsPerSecond, bytesPerSecond); + nodeList->resetPacketStats(); + + statsObject["packets_per_second"] = packetsPerSecond; + statsObject["bytes_per_second"] = bytesPerSecond; + + nodeList->sendStatsToDomainServer(statsObject); + + _sumListeners = 0; + _numStatFrames = 0; +} + const qint64 AVATAR_IDENTITY_KEYFRAME_MSECS = 5000; const qint64 AVATAR_BILLBOARD_KEYFRAME_MSECS = 5000; @@ -250,6 +273,11 @@ void AvatarMixer::run() { NodeList* nodeList = NodeList::getInstance(); nodeList->addNodeTypeToInterestSet(NodeType::Agent); + // send a stats packet every 1 second + QTimer* statsTimer = new QTimer(this); + connect(statsTimer, &QTimer::timeout, this, &AvatarMixer::sendStatsPacket); + statsTimer->start(1000); + nodeList->linkedDataCreateCallback = attachAvatarDataToNode; int nextFrame = 0; @@ -265,6 +293,8 @@ void AvatarMixer::run() { while (!_isFinished) { + ++_numStatFrames; + QCoreApplication::processEvents(); if (_isFinished) { diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index acc5a178aa..8e9364ddf9 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -24,6 +24,14 @@ public slots: void nodeKilled(SharedNodePointer killedNode); void readPendingDatagrams(); + + void sendStatsPacket(); + +private: + void broadcastAvatarData(); + + int _sumListeners; + int _numStatFrames; }; #endif /* defined(__hifi__AvatarMixer__) */ From e7f9acd945a45f8e98996087b514cb4f69a125c2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 15:42:57 -0700 Subject: [PATCH 72/84] add trailing sleep and performance throttling logic to AvatarMixer --- assignment-client/src/audio/AudioMixer.cpp | 22 +++--- assignment-client/src/audio/AudioMixer.h | 2 +- assignment-client/src/avatars/AvatarMixer.cpp | 70 +++++++++++++++++-- assignment-client/src/avatars/AvatarMixer.h | 3 + 4 files changed, 81 insertions(+), 16 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 608362e0d4..f7092cd4ae 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -68,7 +68,7 @@ AudioMixer::AudioMixer(const QByteArray& packet) : ThreadedAssignment(packet), _trailingSleepRatio(1.0f), _minAudibilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2.0f), - _performanceThrottling(0.0f), + _performanceThrottlingRatio(0.0f), _numStatFrames(0), _sumListeners(0), _sumMixes(0) @@ -359,7 +359,7 @@ void AudioMixer::readPendingDatagrams() { void AudioMixer::sendStatsPacket() { static QJsonObject statsObject; statsObject["trailing_sleep_percentage"] = _trailingSleepRatio * 100.0f; - statsObject["performance_throttling"] = _performanceThrottling; + statsObject["performance_throttling_ratio"] = _performanceThrottlingRatio; statsObject["average_listeners_per_frame"] = _sumListeners / (float) _numStatFrames; @@ -436,7 +436,7 @@ void AudioMixer::run() { _trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio) + (usecToSleep * CURRENT_FRAME_RATIO / (float) BUFFER_SEND_INTERVAL_USECS); - float lastCutoffRatio = _performanceThrottling; + float lastCutoffRatio = _performanceThrottlingRatio; bool hasRatioChanged = false; if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { @@ -446,27 +446,27 @@ void AudioMixer::run() { if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { // we're struggling - change our min required loudness to reduce some load - _performanceThrottling = _performanceThrottling + (0.5f * (1.0f - _performanceThrottling)); + _performanceThrottlingRatio = _performanceThrottlingRatio + (0.5f * (1.0f - _performanceThrottlingRatio)); qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" - << lastCutoffRatio << "and is now" << _performanceThrottling; + << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; hasRatioChanged = true; - } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && _performanceThrottling != 0) { + } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && _performanceThrottlingRatio != 0) { // we've recovered and can back off the required loudness - _performanceThrottling = _performanceThrottling - RATIO_BACK_OFF; + _performanceThrottlingRatio = _performanceThrottlingRatio - RATIO_BACK_OFF; - if (_performanceThrottling < 0) { - _performanceThrottling = 0; + if (_performanceThrottlingRatio < 0) { + _performanceThrottlingRatio = 0; } qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" - << lastCutoffRatio << "and is now" << _performanceThrottling; + << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; hasRatioChanged = true; } if (hasRatioChanged) { // set out min audability threshold from the new ratio - _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - _performanceThrottling)); + _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - _performanceThrottlingRatio)); qDebug() << "Minimum audability required to be mixed is now" << _minAudibilityThreshold; framesSinceCutoffEvent = 0; diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 0b1de6f069..0ca241c5ed 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -44,7 +44,7 @@ private: float _trailingSleepRatio; float _minAudibilityThreshold; - float _performanceThrottling; + float _performanceThrottlingRatio; int _numStatFrames; int _sumListeners; int _sumMixes; diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index d243894ea1..09f6923f40 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -31,6 +31,8 @@ const unsigned int AVATAR_DATA_SEND_INTERVAL_USECS = (1 / 60.0) * 1000 * 1000; AvatarMixer::AvatarMixer(const QByteArray& packet) : ThreadedAssignment(packet), + _trailingSleepRatio(0.0f), + _performanceThrottlingRatio(0.0f), _sumListeners(0), _numStatFrames(0) { @@ -258,6 +260,9 @@ void AvatarMixer::sendStatsPacket() { statsObject["packets_per_second"] = packetsPerSecond; statsObject["bytes_per_second"] = bytesPerSecond; + statsObject["trailing_sleep_percentage"] = _trailingSleepRatio * 100; + statsObject["performance_throttling_ratio"] = _performanceThrottlingRatio; + nodeList->sendStatsToDomainServer(statsObject); _sumListeners = 0; @@ -291,14 +296,65 @@ void AvatarMixer::run() { QElapsedTimer billboardTimer; billboardTimer.start(); + int usecToSleep = AVATAR_DATA_SEND_INTERVAL_USECS; + + const int TRAILING_AVERAGE_FRAMES = 100; + int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; + while (!_isFinished) { ++_numStatFrames; - QCoreApplication::processEvents(); + const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; + const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; - if (_isFinished) { - break; + const float RATIO_BACK_OFF = 0.02f; + + const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; + const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; + + if (usecToSleep < 0) { + usecToSleep = 0; + } + + _trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio) + + (usecToSleep * CURRENT_FRAME_RATIO / (float) AVATAR_DATA_SEND_INTERVAL_USECS); + + float lastCutoffRatio = _performanceThrottlingRatio; + bool hasRatioChanged = false; + + if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { + if (framesSinceCutoffEvent % TRAILING_AVERAGE_FRAMES == 0) { + qDebug() << "Current trailing sleep ratio:" << _trailingSleepRatio; + } + + if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { + // we're struggling - change our min required loudness to reduce some load + _performanceThrottlingRatio = _performanceThrottlingRatio + (0.5f * (1.0f - _performanceThrottlingRatio)); + + qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" + << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; + hasRatioChanged = true; + } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && _performanceThrottlingRatio != 0) { + // we've recovered and can back off the required loudness + _performanceThrottlingRatio = _performanceThrottlingRatio - RATIO_BACK_OFF; + + if (_performanceThrottlingRatio < 0) { + _performanceThrottlingRatio = 0; + } + + qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" + << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; + hasRatioChanged = true; + } + + if (hasRatioChanged) { + framesSinceCutoffEvent = 0; + } + } + + if (!hasRatioChanged) { + ++framesSinceCutoffEvent; } broadcastAvatarData(); @@ -316,7 +372,13 @@ void AvatarMixer::run() { billboardTimer.restart(); } - int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * AVATAR_DATA_SEND_INTERVAL_USECS) - usecTimestampNow(); + QCoreApplication::processEvents(); + + if (_isFinished) { + break; + } + + usecToSleep = usecTimestamp(&startTime) + (++nextFrame * AVATAR_DATA_SEND_INTERVAL_USECS) - usecTimestampNow(); if (usecToSleep > 0) { usleep(usecToSleep); diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index 8e9364ddf9..4d54b715f8 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -30,6 +30,9 @@ public slots: private: void broadcastAvatarData(); + float _trailingSleepRatio; + float _performanceThrottlingRatio; + int _sumListeners; int _numStatFrames; }; From 3db8386743f6792bfeb2850425d38601b709623d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 15:46:02 -0700 Subject: [PATCH 73/84] suppress trailing sleep ratio debug --- assignment-client/src/audio/AudioMixer.cpp | 8 -------- assignment-client/src/avatars/AvatarMixer.cpp | 10 +--------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index f7092cd4ae..5aeedd24f3 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -440,10 +440,6 @@ void AudioMixer::run() { bool hasRatioChanged = false; if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { - if (framesSinceCutoffEvent % TRAILING_AVERAGE_FRAMES == 0) { - qDebug() << "Current trailing sleep ratio:" << _trailingSleepRatio; - } - if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { // we're struggling - change our min required loudness to reduce some load _performanceThrottlingRatio = _performanceThrottlingRatio + (0.5f * (1.0f - _performanceThrottlingRatio)); @@ -473,10 +469,6 @@ void AudioMixer::run() { } } - if (!hasRatioChanged) { - ++framesSinceCutoffEvent; - } - foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioRingBuffer()) { diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 09f6923f40..b302c9bdf0 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -31,7 +31,7 @@ const unsigned int AVATAR_DATA_SEND_INTERVAL_USECS = (1 / 60.0) * 1000 * 1000; AvatarMixer::AvatarMixer(const QByteArray& packet) : ThreadedAssignment(packet), - _trailingSleepRatio(0.0f), + _trailingSleepRatio(1.0f), _performanceThrottlingRatio(0.0f), _sumListeners(0), _numStatFrames(0) @@ -324,10 +324,6 @@ void AvatarMixer::run() { bool hasRatioChanged = false; if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { - if (framesSinceCutoffEvent % TRAILING_AVERAGE_FRAMES == 0) { - qDebug() << "Current trailing sleep ratio:" << _trailingSleepRatio; - } - if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { // we're struggling - change our min required loudness to reduce some load _performanceThrottlingRatio = _performanceThrottlingRatio + (0.5f * (1.0f - _performanceThrottlingRatio)); @@ -353,10 +349,6 @@ void AvatarMixer::run() { } } - if (!hasRatioChanged) { - ++framesSinceCutoffEvent; - } - broadcastAvatarData(); if (identityTimer.elapsed() >= AVATAR_IDENTITY_KEYFRAME_MSECS) { From ba338cb7bc93ad75e065c3fae368f3fe685dc656 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 16:06:25 -0700 Subject: [PATCH 74/84] at minimum send packet rate stats for ThreadedAssignment subclasses --- assignment-client/src/Agent.cpp | 17 +++-------- assignment-client/src/audio/AudioMixer.cpp | 18 ++---------- assignment-client/src/avatars/AvatarMixer.cpp | 18 ++---------- .../src/metavoxels/MetavoxelServer.h | 2 +- assignment-client/src/octree/OctreeServer.cpp | 14 ++-------- assignment-client/src/voxels/VoxelServer.h | 1 - libraries/shared/src/ThreadedAssignment.cpp | 28 ++++++++++++++++++- libraries/shared/src/ThreadedAssignment.h | 4 ++- 8 files changed, 42 insertions(+), 60 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index d32d6a3fd7..b23f9d210a 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -120,10 +120,12 @@ void Agent::readPendingDatagrams() { } } +const QString AGENT_LOGGING_NAME = "agent"; + void Agent::run() { - NodeList* nodeList = NodeList::getInstance(); - nodeList->setOwnerType(NodeType::Agent); + ThreadedAssignment::commonInit(AGENT_LOGGING_NAME, NodeType::Agent); + NodeList* nodeList = NodeList::getInstance(); nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer); // figure out the URL for the script for this agent assignment @@ -148,17 +150,6 @@ void Agent::run() { qDebug() << "Downloaded script:" << scriptContents; - timeval startTime; - gettimeofday(&startTime, NULL); - - QTimer* domainServerTimer = new QTimer(this); - connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); - domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_USECS / 1000); - - QTimer* silentNodeTimer = new QTimer(this); - connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); - silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); - // setup an Avatar for the script to use AvatarData scriptedAvatar; diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 5aeedd24f3..2ef1142b70 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -369,32 +369,18 @@ void AudioMixer::sendStatsPacket() { statsObject["average_mixes_per_listener"] = 0.0; } - NodeList* nodeList = NodeList::getInstance(); - - float packetsPerSecond, bytesPerSecond; - nodeList->getPacketStats(packetsPerSecond, bytesPerSecond); - nodeList->resetPacketStats(); - - statsObject["packets_per_second"] = packetsPerSecond; - statsObject["bytes_per_second"] = bytesPerSecond; + ThreadedAssignment::addPacketStatsAndSendStatsPacket(statsObject); _sumListeners = 0; _sumMixes = 0; _numStatFrames = 0; - - nodeList->sendStatsToDomainServer(statsObject); } void AudioMixer::run() { - commonInit(AUDIO_MIXER_LOGGING_TARGET_NAME, NodeType::AudioMixer); + ThreadedAssignment::commonInit(AUDIO_MIXER_LOGGING_TARGET_NAME, NodeType::AudioMixer); NodeList* nodeList = NodeList::getInstance(); - - // send a stats packet every 1 second - QTimer* statsTimer = new QTimer(this); - connect(statsTimer, &QTimer::timeout, this, &AudioMixer::sendStatsPacket); - statsTimer->start(1000); nodeList->addNodeTypeToInterestSet(NodeType::Agent); diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index b302c9bdf0..2400abbde1 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -251,19 +251,10 @@ void AvatarMixer::sendStatsPacket() { QJsonObject statsObject; statsObject["average_listeners_last_second"] = _sumListeners / (float) _numStatFrames; - NodeList* nodeList = NodeList::getInstance(); - - float packetsPerSecond, bytesPerSecond; - nodeList->getPacketStats(packetsPerSecond, bytesPerSecond); - nodeList->resetPacketStats(); - - statsObject["packets_per_second"] = packetsPerSecond; - statsObject["bytes_per_second"] = bytesPerSecond; - statsObject["trailing_sleep_percentage"] = _trailingSleepRatio * 100; statsObject["performance_throttling_ratio"] = _performanceThrottlingRatio; - nodeList->sendStatsToDomainServer(statsObject); + ThreadedAssignment::addPacketStatsAndSendStatsPacket(statsObject); _sumListeners = 0; _numStatFrames = 0; @@ -273,16 +264,11 @@ const qint64 AVATAR_IDENTITY_KEYFRAME_MSECS = 5000; const qint64 AVATAR_BILLBOARD_KEYFRAME_MSECS = 5000; void AvatarMixer::run() { - commonInit(AVATAR_MIXER_LOGGING_NAME, NodeType::AvatarMixer); + ThreadedAssignment::commonInit(AVATAR_MIXER_LOGGING_NAME, NodeType::AvatarMixer); NodeList* nodeList = NodeList::getInstance(); nodeList->addNodeTypeToInterestSet(NodeType::Agent); - // send a stats packet every 1 second - QTimer* statsTimer = new QTimer(this); - connect(statsTimer, &QTimer::timeout, this, &AvatarMixer::sendStatsPacket); - statsTimer->start(1000); - nodeList->linkedDataCreateCallback = attachAvatarDataToNode; int nextFrame = 0; diff --git a/assignment-client/src/metavoxels/MetavoxelServer.h b/assignment-client/src/metavoxels/MetavoxelServer.h index bd7a280c43..d178127ac7 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.h +++ b/assignment-client/src/metavoxels/MetavoxelServer.h @@ -35,7 +35,7 @@ public: virtual void run(); virtual void readPendingDatagrams(); - + private slots: void maybeAttachSession(const SharedNodePointer& node); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 4990de2b55..6f604c5fd5 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -823,9 +823,9 @@ void OctreeServer::run() { _safeServerName = getMyServerName(); // Before we do anything else, create our tree... _tree = createTree(); - - // change the logging target name while this is running - Logging::setTargetName(getMyLoggingServerTargetName()); + + // use common init to setup common timers and logging + commonInit(getMyLoggingServerTargetName(), getMyNodeType()); // Now would be a good time to parse our arguments, if we got them as assignment if (getPayload().size() > 0) { @@ -988,14 +988,6 @@ void OctreeServer::run() { strftime(utcBuffer, MAX_TIME_LENGTH, " [%m/%d/%Y %X UTC]", gmtm); } qDebug() << "Now running... started at: " << localBuffer << utcBuffer; - - QTimer* domainServerTimer = new QTimer(this); - connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); - domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_USECS / 1000); - - QTimer* silentNodeTimer = new QTimer(this); - connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); - silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); } void OctreeServer::nodeAdded(SharedNodePointer node) { diff --git a/assignment-client/src/voxels/VoxelServer.h b/assignment-client/src/voxels/VoxelServer.h index 509d838fff..2e97736963 100644 --- a/assignment-client/src/voxels/VoxelServer.h +++ b/assignment-client/src/voxels/VoxelServer.h @@ -46,7 +46,6 @@ public: virtual bool hasSpecialPacketToSend(const SharedNodePointer& node); virtual int sendSpecialPacket(const SharedNodePointer& node); - private: bool _sendEnvironments; bool _sendMinimalEnvironment; diff --git a/libraries/shared/src/ThreadedAssignment.cpp b/libraries/shared/src/ThreadedAssignment.cpp index b3a54b1488..f4ea383399 100644 --- a/libraries/shared/src/ThreadedAssignment.cpp +++ b/libraries/shared/src/ThreadedAssignment.cpp @@ -7,6 +7,7 @@ // #include +#include #include #include "Logging.h" @@ -34,7 +35,7 @@ void ThreadedAssignment::setFinished(bool isFinished) { } } -void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeType) { +void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats) { // change the logging target name while the assignment is running Logging::setTargetName(targetName); @@ -52,6 +53,31 @@ void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeTy QTimer* silentNodeRemovalTimer = new QTimer(this); connect(silentNodeRemovalTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); silentNodeRemovalTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); + + if (shouldSendStats) { + // send a stats packet every 1 second + QTimer* statsTimer = new QTimer(this); + connect(statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket); + statsTimer->start(1000); + } +} + +void ThreadedAssignment::addPacketStatsAndSendStatsPacket(QJsonObject &statsObject) { + NodeList* nodeList = NodeList::getInstance(); + + float packetsPerSecond, bytesPerSecond; + nodeList->getPacketStats(packetsPerSecond, bytesPerSecond); + nodeList->resetPacketStats(); + + statsObject["packets_per_second"] = packetsPerSecond; + statsObject["bytes_per_second"] = bytesPerSecond; + + nodeList->sendStatsToDomainServer(statsObject); +} + +void ThreadedAssignment::sendStatsPacket() { + QJsonObject statsObject; + addPacketStatsAndSendStatsPacket(statsObject); } void ThreadedAssignment::checkInWithDomainServerOrExit() { diff --git a/libraries/shared/src/ThreadedAssignment.h b/libraries/shared/src/ThreadedAssignment.h index d3502e9c4d..5b78eed56d 100644 --- a/libraries/shared/src/ThreadedAssignment.h +++ b/libraries/shared/src/ThreadedAssignment.h @@ -17,16 +17,18 @@ public: ThreadedAssignment(const QByteArray& packet); void setFinished(bool isFinished); virtual void aboutToFinish() { }; + void addPacketStatsAndSendStatsPacket(QJsonObject& statsObject); public slots: /// threaded run of assignment virtual void run() = 0; virtual void deleteLater(); virtual void readPendingDatagrams() = 0; + virtual void sendStatsPacket(); protected: bool readAvailableDatagram(QByteArray& destinationByteArray, HifiSockAddr& senderSockAddr); - void commonInit(const QString& targetName, NodeType_t nodeType); + void commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats = true); bool _isFinished; private slots: void checkInWithDomainServerOrExit(); From 778209ffe4e5a6bb8f76bb29e7e674350fe6f1d7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 24 Mar 2014 16:28:07 -0700 Subject: [PATCH 75/84] fix bug in Menu.removeMenu() for trees of menus --- examples/menuExample.js | 5 +++++ interface/src/Menu.cpp | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/menuExample.js b/examples/menuExample.js index 3b18021302..874d95ec31 100644 --- a/examples/menuExample.js +++ b/examples/menuExample.js @@ -32,6 +32,7 @@ function setupMenus() { Menu.addSeparator("Foo","Removable Tools"); Menu.addMenuItem("Foo","Remove Foo item 4"); Menu.addMenuItem("Foo","Remove Foo"); + Menu.addMenuItem("Foo","Remove Bar-Spam"); Menu.addMenu("Bar"); Menu.addMenuItem("Bar","Bar item 1", "b"); @@ -91,6 +92,10 @@ function menuItemEvent(menuItem) { if (menuItem == "Remove Foo") { Menu.removeMenu("Foo"); } + if (menuItem == "Remove Bar-Spam") { + Menu.removeMenu("Bar > Spam"); + } + if (menuItem == "Remove Spam item 2") { Menu.removeMenuItem("Bar > Spam", "Spam item 2"); } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6eb03021b3..7adef1be1c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1414,9 +1414,8 @@ void Menu::removeMenu(const QString& menuName) { if (action) { QString finalMenuPart; QMenu* parent = getMenuParent(menuName, finalMenuPart); - if (parent) { - removeAction(parent, finalMenuPart); + parent->removeAction(action); } else { QMenuBar::removeAction(action); } From 03c2ec9376be4ded6e857d314c5ff847a49de3ac Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 24 Mar 2014 16:28:45 -0700 Subject: [PATCH 76/84] add example of selecting the audio device from a menu --- examples/selectAudioDevice.js | 118 ++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 examples/selectAudioDevice.js diff --git a/examples/selectAudioDevice.js b/examples/selectAudioDevice.js new file mode 100644 index 0000000000..882aec87cc --- /dev/null +++ b/examples/selectAudioDevice.js @@ -0,0 +1,118 @@ +// +// audioDeviceExample.js +// hifi +// +// Created by Brad Hefta-Gaub on 3/22/14 +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// +// This is an example script that demonstrates use of the Menu object +// + +if (typeof String.prototype.startsWith != 'function') { + String.prototype.startsWith = function (str){ + return this.slice(0, str.length) == str; + }; +} + +if (typeof String.prototype.endsWith != 'function') { + String.prototype.endsWith = function (str){ + return this.slice(-str.length) == str; + }; +} + +if (typeof String.prototype.trimStartsWith != 'function') { + String.prototype.trimStartsWith = function (str){ + if (this.startsWith(str)) { + return this.substr(str.length); + } + return this; + }; +} + +if (typeof String.prototype.trimEndsWith != 'function') { + String.prototype.trimEndsWith = function (str){ + if (this.endsWith(str)) { + return this.substr(0,this.length - str.length); + } + return this; + }; +} + +var selectedInputMenu = ""; +var selectedOutputMenu = ""; + +function setupAudioMenus() { + Menu.addMenu("Tools > Audio"); + Menu.addSeparator("Tools > Audio","Output Audio Device"); + + var outputDevices = AudioDevice.getOutputDevices(); + var selectedOutputDevice = AudioDevice.getOutputDevice(); + + for(var i = 0; i < outputDevices.length; i++) { + var thisDeviceSelected = (outputDevices[i] == selectedOutputDevice); + var menuItem = "Use " + outputDevices[i] + " for Output"; + Menu.addMenuItem({ + menuName: "Tools > Audio", + menuItemName: menuItem, + isCheckable: true, + isChecked: thisDeviceSelected + }); + if (thisDeviceSelected) { + selectedOutputMenu = menuItem; + } + } + + Menu.addSeparator("Tools > Audio","Input Audio Device"); + + var inputDevices = AudioDevice.getInputDevices(); + var selectedInputDevice = AudioDevice.getInputDevice(); + + for(var i = 0; i < inputDevices.length; i++) { + var thisDeviceSelected = (inputDevices[i] == selectedInputDevice); + var menuItem = "Use " + inputDevices[i] + " for Input"; + Menu.addMenuItem({ + menuName: "Tools > Audio", + menuItemName: menuItem, + isCheckable: true, + isChecked: thisDeviceSelected + }); + if (thisDeviceSelected) { + selectedInputMenu = menuItem; + } + } +} + +setupAudioMenus(); + +function scriptEnding() { + print("scriptEnding()"); + //Menu.removeMenuItem("Tools > Audio"); + Menu.removeMenu("Tools > Audio"); + //Menu.removeMenu("Tools"); + print("DONE... scriptEnding()"); +} +Script.scriptEnding.connect(scriptEnding); + + +function menuItemEvent(menuItem) { + if (menuItem.startsWith("Use ")) { + if (menuItem.endsWith(" for Output")) { + var selectedDevice = menuItem.trimStartsWith("Use ").trimEndsWith(" for Output"); + print("output audio selection..." + selectedDevice); + Menu.setIsOptionChecked(selectedOutputMenu, false); + selectedOutputMenu = menuItem; + Menu.setIsOptionChecked(selectedOutputMenu, true); + AudioDevice.setOutputDevice(selectedDevice); + + } else if (menuItem.endsWith(" for Input")) { + var selectedDevice = menuItem.trimStartsWith("Use ").trimEndsWith(" for Input"); + print("input audio selection..." + selectedDevice); + Menu.setIsOptionChecked(selectedInputMenu, false); + selectedInputMenu = menuItem; + Menu.setIsOptionChecked(selectedInputMenu, true); + AudioDevice.setInputDevice(selectedDevice); + } + } +} + +Menu.menuItemEvent.connect(menuItemEvent); From 547ea047e3609da3544bd6b30411861c0e13ebd3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 24 Mar 2014 16:33:12 -0700 Subject: [PATCH 77/84] cleanup extra debug --- examples/selectAudioDevice.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/selectAudioDevice.js b/examples/selectAudioDevice.js index 882aec87cc..958ca7babf 100644 --- a/examples/selectAudioDevice.js +++ b/examples/selectAudioDevice.js @@ -85,11 +85,7 @@ function setupAudioMenus() { setupAudioMenus(); function scriptEnding() { - print("scriptEnding()"); - //Menu.removeMenuItem("Tools > Audio"); Menu.removeMenu("Tools > Audio"); - //Menu.removeMenu("Tools"); - print("DONE... scriptEnding()"); } Script.scriptEnding.connect(scriptEnding); From 364df16a9f7d901058474e0cfd31ebe6cebde36f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 16:34:00 -0700 Subject: [PATCH 78/84] pretty up the stats table --- domain-server/resources/web/stats/js/stats.js | 10 ++++++++-- domain-server/src/DomainServer.cpp | 9 +++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/domain-server/resources/web/stats/js/stats.js b/domain-server/resources/web/stats/js/stats.js index e82668ea9e..bebd16b883 100644 --- a/domain-server/resources/web/stats/js/stats.js +++ b/domain-server/resources/web/stats/js/stats.js @@ -13,7 +13,13 @@ $(document).ready(function(){ var statsTableBody = ""; $.getJSON("/nodes/" + uuid + ".json", function(json){ - $.each(json, function (key, value) { + + // update the table header with the right node type + $('#stats-lead h3').html(json.node_type + " stats (" + uuid +); + + delete json.node_type; + + $.each(json, function(key, value) { statsTableBody += ""; statsTableBody += "" + key + ""; statsTableBody += "" + value + ""; @@ -21,7 +27,7 @@ $(document).ready(function(){ }); $('#stats-table tbody').html(statsTableBody); - }); + }); } // do the first GET on page load diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 0a8b70a673..913ca44e12 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -737,8 +737,13 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url SharedNodePointer matchingNode = NodeList::getInstance()->nodeWithUUID(matchingUUID); if (matchingNode) { // create a QJsonDocument with the stats QJsonObject - QJsonDocument statsDocument(reinterpret_cast(matchingNode->getLinkedData()) - ->getStatsJSONObject()); + QJsonObject statsObject = + reinterpret_cast(matchingNode->getLinkedData())->getStatsJSONObject(); + + // add the node type to the JSON data for output purposes + statsObject["node_type"] = NodeType::getNodeTypeName(matchingNode->getType()).toLower().replace(' ', '-'); + + QJsonDocument statsDocument(statsObject); // send the response connection->respond(HTTPConnection::StatusCode200, statsDocument.toJson(), qPrintable(JSON_MIME_TYPE)); From b01b2a3311127a711324d92151e16cc972d8b7e8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 16:35:36 -0700 Subject: [PATCH 79/84] use explicit float casts where appropriate --- assignment-client/src/audio/AudioMixer.cpp | 4 ++-- assignment-client/src/avatars/AvatarMixer.cpp | 2 +- libraries/shared/src/NodeList.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 2ef1142b70..450b6e0ad9 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -361,10 +361,10 @@ void AudioMixer::sendStatsPacket() { statsObject["trailing_sleep_percentage"] = _trailingSleepRatio * 100.0f; statsObject["performance_throttling_ratio"] = _performanceThrottlingRatio; - statsObject["average_listeners_per_frame"] = _sumListeners / (float) _numStatFrames; + statsObject["average_listeners_per_frame"] = (float) _sumListeners / (float) _numStatFrames; if (_sumListeners > 0) { - statsObject["average_mixes_per_listener"] = _sumMixes / (float) _sumListeners; + statsObject["average_mixes_per_listener"] = (float) _sumMixes / (float) _sumListeners; } else { statsObject["average_mixes_per_listener"] = 0.0; } diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 2400abbde1..8964c8f771 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -249,7 +249,7 @@ void AvatarMixer::readPendingDatagrams() { void AvatarMixer::sendStatsPacket() { QJsonObject statsObject; - statsObject["average_listeners_last_second"] = _sumListeners / (float) _numStatFrames; + statsObject["average_listeners_last_second"] = (float) _sumListeners / (float) _numStatFrames; statsObject["trailing_sleep_percentage"] = _trailingSleepRatio * 100; statsObject["performance_throttling_ratio"] = _performanceThrottlingRatio; diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index d4babd4557..89e915a722 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -864,8 +864,8 @@ SharedNodePointer NodeList::soloNodeOfType(char nodeType) { } void NodeList::getPacketStats(float& packetsPerSecond, float& bytesPerSecond) { - packetsPerSecond = _numCollectedPackets / (float) (_packetStatTimer.elapsed() / 1000.0f); - bytesPerSecond = _numCollectedBytes / (float) (_packetStatTimer.elapsed() / 1000.0f); + packetsPerSecond = (float) _numCollectedPackets / (float) (_packetStatTimer.elapsed() / 1000.0f); + bytesPerSecond = (float) _numCollectedBytes / (float) (_packetStatTimer.elapsed() / 1000.0f); } void NodeList::resetPacketStats() { From 4f7a8473fde27c66a5d59dfb7d49d7f727fce125 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 16:40:14 -0700 Subject: [PATCH 80/84] make stats red when they become stale --- domain-server/resources/web/css/style.css | 4 ++++ domain-server/resources/web/stats/js/stats.js | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/domain-server/resources/web/css/style.css b/domain-server/resources/web/css/style.css index d641aa5f71..fb295cffc3 100644 --- a/domain-server/resources/web/css/style.css +++ b/domain-server/resources/web/css/style.css @@ -38,4 +38,8 @@ span.port { color: #666666; +} + +.stale { + color: red; } \ No newline at end of file diff --git a/domain-server/resources/web/stats/js/stats.js b/domain-server/resources/web/stats/js/stats.js index bebd16b883..a7b0aecfcf 100644 --- a/domain-server/resources/web/stats/js/stats.js +++ b/domain-server/resources/web/stats/js/stats.js @@ -15,7 +15,7 @@ $(document).ready(function(){ $.getJSON("/nodes/" + uuid + ".json", function(json){ // update the table header with the right node type - $('#stats-lead h3').html(json.node_type + " stats (" + uuid +); + $('#stats-lead h3').html(json.node_type + " stats (" + uuid + ")"); delete json.node_type; @@ -27,6 +27,10 @@ $(document).ready(function(){ }); $('#stats-table tbody').html(statsTableBody); + }).fail(function(data) { + $('#stats-table td').each(function(){ + $(this).addClass('stale'); + }); }); } From ce214bc43998cf277f83f1962ff565e372fbc067 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 16:48:23 -0700 Subject: [PATCH 81/84] use the performance tuning ratio in avatar mixer to send less --- assignment-client/src/avatars/AvatarMixer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 8964c8f771..0ec7c3e15e 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -84,7 +84,8 @@ void AvatarMixer::broadcastAvatarData() { // at a distance of twice the full rate distance, there will be a 50% chance of sending this avatar's update const float FULL_RATE_DISTANCE = 2.f; // Decide whether to send this avatar's data based on it's distance from us - if ((distanceToAvatar == 0.f) || (randFloat() < FULL_RATE_DISTANCE / distanceToAvatar)) { + if ((distanceToAvatar == 0.f) || (randFloat() < FULL_RATE_DISTANCE / distanceToAvatar) + * (1 - _performanceThrottlingRatio)) { QByteArray avatarByteArray; avatarByteArray.append(otherNode->getUUID().toRfc4122()); avatarByteArray.append(otherAvatar.toByteArray()); From a90cd7ed312f50cc66a601637f19dcf50e565804 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 16:54:14 -0700 Subject: [PATCH 82/84] cast numerator to float before divide --- libraries/shared/src/NodeList.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 89e915a722..95417f4f71 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -864,8 +864,8 @@ SharedNodePointer NodeList::soloNodeOfType(char nodeType) { } void NodeList::getPacketStats(float& packetsPerSecond, float& bytesPerSecond) { - packetsPerSecond = (float) _numCollectedPackets / (float) (_packetStatTimer.elapsed() / 1000.0f); - bytesPerSecond = (float) _numCollectedBytes / (float) (_packetStatTimer.elapsed() / 1000.0f); + packetsPerSecond = (float) _numCollectedPackets / ((float) _packetStatTimer.elapsed() / 1000.0f); + bytesPerSecond = (float) _numCollectedBytes / ((float) _packetStatTimer.elapsed() / 1000.0f); } void NodeList::resetPacketStats() { From fcc261cc2b198e10dc57b5d7885b7d27bd008998 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Mar 2014 17:15:53 -0700 Subject: [PATCH 83/84] fix BUILD.md instructions and CMakeLists so QT_CMAKE_PREFIX_PATH can be passed --- BUILD.md | 2 +- CMakeLists.txt | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/BUILD.md b/BUILD.md index e033916e08..8f871c3cea 100644 --- a/BUILD.md +++ b/BUILD.md @@ -38,7 +38,7 @@ Any variables that need to be set for CMake to find dependencies can be set as E For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generation: - cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.2.0/clang_64/lib/cmake + cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.2.0/lib/cmake UNIX diff --git a/CMakeLists.txt b/CMakeLists.txt index 4674df40de..cb1e4224cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,11 @@ elseif (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") endif(WIN32) -set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} $ENV{QT_CMAKE_PREFIX_PATH}) +if (NOT QT_CMAKE_PREFIX_PATH) + set(QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH}) +endif () + +set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${QT_CMAKE_PREFIX_PATH}) # set our Base SDK to 10.8 set(CMAKE_OSX_SYSROOT /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk) From 55622d5f23840b3747728640d5d68c78e62f0b25 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 25 Mar 2014 00:46:07 -0700 Subject: [PATCH 84/84] add stub of default script --- examples/defaultScripts.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 examples/defaultScripts.js diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js new file mode 100644 index 0000000000..4b228492c7 --- /dev/null +++ b/examples/defaultScripts.js @@ -0,0 +1,5 @@ +// defaultScripts.js +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +Script.include("lookWithTouch.js"); +Script.include("editVoxels.js"); +Script.include("selectAudioDevice.js");