From e54fd0dd7d84d798efcddb04d0668948d50cf047 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 24 Apr 2013 16:54:07 -0700 Subject: [PATCH 1/2] renamed "Head" to "Avatar" and did a bunch a cleanups, including removing the three-lined comments --- eve/src/main.cpp | 32 +- interface/src/Audio.cpp | 10 +- interface/src/Audio.h | 4 +- interface/src/AudioData.h | 4 +- interface/src/Head.cpp | 1348 --------------------------------- interface/src/Head.h | 279 ------- interface/src/VoxelSystem.cpp | 6 +- interface/src/VoxelSystem.h | 6 +- interface/src/main.cpp | 12 +- 9 files changed, 37 insertions(+), 1664 deletions(-) delete mode 100644 interface/src/Head.cpp delete mode 100644 interface/src/Head.h diff --git a/eve/src/main.cpp b/eve/src/main.cpp index 903a2e6c96..2da001b368 100644 --- a/eve/src/main.cpp +++ b/eve/src/main.cpp @@ -27,7 +27,6 @@ const float MAX_ITERATIONS_BETWEEN_AUDIO_SENDS = (MAX_AUDIO_SEND_INTERVAL_SECS * bool stopReceiveAgentDataThread; bool injectAudioThreadRunning = false; -int handStateTimer = 0; int TEMP_AUDIO_LISTEN_PORT = 55439; // UDPSocket audioSocket(TEMP_AUDIO_LISTEN_PORT); @@ -124,20 +123,7 @@ int main(int argc, const char* argv[]) { // put her hand out so somebody can shake it eve.setHandPosition(glm::vec3(eve.getPosition()[0] - 0.2, 0.25, - eve.getPosition()[2] + 0.1)); - - // simulate the effect of pressing and un-pressing the mouse button/pad - handStateTimer ++; - if ( handStateTimer == 100 ) { - eve.setHandState(1); - } - if ( handStateTimer == 150 ) { - eve.setHandState(0); - } - if ( handStateTimer >= 200 ) { - handStateTimer = 0; - } - + eve.getPosition()[2] + 0.1)); // read eve's audio data AudioInjector eveAudioInjector("eve.raw"); @@ -152,6 +138,8 @@ int main(int argc, const char* argv[]) { // int numIterationsLeftBeforeAudioSend = 0; // pthread_t injectAudioThread; + int handStateTimer = 0; + while (true) { // update the thisSend timeval to the current time gettimeofday(&thisSend, NULL); @@ -183,7 +171,19 @@ int main(int argc, const char* argv[]) { // sleep for the correct amount of time to have data send be consistently timed if ((numMicrosecondsSleep = (DATA_SEND_INTERVAL_MSECS * 1000) - (usecTimestampNow() - usecTimestamp(&thisSend))) > 0) { usleep(numMicrosecondsSleep); - } + } + + // simulate the effect of pressing and un-pressing the mouse button/pad + handStateTimer++; + if ( handStateTimer == 100 ) { + eve.setHandState(1); + } + if ( handStateTimer == 150 ) { + eve.setHandState(0); + } + if ( handStateTimer >= 200 ) { + handStateTimer = 0; + } } // stop the receive agent data thread diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 287325c090..4b522d5823 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -157,7 +157,7 @@ int audioCallback (const void *inputBuffer, // memcpy the three float positions for (int p = 0; p < 3; p++) { - memcpy(currentPacketPtr, &data->linkedHead->getPosition()[p], sizeof(float)); + memcpy(currentPacketPtr, &data->linkedAvatar->getPosition()[p], sizeof(float)); currentPacketPtr += sizeof(float); } @@ -165,7 +165,7 @@ int audioCallback (const void *inputBuffer, *(currentPacketPtr++) = 255; // memcpy the corrected render yaw - float correctedYaw = fmodf(data->linkedHead->getRenderYaw(), 360); + float correctedYaw = fmodf(data->linkedAvatar->getRenderYaw(), 360); if (correctedYaw > 180) { correctedYaw -= 360; @@ -259,7 +259,7 @@ int audioCallback (const void *inputBuffer, // rotation of the head relative to body, this may effect flange effect! // // - int lastYawMeasured = fabsf(data->linkedHead->getLastMeasuredHeadYaw()); + int lastYawMeasured = fabsf(data->linkedAvatar->getLastMeasuredHeadYaw()); if (!samplesLeftForFlange && lastYawMeasured > MIN_FLANGE_EFFECT_THRESHOLD) { // we should flange for one second @@ -448,7 +448,7 @@ void Audio::setWalkingState(bool newWalkState) { * @return Returns true if successful or false if an error occurred. Use Audio::getError() to retrieve the error code. */ -Audio::Audio(Oscilloscope *s, Head *linkedHead) +Audio::Audio(Oscilloscope *s, Avatar *linkedAvatar) { // read the walking sound from the raw file and store it // in the in memory array @@ -472,7 +472,7 @@ Audio::Audio(Oscilloscope *s, Head *linkedHead) audioData = new AudioData(); - audioData->linkedHead = linkedHead; + audioData->linkedAvatar = linkedAvatar; // setup a UDPSocket audioData->audioSocket = new UDPSocket(AUDIO_UDP_LISTEN_PORT); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index f4bf594b0c..73ff7f32d1 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -12,12 +12,12 @@ #include #include "AudioData.h" #include "Oscilloscope.h" -#include "Head.h" +#include "Avatar.h" class Audio { public: // initializes audio I/O - Audio(Oscilloscope *s, Head *linkedHead); + Audio(Oscilloscope *s, Avatar *linkedAvatar); void render(); void render(int screenWidth, int screenHeight); diff --git a/interface/src/AudioData.h b/interface/src/AudioData.h index fdc15998f0..520291e3e6 100644 --- a/interface/src/AudioData.h +++ b/interface/src/AudioData.h @@ -13,7 +13,7 @@ #include #include "AudioRingBuffer.h" #include "UDPSocket.h" -#include "Head.h" +#include "Avatar.h" class AudioData { public: @@ -23,7 +23,7 @@ class AudioData { UDPSocket *audioSocket; - Head *linkedHead; + Avatar *linkedAvatar; // store current mixer address and port in_addr_t mixerAddress; diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp deleted file mode 100644 index 1e6e78fef2..0000000000 --- a/interface/src/Head.cpp +++ /dev/null @@ -1,1348 +0,0 @@ -// -// Head.cpp -// interface -// -// Created by Philip Rosedale on 9/11/12. -// adapted by Jeffrey Ventrella -// Copyright (c) 2012 Physical, Inc.. All rights reserved. -// - -#include -#include -#include -#include -#include "Head.h" -#include "Log.h" -#include -#include -#include - -using namespace std; - -float skinColor[] = {1.0, 0.84, 0.66}; -float lightBlue[] = { 0.7, 0.8, 1.0 }; -float browColor[] = {210.0/255.0, 105.0/255.0, 30.0/255.0}; -float mouthColor[] = {1, 0, 0}; - -float BrowRollAngle[5] = {0, 15, 30, -30, -15}; -float BrowPitchAngle[3] = {-70, -60, -50}; -float eyeColor[3] = {1,1,1}; - -float MouthWidthChoices[3] = {0.5, 0.77, 0.3}; - -float browWidth = 0.8; -float browThickness = 0.16; - -bool usingBigSphereCollisionTest = true; - -char iris_texture_file[] = "resources/images/green_eye.png"; - -vector iris_texture; -unsigned int iris_texture_width = 512; -unsigned int iris_texture_height = 256; - -Head::Head(bool isMine) { - - _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 ); - _bodyYaw = -90.0; - _bodyPitch = 0.0; - _bodyRoll = 0.0; - _bodyYawDelta = 0.0; - _mousePressed = false; - _mode = AVATAR_MODE_STANDING; - _isMine = isMine; - _maxArmLength = 0.0; - //_transmitterTimer = 0; - _transmitterHz = 0.0; - _transmitterPackets = 0; - - initializeSkeleton(); - - _TEST_bigSphereRadius = 0.3f; - _TEST_bigSpherePosition = glm::vec3( 0.0f, _TEST_bigSphereRadius, 2.0f ); - - for (int i = 0; i < MAX_DRIVE_KEYS; i++) _driveKeys[i] = false; - - _head.pupilSize = 0.10; - _head.interPupilDistance = 0.6; - _head.interBrowDistance = 0.75; - _head.nominalPupilSize = 0.10; - _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.averageLoudness = 0.0; - _head.lastLoudness = 0.0; - _head.browAudioLift = 0.0; - _head.noise = 0; - _movedHandOffset = glm::vec3( 0.0, 0.0, 0.0 ); - _usingBodySprings = true; - _springForce = 6.0f; - _springVelocityDecay = 16.0f; - _renderYaw = 0.0; - _renderPitch = 0.0; - _sphere = NULL; - _interactingOther = NULL; - _interactingOtherIsNearby = false; - - _handHolding.position = glm::vec3( 0.0, 0.0, 0.0 ); - _handHolding.velocity = glm::vec3( 0.0, 0.0, 0.0 ); - _handHolding.force = 10.0f; - - if (iris_texture.size() == 0) { - switchToResourcesParentIfRequired(); - unsigned error = lodepng::decode(iris_texture, iris_texture_width, iris_texture_height, iris_texture_file); - if (error != 0) { - printLog("error %u: %s\n", error, lodepng_error_text(error)); - } - } -} - - - -Head::Head(const Head &otherAvatar) { - - _velocity = otherAvatar._velocity; - _thrust = otherAvatar._thrust; - _rotation = otherAvatar._rotation; - _interactingOtherIsNearby = otherAvatar._interactingOtherIsNearby; - _bodyYaw = otherAvatar._bodyYaw; - _bodyPitch = otherAvatar._bodyPitch; - _bodyRoll = otherAvatar._bodyRoll; - _bodyYawDelta = otherAvatar._bodyYawDelta; - _mousePressed = otherAvatar._mousePressed; - _mode = otherAvatar._mode; - _isMine = otherAvatar._isMine; - _renderYaw = otherAvatar._renderYaw; - _renderPitch = otherAvatar._renderPitch; - _maxArmLength = otherAvatar._maxArmLength; - _transmitterTimer = otherAvatar._transmitterTimer; - _transmitterHz = otherAvatar._transmitterHz; - _transmitterPackets = otherAvatar._transmitterPackets; - _TEST_bigSphereRadius = otherAvatar._TEST_bigSphereRadius; - _TEST_bigSpherePosition = otherAvatar._TEST_bigSpherePosition; - _movedHandOffset = otherAvatar._movedHandOffset; - _usingBodySprings = otherAvatar._usingBodySprings; - _springForce = otherAvatar._springForce; - _springVelocityDecay = otherAvatar._springVelocityDecay; - _orientation.set( otherAvatar._orientation ); - - _sphere = NULL; - - initializeSkeleton(); - - for (int i = 0; i < MAX_DRIVE_KEYS; i++) _driveKeys[i] = otherAvatar._driveKeys[i]; - - _head.pupilSize = otherAvatar._head.pupilSize; - _head.interPupilDistance = otherAvatar._head.interPupilDistance; - _head.interBrowDistance = otherAvatar._head.interBrowDistance; - _head.nominalPupilSize = otherAvatar._head.nominalPupilSize; - _head.yawRate = otherAvatar._head.yawRate; - _head.pitchRate = otherAvatar._head.pitchRate; - _head.rollRate = otherAvatar._head.rollRate; - _head.eyebrowPitch[0] = otherAvatar._head.eyebrowPitch[0]; - _head.eyebrowPitch[1] = otherAvatar._head.eyebrowPitch[1]; - _head.eyebrowRoll [0] = otherAvatar._head.eyebrowRoll [0]; - _head.eyebrowRoll [1] = otherAvatar._head.eyebrowRoll [1]; - _head.mouthPitch = otherAvatar._head.mouthPitch; - _head.mouthYaw = otherAvatar._head.mouthYaw; - _head.mouthWidth = otherAvatar._head.mouthWidth; - _head.mouthHeight = otherAvatar._head.mouthHeight; - _head.eyeballPitch[0] = otherAvatar._head.eyeballPitch[0]; - _head.eyeballPitch[1] = otherAvatar._head.eyeballPitch[1]; - _head.eyeballScaleX = otherAvatar._head.eyeballScaleX; - _head.eyeballScaleY = otherAvatar._head.eyeballScaleY; - _head.eyeballScaleZ = otherAvatar._head.eyeballScaleZ; - _head.eyeballYaw[0] = otherAvatar._head.eyeballYaw[0]; - _head.eyeballYaw[1] = otherAvatar._head.eyeballYaw[1]; - _head.pitchTarget = otherAvatar._head.pitchTarget; - _head.yawTarget = otherAvatar._head.yawTarget; - _head.noiseEnvelope = otherAvatar._head.noiseEnvelope; - _head.pupilConverge = otherAvatar._head.pupilConverge; - _head.leanForward = otherAvatar._head.leanForward; - _head.leanSideways = otherAvatar._head.leanSideways; - _head.eyeContact = otherAvatar._head.eyeContact; - _head.eyeContactTarget = otherAvatar._head.eyeContactTarget; - _head.scale = otherAvatar._head.scale; - _head.audioAttack = otherAvatar._head.audioAttack; - _head.averageLoudness = otherAvatar._head.averageLoudness; - _head.lastLoudness = otherAvatar._head.lastLoudness; - _head.browAudioLift = otherAvatar._head.browAudioLift; - _head.noise = otherAvatar._head.noise; - - if (iris_texture.size() == 0) { - switchToResourcesParentIfRequired(); - unsigned error = lodepng::decode(iris_texture, iris_texture_width, iris_texture_height, iris_texture_file); - if (error != 0) { - printLog("error %u: %s\n", error, lodepng_error_text(error)); - } - } -} - -Head::~Head() { - if (_sphere != NULL) { - gluDeleteQuadric(_sphere); - } -} - -Head* Head::clone() const { - return new Head(*this); -} - -void Head::reset() { - _headPitch = _headYaw = _headRoll = 0; - _head.leanForward = _head.leanSideways = 0; -} - - -//this pertains to moving the head with the glasses -//--------------------------------------------------- -void Head::UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity) -// Using serial data, update avatar/render position and angles -{ - const float PITCH_ACCEL_COUPLING = 0.5; - const float ROLL_ACCEL_COUPLING = -1.0; - float measured_pitch_rate = serialInterface->getRelativeValue(HEAD_PITCH_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) - - PITCH_ACCEL_COUPLING*serialInterface->getRelativeValue(HEAD_PITCH_RATE); - float measured_roll_rate = serialInterface->getRelativeValue(HEAD_ROLL_RATE); - - //printLog("Pitch Rate: %d ACCEL_Z: %d\n", serialInterface->getRelativeValue(PITCH_RATE), - // serialInterface->getRelativeValue(ACCEL_Z)); - //printLog("Pitch Rate: %d ACCEL_X: %d\n", serialInterface->getRelativeValue(PITCH_RATE), - // serialInterface->getRelativeValue(ACCEL_Z)); - //printLog("Pitch: %f\n", Pitch); - - // Update avatar head position based on measured gyro rates - const float HEAD_ROTATION_SCALE = 0.70; - const float HEAD_ROLL_SCALE = 0.40; - const float HEAD_LEAN_SCALE = 0.01; - const float MAX_PITCH = 45; - const float MIN_PITCH = -45; - const float MAX_YAW = 85; - const float MIN_YAW = -85; - - if ((_headPitch < MAX_PITCH) && (_headPitch > MIN_PITCH)) - addHeadPitch(measured_pitch_rate * -HEAD_ROTATION_SCALE * frametime); - - addHeadRoll(measured_roll_rate * HEAD_ROLL_SCALE * frametime); - - if ((_headYaw < MAX_YAW) && (_headYaw > MIN_YAW)) - addHeadYaw(_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 - _head.leanSideways += x; - _head.leanForward += z; -} - - -void Head::setLeanForward(float dist){ - _head.leanForward = dist; -} - -void Head::setLeanSideways(float dist){ - _head.leanSideways = dist; -} - -void Head::setMousePressed( bool d ) { - _mousePressed = d; -} - -void Head::simulate(float deltaTime) { - - //------------------------ - // update avatar skeleton - //------------------------ - updateSkeleton(); - - //------------------------------------------------------------ - // reset hand and arm positions according to hand movement - //------------------------------------------------------------ - updateHandMovement( deltaTime ); - - if ( !_interactingOtherIsNearby ) { - //initialize _handHolding - _handHolding.position = _bone[ AVATAR_BONE_RIGHT_HAND ].position; - _handHolding.velocity = glm::vec3( 0.0, 0.0, 0.0 ); - } - - _interactingOtherIsNearby = false; - - //------------------------------------------------------------- - // if the avatar being simulated is mine, then loop through - // all the other avatars for potential interactions... - //------------------------------------------------------------- - if ( _isMine ) - { - float closestDistance = 10000.0f; - - AgentList * agentList = AgentList::getInstance(); - - for(std::vector::iterator agent = agentList->getAgents().begin(); - agent != agentList->getAgents().end(); - agent++) { - if (( agent->getLinkedData() != NULL && ( agent->getType() == AGENT_TYPE_AVATAR ) )) { - Head *otherAvatar = (Head *)agent->getLinkedData(); - - //------------------------------------------------------ - // check for collisions with other avatars and respond - //------------------------------------------------------ - updateAvatarCollisionDetectionAndResponse - ( - otherAvatar->getPosition(), - otherAvatar->getGirth(), - otherAvatar->getHeight(), - otherAvatar->getBodyUpDirection(), - deltaTime - ); - - //------------------------------------------------- - // test other avatar hand position for proximity - //------------------------------------------------ - glm::vec3 v( _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position ); - v -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); - - float distance = glm::length( v ); - if ( distance < _maxArmLength ) { - - //if ( distance < closestDistance ) { // perhaps I don't need this if we want to allow multi-avatar interactions - { - closestDistance = distance; - _interactingOther = otherAvatar; - _interactingOtherIsNearby = true; - - //--------------------------------------------------------------------- - // if I am holding hands with another avatar, a force is applied - //--------------------------------------------------------------------- - if (( _handState == 1 ) - || ( _interactingOther->_handState == 1 )) { - glm::vec3 vectorToOtherHand = _interactingOther->_handPosition - _handHolding.position; - glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHolding.position; - - _handHolding.velocity *= 0.7; - _handHolding.velocity += ( vectorToOtherHand + vectorToMyHand ) * _handHolding.force * deltaTime; - _handHolding.position += _handHolding.velocity; - - _bone[ AVATAR_BONE_RIGHT_HAND ].position = _handHolding.position; - } - } - } - } - } - - // Set the vector we send for hand position to other people to be our right hand - setHandPosition(_bone[ AVATAR_BONE_RIGHT_HAND ].position); - - }//if ( _isMine ) - - - updateArmIKAndConstraints( deltaTime ); - - if ( ! _interactingOtherIsNearby ) { - _interactingOther = NULL; - } - - if ( usingBigSphereCollisionTest ) { - //-------------------------------------------------------------- - // test for avatar collision response (using a big sphere :) - //-------------------------------------------------------------- - updateAvatarCollisionDetectionAndResponse - ( - _TEST_bigSpherePosition, - _TEST_bigSphereRadius, - _TEST_bigSphereRadius, - glm::vec3( 0.0, 1.0, 0.0 ), - deltaTime - ); - } - - if ( AVATAR_GRAVITY ) { - if ( _position.y > _bone[ AVATAR_BONE_RIGHT_FOOT ].radius * 2.0 ) { - _velocity += glm::dvec3( 0.0, -1.0, 0.0 ) * ( 6.0 * deltaTime ); - } - else { - if ( _position.y < _bone[ AVATAR_BONE_RIGHT_FOOT ].radius ) { - _position.y = _bone[ AVATAR_BONE_RIGHT_FOOT ].radius; - _velocity.y = 0.0; - } - } - } - - // update body springs - updateBodySprings( deltaTime ); - - - 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... - //------------------------------------------------- - _thrust = glm::vec3( 0.0, 0.0, 0.0 ); - - if (_driveKeys[FWD]) { - glm::vec3 front( _orientation.getFront().x, _orientation.getFront().y, _orientation.getFront().z ); - _thrust += front * THRUST_MAG; - } - if (_driveKeys[BACK]) { - glm::vec3 front( _orientation.getFront().x, _orientation.getFront().y, _orientation.getFront().z ); - _thrust -= front * THRUST_MAG; - } - if (_driveKeys[RIGHT]) { - glm::vec3 right( _orientation.getRight().x, _orientation.getRight().y, _orientation.getRight().z ); - _thrust += right * THRUST_MAG; - } - if (_driveKeys[LEFT]) { - glm::vec3 right( _orientation.getRight().x, _orientation.getRight().y, _orientation.getRight().z ); - _thrust -= right * THRUST_MAG; - } - if (_driveKeys[UP]) { - glm::vec3 up( _orientation.getUp().x, _orientation.getUp().y, _orientation.getUp().z ); - _thrust += up * THRUST_MAG; - } - if (_driveKeys[DOWN]) { - glm::vec3 up( _orientation.getUp().x, _orientation.getUp().y, _orientation.getUp().z ); - _thrust -= up * THRUST_MAG; - } - if (_driveKeys[ROT_RIGHT]) { - _bodyYawDelta -= YAW_MAG * deltaTime; - } - if (_driveKeys[ROT_LEFT]) { - _bodyYawDelta += YAW_MAG * deltaTime; - } - } - - - //---------------------------------------------------------- - float translationalSpeed = glm::length( _velocity ); - float rotationalSpeed = fabs( _bodyYawDelta ); - if ( translationalSpeed + rotationalSpeed > 0.2 ) - { - _mode = AVATAR_MODE_WALKING; - } - else - { - _mode = AVATAR_MODE_INTERACTING; - } - - //---------------------------------------------------------- - // update body yaw by body yaw delta - //---------------------------------------------------------- - if (_isMine) { - _bodyYaw += _bodyYawDelta * deltaTime; - } - - //---------------------------------------------------------- - // decay body yaw delta - //---------------------------------------------------------- - _bodyYawDelta *= (1.0 - TEST_YAW_DECAY * deltaTime); - - //---------------------------------------------------------- - // add thrust to velocity - //---------------------------------------------------------- - _velocity += glm::dvec3(_thrust * deltaTime); - - //---------------------------------------------------------- - // update position by velocity - //---------------------------------------------------------- - _position += (glm::vec3)_velocity * deltaTime; - - //---------------------------------------------------------- - // decay velocity - //---------------------------------------------------------- - _velocity *= ( 1.0 - LIN_VEL_DECAY * deltaTime ); - - // - // Update Head information - // - - // we will be eventually getting head rotation from elsewhere. For now, just setting it to body rotation - //_head.yaw = _bodyYaw; - //_head.pitch = _bodyPitch; - //_head.roll = _bodyRoll; - - 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); - } - else { - // Move toward new target - _headPitch += (_head.pitchTarget - _headPitch) * 10 * deltaTime; // (1.f - DECAY*deltaTime)*Pitch + ; - _headYaw += (_head.yawTarget - _headYaw ) * 10 * deltaTime; // (1.f - DECAY*deltaTime); - _headRoll *= 1.f - (DECAY * deltaTime); - } - - _head.leanForward *= (1.f - DECAY * 30 * deltaTime); - _head.leanSideways *= (1.f - DECAY * 30 * deltaTime); - - // Update where the avatar's eyes are - // - // First, decide if we are making eye contact or not - if (randFloat() < 0.005) { - _head.eyeContact = !_head.eyeContact; - _head.eyeContact = 1; - if (!_head.eyeContact) { - // If we just stopped making eye contact,move the eyes markedly away - _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); - } - } - - const float DEGREES_BETWEEN_VIEWER_EYES = 3; - const float DEGREES_TO_VIEWER_MOUTH = 7; - - if (_head.eyeContact) { - // Should we pick a new eye contact target? - if (randFloat() < 0.01) { - // Choose where to look next - if (randFloat() < 0.1) { - _head.eyeContactTarget = MOUTH; - } else { - 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 (_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; - - _head.eyeballPitch[0] = _head.eyeballPitch[1] = -_headPitch + eye_target_pitch_adjust; - _head.eyeballYaw[0] = _head.eyeballYaw[1] = -_headYaw + eye_target_yaw_adjust; - } - - - if (_head.noise) - { - _headPitch += (randFloat() - 0.5) * 0.2 * _head.noiseEnvelope; - _headYaw += (randFloat() - 0.5) * 0.3 *_head.noiseEnvelope; - //PupilSize += (randFloat() - 0.5) * 0.001*NoiseEnvelope; - - if (randFloat() < 0.005) _head.mouthWidth = MouthWidthChoices[rand()%3]; - - 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(_head.pitchTarget - _headPitch) < 1.0) && (fabs(_head.yawTarget - _headYaw) < 1.0)) { - SetNewHeadTarget((randFloat()-0.5) * 20.0, (randFloat()-0.5) * 45.0); - } - - if (0) { - - // Pick new target - _head.pitchTarget = (randFloat() - 0.5) * 45; - _head.yawTarget = (randFloat() - 0.5) * 22; - } - if (randFloat() < 0.01) - { - _head.eyebrowPitch[0] = _head.eyebrowPitch[1] = BrowPitchAngle[rand()%3]; - _head.eyebrowRoll [0] = _head.eyebrowRoll[1] = BrowRollAngle[rand()%5]; - _head.eyebrowRoll [1] *=-1; - } - } - - // Update audio trailing average for rendering facial animations - const float AUDIO_AVERAGING_SECS = 0.05; - _head.averageLoudness = (1.f - deltaTime / AUDIO_AVERAGING_SECS) * _head.averageLoudness + - (deltaTime / AUDIO_AVERAGING_SECS) * _audioLoudness; -} - - -float Head::getGirth() { - return COLLISION_BODY_RADIUS; -} - -float Head::getHeight() { - return COLLISION_HEIGHT; -} - - -glm::vec3 Head::getBodyUpDirection() { - return _orientation.getUp(); -} - -//-------------------------------------------------------------------------------- -// This is a workspace for testing avatar body collision detection and response -//-------------------------------------------------------------------------------- -void Head::updateAvatarCollisionDetectionAndResponse -( glm::vec3 collisionPosition, float collisionGirth, float collisionHeight, glm::vec3 collisionUpVector, float deltaTime ) { - - float myBodyApproximateBoundingRadius = 1.0f; - glm::vec3 vectorFromMyBodyToBigSphere(_position - collisionPosition); - bool jointCollision = false; - - float distanceToBigSphere = glm::length(vectorFromMyBodyToBigSphere); - if ( distanceToBigSphere < myBodyApproximateBoundingRadius + collisionGirth ) - { - for (int b=0; b 0.0) - { - glm::vec3 directionVector = vectorFromJointToBigSphereCenter / distanceToBigSphereCenter; - - float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius); - glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration; - - _bone[b].springyVelocity += collisionForce * 30.0f * deltaTime; - _velocity += collisionForce * 100.0f * deltaTime; - _bone[b].springyPosition = collisionPosition + directionVector * combinedRadius; - } - } - } - - if ( jointCollision ) { - if (!_usingBodySprings) { - _usingBodySprings = true; - initializeBodySprings(); - } - } - } -} - - -void Head::render(bool lookingInMirror) { - - //--------------------------------------------------- - // show avatar position - //--------------------------------------------------- - glColor4f( 0.5f, 0.5f, 0.5f, 0.6 ); - glPushMatrix(); - glTranslatef(_position.x, _position.y, _position.z); - glScalef( 0.03, 0.03, 0.03 ); - glutSolidSphere( 1, 10, 10 ); - glPopMatrix(); - - if ( usingBigSphereCollisionTest ) { - //--------------------------------------------------- - // show TEST big sphere - //--------------------------------------------------- - glColor4f( 0.5f, 0.6f, 0.8f, 0.7 ); - glPushMatrix(); - glTranslatef(_TEST_bigSpherePosition.x, _TEST_bigSpherePosition.y, _TEST_bigSpherePosition.z); - glScalef( _TEST_bigSphereRadius, _TEST_bigSphereRadius, _TEST_bigSphereRadius ); - glutSolidSphere( 1, 20, 20 ); - glPopMatrix(); - } - - //--------------- - // render body - //--------------- - renderBody(); - - //--------------------------------------------------- - // render head - //--------------------------------------------------- - renderHead(lookingInMirror); - - //--------------------------------------------------------------------------- - // if this is my avatar, then render my interactions with the other avatar - //--------------------------------------------------------------------------- - if ( _isMine ) - { - if ( _interactingOtherIsNearby ) { - - glm::vec3 v1( _bone[ AVATAR_BONE_RIGHT_HAND ].position ); - glm::vec3 v2( _interactingOther->_handPosition ); - - glLineWidth( 8.0 ); - glColor4f( 0.7f, 0.4f, 0.1f, 0.6 ); - glBegin( GL_LINE_STRIP ); - glVertex3f( v1.x, v1.y, v1.z ); - glVertex3f( v2.x, v2.y, v2.z ); - glEnd(); - } - } -} - - -void Head::renderHead(bool lookingInMirror) { - int side = 0; - - glEnable(GL_DEPTH_TEST); - glEnable(GL_RESCALE_NORMAL); - - //--------------------------------------------------- - // show head orientation - //--------------------------------------------------- - //renderOrientationDirections( _bone[ AVATAR_BONE_HEAD ].position, _bone[ AVATAR_BONE_HEAD ].orientation, 0.2f ); - - glPushMatrix(); - - if (_usingBodySprings) { - glTranslatef(_bone[ AVATAR_BONE_HEAD ].springyPosition.x, - _bone[ AVATAR_BONE_HEAD ].springyPosition.y, - _bone[ AVATAR_BONE_HEAD ].springyPosition.z); - } - else { - glTranslatef(_bone[ AVATAR_BONE_HEAD ].position.x, - _bone[ AVATAR_BONE_HEAD ].position.y, - _bone[ AVATAR_BONE_HEAD ].position.z); - } - - glScalef( 0.03, 0.03, 0.03 ); - - if (lookingInMirror) { - glRotatef(_bodyYaw - _headYaw, 0, 1, 0); - glRotatef(_bodyPitch + _headPitch, 1, 0, 0); - glRotatef(_bodyRoll - _headRoll, 0, 0, 1); - } else { - glRotatef(_bodyYaw + _headYaw, 0, 1, 0); - glRotatef(_bodyPitch + _headPitch, 1, 0, 0); - glRotatef(_bodyRoll + _headRoll, 0, 0, 1); - } - - glScalef(2.0, 2.0, 2.0); - glColor3fv(skinColor); - - glutSolidSphere(1, 30, 30); - - // Ears - glPushMatrix(); - glTranslatef(1.0, 0, 0); - for(side = 0; side < 2; side++) { - glPushMatrix(); - glScalef(0.3, 0.65, .65); - glutSolidSphere(0.5, 30, 30); - glPopMatrix(); - glTranslatef(-2.0, 0, 0); - } - glPopMatrix(); - - - // Update audio attack data for facial animation (eyebrows and mouth) - _head.audioAttack = 0.9 * _head.audioAttack + 0.1 * fabs(_audioLoudness - _head.lastLoudness); - _head.lastLoudness = _audioLoudness; - - - const float BROW_LIFT_THRESHOLD = 100; - if (_head.audioAttack > BROW_LIFT_THRESHOLD) - _head.browAudioLift += sqrt(_head.audioAttack) / 1000.0; - - _head.browAudioLift *= .90; - - - // Render Eyebrows - glPushMatrix(); - glTranslatef(-_head.interBrowDistance / 2.0,0.4,0.45); - for(side = 0; side < 2; side++) { - glColor3fv(browColor); - glPushMatrix(); - 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(_head.interBrowDistance, 0, 0); - } - glPopMatrix(); - - - // Mouth - - glPushMatrix(); - glTranslatef(0,-0.35,0.75); - glColor3f(0,0,0); - 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(-_head.interPupilDistance/2.0,-0.68,0.7); - // Right Eye - glRotatef(-10, 1, 0, 0); - glColor3fv(eyeColor); - glPushMatrix(); - { - glTranslatef(_head.interPupilDistance/10.0, 0, 0.05); - glRotatef(20, 0, 0, 1); - glScalef(_head.eyeballScaleX, _head.eyeballScaleY, _head.eyeballScaleZ); - glutSolidSphere(0.25, 30, 30); - } - glPopMatrix(); - - // Right Pupil - if (_sphere == NULL) { - _sphere = gluNewQuadric(); - gluQuadricTexture(_sphere, GL_TRUE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gluQuadricOrientation(_sphere, GLU_OUTSIDE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iris_texture_width, iris_texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &iris_texture[0]); - } - - glPushMatrix(); - { - glRotatef(_head.eyeballPitch[1], 1, 0, 0); - glRotatef(_head.eyeballYaw[1] + _headYaw + _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, _head.pupilSize, 15, 15); - glDisable(GL_TEXTURE_2D); - } - - glPopMatrix(); - // Left Eye - glColor3fv(eyeColor); - glTranslatef(_head.interPupilDistance, 0, 0); - glPushMatrix(); - { - glTranslatef(-_head.interPupilDistance/10.0, 0, .05); - glRotatef(-20, 0, 0, 1); - glScalef(_head.eyeballScaleX, _head.eyeballScaleY, _head.eyeballScaleZ); - glutSolidSphere(0.25, 30, 30); - } - glPopMatrix(); - // Left Pupil - glPushMatrix(); - { - glRotatef(_head.eyeballPitch[0], 1, 0, 0); - glRotatef(_head.eyeballYaw[0] + _headYaw - _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, _head.pupilSize, 15, 15); - glDisable(GL_TEXTURE_2D); - } - - glPopMatrix(); - - - glPopMatrix(); - } - -void Head::startHandMovement() { - - if (!_usingBodySprings) { - initializeBodySprings(); - _usingBodySprings = true; - } -} - -void Head::stopHandMovement() { -//_usingBodySprings = false; -} - -void Head::setHandMovementValues( glm::vec3 handOffset ) { - _movedHandOffset = handOffset; -} - -AvatarMode Head::getMode() { - return _mode; -} - -void Head::initializeSkeleton() { - - for (int b=0; b 0.0f ) { - glm::vec3 springDirection = springVector / length; - - float force = ( length - _bone[b].length ) * _springForce * deltaTime; - - _bone[b].springyVelocity -= springDirection * force; - - if ( _bone[b].parent != AVATAR_BONE_NULL ) { - _bone[ _bone[b].parent ].springyVelocity += springDirection * force; - } - } - - _bone[b].springyVelocity += ( _bone[b].position - _bone[b].springyPosition ) * _bone[b].springBodyTightness * deltaTime; - - float decay = 1.0 - _springVelocityDecay * deltaTime; - - if ( decay > 0.0 ) { - _bone[b].springyVelocity *= decay; - } - else { - _bone[b].springyVelocity = glm::vec3( 0.0f, 0.0f, 0.0f ); - } - - _bone[b].springyPosition += _bone[b].springyVelocity; - } -} - -glm::vec3 Head::getHeadLookatDirection() { - return glm::vec3 - ( - _orientation.getFront().x, - _orientation.getFront().y, - _orientation.getFront().z - ); -} - -glm::vec3 Head::getHeadLookatDirectionUp() { - return glm::vec3 - ( - _orientation.getUp().x, - _orientation.getUp().y, - _orientation.getUp().z - ); -} - -glm::vec3 Head::getHeadLookatDirectionRight() { - return glm::vec3 - ( - _orientation.getRight().x, - _orientation.getRight().y, - _orientation.getRight().z - ); -} - -glm::vec3 Head::getHeadPosition() { - - if ( _usingBodySprings ) { - return _bone[ AVATAR_BONE_HEAD ].springyPosition; - } - - return _bone[ AVATAR_BONE_HEAD ].position; -} - - -glm::vec3 Head::getBonePosition( AvatarBoneID b ) { - return _bone[b].position; -} - - - -void Head::updateHandMovement( float deltaTime ) { - glm::vec3 transformedHandMovement; - - transformedHandMovement - = _orientation.getRight() * _movedHandOffset.x - + _orientation.getUp() * -_movedHandOffset.y * 0.5f - + _orientation.getFront() * -_movedHandOffset.y; - - _bone[ AVATAR_BONE_RIGHT_HAND ].position += transformedHandMovement; - - if (_isMine) { - _handState = _mousePressed; - } -} - - -void Head::updateArmIKAndConstraints( float deltaTime ) { - - //------------------------------------------------------------------------------- - // determine the arm vector - //------------------------------------------------------------------------------- - glm::vec3 armVector = _bone[ AVATAR_BONE_RIGHT_HAND ].position; - armVector -= _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; - - //------------------------------------------------------------------------------- - // test to see if right hand is being dragged beyond maximum arm length - //------------------------------------------------------------------------------- - float distance = glm::length( armVector ); - - //------------------------------------------------------------------------------- - // if right hand is being dragged beyond maximum arm length... - //------------------------------------------------------------------------------- - 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 * _maxArmLength; - distance = _maxArmLength; - glm::vec3 constrainedPosition = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; - constrainedPosition += armVector; - _bone[ AVATAR_BONE_RIGHT_HAND ].position = constrainedPosition; - } - - //----------------------------------------------------------------------------- - // set elbow position - //----------------------------------------------------------------------------- - glm::vec3 newElbowPosition = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; - newElbowPosition += armVector * ONE_HALF; - glm::vec3 perpendicular = glm::cross( _orientation.getFront(), armVector ); - newElbowPosition += perpendicular * ( 1.0f - ( _maxArmLength / distance ) ) * ONE_HALF; - _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position = newElbowPosition; - - //----------------------------------------------------------------------------- - // set wrist position - //----------------------------------------------------------------------------- - glm::vec3 vv( _bone[ AVATAR_BONE_RIGHT_HAND ].position ); - vv -= _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position; - glm::vec3 newWristPosition = _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position; - newWristPosition += vv * 0.7f; - _bone[ AVATAR_BONE_RIGHT_FOREARM ].position = newWristPosition; -} - - - - -void Head::renderBody() { - //----------------------------------------- - // Render bone positions as spheres - //----------------------------------------- - for (int b=0; b( (double)TRANSMITTER_COUNT/(msecsElapsed/1000.0) ); - _transmitterTimer = now; - } - /* NOTE: PR: Will add back in when ready to animate avatar hand - - // Add rotational forces to the hand - const float ANG_VEL_SENSITIVITY = 4.0; - const float ANG_VEL_THRESHOLD = 0.0; - float angVelScale = ANG_VEL_SENSITIVITY*(1.0f/getTransmitterHz()); - - addAngularVelocity(fabs(gyrX*angVelScale)>ANG_VEL_THRESHOLD?gyrX*angVelScale:0, - fabs(gyrZ*angVelScale)>ANG_VEL_THRESHOLD?gyrZ*angVelScale:0, - fabs(-gyrY*angVelScale)>ANG_VEL_THRESHOLD?-gyrY*angVelScale:0); - - // Add linear forces to the hand - //const float LINEAR_VEL_SENSITIVITY = 50.0; - const float LINEAR_VEL_SENSITIVITY = 5.0; - float linVelScale = LINEAR_VEL_SENSITIVITY*(1.0f/getTransmitterHz()); - glm::vec3 linVel(linX*linVelScale, linZ*linVelScale, -linY*linVelScale); - addVelocity(linVel); - */ - -} - diff --git a/interface/src/Head.h b/interface/src/Head.h deleted file mode 100644 index 377228986d..0000000000 --- a/interface/src/Head.h +++ /dev/null @@ -1,279 +0,0 @@ -// -// Head.h -// interface -// -// Created by Philip Rosedale on 9/11/12. -// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__head__ -#define __interface__head__ - -#include -#include - -#include "Field.h" -#include "world.h" - -#include "InterfaceConfig.h" -#include "SerialInterface.h" - -#include -#include -#include //looks like we might not need this - -const bool AVATAR_GRAVITY = true; -const float DECAY = 0.1; -const float THRUST_MAG = 10.0; -const float YAW_MAG = 300.0; -const float TEST_YAW_DECAY = 5.0; -const float LIN_VEL_DECAY = 5.0; - -const float COLLISION_BODY_RADIUS = 0.1; -const float COLLISION_HEIGHT = 1.5; - -enum eyeContactTargets {LEFT_EYE, RIGHT_EYE, MOUTH}; - -#define FWD 0 -#define BACK 1 -#define LEFT 2 -#define RIGHT 3 -#define UP 4 -#define DOWN 5 -#define ROT_LEFT 6 -#define ROT_RIGHT 7 -#define MAX_DRIVE_KEYS 8 - -#define MAX_OTHER_AVATARS 10 // temporary - for testing purposes! - -enum AvatarMode -{ - AVATAR_MODE_STANDING = 0, - AVATAR_MODE_WALKING, - AVATAR_MODE_INTERACTING, - NUM_AVATAR_MODES -}; - -enum AvatarBoneID -{ - AVATAR_BONE_NULL = -1, - AVATAR_BONE_PELVIS_SPINE, // connects pelvis joint with torso joint (not supposed to be rotated) - AVATAR_BONE_MID_SPINE, // connects torso joint with chest joint - AVATAR_BONE_CHEST_SPINE, // connects chest joint with neckBase joint (not supposed to be rotated) - AVATAR_BONE_NECK, // connects neckBase joint with headBase joint - AVATAR_BONE_HEAD, // connects headBase joint with headTop joint - AVATAR_BONE_LEFT_CHEST, // connects chest joint with left clavicle joint (not supposed to be rotated) - AVATAR_BONE_LEFT_SHOULDER, // connects left clavicle joint with left shoulder joint - AVATAR_BONE_LEFT_UPPER_ARM, // connects left shoulder joint with left elbow joint - AVATAR_BONE_LEFT_FOREARM, // connects left elbow joint with left wrist joint - AVATAR_BONE_LEFT_HAND, // connects left wrist joint with left fingertips joint - AVATAR_BONE_RIGHT_CHEST, // connects chest joint with right clavicle joint (not supposed to be rotated) - AVATAR_BONE_RIGHT_SHOULDER, // connects right clavicle joint with right shoulder joint - AVATAR_BONE_RIGHT_UPPER_ARM, // connects right shoulder joint with right elbow joint - AVATAR_BONE_RIGHT_FOREARM, // connects right elbow joint with right wrist joint - AVATAR_BONE_RIGHT_HAND, // connects right wrist joint with right fingertips joint - AVATAR_BONE_LEFT_PELVIS, // connects pelvis joint with left hip joint (not supposed to be rotated) - AVATAR_BONE_LEFT_THIGH, // connects left hip joint with left knee joint - AVATAR_BONE_LEFT_SHIN, // connects left knee joint with left heel joint - AVATAR_BONE_LEFT_FOOT, // connects left heel joint with left toes joint - AVATAR_BONE_RIGHT_PELVIS, // connects pelvis joint with right hip joint (not supposed to be rotated) - AVATAR_BONE_RIGHT_THIGH, // connects right hip joint with right knee joint - AVATAR_BONE_RIGHT_SHIN, // connects right knee joint with right heel joint - AVATAR_BONE_RIGHT_FOOT, // connects right heel joint with right toes joint - - NUM_AVATAR_BONES -}; - -struct AvatarCollisionElipsoid -{ - bool colliding; - glm::vec3 position; - float girth; - float height; - glm::vec3 upVector; -}; - -struct AvatarHandHolding -{ - glm::vec3 position; - glm::vec3 velocity; - float force; -}; - -/* -struct OtherAvatar -{ - bool nearby; - //glm::vec3 handPosition; - //int handState; -}; -*/ - -struct AvatarBone -{ - AvatarBoneID parent; // which bone is this bone connected to? - glm::vec3 position; // the position at the "end" of the bone - glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" - glm::vec3 springyPosition; // used for special effects (a 'flexible' variant of position) - glm::dvec3 springyVelocity; // used for special effects ( the velocity of the springy position) - float springBodyTightness; // how tightly the springy position tries to stay on the position - glm::quat rotation; // this will eventually replace yaw, pitch and roll (and maybe orientation) - float yaw; // the yaw Euler angle of the bone rotation off the parent - float pitch; // the pitch Euler angle of the bone rotation off the parent - float roll; // the roll Euler angle of the bone rotation off the parent - Orientation orientation; // three orthogonal normals determined by yaw, pitch, roll - float length; // the length of the bone - float radius; // used for detecting collisions for certain physical effects -}; - -struct AvatarHead -{ - float pitchRate; - float yawRate; - float rollRate; - float noise; - float eyeballPitch[2]; - float eyeballYaw [2]; - float eyebrowPitch[2]; - float eyebrowRoll [2]; - float eyeballScaleX; - float eyeballScaleY; - float eyeballScaleZ; - float interPupilDistance; - float interBrowDistance; - float nominalPupilSize; - float pupilSize; - float mouthPitch; - float mouthYaw; - float mouthWidth; - float mouthHeight; - float leanForward; - float leanSideways; - float pitchTarget; - float yawTarget; - float noiseEnvelope; - float pupilConverge; - float scale; - int eyeContact; - float browAudioLift; - eyeContactTargets eyeContactTarget; - - // Sound loudness information - float lastLoudness; - float averageLoudness; - float audioAttack; -}; - - -class Head : public AvatarData { - public: - Head(bool isMine); - ~Head(); - Head(const Head &otherHead); - Head* clone() const; - - void reset(); - void UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity); - void setNoise (float mag) { _head.noise = mag; } - void setScale(float s) {_head.scale = s; }; - void setRenderYaw(float y) {_renderYaw = y;} - void setRenderPitch(float p) {_renderPitch = p;} - float getRenderYaw() {return _renderYaw;} - float getRenderPitch() {return _renderPitch;} - void setLeanForward(float dist); - void setLeanSideways(float dist); - void addLean(float x, float z); - float getLastMeasuredHeadYaw() const {return _head.yawRate;} - float getBodyYaw() {return _bodyYaw;}; - void addBodyYaw(float y) {_bodyYaw += y;}; - - glm::vec3 getHeadLookatDirection(); - glm::vec3 getHeadLookatDirectionUp(); - glm::vec3 getHeadLookatDirectionRight(); - glm::vec3 getHeadPosition(); - glm::vec3 getBonePosition( AvatarBoneID b ); - glm::vec3 getBodyUpDirection(); - float getGirth(); - float getHeight(); - - AvatarMode getMode(); - - void setMousePressed( bool pressed ); - void render(bool lookingInMirror); - void renderBody(); - void renderHead(bool lookingInMirror); - void simulate(float); - void startHandMovement(); - void stopHandMovement(); - void setHandMovementValues( glm::vec3 movement ); - void updateHandMovement( float deltaTime ); - void updateArmIKAndConstraints( float deltaTime ); - - float getAverageLoudness() {return _head.averageLoudness;}; - void setAverageLoudness(float al) {_head.averageLoudness = al;}; - - void SetNewHeadTarget(float, float); - - // Set what driving keys are being pressed to control thrust levels - void setDriveKeys(int key, bool val) { _driveKeys[key] = val; }; - bool getDriveKeys(int key) { return _driveKeys[key]; }; - - // Set/Get update the thrust that will move the avatar around - void setThrust(glm::vec3 newThrust) { _thrust = newThrust; }; - void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; - glm::vec3 getThrust() { return _thrust; }; - - // Related to getting transmitter UDP data used to animate the avatar hand - void processTransmitterData(unsigned char * packetData, int numBytes); - float getTransmitterHz() { return _transmitterHz; }; - - private: - AvatarHead _head; - bool _isMine; - glm::vec3 _TEST_bigSpherePosition; - float _TEST_bigSphereRadius; - bool _mousePressed; - float _bodyYawDelta; - bool _usingBodySprings; - glm::vec3 _movedHandOffset; - float _springVelocityDecay; - float _springForce; - glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion - AvatarBone _bone[ NUM_AVATAR_BONES ]; - AvatarMode _mode; - AvatarHandHolding _handHolding; - glm::dvec3 _velocity; - glm::vec3 _thrust; - float _maxArmLength; - Orientation _orientation; - int _driveKeys[MAX_DRIVE_KEYS]; - GLUquadric* _sphere; - float _renderYaw; - float _renderPitch; // Pitch from view frustum when this is own head - timeval _transmitterTimer; - float _transmitterHz; - int _transmitterPackets; - Head* _interactingOther; - bool _interactingOtherIsNearby; - - //----------------------------- - // private methods... - //----------------------------- - void initializeSkeleton(); - void updateSkeleton(); - void initializeBodySprings(); - void updateBodySprings( float deltaTime ); - void calculateBoneLengths(); - void readSensors(); - void renderBoneAsBlock( AvatarBoneID b ); - void updateAvatarCollisionDetectionAndResponse - ( - glm::vec3 collisionPosition, - float collisionGirth, - float collisionHeight, - glm::vec3 collisionUpVector, - float deltaTime - ); -}; - -#endif diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 8bf6222aec..e96dc5ef8b 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -60,8 +60,8 @@ VoxelSystem::~VoxelSystem() { pthread_mutex_destroy(&bufferWriteLock); } -void VoxelSystem::setViewerHead(Head *newViewerHead) { - viewerHead = newViewerHead; +void VoxelSystem::setViewerAvatar(Avatar *newViewerAvatar) { + viewerAvatar = newViewerAvatar; } ////////////////////////////////////////////////////////////////////////////////////////// @@ -187,7 +187,7 @@ int VoxelSystem::treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosi int voxelsAdded = 0; float halfUnitForVoxel = powf(0.5, *currentNode->octalCode) * (0.5 * TREE_SCALE); - glm::vec3 viewerPosition = viewerHead->getPosition(); + glm::vec3 viewerPosition = viewerAvatar->getPosition(); // debug LOD code glm::vec3 debugNodePosition; diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 9d831ee5f2..ca4825121b 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -15,7 +15,7 @@ #include #include #include -#include "Head.h" +#include "Avatar.h" #include "Util.h" #include "world.h" @@ -34,7 +34,7 @@ public: void render(); void setVoxelsRendered(int v) {voxelsRendered = v;}; int getVoxelsRendered() {return voxelsRendered;}; - void setViewerHead(Head *newViewerHead); + void setViewerAvatar(Avatar *newViewerAvatar); void loadVoxelsFile(const char* fileName,bool wantColorRandomizer); void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer); @@ -67,7 +67,7 @@ private: static float _minDistance; int voxelsRendered; - Head *viewerHead; + Avatar *viewerAvatar; VoxelTree *tree; GLfloat *readVerticesArray; GLubyte *readColorsArray; diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 41ffdc1e92..b4e6545271 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -64,7 +64,7 @@ #include "MenuColumn.h" #include "Menu.h" #include "Camera.h" -#include "Head.h" +#include "Avatar.h" #include "Particle.h" #include "Texture.h" #include "Cloud.h" @@ -107,7 +107,7 @@ Oscilloscope audioScope(256,200,true); ViewFrustum viewFrustum; // current state of view frustum, perspective, orientation, etc. -Head myAvatar(true); // The rendered avatar of oneself +Avatar myAvatar(true); // The rendered avatar of oneself Camera myCamera; // My view onto the world (sometimes on myself :) Camera viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode @@ -382,7 +382,7 @@ void initDisplay(void) void init(void) { voxels.init(); - voxels.setViewerHead(&myAvatar); + voxels.setViewerAvatar(&myAvatar); myAvatar.setRenderYaw(startYaw); initializeHandController(); @@ -911,7 +911,7 @@ void display(void) agent != agentList->getAgents().end(); agent++) { if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { - Head *avatar = (Head *)agent->getLinkedData(); + Avatar *avatar = (Avatar *)agent->getLinkedData(); avatar->render(0); } } @@ -1493,7 +1493,7 @@ void idle(void) { { if (agent->getLinkedData() != NULL) { - Head *avatar = (Head *)agent->getLinkedData(); + Avatar *avatar = (Avatar *)agent->getLinkedData(); avatar->simulate(deltaTime); } } @@ -1604,7 +1604,7 @@ void mouseoverFunc( int x, int y) void attachNewHeadToAgent(Agent *newAgent) { if (newAgent->getLinkedData() == NULL) { - newAgent->setLinkedData(new Head(false)); + newAgent->setLinkedData(new Avatar(false)); } } From 2163976f067c26fb677884ccf59dfb30ace4795c Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 24 Apr 2013 17:01:59 -0700 Subject: [PATCH 2/2] adding the files --- interface/src/Avatar.cpp | 1270 ++++++++++++++++++++++++++++++++++++++ interface/src/Avatar.h | 268 ++++++++ 2 files changed, 1538 insertions(+) create mode 100644 interface/src/Avatar.cpp create mode 100644 interface/src/Avatar.h diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp new file mode 100644 index 0000000000..ae082fd71c --- /dev/null +++ b/interface/src/Avatar.cpp @@ -0,0 +1,1270 @@ +// +// Avatar.cpp +// interface +// +// Created by Philip Rosedale on 9/11/12. +// adapted by Jeffrey Ventrella +// Copyright (c) 2012 Physical, Inc.. All rights reserved. +// + +#include +#include +#include +#include +#include "Avatar.h" +#include "Log.h" +#include +#include +#include + +using namespace std; + +float skinColor[] = {1.0, 0.84, 0.66}; +float lightBlue[] = { 0.7, 0.8, 1.0 }; +float browColor[] = {210.0/255.0, 105.0/255.0, 30.0/255.0}; +float mouthColor[] = {1, 0, 0}; + +float BrowRollAngle[5] = {0, 15, 30, -30, -15}; +float BrowPitchAngle[3] = {-70, -60, -50}; +float eyeColor[3] = {1,1,1}; + +float MouthWidthChoices[3] = {0.5, 0.77, 0.3}; + +float browWidth = 0.8; +float browThickness = 0.16; + +bool usingBigSphereCollisionTest = true; + +char iris_texture_file[] = "resources/images/green_eye.png"; + +vector iris_texture; +unsigned int iris_texture_width = 512; +unsigned int iris_texture_height = 256; + +Avatar::Avatar(bool isMine) { + + _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 ); + _bodyYaw = -90.0; + _bodyPitch = 0.0; + _bodyRoll = 0.0; + _bodyYawDelta = 0.0; + _mousePressed = false; + _mode = AVATAR_MODE_STANDING; + _isMine = isMine; + _maxArmLength = 0.0; + //_transmitterTimer = 0; + _transmitterHz = 0.0; + _transmitterPackets = 0; + + initializeSkeleton(); + + _TEST_bigSphereRadius = 0.3f; + _TEST_bigSpherePosition = glm::vec3( 0.0f, _TEST_bigSphereRadius, 2.0f ); + + for (int i = 0; i < MAX_DRIVE_KEYS; i++) _driveKeys[i] = false; + + _head.pupilSize = 0.10; + _head.interPupilDistance = 0.6; + _head.interBrowDistance = 0.75; + _head.nominalPupilSize = 0.10; + _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.averageLoudness = 0.0; + _head.lastLoudness = 0.0; + _head.browAudioLift = 0.0; + _head.noise = 0; + _movedHandOffset = glm::vec3( 0.0, 0.0, 0.0 ); + _usingBodySprings = true; + _springForce = 6.0f; + _springVelocityDecay = 16.0f; + _renderYaw = 0.0; + _renderPitch = 0.0; + _sphere = NULL; + _interactingOther = NULL; + _interactingOtherIsNearby = false; + + _handHolding.position = glm::vec3( 0.0, 0.0, 0.0 ); + _handHolding.velocity = glm::vec3( 0.0, 0.0, 0.0 ); + _handHolding.force = 10.0f; + + if (iris_texture.size() == 0) { + switchToResourcesParentIfRequired(); + unsigned error = lodepng::decode(iris_texture, iris_texture_width, iris_texture_height, iris_texture_file); + if (error != 0) { + printLog("error %u: %s\n", error, lodepng_error_text(error)); + } + } +} + + + +Avatar::Avatar(const Avatar &otherAvatar) { + + _velocity = otherAvatar._velocity; + _thrust = otherAvatar._thrust; + _rotation = otherAvatar._rotation; + _interactingOtherIsNearby = otherAvatar._interactingOtherIsNearby; + _bodyYaw = otherAvatar._bodyYaw; + _bodyPitch = otherAvatar._bodyPitch; + _bodyRoll = otherAvatar._bodyRoll; + _bodyYawDelta = otherAvatar._bodyYawDelta; + _mousePressed = otherAvatar._mousePressed; + _mode = otherAvatar._mode; + _isMine = otherAvatar._isMine; + _renderYaw = otherAvatar._renderYaw; + _renderPitch = otherAvatar._renderPitch; + _maxArmLength = otherAvatar._maxArmLength; + _transmitterTimer = otherAvatar._transmitterTimer; + _transmitterHz = otherAvatar._transmitterHz; + _transmitterPackets = otherAvatar._transmitterPackets; + _TEST_bigSphereRadius = otherAvatar._TEST_bigSphereRadius; + _TEST_bigSpherePosition = otherAvatar._TEST_bigSpherePosition; + _movedHandOffset = otherAvatar._movedHandOffset; + _usingBodySprings = otherAvatar._usingBodySprings; + _springForce = otherAvatar._springForce; + _springVelocityDecay = otherAvatar._springVelocityDecay; + _orientation.set( otherAvatar._orientation ); + + _sphere = NULL; + + initializeSkeleton(); + + for (int i = 0; i < MAX_DRIVE_KEYS; i++) _driveKeys[i] = otherAvatar._driveKeys[i]; + + _head.pupilSize = otherAvatar._head.pupilSize; + _head.interPupilDistance = otherAvatar._head.interPupilDistance; + _head.interBrowDistance = otherAvatar._head.interBrowDistance; + _head.nominalPupilSize = otherAvatar._head.nominalPupilSize; + _head.yawRate = otherAvatar._head.yawRate; + _head.pitchRate = otherAvatar._head.pitchRate; + _head.rollRate = otherAvatar._head.rollRate; + _head.eyebrowPitch[0] = otherAvatar._head.eyebrowPitch[0]; + _head.eyebrowPitch[1] = otherAvatar._head.eyebrowPitch[1]; + _head.eyebrowRoll [0] = otherAvatar._head.eyebrowRoll [0]; + _head.eyebrowRoll [1] = otherAvatar._head.eyebrowRoll [1]; + _head.mouthPitch = otherAvatar._head.mouthPitch; + _head.mouthYaw = otherAvatar._head.mouthYaw; + _head.mouthWidth = otherAvatar._head.mouthWidth; + _head.mouthHeight = otherAvatar._head.mouthHeight; + _head.eyeballPitch[0] = otherAvatar._head.eyeballPitch[0]; + _head.eyeballPitch[1] = otherAvatar._head.eyeballPitch[1]; + _head.eyeballScaleX = otherAvatar._head.eyeballScaleX; + _head.eyeballScaleY = otherAvatar._head.eyeballScaleY; + _head.eyeballScaleZ = otherAvatar._head.eyeballScaleZ; + _head.eyeballYaw[0] = otherAvatar._head.eyeballYaw[0]; + _head.eyeballYaw[1] = otherAvatar._head.eyeballYaw[1]; + _head.pitchTarget = otherAvatar._head.pitchTarget; + _head.yawTarget = otherAvatar._head.yawTarget; + _head.noiseEnvelope = otherAvatar._head.noiseEnvelope; + _head.pupilConverge = otherAvatar._head.pupilConverge; + _head.leanForward = otherAvatar._head.leanForward; + _head.leanSideways = otherAvatar._head.leanSideways; + _head.eyeContact = otherAvatar._head.eyeContact; + _head.eyeContactTarget = otherAvatar._head.eyeContactTarget; + _head.scale = otherAvatar._head.scale; + _head.audioAttack = otherAvatar._head.audioAttack; + _head.averageLoudness = otherAvatar._head.averageLoudness; + _head.lastLoudness = otherAvatar._head.lastLoudness; + _head.browAudioLift = otherAvatar._head.browAudioLift; + _head.noise = otherAvatar._head.noise; + + if (iris_texture.size() == 0) { + switchToResourcesParentIfRequired(); + unsigned error = lodepng::decode(iris_texture, iris_texture_width, iris_texture_height, iris_texture_file); + if (error != 0) { + printLog("error %u: %s\n", error, lodepng_error_text(error)); + } + } +} + +Avatar::~Avatar() { + if (_sphere != NULL) { + gluDeleteQuadric(_sphere); + } +} + +Avatar* Avatar::clone() const { + return new Avatar(*this); +} + +void Avatar::reset() { + _headPitch = _headYaw = _headRoll = 0; + _head.leanForward = _head.leanSideways = 0; +} + + +//this pertains to moving the head with the glasses +void Avatar::UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity) +// Using serial data, update avatar/render position and angles +{ + const float PITCH_ACCEL_COUPLING = 0.5; + const float ROLL_ACCEL_COUPLING = -1.0; + float measured_pitch_rate = serialInterface->getRelativeValue(HEAD_PITCH_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) - + PITCH_ACCEL_COUPLING*serialInterface->getRelativeValue(HEAD_PITCH_RATE); + float measured_roll_rate = serialInterface->getRelativeValue(HEAD_ROLL_RATE); + + //printLog("Pitch Rate: %d ACCEL_Z: %d\n", serialInterface->getRelativeValue(PITCH_RATE), + // serialInterface->getRelativeValue(ACCEL_Z)); + //printLog("Pitch Rate: %d ACCEL_X: %d\n", serialInterface->getRelativeValue(PITCH_RATE), + // serialInterface->getRelativeValue(ACCEL_Z)); + //printLog("Pitch: %f\n", Pitch); + + // Update avatar head position based on measured gyro rates + const float HEAD_ROTATION_SCALE = 0.70; + const float HEAD_ROLL_SCALE = 0.40; + const float HEAD_LEAN_SCALE = 0.01; + const float MAX_PITCH = 45; + const float MIN_PITCH = -45; + const float MAX_YAW = 85; + const float MIN_YAW = -85; + + if ((_headPitch < MAX_PITCH) && (_headPitch > MIN_PITCH)) + addHeadPitch(measured_pitch_rate * -HEAD_ROTATION_SCALE * frametime); + + addHeadRoll(measured_roll_rate * HEAD_ROLL_SCALE * frametime); + + if ((_headYaw < MAX_YAW) && (_headYaw > MIN_YAW)) + addHeadYaw(_head.yawRate * HEAD_ROTATION_SCALE * frametime); + + addLean(-measured_lateral_accel * frametime * HEAD_LEAN_SCALE, -measured_fwd_accel*frametime * HEAD_LEAN_SCALE); +} + +void Avatar::addLean(float x, float z) { + // Add Body lean as impulse + _head.leanSideways += x; + _head.leanForward += z; +} + + +void Avatar::setLeanForward(float dist){ + _head.leanForward = dist; +} + +void Avatar::setLeanSideways(float dist){ + _head.leanSideways = dist; +} + +void Avatar::setMousePressed( bool d ) { + _mousePressed = d; +} + +void Avatar::simulate(float deltaTime) { + + // update avatar skeleton + updateSkeleton(); + + // reset hand and arm positions according to hand movement + updateHandMovement( deltaTime ); + + if ( !_interactingOtherIsNearby ) { + //initialize _handHolding + _handHolding.position = _bone[ AVATAR_BONE_RIGHT_HAND ].position; + _handHolding.velocity = glm::vec3( 0.0, 0.0, 0.0 ); + } + + _interactingOtherIsNearby = false; + + // if the avatar being simulated is mine, then loop through + // all the other avatars for potential interactions... + if ( _isMine ) + { + float closestDistance = 10000.0f; + + AgentList * agentList = AgentList::getInstance(); + + for(std::vector::iterator agent = agentList->getAgents().begin(); + agent != agentList->getAgents().end(); + agent++) { + if (( agent->getLinkedData() != NULL && ( agent->getType() == AGENT_TYPE_AVATAR ) )) { + Avatar *otherAvatar = (Avatar *)agent->getLinkedData(); + + // check for collisions with other avatars and respond + updateAvatarCollisionDetectionAndResponse + ( + otherAvatar->getPosition(), + otherAvatar->getGirth(), + otherAvatar->getHeight(), + otherAvatar->getBodyUpDirection(), + deltaTime + ); + + // test other avatar hand position for proximity + glm::vec3 v( _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position ); + v -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); + + float distance = glm::length( v ); + if ( distance < _maxArmLength ) { + + //if ( distance < closestDistance ) { // perhaps I don't need this if we want to allow multi-avatar interactions + { + closestDistance = distance; + _interactingOther = otherAvatar; + _interactingOtherIsNearby = true; + + // if I am holding hands with another avatar, a force is applied + if (( _handState == 1 ) || ( _interactingOther->_handState == 1 )) { + glm::vec3 vectorToOtherHand = _interactingOther->_handPosition - _handHolding.position; + glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHolding.position; + + _handHolding.velocity *= 0.7; + _handHolding.velocity += ( vectorToOtherHand + vectorToMyHand ) * _handHolding.force * deltaTime; + _handHolding.position += _handHolding.velocity; + + _bone[ AVATAR_BONE_RIGHT_HAND ].position = _handHolding.position; + } + } + } + } + } + + // Set the vector we send for hand position to other people to be our right hand + setHandPosition(_bone[ AVATAR_BONE_RIGHT_HAND ].position); + + }//if ( _isMine ) + + + updateArmIKAndConstraints( deltaTime ); + + if (!_interactingOtherIsNearby) { + _interactingOther = NULL; + } + + if ( usingBigSphereCollisionTest ) { + + // test for avatar collision response (using a big sphere :) + updateAvatarCollisionDetectionAndResponse + ( + _TEST_bigSpherePosition, + _TEST_bigSphereRadius, + _TEST_bigSphereRadius, + glm::vec3( 0.0, 1.0, 0.0 ), + deltaTime + ); + } + + if ( AVATAR_GRAVITY ) { + if ( _position.y > _bone[ AVATAR_BONE_RIGHT_FOOT ].radius * 2.0 ) { + _velocity += glm::dvec3( 0.0, -1.0, 0.0 ) * ( 6.0 * deltaTime ); + } + else { + if ( _position.y < _bone[ AVATAR_BONE_RIGHT_FOOT ].radius ) { + _position.y = _bone[ AVATAR_BONE_RIGHT_FOOT ].radius; + _velocity.y = 0.0; + } + } + } + + // update body springs + updateBodySprings( deltaTime ); + + // driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely) + if ( _isMine ) { + + _thrust = glm::vec3( 0.0, 0.0, 0.0 ); + + if (_driveKeys[FWD]) { + glm::vec3 front( _orientation.getFront().x, _orientation.getFront().y, _orientation.getFront().z ); + _thrust += front * THRUST_MAG; + } + if (_driveKeys[BACK]) { + glm::vec3 front( _orientation.getFront().x, _orientation.getFront().y, _orientation.getFront().z ); + _thrust -= front * THRUST_MAG; + } + if (_driveKeys[RIGHT]) { + glm::vec3 right( _orientation.getRight().x, _orientation.getRight().y, _orientation.getRight().z ); + _thrust += right * THRUST_MAG; + } + if (_driveKeys[LEFT]) { + glm::vec3 right( _orientation.getRight().x, _orientation.getRight().y, _orientation.getRight().z ); + _thrust -= right * THRUST_MAG; + } + if (_driveKeys[UP]) { + glm::vec3 up( _orientation.getUp().x, _orientation.getUp().y, _orientation.getUp().z ); + _thrust += up * THRUST_MAG; + } + if (_driveKeys[DOWN]) { + glm::vec3 up( _orientation.getUp().x, _orientation.getUp().y, _orientation.getUp().z ); + _thrust -= up * THRUST_MAG; + } + if (_driveKeys[ROT_RIGHT]) { + _bodyYawDelta -= YAW_MAG * deltaTime; + } + if (_driveKeys[ROT_LEFT]) { + _bodyYawDelta += YAW_MAG * deltaTime; + } + } + + float translationalSpeed = glm::length( _velocity ); + float rotationalSpeed = fabs( _bodyYawDelta ); + if ( translationalSpeed + rotationalSpeed > 0.2 ) + { + _mode = AVATAR_MODE_WALKING; + } + else + { + _mode = AVATAR_MODE_INTERACTING; + } + + // update body yaw by body yaw delta + if (_isMine) { + _bodyYaw += _bodyYawDelta * deltaTime; + } + + // decay body yaw delta + _bodyYawDelta *= (1.0 - TEST_YAW_DECAY * deltaTime); + + // add thrust to velocity + _velocity += glm::dvec3(_thrust * deltaTime); + + // update position by velocity + _position += (glm::vec3)_velocity * deltaTime; + + // decay velocity + _velocity *= ( 1.0 - LIN_VEL_DECAY * deltaTime ); + + // + // Update Head information + // + + 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); + } + else { + // Move toward new target + _headPitch += (_head.pitchTarget - _headPitch) * 10 * deltaTime; // (1.f - DECAY*deltaTime)*Pitch + ; + _headYaw += (_head.yawTarget - _headYaw ) * 10 * deltaTime; // (1.f - DECAY*deltaTime); + _headRoll *= 1.f - (DECAY * deltaTime); + } + + _head.leanForward *= (1.f - DECAY * 30 * deltaTime); + _head.leanSideways *= (1.f - DECAY * 30 * deltaTime); + + // Update where the avatar's eyes are + // + // First, decide if we are making eye contact or not + if (randFloat() < 0.005) { + _head.eyeContact = !_head.eyeContact; + _head.eyeContact = 1; + if (!_head.eyeContact) { + // If we just stopped making eye contact,move the eyes markedly away + _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); + } + } + + const float DEGREES_BETWEEN_VIEWER_EYES = 3; + const float DEGREES_TO_VIEWER_MOUTH = 7; + + if (_head.eyeContact) { + // Should we pick a new eye contact target? + if (randFloat() < 0.01) { + // Choose where to look next + if (randFloat() < 0.1) { + _head.eyeContactTarget = MOUTH; + } else { + 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 (_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; + + _head.eyeballPitch[0] = _head.eyeballPitch[1] = -_headPitch + eye_target_pitch_adjust; + _head.eyeballYaw[0] = _head.eyeballYaw[1] = -_headYaw + eye_target_yaw_adjust; + } + + + if (_head.noise) + { + _headPitch += (randFloat() - 0.5) * 0.2 * _head.noiseEnvelope; + _headYaw += (randFloat() - 0.5) * 0.3 *_head.noiseEnvelope; + //PupilSize += (randFloat() - 0.5) * 0.001*NoiseEnvelope; + + if (randFloat() < 0.005) _head.mouthWidth = MouthWidthChoices[rand()%3]; + + 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(_head.pitchTarget - _headPitch) < 1.0) && (fabs(_head.yawTarget - _headYaw) < 1.0)) { + SetNewHeadTarget((randFloat()-0.5) * 20.0, (randFloat()-0.5) * 45.0); + } + + if (0) { + + // Pick new target + _head.pitchTarget = (randFloat() - 0.5) * 45; + _head.yawTarget = (randFloat() - 0.5) * 22; + } + if (randFloat() < 0.01) + { + _head.eyebrowPitch[0] = _head.eyebrowPitch[1] = BrowPitchAngle[rand()%3]; + _head.eyebrowRoll [0] = _head.eyebrowRoll[1] = BrowRollAngle[rand()%5]; + _head.eyebrowRoll [1] *=-1; + } + } + + // Update audio trailing average for rendering facial animations + const float AUDIO_AVERAGING_SECS = 0.05; + _head.averageLoudness = (1.f - deltaTime / AUDIO_AVERAGING_SECS) * _head.averageLoudness + + (deltaTime / AUDIO_AVERAGING_SECS) * _audioLoudness; +} + + +float Avatar::getGirth() { + return COLLISION_BODY_RADIUS; +} + +float Avatar::getHeight() { + return COLLISION_HEIGHT; +} + + +glm::vec3 Avatar::getBodyUpDirection() { + return _orientation.getUp(); +} + +// This is a workspace for testing avatar body collision detection and response +void Avatar::updateAvatarCollisionDetectionAndResponse +( glm::vec3 collisionPosition, float collisionGirth, float collisionHeight, glm::vec3 collisionUpVector, float deltaTime ) { + + float myBodyApproximateBoundingRadius = 1.0f; + glm::vec3 vectorFromMyBodyToBigSphere(_position - collisionPosition); + bool jointCollision = false; + + float distanceToBigSphere = glm::length(vectorFromMyBodyToBigSphere); + if ( distanceToBigSphere < myBodyApproximateBoundingRadius + collisionGirth ) + { + for (int b=0; b 0.0) + { + glm::vec3 directionVector = vectorFromJointToBigSphereCenter / distanceToBigSphereCenter; + + float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius); + glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration; + + _bone[b].springyVelocity += collisionForce * 30.0f * deltaTime; + _velocity += collisionForce * 100.0f * deltaTime; + _bone[b].springyPosition = collisionPosition + directionVector * combinedRadius; + } + } + } + + if ( jointCollision ) { + if (!_usingBodySprings) { + _usingBodySprings = true; + initializeBodySprings(); + } + } + } +} + + +void Avatar::render(bool lookingInMirror) { + + // show avatar position + glColor4f( 0.5f, 0.5f, 0.5f, 0.6 ); + glPushMatrix(); + glTranslatef(_position.x, _position.y, _position.z); + glScalef( 0.03, 0.03, 0.03 ); + glutSolidSphere( 1, 10, 10 ); + glPopMatrix(); + + if ( usingBigSphereCollisionTest ) { + + // show TEST big sphere + glColor4f( 0.5f, 0.6f, 0.8f, 0.7 ); + glPushMatrix(); + glTranslatef(_TEST_bigSpherePosition.x, _TEST_bigSpherePosition.y, _TEST_bigSpherePosition.z); + glScalef( _TEST_bigSphereRadius, _TEST_bigSphereRadius, _TEST_bigSphereRadius ); + glutSolidSphere( 1, 20, 20 ); + glPopMatrix(); + } + + // render body + renderBody(); + + // render head + renderHead(lookingInMirror); + + // if this is my avatar, then render my interactions with the other avatar + if ( _isMine ) + { + if ( _interactingOtherIsNearby ) { + + glm::vec3 v1( _bone[ AVATAR_BONE_RIGHT_HAND ].position ); + glm::vec3 v2( _interactingOther->_handPosition ); + + glLineWidth( 8.0 ); + glColor4f( 0.7f, 0.4f, 0.1f, 0.6 ); + glBegin( GL_LINE_STRIP ); + glVertex3f( v1.x, v1.y, v1.z ); + glVertex3f( v2.x, v2.y, v2.z ); + glEnd(); + } + } +} + + +void Avatar::renderHead(bool lookingInMirror) { + int side = 0; + + glEnable(GL_DEPTH_TEST); + glEnable(GL_RESCALE_NORMAL); + + // show head orientation + //renderOrientationDirections( _bone[ AVATAR_BONE_HEAD ].position, _bone[ AVATAR_BONE_HEAD ].orientation, 0.2f ); + + glPushMatrix(); + + if (_usingBodySprings) { + glTranslatef(_bone[ AVATAR_BONE_HEAD ].springyPosition.x, + _bone[ AVATAR_BONE_HEAD ].springyPosition.y, + _bone[ AVATAR_BONE_HEAD ].springyPosition.z); + } + else { + glTranslatef(_bone[ AVATAR_BONE_HEAD ].position.x, + _bone[ AVATAR_BONE_HEAD ].position.y, + _bone[ AVATAR_BONE_HEAD ].position.z); + } + + glScalef( 0.03, 0.03, 0.03 ); + + if (lookingInMirror) { + glRotatef(_bodyYaw - _headYaw, 0, 1, 0); + glRotatef(_bodyPitch + _headPitch, 1, 0, 0); + glRotatef(_bodyRoll - _headRoll, 0, 0, 1); + } else { + glRotatef(_bodyYaw + _headYaw, 0, 1, 0); + glRotatef(_bodyPitch + _headPitch, 1, 0, 0); + glRotatef(_bodyRoll + _headRoll, 0, 0, 1); + } + + glScalef(2.0, 2.0, 2.0); + glColor3fv(skinColor); + + glutSolidSphere(1, 30, 30); + + // Ears + glPushMatrix(); + glTranslatef(1.0, 0, 0); + for(side = 0; side < 2; side++) { + glPushMatrix(); + glScalef(0.3, 0.65, .65); + glutSolidSphere(0.5, 30, 30); + glPopMatrix(); + glTranslatef(-2.0, 0, 0); + } + glPopMatrix(); + + + // Update audio attack data for facial animation (eyebrows and mouth) + _head.audioAttack = 0.9 * _head.audioAttack + 0.1 * fabs(_audioLoudness - _head.lastLoudness); + _head.lastLoudness = _audioLoudness; + + + const float BROW_LIFT_THRESHOLD = 100; + if (_head.audioAttack > BROW_LIFT_THRESHOLD) + _head.browAudioLift += sqrt(_head.audioAttack) / 1000.0; + + _head.browAudioLift *= .90; + + + // Render Eyebrows + glPushMatrix(); + glTranslatef(-_head.interBrowDistance / 2.0,0.4,0.45); + for(side = 0; side < 2; side++) { + glColor3fv(browColor); + glPushMatrix(); + 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(_head.interBrowDistance, 0, 0); + } + glPopMatrix(); + + + // Mouth + + glPushMatrix(); + glTranslatef(0,-0.35,0.75); + glColor3f(0,0,0); + 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(-_head.interPupilDistance/2.0,-0.68,0.7); + // Right Eye + glRotatef(-10, 1, 0, 0); + glColor3fv(eyeColor); + glPushMatrix(); + { + glTranslatef(_head.interPupilDistance/10.0, 0, 0.05); + glRotatef(20, 0, 0, 1); + glScalef(_head.eyeballScaleX, _head.eyeballScaleY, _head.eyeballScaleZ); + glutSolidSphere(0.25, 30, 30); + } + glPopMatrix(); + + // Right Pupil + if (_sphere == NULL) { + _sphere = gluNewQuadric(); + gluQuadricTexture(_sphere, GL_TRUE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gluQuadricOrientation(_sphere, GLU_OUTSIDE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iris_texture_width, iris_texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &iris_texture[0]); + } + + glPushMatrix(); + { + glRotatef(_head.eyeballPitch[1], 1, 0, 0); + glRotatef(_head.eyeballYaw[1] + _headYaw + _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, _head.pupilSize, 15, 15); + glDisable(GL_TEXTURE_2D); + } + + glPopMatrix(); + // Left Eye + glColor3fv(eyeColor); + glTranslatef(_head.interPupilDistance, 0, 0); + glPushMatrix(); + { + glTranslatef(-_head.interPupilDistance/10.0, 0, .05); + glRotatef(-20, 0, 0, 1); + glScalef(_head.eyeballScaleX, _head.eyeballScaleY, _head.eyeballScaleZ); + glutSolidSphere(0.25, 30, 30); + } + glPopMatrix(); + // Left Pupil + glPushMatrix(); + { + glRotatef(_head.eyeballPitch[0], 1, 0, 0); + glRotatef(_head.eyeballYaw[0] + _headYaw - _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, _head.pupilSize, 15, 15); + glDisable(GL_TEXTURE_2D); + } + + glPopMatrix(); + + + glPopMatrix(); + } + +void Avatar::startHandMovement() { + + if (!_usingBodySprings) { + initializeBodySprings(); + _usingBodySprings = true; + } +} + +void Avatar::stopHandMovement() { +//_usingBodySprings = false; +} + +void Avatar::setHandMovementValues( glm::vec3 handOffset ) { + _movedHandOffset = handOffset; +} + +AvatarMode Avatar::getMode() { + return _mode; +} + +void Avatar::initializeSkeleton() { + + for (int b=0; b 0.0f ) { + glm::vec3 springDirection = springVector / length; + + float force = ( length - _bone[b].length ) * _springForce * deltaTime; + + _bone[b].springyVelocity -= springDirection * force; + + if ( _bone[b].parent != AVATAR_BONE_NULL ) { + _bone[ _bone[b].parent ].springyVelocity += springDirection * force; + } + } + + _bone[b].springyVelocity += ( _bone[b].position - _bone[b].springyPosition ) * _bone[b].springBodyTightness * deltaTime; + + float decay = 1.0 - _springVelocityDecay * deltaTime; + + if ( decay > 0.0 ) { + _bone[b].springyVelocity *= decay; + } + else { + _bone[b].springyVelocity = glm::vec3( 0.0f, 0.0f, 0.0f ); + } + + _bone[b].springyPosition += _bone[b].springyVelocity; + } +} + +glm::vec3 Avatar::getHeadLookatDirection() { + return glm::vec3 + ( + _orientation.getFront().x, + _orientation.getFront().y, + _orientation.getFront().z + ); +} + +glm::vec3 Avatar::getHeadLookatDirectionUp() { + return glm::vec3 + ( + _orientation.getUp().x, + _orientation.getUp().y, + _orientation.getUp().z + ); +} + +glm::vec3 Avatar::getHeadLookatDirectionRight() { + return glm::vec3 + ( + _orientation.getRight().x, + _orientation.getRight().y, + _orientation.getRight().z + ); +} + +glm::vec3 Avatar::getHeadPosition() { + + if ( _usingBodySprings ) { + return _bone[ AVATAR_BONE_HEAD ].springyPosition; + } + + return _bone[ AVATAR_BONE_HEAD ].position; +} + + +glm::vec3 Avatar::getBonePosition( AvatarBoneID b ) { + return _bone[b].position; +} + + + +void Avatar::updateHandMovement( float deltaTime ) { + glm::vec3 transformedHandMovement; + + transformedHandMovement + = _orientation.getRight() * _movedHandOffset.x + + _orientation.getUp() * -_movedHandOffset.y * 0.5f + + _orientation.getFront() * -_movedHandOffset.y; + + _bone[ AVATAR_BONE_RIGHT_HAND ].position += transformedHandMovement; + + if (_isMine) { + _handState = _mousePressed; + } +} + + +void Avatar::updateArmIKAndConstraints( float deltaTime ) { + + // determine the arm vector + glm::vec3 armVector = _bone[ AVATAR_BONE_RIGHT_HAND ].position; + armVector -= _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; + + // test to see if right hand is being dragged beyond maximum arm length + float distance = glm::length( armVector ); + + // if right hand is being dragged beyond maximum arm length... + 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 * _maxArmLength; + distance = _maxArmLength; + glm::vec3 constrainedPosition = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; + constrainedPosition += armVector; + _bone[ AVATAR_BONE_RIGHT_HAND ].position = constrainedPosition; + } + + // set elbow position + glm::vec3 newElbowPosition = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; + newElbowPosition += armVector * ONE_HALF; + glm::vec3 perpendicular = glm::cross( _orientation.getFront(), armVector ); + newElbowPosition += perpendicular * ( 1.0f - ( _maxArmLength / distance ) ) * ONE_HALF; + _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position = newElbowPosition; + + // set wrist position + glm::vec3 vv( _bone[ AVATAR_BONE_RIGHT_HAND ].position ); + vv -= _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position; + glm::vec3 newWristPosition = _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position; + newWristPosition += vv * 0.7f; + _bone[ AVATAR_BONE_RIGHT_FOREARM ].position = newWristPosition; +} + + + + +void Avatar::renderBody() { + + // Render bone positions as spheres + for (int b=0; b( (double)TRANSMITTER_COUNT/(msecsElapsed/1000.0) ); + _transmitterTimer = now; + } + /* NOTE: PR: Will add back in when ready to animate avatar hand + + // Add rotational forces to the hand + const float ANG_VEL_SENSITIVITY = 4.0; + const float ANG_VEL_THRESHOLD = 0.0; + float angVelScale = ANG_VEL_SENSITIVITY*(1.0f/getTransmitterHz()); + + addAngularVelocity(fabs(gyrX*angVelScale)>ANG_VEL_THRESHOLD?gyrX*angVelScale:0, + fabs(gyrZ*angVelScale)>ANG_VEL_THRESHOLD?gyrZ*angVelScale:0, + fabs(-gyrY*angVelScale)>ANG_VEL_THRESHOLD?-gyrY*angVelScale:0); + + // Add linear forces to the hand + //const float LINEAR_VEL_SENSITIVITY = 50.0; + const float LINEAR_VEL_SENSITIVITY = 5.0; + float linVelScale = LINEAR_VEL_SENSITIVITY*(1.0f/getTransmitterHz()); + glm::vec3 linVel(linX*linVelScale, linZ*linVelScale, -linY*linVelScale); + addVelocity(linVel); + */ + +} + diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h new file mode 100644 index 0000000000..32d31184a8 --- /dev/null +++ b/interface/src/Avatar.h @@ -0,0 +1,268 @@ +// +// Avatar.h +// interface +// +// Created by Philip Rosedale on 9/11/12. +// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__avatar__ +#define __interface__avatar__ + +#include +#include + +#include "Field.h" +#include "world.h" + +#include "InterfaceConfig.h" +#include "SerialInterface.h" + +#include +#include +#include //looks like we might not need this + +const bool AVATAR_GRAVITY = true; +const float DECAY = 0.1; +const float THRUST_MAG = 10.0; +const float YAW_MAG = 300.0; +const float TEST_YAW_DECAY = 5.0; +const float LIN_VEL_DECAY = 5.0; + +const float COLLISION_BODY_RADIUS = 0.1; +const float COLLISION_HEIGHT = 1.5; + +enum eyeContactTargets {LEFT_EYE, RIGHT_EYE, MOUTH}; + +#define FWD 0 +#define BACK 1 +#define LEFT 2 +#define RIGHT 3 +#define UP 4 +#define DOWN 5 +#define ROT_LEFT 6 +#define ROT_RIGHT 7 +#define MAX_DRIVE_KEYS 8 + +#define MAX_OTHER_AVATARS 10 // temporary - for testing purposes! + +enum AvatarMode +{ + AVATAR_MODE_STANDING = 0, + AVATAR_MODE_WALKING, + AVATAR_MODE_INTERACTING, + NUM_AVATAR_MODES +}; + +enum AvatarBoneID +{ + AVATAR_BONE_NULL = -1, + AVATAR_BONE_PELVIS_SPINE, // connects pelvis joint with torso joint (not supposed to be rotated) + AVATAR_BONE_MID_SPINE, // connects torso joint with chest joint + AVATAR_BONE_CHEST_SPINE, // connects chest joint with neckBase joint (not supposed to be rotated) + AVATAR_BONE_NECK, // connects neckBase joint with headBase joint + AVATAR_BONE_HEAD, // connects headBase joint with headTop joint + AVATAR_BONE_LEFT_CHEST, // connects chest joint with left clavicle joint (not supposed to be rotated) + AVATAR_BONE_LEFT_SHOULDER, // connects left clavicle joint with left shoulder joint + AVATAR_BONE_LEFT_UPPER_ARM, // connects left shoulder joint with left elbow joint + AVATAR_BONE_LEFT_FOREARM, // connects left elbow joint with left wrist joint + AVATAR_BONE_LEFT_HAND, // connects left wrist joint with left fingertips joint + AVATAR_BONE_RIGHT_CHEST, // connects chest joint with right clavicle joint (not supposed to be rotated) + AVATAR_BONE_RIGHT_SHOULDER, // connects right clavicle joint with right shoulder joint + AVATAR_BONE_RIGHT_UPPER_ARM, // connects right shoulder joint with right elbow joint + AVATAR_BONE_RIGHT_FOREARM, // connects right elbow joint with right wrist joint + AVATAR_BONE_RIGHT_HAND, // connects right wrist joint with right fingertips joint + AVATAR_BONE_LEFT_PELVIS, // connects pelvis joint with left hip joint (not supposed to be rotated) + AVATAR_BONE_LEFT_THIGH, // connects left hip joint with left knee joint + AVATAR_BONE_LEFT_SHIN, // connects left knee joint with left heel joint + AVATAR_BONE_LEFT_FOOT, // connects left heel joint with left toes joint + AVATAR_BONE_RIGHT_PELVIS, // connects pelvis joint with right hip joint (not supposed to be rotated) + AVATAR_BONE_RIGHT_THIGH, // connects right hip joint with right knee joint + AVATAR_BONE_RIGHT_SHIN, // connects right knee joint with right heel joint + AVATAR_BONE_RIGHT_FOOT, // connects right heel joint with right toes joint + + NUM_AVATAR_BONES +}; + +struct AvatarCollisionElipsoid +{ + bool colliding; + glm::vec3 position; + float girth; + float height; + glm::vec3 upVector; +}; + +struct AvatarHandHolding +{ + glm::vec3 position; + glm::vec3 velocity; + float force; +}; + +struct AvatarBone +{ + AvatarBoneID parent; // which bone is this bone connected to? + glm::vec3 position; // the position at the "end" of the bone + glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" + glm::vec3 springyPosition; // used for special effects (a 'flexible' variant of position) + glm::dvec3 springyVelocity; // used for special effects ( the velocity of the springy position) + float springBodyTightness; // how tightly the springy position tries to stay on the position + glm::quat rotation; // this will eventually replace yaw, pitch and roll (and maybe orientation) + float yaw; // the yaw Euler angle of the bone rotation off the parent + float pitch; // the pitch Euler angle of the bone rotation off the parent + float roll; // the roll Euler angle of the bone rotation off the parent + Orientation orientation; // three orthogonal normals determined by yaw, pitch, roll + float length; // the length of the bone + float radius; // used for detecting collisions for certain physical effects +}; + +struct AvatarHead +{ + float pitchRate; + float yawRate; + float rollRate; + float noise; + float eyeballPitch[2]; + float eyeballYaw [2]; + float eyebrowPitch[2]; + float eyebrowRoll [2]; + float eyeballScaleX; + float eyeballScaleY; + float eyeballScaleZ; + float interPupilDistance; + float interBrowDistance; + float nominalPupilSize; + float pupilSize; + float mouthPitch; + float mouthYaw; + float mouthWidth; + float mouthHeight; + float leanForward; + float leanSideways; + float pitchTarget; + float yawTarget; + float noiseEnvelope; + float pupilConverge; + float scale; + int eyeContact; + float browAudioLift; + eyeContactTargets eyeContactTarget; + + // Sound loudness information + float lastLoudness; + float averageLoudness; + float audioAttack; +}; + + +class Avatar : public AvatarData { + public: + Avatar(bool isMine); + ~Avatar(); + Avatar(const Avatar &otherAvatar); + Avatar* clone() const; + + void reset(); + void UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity); + void setNoise (float mag) { _head.noise = mag; } + void setScale(float s) {_head.scale = s; }; + void setRenderYaw(float y) {_renderYaw = y;} + void setRenderPitch(float p) {_renderPitch = p;} + float getRenderYaw() {return _renderYaw;} + float getRenderPitch() {return _renderPitch;} + void setLeanForward(float dist); + void setLeanSideways(float dist); + void addLean(float x, float z); + float getLastMeasuredHeadYaw() const {return _head.yawRate;} + float getBodyYaw() {return _bodyYaw;}; + void addBodyYaw(float y) {_bodyYaw += y;}; + + glm::vec3 getHeadLookatDirection(); + glm::vec3 getHeadLookatDirectionUp(); + glm::vec3 getHeadLookatDirectionRight(); + glm::vec3 getHeadPosition(); + glm::vec3 getBonePosition( AvatarBoneID b ); + glm::vec3 getBodyUpDirection(); + float getGirth(); + float getHeight(); + + AvatarMode getMode(); + + void setMousePressed( bool pressed ); + void render(bool lookingInMirror); + void renderBody(); + void renderHead(bool lookingInMirror); + void simulate(float); + void startHandMovement(); + void stopHandMovement(); + void setHandMovementValues( glm::vec3 movement ); + void updateHandMovement( float deltaTime ); + void updateArmIKAndConstraints( float deltaTime ); + + float getAverageLoudness() {return _head.averageLoudness;}; + void setAverageLoudness(float al) {_head.averageLoudness = al;}; + + void SetNewHeadTarget(float, float); + + // Set what driving keys are being pressed to control thrust levels + void setDriveKeys(int key, bool val) { _driveKeys[key] = val; }; + bool getDriveKeys(int key) { return _driveKeys[key]; }; + + // Set/Get update the thrust that will move the avatar around + void setThrust(glm::vec3 newThrust) { _thrust = newThrust; }; + void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; + glm::vec3 getThrust() { return _thrust; }; + + // Related to getting transmitter UDP data used to animate the avatar hand + void processTransmitterData(unsigned char * packetData, int numBytes); + float getTransmitterHz() { return _transmitterHz; }; + + private: + AvatarHead _head; + bool _isMine; + glm::vec3 _TEST_bigSpherePosition; + float _TEST_bigSphereRadius; + bool _mousePressed; + float _bodyYawDelta; + bool _usingBodySprings; + glm::vec3 _movedHandOffset; + float _springVelocityDecay; + float _springForce; + glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion + AvatarBone _bone[ NUM_AVATAR_BONES ]; + AvatarMode _mode; + AvatarHandHolding _handHolding; + glm::dvec3 _velocity; + glm::vec3 _thrust; + float _maxArmLength; + Orientation _orientation; + int _driveKeys[MAX_DRIVE_KEYS]; + GLUquadric* _sphere; + float _renderYaw; + float _renderPitch; // Pitch from view frustum when this is own head + timeval _transmitterTimer; + float _transmitterHz; + int _transmitterPackets; + Avatar* _interactingOther; + bool _interactingOtherIsNearby; + + // private methods... + void initializeSkeleton(); + void updateSkeleton(); + void initializeBodySprings(); + void updateBodySprings( float deltaTime ); + void calculateBoneLengths(); + void readSensors(); + void renderBoneAsBlock( AvatarBoneID b ); + void updateAvatarCollisionDetectionAndResponse + ( + glm::vec3 collisionPosition, + float collisionGirth, + float collisionHeight, + glm::vec3 collisionUpVector, + float deltaTime + ); +}; + +#endif