diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 8ab62eaeeb..05e1583fca 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -133,7 +133,7 @@ int main(int argc, const char * argv[]) if (DEBUG_TO_SELF || !agent->matches((sockaddr *)&agentPublicAddress, (sockaddr *)&agentLocalAddress, agentType)) { - if (strchr(SOLO_AGENT_TYPES_STRING, (int) agent->getType()) == NULL) { + if (memchr(SOLO_AGENT_TYPES_STRING, agent->getType(), 1) == NULL) { // this is an agent of which there can be multiple, just add them to the packet currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, &(*agent)); } else { diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 91a227a72a..821ff2e111 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -47,9 +47,9 @@ unsigned int iris_texture_height = 256; Head::Head(bool isMine) { - _avatar.orientation.setToIdentity(); - _avatar.velocity = glm::vec3( 0.0, 0.0, 0.0 ); - _avatar.thrust = glm::vec3( 0.0, 0.0, 0.0 ); + _orientation.setToIdentity(); + _velocity = glm::vec3( 0.0, 0.0, 0.0 ); + _thrust = glm::vec3( 0.0, 0.0, 0.0 ); _rotation = glm::quat( 0.0f, 0.0f, 0.0f, 0.0f ); _closestOtherAvatar = 0; _bodyYaw = -90.0; @@ -59,6 +59,10 @@ Head::Head(bool isMine) { _triggeringAction = false; _mode = AVATAR_MODE_STANDING; _isMine = isMine; + _maxArmLength = 0.0; + //_transmitterTimer = 0; + _transmitterHz = 0.0; + _transmitterPackets = 0; initializeSkeleton(); @@ -67,49 +71,53 @@ Head::Head(bool isMine) { for (int i = 0; i < MAX_DRIVE_KEYS; i++) _driveKeys[i] = false; - _pupilSize = 0.10; - _interPupilDistance = 0.6; - _interBrowDistance = 0.75; - _nominalPupilSize = 0.10; - _headYaw = 0.0; - _eyebrowPitch[0] = -30; - _eyebrowPitch[1] = -30; - _eyebrowRoll [0] = 20; - _eyebrowRoll [1] = -20; - _mouthPitch = 0; - _mouthYaw = 0; - _mouthWidth = 1.0; - _mouthHeight = 0.2; - _eyeballPitch[0] = 0; - _eyeballPitch[1] = 0; - _eyeballScaleX = 1.2; - _eyeballScaleY = 1.5; - _eyeballScaleZ = 1.0; - _eyeballYaw[0] = 0; - _eyeballYaw[1] = 0; - _pitchTarget = 0; - _yawTarget = 0; - _noiseEnvelope = 1.0; - _pupilConverge = 10.0; - _leanForward = 0.0; - _leanSideways = 0.0; - _eyeContact = 1; - _eyeContactTarget = LEFT_EYE; - _scale = 1.0; - _renderYaw = 0.0; - _renderPitch = 0.0; - _audioAttack = 0.0; - _loudness = 0.0; - _averageLoudness = 0.0; - _lastLoudness = 0.0; - _browAudioLift = 0.0; - _noise = 0; - _handBeingMoved = false; - _previousHandBeingMoved = false; - _movedHandOffset = glm::vec3( 0.0, 0.0, 0.0 ); - _usingSprings = false; - _springForce = 6.0f; - _springVelocityDecay = 16.0f; + _head.pupilSize = 0.10; + _head.interPupilDistance = 0.6; + _head.interBrowDistance = 0.75; + _head.nominalPupilSize = 0.10; + _head.yaw = 0.0; + _head.pitch = 0.0; + _head.roll = 0.0; + _head.pitchRate = 0.0; + _head.yawRate = 0.0; + _head.rollRate = 0.0; + _head.eyebrowPitch[0] = -30; + _head.eyebrowPitch[1] = -30; + _head.eyebrowRoll [0] = 20; + _head.eyebrowRoll [1] = -20; + _head.mouthPitch = 0; + _head.mouthYaw = 0; + _head.mouthWidth = 1.0; + _head.mouthHeight = 0.2; + _head.eyeballPitch[0] = 0; + _head.eyeballPitch[1] = 0; + _head.eyeballScaleX = 1.2; + _head.eyeballScaleY = 1.5; + _head.eyeballScaleZ = 1.0; + _head.eyeballYaw[0] = 0; + _head.eyeballYaw[1] = 0; + _head.pitchTarget = 0; + _head.yawTarget = 0; + _head.noiseEnvelope = 1.0; + _head.pupilConverge = 10.0; + _head.leanForward = 0.0; + _head.leanSideways = 0.0; + _head.eyeContact = 1; + _head.eyeContactTarget = LEFT_EYE; + _head.scale = 1.0; + _head.audioAttack = 0.0; + _head.loudness = 0.0; + _head.averageLoudness = 0.0; + _head.lastLoudness = 0.0; + _head.browAudioLift = 0.0; + _head.noise = 0; + + _movedHandOffset = glm::vec3( 0.0, 0.0, 0.0 ); + _usingBodySprings = false; + _springForce = 6.0f; + _springVelocityDecay = 16.0f; + _renderYaw = 0.0; + _renderPitch = 0.0; _sphere = NULL; @@ -120,80 +128,104 @@ Head::Head(bool isMine) { printLog("error %u: %s\n", error, lodepng_error_text(error)); } } - - for (int o=0; ogetRelativeValue(HEAD_PITCH_RATE); - _headYawRate = serialInterface->getRelativeValue(HEAD_YAW_RATE); + _head.yawRate = serialInterface->getRelativeValue(HEAD_YAW_RATE); float measured_lateral_accel = serialInterface->getRelativeValue(ACCEL_X) - ROLL_ACCEL_COUPLING*serialInterface->getRelativeValue(HEAD_ROLL_RATE); float measured_fwd_accel = serialInterface->getRelativeValue(ACCEL_Z) - @@ -242,35 +274,35 @@ void Head::UpdateGyros(float frametime, SerialInterface * serialInterface, int h const float MAX_YAW = 85; const float MIN_YAW = -85; - if ((_headPitch < MAX_PITCH) && (_headPitch > MIN_PITCH)) + if ((_head.pitch < MAX_PITCH) && (_head.pitch > MIN_PITCH)) addPitch(measured_pitch_rate * -HEAD_ROTATION_SCALE * frametime); addRoll(-measured_roll_rate * HEAD_ROLL_SCALE * frametime); if (head_mirror) { - if ((_headYaw < MAX_YAW) && (_headYaw > MIN_YAW)) - addYaw(-_headYawRate * HEAD_ROTATION_SCALE * frametime); + if ((_head.yaw < MAX_YAW) && (_head.yaw > MIN_YAW)) + addYaw(-_head.yawRate * HEAD_ROTATION_SCALE * frametime); addLean(-measured_lateral_accel * frametime * HEAD_LEAN_SCALE, -measured_fwd_accel*frametime * HEAD_LEAN_SCALE); } else { - if ((_headYaw < MAX_YAW) && (_headYaw > MIN_YAW)) - addYaw(_headYawRate * -HEAD_ROTATION_SCALE * frametime); + if ((_head.yaw < MAX_YAW) && (_head.yaw > MIN_YAW)) + addYaw(_head.yawRate * -HEAD_ROTATION_SCALE * frametime); addLean(measured_lateral_accel * frametime * -HEAD_LEAN_SCALE, measured_fwd_accel*frametime * HEAD_LEAN_SCALE); } } void Head::addLean(float x, float z) { // Add Body lean as impulse - _leanSideways += x; - _leanForward += z; + _head.leanSideways += x; + _head.leanForward += z; } void Head::setLeanForward(float dist){ - _leanForward = dist; + _head.leanForward = dist; } void Head::setLeanSideways(float dist){ - _leanSideways = dist; + _head.leanSideways = dist; } void Head::setTriggeringAction( bool d ) { @@ -318,7 +350,7 @@ void Head::simulate(float deltaTime) { float distance = glm::length( v ); - if ( distance < _avatar.maxArmLength ) { + if ( distance < _maxArmLength ) { if ( distance < closestDistance ) { closestDistance = distance; _closestOtherAvatar = o; @@ -340,60 +372,43 @@ void Head::simulate(float deltaTime) { //------------------------ updateSkeleton(); - //------------------------------------------------------------------------ - // reset hand and elbow position according to hand movement - //------------------------------------------------------------------------ - if ( _handBeingMoved ){ - if (! _previousHandBeingMoved ){ - initializeBodySprings(); - _usingSprings = true; - //printLog( "just started moving hand\n" ); - } - } - else { - if ( _previousHandBeingMoved ){ - _usingSprings = false; - //printLog( "just stopped moving hand\n" ); - } - } - - if ( _handBeingMoved ) { + //------------------------------------------------------------ + // reset hand and arm positions according to hand movement + //------------------------------------------------------------ + if (_usingBodySprings) { updateHandMovement(); updateBodySprings( deltaTime ); } - - _previousHandBeingMoved = _handBeingMoved; - _handBeingMoved = false; - if ( _isMine ) { // driving the avatar around should only apply is this is my avatar (as opposed to an avatar being driven remotely) + if ( _isMine ) { // driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely) //------------------------------------------------- // this handles the avatar being driven around... //------------------------------------------------- - _avatar.thrust = glm::vec3( 0.0, 0.0, 0.0 ); + _thrust = glm::vec3( 0.0, 0.0, 0.0 ); if (_driveKeys[FWD]) { - glm::vec3 front( _avatar.orientation.getFront().x, _avatar.orientation.getFront().y, _avatar.orientation.getFront().z ); - _avatar.thrust += front * THRUST_MAG; + glm::vec3 front( _orientation.getFront().x, _orientation.getFront().y, _orientation.getFront().z ); + _thrust += front * THRUST_MAG; } if (_driveKeys[BACK]) { - glm::vec3 front( _avatar.orientation.getFront().x, _avatar.orientation.getFront().y, _avatar.orientation.getFront().z ); - _avatar.thrust -= front * THRUST_MAG; + glm::vec3 front( _orientation.getFront().x, _orientation.getFront().y, _orientation.getFront().z ); + _thrust -= front * THRUST_MAG; } if (_driveKeys[RIGHT]) { - glm::vec3 right( _avatar.orientation.getRight().x, _avatar.orientation.getRight().y, _avatar.orientation.getRight().z ); - _avatar.thrust -= right * THRUST_MAG; + glm::vec3 right( _orientation.getRight().x, _orientation.getRight().y, _orientation.getRight().z ); + _thrust += right * THRUST_MAG; } if (_driveKeys[LEFT]) { - glm::vec3 right( _avatar.orientation.getRight().x, _avatar.orientation.getRight().y, _avatar.orientation.getRight().z ); - _avatar.thrust += right * THRUST_MAG; + glm::vec3 right( _orientation.getRight().x, _orientation.getRight().y, _orientation.getRight().z ); + _thrust -= right * THRUST_MAG; } if (_driveKeys[UP]) { - glm::vec3 up( _avatar.orientation.getUp().x, _avatar.orientation.getUp().y, _avatar.orientation.getUp().z ); - _avatar.thrust += up * THRUST_MAG; + glm::vec3 up( _orientation.getUp().x, _orientation.getUp().y, _orientation.getUp().z ); + _thrust += up * THRUST_MAG; } if (_driveKeys[DOWN]) { - glm::vec3 up( _avatar.orientation.getUp().x, _avatar.orientation.getUp().y, _avatar.orientation.getUp().z ); - _avatar.thrust -= up * THRUST_MAG; + glm::vec3 up( _orientation.getUp().x, _orientation.getUp().y, _orientation.getUp().z ); + _thrust -= up * THRUST_MAG; } if (_driveKeys[ROT_RIGHT]) { _bodyYawDelta -= YAW_MAG * deltaTime; @@ -405,7 +420,7 @@ void Head::simulate(float deltaTime) { //---------------------------------------------------------- - float translationalSpeed = glm::length( _avatar.velocity ); + float translationalSpeed = glm::length( _velocity ); float rotationalSpeed = fabs( _bodyYawDelta ); if ( translationalSpeed + rotationalSpeed > 0.2 ) { @@ -413,7 +428,7 @@ void Head::simulate(float deltaTime) { } else { - _mode = AVATAR_MODE_COMMUNICATING; + _mode = AVATAR_MODE_INTERACTING; } //---------------------------------------------------------- @@ -424,9 +439,9 @@ void Head::simulate(float deltaTime) { } // we will be eventually getting head rotation from elsewhere. For now, just setting it to body rotation - _headYaw = _bodyYaw; - _headPitch = _bodyPitch; - _headRoll = _bodyRoll; + _head.yaw = _bodyYaw; + _head.pitch = _bodyPitch; + _head.roll = _bodyRoll; //---------------------------------------------------------- // decay body yaw delta @@ -437,45 +452,45 @@ void Head::simulate(float deltaTime) { //---------------------------------------------------------- // add thrust to velocity //---------------------------------------------------------- - _avatar.velocity += glm::dvec3(_avatar.thrust * deltaTime); + _velocity += glm::dvec3(_thrust * deltaTime); //---------------------------------------------------------- // update position by velocity //---------------------------------------------------------- - _bodyPosition += (glm::vec3)_avatar.velocity * deltaTime; + _bodyPosition += (glm::vec3)_velocity * deltaTime; //---------------------------------------------------------- // decay velocity //---------------------------------------------------------- const float LIN_VEL_DECAY = 5.0; - _avatar.velocity *= ( 1.0 - LIN_VEL_DECAY * deltaTime ); + _velocity *= ( 1.0 - LIN_VEL_DECAY * deltaTime ); - if (!_noise) { + if (!_head.noise) { // Decay back toward center - _headPitch *= (1.0f - DECAY*2*deltaTime); - _headYaw *= (1.0f - DECAY*2*deltaTime); - _headRoll *= (1.0f - DECAY*2*deltaTime); + _head.pitch *= (1.0f - DECAY*2*deltaTime); + _head.yaw *= (1.0f - DECAY*2*deltaTime); + _head.roll *= (1.0f - DECAY*2*deltaTime); } else { // Move toward new target - _headPitch += (_pitchTarget - _headPitch)*10*deltaTime; // (1.f - DECAY*deltaTime)*Pitch + ; - _headYaw += (_yawTarget - _headYaw)*10*deltaTime; // (1.f - DECAY*deltaTime); - _headRoll *= (1.f - DECAY*deltaTime); + _head.pitch += (_head.pitchTarget - _head.pitch)*10*deltaTime; // (1.f - DECAY*deltaTime)*Pitch + ; + _head.yaw += (_head.yawTarget - _head.yaw )*10*deltaTime; // (1.f - DECAY*deltaTime); + _head.roll *= (1.f - DECAY*deltaTime); } - _leanForward *= (1.f - DECAY*30.f*deltaTime); - _leanSideways *= (1.f - DECAY*30.f*deltaTime); + _head.leanForward *= (1.f - DECAY*30.f*deltaTime); + _head.leanSideways *= (1.f - DECAY*30.f*deltaTime); // Update where the avatar's eyes are // // First, decide if we are making eye contact or not if (randFloat() < 0.005) { - _eyeContact = !_eyeContact; - _eyeContact = 1; - if (!_eyeContact) { + _head.eyeContact = !_head.eyeContact; + _head.eyeContact = 1; + if (!_head.eyeContact) { // If we just stopped making eye contact,move the eyes markedly away - _eyeballPitch[0] = _eyeballPitch[1] = _eyeballPitch[0] + 5.0 + (randFloat() - 0.5)*10; - _eyeballYaw[0] = _eyeballYaw[1] = _eyeballYaw[0] + 5.0 + (randFloat()- 0.5)*5; + _head.eyeballPitch[0] = _head.eyeballPitch[1] = _head.eyeballPitch[0] + 5.0 + (randFloat() - 0.5)*10; + _head.eyeballYaw [0] = _head.eyeballYaw [1] = _head.eyeballYaw [0] + 5.0 + (randFloat() - 0.5)*5; } else { // If now making eye contact, turn head to look right at viewer SetNewHeadTarget(0,0); @@ -485,56 +500,56 @@ void Head::simulate(float deltaTime) { const float DEGREES_BETWEEN_VIEWER_EYES = 3; const float DEGREES_TO_VIEWER_MOUTH = 7; - if (_eyeContact) { + if (_head.eyeContact) { // Should we pick a new eye contact target? if (randFloat() < 0.01) { // Choose where to look next if (randFloat() < 0.1) { - _eyeContactTarget = MOUTH; + _head.eyeContactTarget = MOUTH; } else { - if (randFloat() < 0.5) _eyeContactTarget = LEFT_EYE; else _eyeContactTarget = RIGHT_EYE; + if (randFloat() < 0.5) _head.eyeContactTarget = LEFT_EYE; else _head.eyeContactTarget = RIGHT_EYE; } } // Set eyeball pitch and yaw to make contact float eye_target_yaw_adjust = 0; float eye_target_pitch_adjust = 0; - if (_eyeContactTarget == LEFT_EYE) eye_target_yaw_adjust = DEGREES_BETWEEN_VIEWER_EYES; - if (_eyeContactTarget == RIGHT_EYE) eye_target_yaw_adjust = -DEGREES_BETWEEN_VIEWER_EYES; - if (_eyeContactTarget == MOUTH) eye_target_pitch_adjust = DEGREES_TO_VIEWER_MOUTH; + if (_head.eyeContactTarget == LEFT_EYE) eye_target_yaw_adjust = DEGREES_BETWEEN_VIEWER_EYES; + if (_head.eyeContactTarget == RIGHT_EYE) eye_target_yaw_adjust = -DEGREES_BETWEEN_VIEWER_EYES; + if (_head.eyeContactTarget == MOUTH) eye_target_pitch_adjust = DEGREES_TO_VIEWER_MOUTH; - _eyeballPitch[0] = _eyeballPitch[1] = -_headPitch + eye_target_pitch_adjust; - _eyeballYaw[0] = _eyeballYaw[1] = -_headYaw + eye_target_yaw_adjust; + _head.eyeballPitch[0] = _head.eyeballPitch[1] = -_head.pitch + eye_target_pitch_adjust; + _head.eyeballYaw[0] = _head.eyeballYaw[1] = -_head.yaw + eye_target_yaw_adjust; } - if (_noise) + if (_head.noise) { - _headPitch += (randFloat() - 0.5)*0.2*_noiseEnvelope; - _headYaw += (randFloat() - 0.5)*0.3*_noiseEnvelope; + _head.pitch += (randFloat() - 0.5)*0.2*_head.noiseEnvelope; + _head.yaw += (randFloat() - 0.5)*0.3*_head.noiseEnvelope; //PupilSize += (randFloat() - 0.5)*0.001*NoiseEnvelope; - if (randFloat() < 0.005) _mouthWidth = MouthWidthChoices[rand()%3]; + if (randFloat() < 0.005) _head.mouthWidth = MouthWidthChoices[rand()%3]; - if (!_eyeContact) { - if (randFloat() < 0.01) _eyeballPitch[0] = _eyeballPitch[1] = (randFloat() - 0.5)*20; - if (randFloat() < 0.01) _eyeballYaw[0] = _eyeballYaw[1] = (randFloat()- 0.5)*10; + if (!_head.eyeContact) { + if (randFloat() < 0.01) _head.eyeballPitch[0] = _head.eyeballPitch[1] = (randFloat() - 0.5)*20; + if (randFloat() < 0.01) _head.eyeballYaw[0] = _head.eyeballYaw[1] = (randFloat()- 0.5)*10; } - if ((randFloat() < 0.005) && (fabs(_pitchTarget - _headPitch) < 1.0) && (fabs(_yawTarget - _headYaw) < 1.0)) { + if ((randFloat() < 0.005) && (fabs(_head.pitchTarget - _head.pitch) < 1.0) && (fabs(_head.yawTarget - _head.yaw) < 1.0)) { SetNewHeadTarget((randFloat()-0.5)*20.0, (randFloat()-0.5)*45.0); } if (0) { // Pick new target - _pitchTarget = (randFloat() - 0.5)*45; - _yawTarget = (randFloat() - 0.5)*22; + _head.pitchTarget = (randFloat() - 0.5)*45; + _head.yawTarget = (randFloat() - 0.5)*22; } if (randFloat() < 0.01) { - _eyebrowPitch[0] = _eyebrowPitch[1] = BrowPitchAngle[rand()%3]; - _eyebrowRoll[0] = _eyebrowRoll[1] = BrowRollAngle[rand()%5]; - _eyebrowRoll[1]*=-1; + _head.eyebrowPitch[0] = _head.eyebrowPitch[1] = BrowPitchAngle[rand()%3]; + _head.eyebrowRoll [0] = _head.eyebrowRoll[1] = BrowRollAngle[rand()%5]; + _head.eyebrowRoll [1]*=-1; } } } @@ -567,24 +582,36 @@ void Head::updateBigSphereCollisionTest( float deltaTime ) { float amp = 1.0 - (distanceToBigSphereCenter / combinedRadius); glm::vec3 collisionForce = vectorFromJointToBigSphere * amp; _bone[b].springyVelocity += collisionForce * 8.0f * deltaTime; - _avatar.velocity += collisionForce * 18.0f * deltaTime; + _velocity += collisionForce * 18.0f * deltaTime; } } } if ( jointCollision ) { + if (!_usingBodySprings) { + _usingBodySprings = true; + initializeBodySprings(); + } + /* + else { + if (_usingSprings) { + _usingSprings = false; + } + } + */ + //---------------------------------------------------------- // add gravity to velocity //---------------------------------------------------------- - _avatar.velocity += glm::dvec3( 0.0, -1.0, 0.0 ) * 0.05; + _velocity += glm::dvec3( 0.0, -1.0, 0.0 ) * 0.05; //---------------------------------------------------------- // ground collisions //---------------------------------------------------------- if ( _bodyPosition.y < 0.0 ) { _bodyPosition.y = 0.0; - if ( _avatar.velocity.y < 0.0 ) { - _avatar.velocity.y *= -0.7; + if ( _velocity.y < 0.0 ) { + _velocity.y *= -0.7; } } } @@ -650,7 +677,7 @@ void Head::render(int faceToFace) { glPopMatrix(); } - if ( _usingSprings ) { + if (_usingBodySprings) { if ( _closestOtherAvatar != -1 ) { glm::vec3 v1( _bone[ AVATAR_BONE_RIGHT_HAND ].position ); @@ -667,35 +694,6 @@ void Head::render(int faceToFace) { } } - - -//this has been moved to Utils.cpp -/* -void Head::renderOrientationDirections( glm::vec3 position, Orientation orientation, float size ) { - glm::vec3 pRight = position + orientation.right * size; - glm::vec3 pUp = position + orientation.up * size; - glm::vec3 pFront = position + orientation.front * size; - - glColor3f( 1.0f, 0.0f, 0.0f ); - glBegin( GL_LINE_STRIP ); - glVertex3f( position.x, position.y, position.z ); - glVertex3f( pRight.x, pRight.y, pRight.z ); - glEnd(); - - glColor3f( 0.0f, 1.0f, 0.0f ); - glBegin( GL_LINE_STRIP ); - glVertex3f( position.x, position.y, position.z ); - glVertex3f( pUp.x, pUp.y, pUp.z ); - glEnd(); - - glColor3f( 0.0f, 0.0f, 1.0f ); - glBegin( GL_LINE_STRIP ); - glVertex3f( position.x, position.y, position.z ); - glVertex3f( pFront.x, pFront.y, pFront.z ); - glEnd(); -} -*/ - void Head::renderHead(int faceToFace) { @@ -706,7 +704,7 @@ void Head::renderHead(int faceToFace) { glPushMatrix(); - if (_usingSprings) { + if (_usingBodySprings) { glTranslatef ( _bone[ AVATAR_BONE_HEAD ].springyPosition.x, @@ -726,9 +724,9 @@ void Head::renderHead(int faceToFace) { glScalef( 0.03, 0.03, 0.03 ); - glRotatef(_headYaw, 0, 1, 0); - glRotatef(_headPitch, 1, 0, 0); - glRotatef(_headRoll, 0, 0, 1); + glRotatef(_head.yaw, 0, 1, 0); + glRotatef(_head.pitch, 1, 0, 0); + glRotatef(_head.roll, 0, 0, 1); // Overall scale of head if (faceToFace) glScalef(2.0, 2.0, 2.0); @@ -757,27 +755,27 @@ void Head::renderHead(int faceToFace) { glPopMatrix(); // _eyebrows - _audioAttack = 0.9*_audioAttack + 0.1*fabs(_loudness - _lastLoudness); - _lastLoudness = _loudness; + _head.audioAttack = 0.9*_head.audioAttack + 0.1*fabs(_head.loudness - _head.lastLoudness); + _head.lastLoudness = _head.loudness; const float BROW_LIFT_THRESHOLD = 100; - if (_audioAttack > BROW_LIFT_THRESHOLD) - _browAudioLift += sqrt(_audioAttack)/1000.0; + if (_head.audioAttack > BROW_LIFT_THRESHOLD) + _head.browAudioLift += sqrt(_head.audioAttack)/1000.0; - _browAudioLift *= .90; + _head.browAudioLift *= .90; glPushMatrix(); - glTranslatef(-_interBrowDistance/2.0,0.4,0.45); + glTranslatef(-_head.interBrowDistance/2.0,0.4,0.45); for(side = 0; side < 2; side++) { glColor3fv(browColor); glPushMatrix(); - glTranslatef(0, 0.35 + _browAudioLift, 0); - glRotatef(_eyebrowPitch[side]/2.0, 1, 0, 0); - glRotatef(_eyebrowRoll[side]/2.0, 0, 0, 1); + glTranslatef(0, 0.35 + _head.browAudioLift, 0); + glRotatef(_head.eyebrowPitch[side]/2.0, 1, 0, 0); + glRotatef(_head.eyebrowRoll[side]/2.0, 0, 0, 1); glScalef(browWidth, browThickness, 1); glutSolidCube(0.5); glPopMatrix(); - glTranslatef(_interBrowDistance, 0, 0); + glTranslatef(_head.interBrowDistance, 0, 0); } glPopMatrix(); @@ -787,23 +785,23 @@ void Head::renderHead(int faceToFace) { glPushMatrix(); glTranslatef(0,-0.35,0.75); glColor3f(0,0,0); - glRotatef(_mouthPitch, 1, 0, 0); - glRotatef(_mouthYaw, 0, 0, 1); - glScalef(_mouthWidth*(.7 + sqrt(_averageLoudness)/60.0), _mouthHeight*(1.0 + sqrt(_averageLoudness)/30.0), 1); + glRotatef(_head.mouthPitch, 1, 0, 0); + glRotatef(_head.mouthYaw, 0, 0, 1); + glScalef(_head.mouthWidth*(.7 + sqrt(_head.averageLoudness)/60.0), _head.mouthHeight*(1.0 + sqrt(_head.averageLoudness)/30.0), 1); glutSolidCube(0.5); glPopMatrix(); glTranslatef(0, 1.0, 0); - glTranslatef(-_interPupilDistance/2.0,-0.68,0.7); + glTranslatef(-_head.interPupilDistance/2.0,-0.68,0.7); // Right Eye glRotatef(-10, 1, 0, 0); glColor3fv(eyeColor); glPushMatrix(); { - glTranslatef(_interPupilDistance/10.0, 0, 0.05); + glTranslatef(_head.interPupilDistance/10.0, 0, 0.05); glRotatef(20, 0, 0, 1); - glScalef(_eyeballScaleX, _eyeballScaleY, _eyeballScaleZ); + glScalef(_head.eyeballScaleX, _head.eyeballScaleY, _head.eyeballScaleZ); glutSolidSphere(0.25, 30, 30); } glPopMatrix(); @@ -820,40 +818,40 @@ void Head::renderHead(int faceToFace) { glPushMatrix(); { - glRotatef(_eyeballPitch[1], 1, 0, 0); - glRotatef(_eyeballYaw[1] + _pupilConverge, 0, 1, 0); + glRotatef(_head.eyeballPitch[1], 1, 0, 0); + glRotatef(_head.eyeballYaw[1] + _head.yaw + _head.pupilConverge, 0, 1, 0); glTranslatef(0,0,.35); glRotatef(-75,1,0,0); glScalef(1.0, 0.4, 1.0); glEnable(GL_TEXTURE_2D); - gluSphere(_sphere, _pupilSize, 15, 15); + gluSphere(_sphere, _head.pupilSize, 15, 15); glDisable(GL_TEXTURE_2D); } glPopMatrix(); // Left Eye glColor3fv(eyeColor); - glTranslatef(_interPupilDistance, 0, 0); + glTranslatef(_head.interPupilDistance, 0, 0); glPushMatrix(); { - glTranslatef(-_interPupilDistance/10.0, 0, .05); + glTranslatef(-_head.interPupilDistance/10.0, 0, .05); glRotatef(-20, 0, 0, 1); - glScalef(_eyeballScaleX, _eyeballScaleY, _eyeballScaleZ); + glScalef(_head.eyeballScaleX, _head.eyeballScaleY, _head.eyeballScaleZ); glutSolidSphere(0.25, 30, 30); } glPopMatrix(); // Left Pupil glPushMatrix(); { - glRotatef(_eyeballPitch[0], 1, 0, 0); - glRotatef(_eyeballYaw[0] - _pupilConverge, 0, 1, 0); + glRotatef(_head.eyeballPitch[0], 1, 0, 0); + glRotatef(_head.eyeballYaw[0] + _head.yaw - _head.pupilConverge, 0, 1, 0); glTranslatef(0, 0, .35); glRotatef(-75, 1, 0, 0); glScalef(1.0, 0.4, 1.0); glEnable(GL_TEXTURE_2D); - gluSphere(_sphere, _pupilSize, 15, 15); + gluSphere(_sphere, _head.pupilSize, 15, 15); glDisable(GL_TEXTURE_2D); } @@ -864,10 +862,19 @@ void Head::renderHead(int faceToFace) { } - +void Head::startHandMovement() { -void Head::setHandMovement( glm::vec3 handOffset ) { - _handBeingMoved = true; + if (!_usingBodySprings) { + initializeBodySprings(); + _usingBodySprings = true; + } +} + +void Head::stopHandMovement() { + _usingBodySprings = false; +} + +void Head::setHandMovementValues( glm::vec3 handOffset ) { _movedHandOffset = handOffset; } @@ -875,7 +882,6 @@ AvatarMode Head::getMode() { return _mode; } - void Head::initializeSkeleton() { for (int b=0; b _avatar.maxArmLength ) { + if ( distance > _maxArmLength ) { //------------------------------------------------------------------------------- // reset right hand to be constrained to maximum arm length //------------------------------------------------------------------------------- _bone[ AVATAR_BONE_RIGHT_HAND ].position = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; glm::vec3 armNormal = armVector / distance; - armVector = armNormal * _avatar.maxArmLength; - distance = _avatar.maxArmLength; + armVector = armNormal * _maxArmLength; + distance = _maxArmLength; glm::vec3 constrainedPosition = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; constrainedPosition += armVector; _bone[ AVATAR_BONE_RIGHT_HAND ].position = constrainedPosition; @@ -1197,9 +1207,9 @@ void Head::updateHandMovement() { //----------------------------------------------------------------------------- glm::vec3 newElbowPosition = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; newElbowPosition += armVector * ONE_HALF; - glm::vec3 perpendicular = glm::cross( _avatar.orientation.getFront(), armVector ); + glm::vec3 perpendicular = glm::cross( _orientation.getFront(), armVector ); - newElbowPosition += perpendicular * ( 1.0f - ( _avatar.maxArmLength / distance ) ) * ONE_HALF; + newElbowPosition += perpendicular * ( 1.0f - ( _maxArmLength / distance ) ) * ONE_HALF; _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position = newElbowPosition; //----------------------------------------------------------------------------- @@ -1223,7 +1233,7 @@ void Head::renderBody() { // Render bone positions as spheres //----------------------------------------- for (int b=0; bvoxelsCreated; } -long int VoxelSystem::getVoxelsCreatedRunningAverage() { - return tree->voxelsCreatedStats.getRunningAverage(); +float VoxelSystem::getVoxelsCreatedPerSecondAverage() { + return (1 / tree->voxelsCreatedStats.getEventDeltaAverage()); } long int VoxelSystem::getVoxelsColored() { return tree->voxelsColored; } -long int VoxelSystem::getVoxelsColoredRunningAverage() { - return tree->voxelsColoredStats.getRunningAverage(); +float VoxelSystem::getVoxelsColoredPerSecondAverage() { + return (1 / tree->voxelsColoredStats.getEventDeltaAverage()); } long int VoxelSystem::getVoxelsBytesRead() { return tree->voxelsBytesRead; } -long int VoxelSystem::getVoxelsBytesReadRunningAverage() { - return tree->voxelsBytesReadStats.getRunningAverage(); +float VoxelSystem::getVoxelsBytesReadPerSecondAverage() { + return tree->voxelsBytesReadStats.getAverageSampleValuePerSecond(); } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 6c9b5d972e..e133b4c039 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -41,9 +41,9 @@ public: long int getVoxelsCreated(); long int getVoxelsColored(); long int getVoxelsBytesRead(); - long int getVoxelsCreatedRunningAverage(); - long int getVoxelsColoredRunningAverage(); - long int getVoxelsBytesReadRunningAverage(); + float getVoxelsCreatedPerSecondAverage(); + float getVoxelsColoredPerSecondAverage(); + float getVoxelsBytesReadPerSecondAverage(); // Methods that recurse tree void randomizeVoxelColors(); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 86b39fee2f..fba8633ac1 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -74,10 +74,11 @@ #include "Oscilloscope.h" #include "UDPSocket.h" #include "SerialInterface.h" -#include #include #include #include +#include +#include #include "ViewFrustum.h" @@ -167,15 +168,90 @@ int displayField = 0; int displayHeadMouse = 1; // Display sample mouse pointer controlled by head movement int headMouseX, headMouseY; -int mouseX, mouseY; // Where is the mouse +int mouseX = 0; +int mouseY = 0; // Mouse location at start of last down click -int mouseStartX = WIDTH / 2; -int mouseStartY = HEIGHT / 2; int mousePressed = 0; // true if mouse has been pressed (clear when finished) -Menu menu; // main menu -int menuOn = 1; // Whether to show onscreen menu +Menu menu; // main menu +int menuOn = 1; // Whether to show onscreen menu + +struct HandController +{ + bool enabled; + int startX; + int startY; + int x; + int y; + int lastX; + int lastY; + int velocityX; + int velocityY; + float rampUpRate; + float rampDownRate; + float envelope; +}; + +HandController handController; + +void initializeHandController() { + handController.enabled = false; + handController.startX = WIDTH / 2; + handController.startY = HEIGHT / 2; + handController.x = 0; + handController.y = 0; + handController.lastX = 0; + handController.lastY = 0; + handController.velocityX = 0; + handController.velocityY = 0; + handController.rampUpRate = 0.05; + handController.rampDownRate = 0.02; + handController.envelope = 0.0f; + +} + +void updateHandController( int x, int y ) { + handController.lastX = handController.x; + handController.lastY = handController.y; + handController.x = x; + handController.y = y; + handController.velocityX = handController.x - handController.lastX; + handController.velocityY = handController.y - handController.lastY; + + if (( handController.velocityX != 0 ) + || ( handController.velocityY != 0 )) { + handController.enabled = true; + myAvatar.startHandMovement(); + if ( handController.envelope < 1.0 ) { + handController.envelope += handController.rampUpRate; + if ( handController.envelope >= 1.0 ) { + handController.envelope = 1.0; + } + } + } + + if ( ! handController.enabled ) { + if ( handController.envelope > 0.0 ) { + handController.envelope -= handController.rampDownRate; + if ( handController.envelope <= 0.0 ) { + handController.startX = WIDTH / 2; + handController.startY = HEIGHT / 2; + handController.envelope = 0.0; + myAvatar.stopHandMovement(); + } + } + } + + if ( handController.envelope > 0.0 ) { + float leftRight = ( ( handController.x - handController.startX ) / (float)WIDTH ) * handController.envelope; + float downUp = ( ( handController.y - handController.startY ) / (float)HEIGHT ) * handController.envelope; + float backFront = 0.0; + myAvatar.setHandMovementValues( glm::vec3( leftRight, downUp, backFront ) ); + } +} + + // // Serial USB Variables @@ -239,31 +315,36 @@ void displayStats(void) std::stringstream voxelStats; voxelStats << "Voxels Rendered: " << voxels.getVoxelsRendered(); drawtext(10, statsVerticalOffset + 70, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); - + voxelStats.str(""); - voxelStats << "Voxels Created: " << voxels.getVoxelsCreated() << " (" << voxels.getVoxelsCreatedRunningAverage() - << "/sec in last "<< COUNTETSTATS_TIME_FRAME << " seconds) "; + voxelStats << "Voxels Created: " << voxels.getVoxelsCreated() << " (" << voxels.getVoxelsCreatedPerSecondAverage() + << "/sec) "; drawtext(10, statsVerticalOffset + 250, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); - + voxelStats.str(""); - voxelStats << "Voxels Colored: " << voxels.getVoxelsColored() << " (" << voxels.getVoxelsColoredRunningAverage() - << "/sec in last "<< COUNTETSTATS_TIME_FRAME << " seconds) "; + voxelStats << "Voxels Colored: " << voxels.getVoxelsColored() << " (" << voxels.getVoxelsColoredPerSecondAverage() + << "/sec) "; drawtext(10, statsVerticalOffset + 270, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); - + voxelStats.str(""); - voxelStats << "Voxels Bytes Read: " << voxels.getVoxelsBytesRead() - << " (" << voxels.getVoxelsBytesReadRunningAverage() << "/sec in last "<< COUNTETSTATS_TIME_FRAME << " seconds) "; + voxelStats << "Voxels Bytes Read: " << voxels.getVoxelsBytesRead() + << " (" << voxels.getVoxelsBytesReadPerSecondAverage() << " Bps)"; drawtext(10, statsVerticalOffset + 290,0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); voxelStats.str(""); - long int voxelsBytesPerColored = voxels.getVoxelsColored() ? voxels.getVoxelsBytesRead()/voxels.getVoxelsColored() : 0; - long int voxelsBytesPerColoredAvg = voxels.getVoxelsColoredRunningAverage() ? - voxels.getVoxelsBytesReadRunningAverage()/voxels.getVoxelsColoredRunningAverage() : 0; - - voxelStats << "Voxels Bytes per Colored: " << voxelsBytesPerColored - << " (" << voxelsBytesPerColoredAvg << "/sec in last "<< COUNTETSTATS_TIME_FRAME << " seconds) "; + float voxelsBytesPerColored = voxels.getVoxelsColored() + ? ((float) voxels.getVoxelsBytesRead() / voxels.getVoxelsColored()) + : 0; + + voxelStats << "Voxels Bytes per Colored: " << voxelsBytesPerColored; drawtext(10, statsVerticalOffset + 310, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); - + + Agent *avatarMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER); + char avatarMixerStats[200]; + sprintf(avatarMixerStats, "Avatar Mixer - %.f kbps, %.f pps", + roundf(avatarMixer->getAverageKilobitsPerSecond()), + roundf(avatarMixer->getAveragePacketsPerSecond())); + drawtext(10, statsVerticalOffset + 330, 0.10f, 0, 1.0, 0, avatarMixerStats); if (::perfStatsOn) { // Get the PerfStats group details. We need to allocate and array of char* long enough to hold 1+groups @@ -298,6 +379,8 @@ void init(void) voxels.init(); voxels.setViewerHead(&myAvatar); myAvatar.setRenderYaw(startYaw); + + initializeHandController(); headMouseX = WIDTH/2; headMouseY = HEIGHT/2; @@ -363,20 +446,6 @@ void reset_sensors() } } -void updateAvatarHand(float deltaTime) { - // If mouse is being dragged, send current force to the hand controller - if (mousePressed == 1) - { - // NOTE--PER: Need to re-implement when ready for new avatar hand movements - - const float MOUSE_HAND_FORCE = 1.5; - float dx = mouseX - mouseStartX; - float dy = mouseY - mouseStartY; - glm::vec3 vel(dx*MOUSE_HAND_FORCE, -dy*MOUSE_HAND_FORCE*(WIDTH/HEIGHT), 0); - //myAvatar.hand->addVelocity(vel*deltaTime); - } -} - // // Using gyro data, update both view frustum and avatar head position // @@ -828,10 +897,10 @@ void display(void) agent != agentList->getAgents().end(); agent++) { if (agent->getLinkedData() != NULL) { - Head *agentHead = (Head *)agent->getLinkedData(); - glPushMatrix(); - agentHead->render(0); - glPopMatrix(); + Head *avatar = (Head *)agent->getLinkedData(); + //glPushMatrix(); + avatar->render(0); + //glPopMatrix(); } } @@ -1368,55 +1437,49 @@ void idle(void) { if (diffclock(&lastTimeIdle, &check) > IDLE_SIMULATE_MSECS) { - //if ( myAvatar.getMode() == AVATAR_MODE_COMMUNICATING ) { - float leftRight = ( mouseX - mouseStartX ) / (float)WIDTH; - float downUp = ( mouseY - mouseStartY ) / (float)HEIGHT; - float backFront = 0.0; - glm::vec3 handMovement( leftRight, downUp, backFront ); - myAvatar.setHandMovement( handMovement ); - /*} - else { - mouseStartX = mouseX; - mouseStartY = mouseY; - //mouseStartX = (float)WIDTH / 2.0f; - //mouseStartY = (float)HEIGHT / 2.0f; - } - */ - - //-------------------------------------------------------- + float deltaTime = 1.f/FPS; + + // update behaviors for avatar hand movement + updateHandController( mouseX, mouseY ); + // when the mouse is being pressed, an 'action' is being // triggered in the avatar. The action is context-based. - //-------------------------------------------------------- if ( mousePressed == 1 ) { myAvatar.setTriggeringAction( true ); } else { myAvatar.setTriggeringAction( false ); } - + + // walking triggers the handController to stop + if ( myAvatar.getMode() == AVATAR_MODE_WALKING ) { + handController.enabled = false; + } + // // Sample hardware, update view frustum if needed, Lsend avatar data to mixer/agents // updateAvatar( 1.f/FPS ); + //loop through all the other avatars and simulate them. AgentList * agentList = AgentList::getInstance(); for(std::vector::iterator agent = agentList->getAgents().begin(); agent != agentList->getAgents().end(); agent++) { if (agent->getLinkedData() != NULL) { - Head *agentHead = (Head *)agent->getLinkedData(); - agentHead->simulate(1.f/FPS); + Head *avatar = (Head *)agent->getLinkedData(); + avatar->simulate(deltaTime); } } + - - updateAvatarHand(1.f/FPS); + //updateAvatarHand(1.f/FPS); - field.simulate(1.f/FPS); - myAvatar.simulate(1.f/FPS); - balls.simulate(1.f/FPS); - cloud.simulate(1.f/FPS); + field.simulate (deltaTime); + myAvatar.simulate(deltaTime); + balls.simulate (deltaTime); + cloud.simulate (deltaTime); glutPostRedisplay(); lastTimeIdle = check; @@ -1490,8 +1553,6 @@ void mouseFunc( int button, int state, int x, int y ) mouseX = x; mouseY = y; mousePressed = 1; - //mouseStartX = x; - //mouseStartY = y; } } if( button == GLUT_LEFT_BUTTON && state == GLUT_UP ) { @@ -1511,12 +1572,17 @@ void motionFunc( int x, int y) void mouseoverFunc( int x, int y) { menu.mouseOver(x, y); + mouseX = x; mouseY = y; if (mousePressed == 0) {} } + + + + void attachNewHeadToAgent(Agent *newAgent) { if (newAgent->getLinkedData() == NULL) { newAgent->setLinkedData(new Head(false)); diff --git a/libraries/avatars/src/Orientation.cpp b/libraries/avatars/src/Orientation.cpp index 1cedb7305e..066c1edc58 100755 --- a/libraries/avatars/src/Orientation.cpp +++ b/libraries/avatars/src/Orientation.cpp @@ -20,8 +20,7 @@ using avatars_lib::printLog; // // tosh - yep, I noticed... :-) // -// JJV - I noticed too :-) -// + static bool testingForNormalizationAndOrthogonality = false; Orientation::Orientation() { diff --git a/libraries/shared/src/Agent.cpp b/libraries/shared/src/Agent.cpp index e50392c96f..d05afe5e26 100644 --- a/libraries/shared/src/Agent.cpp +++ b/libraries/shared/src/Agent.cpp @@ -37,6 +37,7 @@ Agent::Agent(sockaddr *agentPublicSocket, sockaddr *agentLocalSocket, char agent activeSocket = NULL; linkedData = NULL; + _bytesReceivedMovingAverage = NULL; deleteMutex = new pthread_mutex_t; pthread_mutex_init(deleteMutex, NULL); @@ -69,6 +70,13 @@ Agent::Agent(const Agent &otherAgent) { linkedData = NULL; } + if (otherAgent._bytesReceivedMovingAverage != NULL) { + _bytesReceivedMovingAverage = new SimpleMovingAverage(100); + memcpy(_bytesReceivedMovingAverage, otherAgent._bytesReceivedMovingAverage, sizeof(SimpleMovingAverage)); + } else { + _bytesReceivedMovingAverage = NULL; + } + deleteMutex = new pthread_mutex_t; pthread_mutex_init(deleteMutex, NULL); } @@ -89,6 +97,7 @@ void Agent::swap(Agent &first, Agent &second) { swap(first.agentId, second.agentId); swap(first.firstRecvTimeUsecs, second.firstRecvTimeUsecs); swap(first.lastRecvTimeUsecs, second.lastRecvTimeUsecs); + swap(first._bytesReceivedMovingAverage, second._bytesReceivedMovingAverage); swap(first.deleteMutex, second.deleteMutex); } @@ -99,6 +108,7 @@ Agent::~Agent() { delete publicSocket; delete localSocket; delete linkedData; + delete _bytesReceivedMovingAverage; } char Agent::getType() const { @@ -199,7 +209,6 @@ void Agent::setLinkedData(AgentData *newData) { linkedData = newData; } - bool Agent::operator==(const Agent& otherAgent) { return matches(otherAgent.publicSocket, otherAgent.localSocket, otherAgent.type); } @@ -211,6 +220,30 @@ bool Agent::matches(sockaddr *otherPublicSocket, sockaddr *otherLocalSocket, cha && socketMatch(localSocket, otherLocalSocket); } +void Agent::recordBytesReceived(int bytesReceived) { + if (_bytesReceivedMovingAverage == NULL) { + _bytesReceivedMovingAverage = new SimpleMovingAverage(100); + } + + _bytesReceivedMovingAverage->updateAverage((float) bytesReceived); +} + +float Agent::getAveragePacketsPerSecond() { + if (_bytesReceivedMovingAverage != NULL) { + return (1 / _bytesReceivedMovingAverage->getEventDeltaAverage()); + } else { + return 0; + } +} + +float Agent::getAverageKilobitsPerSecond() { + if (_bytesReceivedMovingAverage != NULL) { + return (_bytesReceivedMovingAverage->getAverageSampleValuePerSecond() * (8.0f / 1000)); + } else { + return 0; + } +} + void Agent::printLog(Agent const& agent) { sockaddr_in *agentPublicSocket = (sockaddr_in *) agent.publicSocket; diff --git a/libraries/shared/src/Agent.h b/libraries/shared/src/Agent.h index 601df8d1f0..14942defcb 100644 --- a/libraries/shared/src/Agent.h +++ b/libraries/shared/src/Agent.h @@ -11,7 +11,6 @@ #include #include -#include "AgentData.h" #ifdef _WIN32 #include "Syssocket.h" @@ -19,6 +18,9 @@ #include #endif +#include "SimpleMovingAverage.h" +#include "AgentData.h" + class Agent { public: Agent(sockaddr *agentPublicSocket, sockaddr *agentLocalSocket, char agentType, uint16_t thisAgentId); @@ -34,32 +36,45 @@ public: char getType() const; const char* getTypeName() const; void setType(char newType); + uint16_t getAgentId(); void setAgentId(uint16_t thisAgentId); + double getFirstRecvTimeUsecs(); void setFirstRecvTimeUsecs(double newTimeUsecs); + double getLastRecvTimeUsecs(); void setLastRecvTimeUsecs(double newTimeUsecs); + sockaddr* getPublicSocket(); void setPublicSocket(sockaddr *newSocket); sockaddr* getLocalSocket(); void setLocalSocket(sockaddr *newSocket); sockaddr* getActiveSocket(); + void activatePublicSocket(); void activateLocalSocket(); + AgentData* getLinkedData(); void setLinkedData(AgentData *newData); + + void recordBytesReceived(int bytesReceived); + float getAverageKilobitsPerSecond(); + float getAveragePacketsPerSecond(); static void printLog(Agent const&); friend std::ostream& operator<<(std::ostream& os, const Agent* agent); private: void swap(Agent &first, Agent &second); + sockaddr *publicSocket, *localSocket, *activeSocket; char type; uint16_t agentId; double firstRecvTimeUsecs; double lastRecvTimeUsecs; - AgentData *linkedData; + SimpleMovingAverage* _bytesReceivedMovingAverage; + AgentData* linkedData; + }; std::ostream& operator<<(std::ostream& os, const Agent* agent); diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 36627d409e..5316eee79c 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -24,7 +24,12 @@ using shared_lib::printLog; -const char * SOLO_AGENT_TYPES_STRING = "MV"; +const char SOLO_AGENT_TYPES_STRING[] = { + AGENT_TYPE_AVATAR_MIXER, + AGENT_TYPE_AUDIO_MIXER, + AGENT_TYPE_VOXEL +}; + char DOMAIN_HOSTNAME[] = "highfidelity.below92.com"; char DOMAIN_IP[100] = ""; // IP Address will be re-set by lookup on startup const int DOMAINSERVER_PORT = 40102; @@ -108,6 +113,7 @@ void AgentList::processBulkAgentData(sockaddr *senderAddress, unsigned char *pac if (bulkSendAgentIndex >= 0) { Agent *bulkSendAgent = &agents[bulkSendAgentIndex]; bulkSendAgent->setLastRecvTimeUsecs(usecTimestampNow()); + bulkSendAgent->recordBytesReceived(numTotalBytes); } unsigned char *startPosition = packetData; @@ -144,6 +150,7 @@ void AgentList::updateAgentWithData(sockaddr *senderAddress, unsigned char *pack void AgentList::updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes) { agent->setLastRecvTimeUsecs(usecTimestampNow()); + agent->recordBytesReceived(dataBytes); if (agent->getLinkedData() == NULL) { if (linkedDataCreateCallback != NULL) { @@ -285,6 +292,18 @@ void AgentList::handlePingReply(sockaddr *agentAddress) { } } +Agent* AgentList::soloAgentOfType(char agentType) { + if (memchr(SOLO_AGENT_TYPES_STRING, agentType, 1)) { + for(std::vector::iterator agent = agents.begin(); agent != agents.end(); agent++) { + if (agent->getType() == agentType) { + return &*agent; + } + } + } + + return NULL; +} + void *pingUnknownAgents(void *args) { AgentList *agentList = (AgentList *)args; diff --git a/libraries/shared/src/AgentList.h b/libraries/shared/src/AgentList.h index 4dfa9359bf..adc66333f9 100644 --- a/libraries/shared/src/AgentList.h +++ b/libraries/shared/src/AgentList.h @@ -22,7 +22,7 @@ const int MAX_PACKET_SIZE = 1500; const unsigned int AGENT_SOCKET_LISTEN_PORT = 40103; const int AGENT_SILENCE_THRESHOLD_USECS = 2 * 1000000; -extern const char *SOLO_AGENT_TYPES_STRING; +extern const char SOLO_AGENT_TYPES_STRING[]; extern char DOMAIN_HOSTNAME[]; extern char DOMAIN_IP[100]; // IP Address will be re-set by lookup on startup @@ -59,6 +59,8 @@ public: char getOwnerType(); unsigned int getSocketListenPort(); + Agent* soloAgentOfType(char agentType); + void startSilentAgentRemovalThread(); void stopSilentAgentRemovalThread(); void startDomainServerCheckInThread(); diff --git a/libraries/shared/src/CounterStats.cpp b/libraries/shared/src/CounterStats.cpp deleted file mode 100644 index 51d991f0f1..0000000000 --- a/libraries/shared/src/CounterStats.cpp +++ /dev/null @@ -1,142 +0,0 @@ -// -// CounterStats.cpp -// hifi -// -// Created by Brad Hefta-Gaub on 2013/04/08. -// -// Poor-man's counter stats collector class. Useful for collecting running averages -// and other stats for countable things. -// -// - -#include "CounterStats.h" -#include - -#ifdef _WIN32 -#include "Systime.h" -#else -#include -#endif -#include -#include -#include "shared_Log.h" - -//private: -// long int currentCount; -// long int currentDelta; -// double currentTime; -// double totalTime; -// -// long int countSamples[COUNTETSTATS_SAMPLES_TO_KEEP] = {}; -// long int deltaSamples[COUNTETSTATS_SAMPLES_TO_KEEP] = {}; -// double timeSamples[COUNTETSTATS_SAMPLES_TO_KEEP] = {}; -// int sampleAt; - - -CounterStatHistory::CounterStatHistory() : - currentCount(0), - currentDelta(0), - currentTime(0.0), - lastCount(0), - lastTime(0.0), - totalTime(0.0), - sampleAt(-1), - sampleCount(0) { -} - -CounterStatHistory::CounterStatHistory(std::string myName) : - name(myName), - currentCount(0), - currentDelta(0), - currentTime(0.0), - lastCount(0), - lastTime(0.0), - totalTime(0.0), - sampleAt(-1), - sampleCount(0) { -} - - -CounterStatHistory::CounterStatHistory(std::string myName, double initialTime, long initialCount) : - name(myName), - currentCount(initialCount), - currentDelta(0), - currentTime(initialTime), - lastCount(initialCount), - lastTime(initialTime), - totalTime(initialTime), - sampleAt(-1), - sampleCount(0) { -} - -void CounterStatHistory::init() { - currentCount = 0; - currentDelta = 0; - currentTime = 0.0; - lastCount = 0; - lastTime = 0.0; - totalTime = 0.0; - sampleAt = -1; - sampleCount = 0; -} - -void CounterStatHistory::recordSample(long thisCount) { - timeval now; - gettimeofday(&now,NULL); - double nowSeconds = (now.tv_usec/1000000.0)+(now.tv_sec); - this->recordSample(nowSeconds,thisCount); -} - -void CounterStatHistory::recordSample(double thisTime, long thisCount) { - - // how much did we change since last sample? - long thisDelta = thisCount - this->lastCount; - double elapsed = thisTime - this->lastTime; - - // record the latest values - this->currentCount = thisCount; - this->currentTime = thisTime; - this->currentDelta = thisDelta; - - //printLog("CounterStatHistory[%s]::recordSample(thisTime %lf, thisCount= %ld)\n",this->name.c_str(),thisTime,thisCount); - - // if more than 1/10th of a second has passed, then record - // things in our rolling history - if (elapsed > 0.1) { - this->lastTime = thisTime; - this->lastCount = thisCount; - - // record it in our history... - this->sampleAt = (this->sampleAt+1)%COUNTETSTATS_SAMPLES_TO_KEEP; - if (this->sampleCountsampleCount++; - } - this->countSamples[this->sampleAt]=thisCount; - this->timeSamples[this->sampleAt]=thisTime; - this->deltaSamples[this->sampleAt]=thisDelta; - - //printLog("CounterStatHistory[%s]::recordSample() ACTUALLY RECORDING IT sampleAt=%d thisTime %lf, thisCount= %ld)\n",this->name.c_str(),this->sampleAt,thisTime,thisCount); - - } - -} - -long CounterStatHistory::getRunningAverage() { - // before we calculate our running average, always "reset" the current count, with the current time - // this will flush out old data, if we haven't been adding any new data. - this->recordSample(this->currentCount); - - long runningTotal = 0; - double minTime = this->timeSamples[0]; - double maxTime = this->timeSamples[0]; - - for (int i =0; i < this->sampleCount; i++) { - minTime = std::min(minTime,this->timeSamples[i]); - maxTime = std::max(maxTime,this->timeSamples[i]); - runningTotal += this->deltaSamples[i]; - } - - double elapsedTime = maxTime-minTime; - long runningAverage = runningTotal/elapsedTime; - return runningAverage; -} diff --git a/libraries/shared/src/CounterStats.h b/libraries/shared/src/CounterStats.h deleted file mode 100644 index 81e34853ef..0000000000 --- a/libraries/shared/src/CounterStats.h +++ /dev/null @@ -1,65 +0,0 @@ -// -// CounterStats.h -// hifi -// -// Created by Brad Hefta-Gaub on 3/29/13. -// -// Poor-man's counter stats collector class. Useful for collecting running averages -// and other stats for countable things. -// -// - -#ifndef __hifi__CounterStats__ -#define __hifi__CounterStats__ - -#include -#include -#include - -// TIME_FRAME should be SAMPLES_TO_KEEP * TIME_BETWEEN_SAMPLES -#define COUNTETSTATS_SAMPLES_TO_KEEP 50 -#define COUNTETSTATS_TIME_BETWEEN_SAMPLES 0.1 -#define COUNTETSTATS_TIME_FRAME (COUNTETSTATS_SAMPLES_TO_KEEP*COUNTETSTATS_TIME_BETWEEN_SAMPLES) - -class CounterStatHistory { -public: - std::string name; - - CounterStatHistory(); - CounterStatHistory(std::string myName); - CounterStatHistory(std::string myName, double initialTime, long initialCount); - - void recordSample(long thisCount); - void recordSample(double thisTime, long thisCount); - long getRunningAverage(); - - long getAverage() { - return currentCount/totalTime; - }; - - double getTotalTime() { - return totalTime; - }; - long getCount() { - return currentCount; - }; -private: - void init(); - - long currentCount; - long currentDelta; - double currentTime; - - long lastCount; - double lastTime; - - double totalTime; - - long countSamples[COUNTETSTATS_SAMPLES_TO_KEEP]; - long deltaSamples[COUNTETSTATS_SAMPLES_TO_KEEP]; - double timeSamples[COUNTETSTATS_SAMPLES_TO_KEEP]; - int sampleAt; - int sampleCount; -}; - -#endif /* defined(__hifi__CounterStat__) */ diff --git a/libraries/shared/src/SimpleMovingAverage.cpp b/libraries/shared/src/SimpleMovingAverage.cpp new file mode 100644 index 0000000000..db433c020f --- /dev/null +++ b/libraries/shared/src/SimpleMovingAverage.cpp @@ -0,0 +1,54 @@ +// +// SimpleMovingAverage.cpp +// hifi +// +// Created by Stephen Birarda on 4/18/13. +// +// + +#include "SharedUtil.h" +#include "SimpleMovingAverage.h" + +SimpleMovingAverage::SimpleMovingAverage(int numSamplesToAverage) : + _numSamples(0), + _average(0), + _eventDeltaAverage(0), + WEIGHTING(1.0f / numSamplesToAverage), + ONE_MINUS_WEIGHTING(1 - WEIGHTING) { + +} + +int SimpleMovingAverage::updateAverage(float sample) { + if (_numSamples > 0) { + _average = (ONE_MINUS_WEIGHTING * _average) + (WEIGHTING * sample); + + float eventDelta = (usecTimestampNow() - _lastEventTimestamp) / 1000000; + + if (_numSamples > 1) { + _eventDeltaAverage = (ONE_MINUS_WEIGHTING * _eventDeltaAverage) + + (WEIGHTING * eventDelta); + } else { + _eventDeltaAverage = eventDelta; + } + } else { + _average = sample; + _eventDeltaAverage = 0; + } + + _lastEventTimestamp = usecTimestampNow(); + + return ++_numSamples; +} + +void SimpleMovingAverage::reset() { + _numSamples = 0; +} + +float SimpleMovingAverage::getEventDeltaAverage() { + return (ONE_MINUS_WEIGHTING * _eventDeltaAverage) + + (WEIGHTING * ((usecTimestampNow() - _lastEventTimestamp) / 1000000)); +} + +float SimpleMovingAverage::getAverageSampleValuePerSecond() { + return _average * (1 / getEventDeltaAverage()); +} \ No newline at end of file diff --git a/libraries/shared/src/SimpleMovingAverage.h b/libraries/shared/src/SimpleMovingAverage.h new file mode 100644 index 0000000000..e24b639133 --- /dev/null +++ b/libraries/shared/src/SimpleMovingAverage.h @@ -0,0 +1,36 @@ +// +// SimpleMovingAverage.h +// hifi +// +// Created by Stephen Birarda on 4/18/13. +// Replaces Brad Hefta-Gaub's CounterStats class (RIP) +// +// + +#ifndef __hifi__Stats__ +#define __hifi__Stats__ + +#include + +class SimpleMovingAverage { +public: + SimpleMovingAverage(int numSamplesToAverage); + + int updateAverage(float sample); + void reset(); + + int getSampleCount() { return _numSamples; }; + float getAverage() { return _average; }; + float getEventDeltaAverage(); + float getAverageSampleValuePerSecond(); +private: + int _numSamples; + double _lastEventTimestamp; + float _average; + float _eventDeltaAverage; + + const float WEIGHTING; + const float ONE_MINUS_WEIGHTING; +}; + +#endif /* defined(__hifi__Stats__) */ diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index dc0913c513..bd197b53cb 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -15,7 +15,6 @@ #include "SharedUtil.h" #include "voxels_Log.h" #include "PacketHeaders.h" -#include "CounterStats.h" #include "OctalCode.h" #include "VoxelTree.h" #include // to load voxels from file @@ -46,19 +45,17 @@ int boundaryDistanceForRenderLevel(unsigned int renderLevel) { } } -VoxelTree::VoxelTree() { +VoxelTree::VoxelTree() : + voxelsCreated(0), + voxelsColored(0), + voxelsBytesRead(0), + voxelsCreatedStats(100), + voxelsColoredStats(100), + voxelsBytesReadStats(100) { + rootNode = new VoxelNode(); rootNode->octalCode = new unsigned char[1]; *rootNode->octalCode = 0; - - // Some stats tracking - this->voxelsCreated = 0; // when a voxel is created in the tree (object new'd) - this->voxelsColored = 0; // when a voxel is colored/set in the tree (object may have already existed) - this->voxelsBytesRead = 0; - voxelsCreatedStats.name = "voxelsCreated"; - voxelsColoredStats.name = "voxelsColored"; - voxelsBytesReadStats.name = "voxelsBytesRead"; - } VoxelTree::~VoxelTree() { @@ -147,7 +144,7 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode, if (destinationNode->children[i] == NULL) { destinationNode->addChildAtIndex(i); this->voxelsCreated++; - this->voxelsCreatedStats.recordSample(this->voxelsCreated); + this->voxelsCreatedStats.updateAverage(1); } // pull the color for this child @@ -156,7 +153,7 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode, newColor[3] = 1; destinationNode->children[i]->setColor(newColor); this->voxelsColored++; - this->voxelsColoredStats.recordSample(this->voxelsColored); + this->voxelsColoredStats.updateAverage(1); bytesRead += 3; } @@ -179,7 +176,7 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode, // add a child at that index, if it doesn't exist destinationNode->addChildAtIndex(childIndex); this->voxelsCreated++; - this->voxelsCreatedStats.recordSample(this->voxelsCreated); + this->voxelsCreatedStats.updateAverage(this->voxelsCreated); } // tell the child to read the subsequent data @@ -207,7 +204,7 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeByt readNodeData(bitstreamRootNode, bitstream + octalCodeBytes, bufferSizeBytes - octalCodeBytes); this->voxelsBytesRead += bufferSizeBytes; - this->voxelsBytesReadStats.recordSample(this->voxelsBytesRead); + this->voxelsBytesReadStats.updateAverage(bufferSizeBytes); } // Note: uses the codeColorBuffer format, but the color's are ignored, because diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 79c7b75fa4..62ff4e4815 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -9,7 +9,7 @@ #ifndef __hifi__VoxelTree__ #define __hifi__VoxelTree__ -#include "CounterStats.h" +#include "SimpleMovingAverage.h" #include "VoxelNode.h" #include "MarkerNode.h" @@ -23,13 +23,15 @@ typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, bool down, void* extr class VoxelTree { public: + // when a voxel is created in the tree (object new'd) long voxelsCreated; + // when a voxel is colored/set in the tree (object may have already existed) long voxelsColored; long voxelsBytesRead; - - CounterStatHistory voxelsCreatedStats; - CounterStatHistory voxelsColoredStats; - CounterStatHistory voxelsBytesReadStats; + + SimpleMovingAverage voxelsCreatedStats; + SimpleMovingAverage voxelsColoredStats; + SimpleMovingAverage voxelsBytesReadStats; VoxelTree(); ~VoxelTree();