diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index fceedc6678..52631a3c25 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 (memchr(SOLO_AGENT_TYPES_STRING, agent->getType(), 1) == NULL) { + if (memchr(SOLO_AGENT_TYPES, agent->getType(), sizeof(SOLO_AGENT_TYPES)) == NULL) { // this is an agent of which there can be multiple, just add them to the packet // don't send avatar agents to other avatars, that will come from avatar mixer if (agentType != AGENT_TYPE_AVATAR || agent->getType() != AGENT_TYPE_AVATAR) { diff --git a/eve/src/main.cpp b/eve/src/main.cpp index 1478f3d1b2..3e075f7ba0 100644 --- a/eve/src/main.cpp +++ b/eve/src/main.cpp @@ -13,20 +13,31 @@ #include #include #include +#include -const int EVE_AGENT_LIST_PORT = 55441; -const float DATA_SEND_INTERVAL_MSECS = 10; +const int EVE_AGENT_LISTEN_PORT = 55441; + +const float RANDOM_POSITION_MAX_DIMENSION = 5.0f; + +const float DATA_SEND_INTERVAL_MSECS = 15; +const float MIN_AUDIO_SEND_INTERVAL_SECS = 10; +const int MIN_ITERATIONS_BETWEEN_AUDIO_SENDS = (MIN_AUDIO_SEND_INTERVAL_SECS * 1000) / DATA_SEND_INTERVAL_MSECS; +const int MAX_AUDIO_SEND_INTERVAL_SECS = 15; +const float MAX_ITERATIONS_BETWEEN_AUDIO_SENDS = (MAX_AUDIO_SEND_INTERVAL_SECS * 1000) / DATA_SEND_INTERVAL_MSECS; bool stopReceiveAgentDataThread; +bool injectAudioThreadRunning = false; -void *receiveAgentData(void *args) -{ +int TEMP_AUDIO_LISTEN_PORT = 55439; +// UDPSocket audioSocket(TEMP_AUDIO_LISTEN_PORT); + +void *receiveAgentData(void *args) { sockaddr senderAddress; ssize_t bytesReceived; unsigned char incomingPacket[MAX_PACKET_SIZE]; - AgentList *agentList = AgentList::getInstance(); - Agent *avatarMixer = NULL; + AgentList* agentList = AgentList::getInstance(); + Agent* avatarMixer = NULL; while (!::stopReceiveAgentDataThread) { if (agentList->getAgentSocket().receive(&senderAddress, incomingPacket, &bytesReceived)) { @@ -54,9 +65,35 @@ void *receiveAgentData(void *args) return NULL; } -int main(int argc, char* argv[]) { +void *injectAudio(void *args) { + ::injectAudioThreadRunning = true; + + AudioInjector* eveAudioInjector = (AudioInjector *)args; + + // look for an audio mixer in our agent list + Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); + + if (audioMixer != NULL) { + // until the audio mixer is setup for ping-reply, activate the public socket if it's not active + if (audioMixer->getActiveSocket() == NULL) { + audioMixer->activatePublicSocket(); + } + + // we have an active audio mixer we can send data to +// eveAudioInjector->injectAudio(&::audioSocket, audioMixer->getActiveSocket()); + } + + ::injectAudioThreadRunning = false; + pthread_exit(0); + return NULL; +} + +int main(int argc, const char* argv[]) { + // new seed for random audio sleep times + srand(time(0)); + // create an AgentList instance to handle communication with other agents - AgentList *agentList = AgentList::createInstance(AGENT_TYPE_AVATAR, EVE_AGENT_LIST_PORT); + AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AVATAR, EVE_AGENT_LISTEN_PORT); // start telling the domain server that we are alive agentList->startDomainServerCheckInThread(); @@ -74,15 +111,22 @@ int main(int argc, char* argv[]) { AvatarData eve = AvatarData(); // move eve away from the origin - eve.setBodyPosition(glm::vec3(3, 0, -3)); + // pick a random point inside a 10x10 grid - // turn her back towards the origin - eve.setBodyYaw(-45); + eve.setPosition(glm::vec3(randFloatInRange(-RANDOM_POSITION_MAX_DIMENSION, RANDOM_POSITION_MAX_DIMENSION), + 0, + randFloatInRange(-RANDOM_POSITION_MAX_DIMENSION, RANDOM_POSITION_MAX_DIMENSION))); + + // face any instance of eve down the z-axis + eve.setBodyYaw(0); // put her hand out so somebody can shake it - eve.setHandPosition(glm::vec3(eve.getBodyPosition()[0] - 0.2, + eve.setHandPosition(glm::vec3(eve.getPosition()[0] - 0.2, 0.25, - eve.getBodyPosition()[2] + 0.1)); + eve.getPosition()[2] + 0.1)); + + // read eve's audio data + AudioInjector eveAudioInjector("eve.raw"); unsigned char broadcastPacket[MAX_PACKET_SIZE]; broadcastPacket[0] = PACKET_HEADER_HEAD_DATA; @@ -92,6 +136,9 @@ int main(int argc, char* argv[]) { timeval thisSend; double numMicrosecondsSleep = 0; +// int numIterationsLeftBeforeAudioSend = 0; +// pthread_t injectAudioThread; + while (true) { // update the thisSend timeval to the current time gettimeofday(&thisSend, NULL); @@ -104,10 +151,21 @@ int main(int argc, char* argv[]) { // use the getBroadcastData method in the AvatarData class to populate the broadcastPacket buffer numBytesToSend = eve.getBroadcastData((broadcastPacket + 1)); - // use the UDPSocket instance attached to our agent list to send avatar data to mixer agentList->getAgentSocket().send(avatarMixer->getActiveSocket(), broadcastPacket, numBytesToSend); } + + // temporarily disable Eve's audio sending until the file is actually available on EC2 box +// if (numIterationsLeftBeforeAudioSend == 0) { +// if (!::injectAudioThreadRunning) { +// pthread_create(&injectAudioThread, NULL, injectAudio, (void*) &eveAudioInjector); +// +// numIterationsLeftBeforeAudioSend = randIntInRange(MIN_ITERATIONS_BETWEEN_AUDIO_SENDS, +// MAX_ITERATIONS_BETWEEN_AUDIO_SENDS); +// } +// } else { +// numIterationsLeftBeforeAudioSend--; +// } // 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) { diff --git a/injector/CMakeLists.txt b/injector/CMakeLists.txt index 6e3e61326c..6bea5b51d3 100644 --- a/injector/CMakeLists.txt +++ b/injector/CMakeLists.txt @@ -14,4 +14,4 @@ link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) # link the threads library find_package(Threads REQUIRED) -target_link_libraries(injector ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) \ No newline at end of file diff --git a/injector/src/injector.cpp b/injector/src/main.cpp similarity index 53% rename from injector/src/injector.cpp rename to injector/src/main.cpp index 3f6bb7f689..61327ec41b 100644 --- a/injector/src/injector.cpp +++ b/injector/src/main.cpp @@ -1,5 +1,5 @@ // -// injector.cpp +// main.cpp // Audio Injector // // Created by Leonardo Murillo on 3/5/13. @@ -11,39 +11,27 @@ #include #include #include -#include -#include -#include #include #include #include -#include "UDPSocket.h" -#include "UDPSocket.cpp" + + #include #include - +#include +#include char EC2_WEST_AUDIO_SERVER[] = "54.241.92.53"; const int AUDIO_UDP_LISTEN_PORT = 55443; -const int BUFFER_LENGTH_BYTES = 512; -const int BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t); -const float SAMPLE_RATE = 22050.0; -const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES / SAMPLE_RATE) * 1000000; // Command line parameter defaults bool loopAudio = true; float sleepIntervalMin = 1.00; float sleepIntervalMax = 2.00; -float positionInUniverse[] = {0, 0, 0, 0}; -unsigned char attenuationModifier = 255; -char *sourceAudioFile; +char *sourceAudioFile = NULL; const char *allowedParameters = ":rb::t::c::a::f:"; - -char *charBuffer; -int16_t *buffer; -long length; - -UDPSocket *streamSocket; +float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f}; +unsigned char attenuationModifier = 255; void usage(void) { @@ -62,19 +50,19 @@ bool processParameters(int parameterCount, char* parameterData[]) while ((p = getopt(parameterCount, parameterData, allowedParameters)) != -1) { switch (p) { case 'r': - loopAudio = false; + ::loopAudio = false; std::cout << "[DEBUG] Random sleep mode enabled" << std::endl; break; case 'b': - sleepIntervalMin = atof(optarg); + ::sleepIntervalMin = atof(optarg); std::cout << "[DEBUG] Min delay between plays " << sleepIntervalMin << "sec" << std::endl; break; case 't': - sleepIntervalMax = atof(optarg); + ::sleepIntervalMax = atof(optarg); std::cout << "[DEBUG] Max delay between plays " << sleepIntervalMax << "sec" << std::endl; break; case 'f': - sourceAudioFile = optarg; + ::sourceAudioFile = optarg; std::cout << "[DEBUG] Opening file: " << sourceAudioFile << std::endl; break; case 'c': @@ -84,7 +72,7 @@ bool processParameters(int parameterCount, char* parameterData[]) int i = 0; while (std::getline(ss, token, ',')) { - positionInUniverse[i] = atof(token.c_str()); + ::floatArguments[i] = atof(token.c_str()); ++i; if (i == 4) { break; @@ -94,7 +82,7 @@ bool processParameters(int parameterCount, char* parameterData[]) break; } case 'a': - attenuationModifier = atoi(optarg); + ::attenuationModifier = atoi(optarg); std::cout << "[DEBUG] Attenuation modifier: " << optarg << std::endl; break; default: @@ -103,79 +91,44 @@ bool processParameters(int parameterCount, char* parameterData[]) } } return true; -}; +};_Position -void loadFile(void) { - std::fstream sourceFile; - sourceFile.open(sourceAudioFile, std::ios::in | std::ios::binary); - sourceFile.seekg(0, std::ios::end); - length = sourceFile.tellg(); - sourceFile.seekg(0, std::ios::beg); - long sizeOfShortArray = length / 2; - buffer = new int16_t[sizeOfShortArray]; - sourceFile.read((char *)buffer, length); -} - -void stream(void) -{ - timeval startTime; - - int leadingBytes = 1 + (sizeof(float) * 4); - unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes]; - - dataPacket[0] = PACKET_HEADER_INJECT_AUDIO; - unsigned char *currentPacketPtr = dataPacket + 1; - - for (int p = 0; p < 4; p++) { - memcpy(currentPacketPtr, &positionInUniverse[p], sizeof(float)); - currentPacketPtr += sizeof(float); - } - - *currentPacketPtr = attenuationModifier; - currentPacketPtr++; - - for (int i = 0; i < length; i += BUFFER_LENGTH_SAMPLES) { - gettimeofday(&startTime, NULL); - memcpy(currentPacketPtr, &buffer[i], BUFFER_LENGTH_BYTES); - streamSocket->send(EC2_WEST_AUDIO_SERVER, AUDIO_UDP_LISTEN_PORT, dataPacket, sizeof(dataPacket)); - double usecToSleep = usecTimestamp(&startTime) + BUFFER_SEND_INTERVAL_USECS - usecTimestampNow(); - usleep(usecToSleep); - } -}; - -int main(int argc, char* argv[]) -{ +int main(int argc, const char* argv[]) { srand(time(0)); int AUDIO_UDP_SEND_PORT = 1500 + (rand() % (int)(1500 - 2000 + 1)); - streamSocket = new UDPSocket(AUDIO_UDP_SEND_PORT); + UDPSocket streamSocket(AUDIO_UDP_SEND_PORT); - if (processParameters(argc, argv)) { - if (sourceAudioFile) { - loadFile(); - } else { + sockaddr_in mixerSocket; + mixerSocket.sin_family = AF_INET; + mixerSocket.sin_addr.s_addr = inet_addr(EC2_WEST_AUDIO_SERVER); + mixerSocket.sin_port = htons((uint16_t)AUDIO_UDP_LISTEN_PORT); + + if (processParameters(argc, argv)) { + if (::sourceAudioFile == NULL) { std::cout << "[FATAL] Source audio file not specified" << std::endl; exit(-1); - } - - for (int i = 0; i < sizeof(positionInUniverse)/sizeof(positionInUniverse[0]); ++i) { - std::cout << "Position " << positionInUniverse[i] << std::endl; - } - - float delay; - int usecDelay; - while (true) { - stream(); + } else { + AudioInjector injector(sourceAudioFile); - if (loopAudio) { - delay = 0; - } else { - delay = randFloatInRange(sleepIntervalMin, sleepIntervalMax); + injector.setPosition(::floatArguments); + injector.setBearing(*(::floatArguments + 3)); + injector.setAttenuationModifier(::attenuationModifier); + + float delay = 0; + int usecDelay = 0; + + while (true) { + injector.injectAudio(&streamSocket, (sockaddr*) &mixerSocket); + + if (!::loopAudio) { + delay = randFloatInRange(::sleepIntervalMin, ::sleepIntervalMax); + usecDelay = delay * 1000 * 1000; + usleep(usecDelay); + } } - usecDelay = delay * 1000 * 1000; - usleep(usecDelay); - } + } } return 0; } diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 4e8c249f16..9dbfdbf07f 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->getBodyPosition()[p], sizeof(float)); + memcpy(currentPacketPtr, &data->linkedHead->getPosition()[p], sizeof(float)); currentPacketPtr += sizeof(float); } @@ -250,8 +250,16 @@ int audioCallback (const void *inputBuffer, } // play whatever we have in the audio buffer + // // if we haven't fired off the flange effect, check if we should - int lastYawMeasured = fabsf(data->linkedHead->getLastMeasuredYaw()); + // + + // + // NOTE: PER - LastMeasuredHeadYaw is now relative to body position, represents the local + // rotation of the head relative to body, this may effect flange effect! + // + // + int lastYawMeasured = fabsf(data->linkedHead->getLastMeasuredHeadYaw()); if (!samplesLeftForFlange && lastYawMeasured > MIN_FLANGE_EFFECT_THRESHOLD) { // we should flange for one second diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index d1bbf5e65b..de6ce91bbd 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -35,8 +35,6 @@ float browThickness = 0.16; bool usingBigSphereCollisionTest = true; - - char iris_texture_file[] = "resources/images/green_eye.png"; vector iris_texture; @@ -50,7 +48,7 @@ Head::Head(bool isMine) { _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; + _nearOtherAvatar = false; _bodyYaw = -90.0; _bodyPitch = 0.0; _bodyRoll = 0.0; @@ -62,7 +60,7 @@ Head::Head(bool isMine) { //_transmitterTimer = 0; _transmitterHz = 0.0; _transmitterPackets = 0; - _numOtherAvatarsInView = 0; + //_numOtherAvatars = 0; initializeSkeleton(); @@ -75,9 +73,9 @@ Head::Head(bool isMine) { _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.yaw = 0.0; + //_head.pitch = 0.0; + //_head.roll = 0.0; _head.pitchRate = 0.0; _head.yawRate = 0.0; _head.rollRate = 0.0; @@ -106,7 +104,6 @@ Head::Head(bool isMine) { _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; @@ -120,7 +117,11 @@ Head::Head(bool isMine) { _renderPitch = 0.0; _sphere = NULL; - + + _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); @@ -128,23 +129,19 @@ Head::Head(bool isMine) { printLog("error %u: %s\n", error, lodepng_error_text(error)); } } - - //-------------------------------------------------- - // test... just slam them into random positions... - //-------------------------------------------------- - _otherAvatarHandPosition[ 0 ] = glm::vec3( 0.0f, 0.3f, 2.0f ); - _otherAvatarHandPosition[ 1 ] = glm::vec3( 4.0f, 0.3f, 2.0f ); - _otherAvatarHandPosition[ 2 ] = glm::vec3( 2.0f, 0.3f, 2.0f ); - _otherAvatarHandPosition[ 3 ] = glm::vec3( 1.0f, 0.3f, -4.0f ); - _otherAvatarHandPosition[ 4 ] = glm::vec3( -2.0f, 0.3f, -2.0f ); + + _otherAvatar.handPosition = glm::vec3( 0.0f, 0.0f, 0.0f ); + _otherAvatar.handState = 0; } + + Head::Head(const Head &otherAvatar) { _velocity = otherAvatar._velocity; _thrust = otherAvatar._thrust; _rotation = otherAvatar._rotation; - _closestOtherAvatar = otherAvatar._closestOtherAvatar; + _nearOtherAvatar = otherAvatar._nearOtherAvatar; _bodyYaw = otherAvatar._bodyYaw; _bodyPitch = otherAvatar._bodyPitch; _bodyRoll = otherAvatar._bodyRoll; @@ -176,9 +173,9 @@ Head::Head(const Head &otherAvatar) { _head.interPupilDistance = otherAvatar._head.interPupilDistance; _head.interBrowDistance = otherAvatar._head.interBrowDistance; _head.nominalPupilSize = otherAvatar._head.nominalPupilSize; - _head.yaw = otherAvatar._head.yaw; - _head.pitch = otherAvatar._head.pitch; - _head.roll = otherAvatar._head.roll; + //_head.yaw = otherAvatar._head.yaw; + //_head.pitch = otherAvatar._head.pitch; + //_head.roll = otherAvatar._head.roll; _head.yawRate = otherAvatar._head.yawRate; _head.pitchRate = otherAvatar._head.pitchRate; _head.rollRate = otherAvatar._head.rollRate; @@ -207,7 +204,6 @@ Head::Head(const Head &otherAvatar) { _head.eyeContactTarget = otherAvatar._head.eyeContactTarget; _head.scale = otherAvatar._head.scale; _head.audioAttack = otherAvatar._head.audioAttack; - _head.loudness = otherAvatar._head.loudness; _head.averageLoudness = otherAvatar._head.averageLoudness; _head.lastLoudness = otherAvatar._head.lastLoudness; _head.browAudioLift = otherAvatar._head.browAudioLift; @@ -234,14 +230,14 @@ Head* Head::clone() const { } void Head::reset() { - _head.pitch = _head.yaw = _head.roll = 0; + _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, int head_mirror, glm::vec3 * gravity) +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; @@ -269,20 +265,15 @@ void Head::UpdateGyros(float frametime, SerialInterface * serialInterface, int h const float MAX_YAW = 85; const float MIN_YAW = -85; - if ((_head.pitch < MAX_PITCH) && (_head.pitch > MIN_PITCH)) - addPitch(measured_pitch_rate * -HEAD_ROTATION_SCALE * frametime); + if ((_headPitch < MAX_PITCH) && (_headPitch > MIN_PITCH)) + addHeadPitch(measured_pitch_rate * -HEAD_ROTATION_SCALE * frametime); - addRoll(-measured_roll_rate * HEAD_ROLL_SCALE * frametime); + addHeadRoll(measured_roll_rate * HEAD_ROLL_SCALE * frametime); - if (head_mirror) { - 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 ((_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); - } + 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) { @@ -304,7 +295,6 @@ void Head::setMousePressed( bool d ) { _mousePressed = d; } - void Head::simulate(float deltaTime) { //------------------------------------------------------------- @@ -313,15 +303,12 @@ void Head::simulate(float deltaTime) { //------------------------------------------------------------- if ( _isMine ) { - //------------------------------------- - // DEBUG - other avatars... - //------------------------------------- - _closestOtherAvatar = -1; + _nearOtherAvatar = false; float closestDistance = 10000.0f; AgentList * agentList = AgentList::getInstance(); - _numOtherAvatarsInView =0; + //_numOtherAvatars = 0; for(std::vector::iterator agent = agentList->getAgents().begin(); agent != agentList->getAgents().end(); @@ -329,63 +316,63 @@ void Head::simulate(float deltaTime) { if (( agent->getLinkedData() != NULL && ( agent->getType() == AGENT_TYPE_AVATAR ) )) { Head *otherAvatar = (Head *)agent->getLinkedData(); - if ( _numOtherAvatarsInView < MAX_OTHER_AVATARS ) { + // if ( _numOtherAvatars < MAX_OTHER_AVATARS ) + { - //----------------------------------------------------------- - // test other avatar hand position for proximity... - //----------------------------------------------------------- - _otherAvatarHandPosition[ _numOtherAvatarsInView ] = otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); + //------------------------------------------------------ + // 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 -= _otherAvatarHandPosition[ _numOtherAvatarsInView ]; + v -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); float distance = glm::length( v ); if ( distance < _maxArmLength ) { if ( distance < closestDistance ) { closestDistance = distance; - _closestOtherAvatar = _numOtherAvatarsInView; - _numOtherAvatarsInView++; + _nearOtherAvatar = true; + _otherAvatar.handPosition = otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); + _otherAvatar.handState = (int)otherAvatar->getHandState(); } } } } } - /* - ///for testing only (prior to having real avs working) - for (int o=0; o _bone[ AVATAR_BONE_RIGHT_FOOT ].radius * 2.0 ) { + 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 ( _bodyPosition.y < _bone[ AVATAR_BONE_RIGHT_FOOT ].radius ) { - _bodyPosition.y = _bone[ AVATAR_BONE_RIGHT_FOOT ].radius; + if ( _position.y < _bone[ AVATAR_BONE_RIGHT_FOOT ].radius ) { + _position.y = _bone[ AVATAR_BONE_RIGHT_FOOT ].radius; _velocity.y = 0.0; } } @@ -400,7 +387,7 @@ void Head::simulate(float deltaTime) { // reset hand and arm positions according to hand movement //------------------------------------------------------------ if (_usingBodySprings) { - updateHandMovement(); + updateHandMovement( deltaTime ); updateBodySprings( deltaTime ); } @@ -462,10 +449,6 @@ void Head::simulate(float deltaTime) { _bodyYaw += _bodyYawDelta * deltaTime; } - // 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; //---------------------------------------------------------- // decay body yaw delta @@ -480,28 +463,37 @@ void Head::simulate(float deltaTime) { //---------------------------------------------------------- // update position by velocity //---------------------------------------------------------- - _bodyPosition += (glm::vec3)_velocity * deltaTime; + _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 - _head.pitch *= (1.0f - DECAY*2*deltaTime); - _head.yaw *= (1.0f - DECAY*2*deltaTime); - _head.roll *= (1.0f - DECAY*2*deltaTime); + _headPitch *= (1.0f - DECAY * 2 * deltaTime); + _headYaw *= (1.0f - DECAY * 2 * deltaTime); + _headRoll *= (1.0f - DECAY * 2 * deltaTime); } else { // Move toward new target - _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); + _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.f*deltaTime); - _head.leanSideways *= (1.f - DECAY*30.f*deltaTime); + _head.leanForward *= (1.f - DECAY * 30 * deltaTime); + _head.leanSideways *= (1.f - DECAY * 30 * deltaTime); // Update where the avatar's eyes are // @@ -511,8 +503,8 @@ void Head::simulate(float deltaTime) { _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; + _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); @@ -539,63 +531,75 @@ void Head::simulate(float deltaTime) { 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] = -_head.pitch + eye_target_pitch_adjust; - _head.eyeballYaw[0] = _head.eyeballYaw[1] = -_head.yaw + eye_target_yaw_adjust; + _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) { - _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; + _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.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 - _head.pitch) < 1.0) && (fabs(_head.yawTarget - _head.yaw) < 1.0)) { - SetNewHeadTarget((randFloat()-0.5)*20.0, (randFloat()-0.5)*45.0); + 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; + _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; + _head.eyebrowRoll [1] *=-1; } } } + +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::updateBigSphereCollisionTest( float deltaTime ) { +void Head::updateAvatarCollisionDetectionAndResponse +( glm::vec3 collisionPosition, float collisionGirth, float collisionHeight, glm::vec3 collisionUpVector, float deltaTime ) { float myBodyApproximateBoundingRadius = 1.0f; - glm::vec3 vectorFromMyBodyToBigSphere(_bodyPosition - _TEST_bigSpherePosition); + glm::vec3 vectorFromMyBodyToBigSphere(_position - collisionPosition); bool jointCollision = false; float distanceToBigSphere = glm::length(vectorFromMyBodyToBigSphere); - if ( distanceToBigSphere < myBodyApproximateBoundingRadius + _TEST_bigSphereRadius) + if ( distanceToBigSphere < myBodyApproximateBoundingRadius + collisionGirth ) { for (int b=0; b BROW_LIFT_THRESHOLD) - _head.browAudioLift += sqrt(_head.audioAttack)/1000.0; + _head.browAudioLift += sqrt(_head.audioAttack) / 1000.0; _head.browAudioLift *= .90; glPushMatrix(); - glTranslatef(-_head.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(); @@ -809,7 +805,7 @@ void Head::renderHead(int faceToFace) { glPushMatrix(); { glRotatef(_head.eyeballPitch[1], 1, 0, 0); - glRotatef(_head.eyeballYaw[1] + _head.yaw + _head.pupilConverge, 0, 1, 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); @@ -835,7 +831,7 @@ void Head::renderHead(int faceToFace) { glPushMatrix(); { glRotatef(_head.eyeballPitch[0], 1, 0, 0); - glRotatef(_head.eyeballYaw[0] + _head.yaw - _head.pupilConverge, 0, 1, 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); @@ -979,9 +975,6 @@ void Head::initializeSkeleton() { updateSkeleton(); } - - - void Head::calculateBoneLengths() { for (int b=0; boctalCode) * (0.5 * TREE_SCALE); - glm::vec3 viewerPosition = viewerHead->getBodyPosition(); + glm::vec3 viewerPosition = viewerHead->getPosition(); // debug LOD code glm::vec3 debugNodePosition; diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 66d3996e51..b836908350 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -96,8 +96,6 @@ int packetsPerSecond = 0; int bytesPerSecond = 0; int bytesCount = 0; -int headMirror = 1; // Whether to mirror own head when viewing it - int WIDTH = 1200; // Window size int HEIGHT = 800; int fullscreen = 0; @@ -163,7 +161,7 @@ int noiseOn = 0; // Whether to add random noise float noise = 1.0; // Overall magnitude scaling for random noise levels int displayLevels = 0; -int displayHead = 0; +bool lookingInMirror = 0; // Are we currently rendering one's own head as if in mirror? int displayField = 0; int displayHeadMouse = 1; // Display sample mouse pointer controlled by head movement @@ -306,7 +304,7 @@ void displayStats(void) char legend2[] = "* - toggle stars, & - toggle paint mode, '-' - send erase all, '%' - send add scene"; drawtext(10, statsVerticalOffset + 32, 0.10f, 0, 1.0, 0, legend2); - glm::vec3 avatarPos = myAvatar.getBodyPosition(); + glm::vec3 avatarPos = myAvatar.getPosition(); char stats[200]; sprintf(stats, "FPS = %3.0f Pkts/s = %d Bytes/s = %d Head(x,y,z)= %4.2f, %4.2f, %4.2f ", @@ -398,8 +396,8 @@ void init(void) if (noiseOn) { myAvatar.setNoise(noise); } - myAvatar.setBodyPosition(start_location); - myCamera.setPosition( start_location ); + myAvatar.setPosition(start_location); + myCamera.setPosition(start_location); #ifdef MARKER_CAPTURE @@ -440,7 +438,7 @@ void reset_sensors() renderYawRate = 0; renderPitchRate = 0; - myAvatar.setBodyPosition(start_location); + myAvatar.setPosition(start_location); headMouseX = WIDTH/2; headMouseY = HEIGHT/2; @@ -459,7 +457,7 @@ void updateAvatar(float frametime) float gyroPitchRate = serialPort.getRelativeValue(HEAD_PITCH_RATE); float gyroYawRate = serialPort.getRelativeValue(HEAD_YAW_RATE ); - myAvatar.UpdateGyros(frametime, &serialPort, headMirror, &gravity); + myAvatar.UpdateGyros(frametime, &serialPort, &gravity); // // Update gyro-based mouse (X,Y on screen) @@ -553,7 +551,7 @@ void updateAvatar(float frametime) // If I'm in paint mode, send a voxel out to VOXEL server agents. if (::paintOn) { - glm::vec3 avatarPos = myAvatar.getBodyPosition(); + glm::vec3 avatarPos = myAvatar.getPosition(); // For some reason, we don't want to flip X and Z here. ::paintingVoxel.x = avatarPos.x/10.0; @@ -819,7 +817,7 @@ void display(void) //-------------------------------------------------------- // camera settings //-------------------------------------------------------- - if ( displayHead ) { + if ( ::lookingInMirror ) { //----------------------------------------------- // set the camera to looking at my own face //----------------------------------------------- @@ -835,7 +833,7 @@ void display(void) //---------------------------------------------------- // set the camera to third-person view behind my av //---------------------------------------------------- - myCamera.setTargetPosition ( myAvatar.getBodyPosition() ); + myCamera.setTargetPosition ( myAvatar.getPosition() ); myCamera.setYaw ( 180.0 - myAvatar.getBodyYaw() ); myCamera.setPitch ( 0.0 ); // temporarily, this must be 0.0 or else bad juju myCamera.setRoll ( 0.0 ); @@ -913,7 +911,7 @@ void display(void) drawGroundPlaneGrid( 5.0f, 9 ); // Draw cloud of dots - if (!displayHead) cloud.render(); + if (!::lookingInMirror) cloud.render(); // Draw voxels if ( showingVoxels ) @@ -935,16 +933,16 @@ void display(void) } } - if ( !displayHead ) balls.render(); + if ( !::lookingInMirror ) balls.render(); // Render the world box - if (!displayHead && statsOn) render_world_box(); + if (!::lookingInMirror && statsOn) render_world_box(); // brad's frustum for debugging if (::frustumOn) renderViewFrustum(::viewFrustum); //Render my own avatar - myAvatar.render(true); + myAvatar.render(::lookingInMirror); } glPopMatrix(); @@ -962,7 +960,7 @@ void display(void) if (audioScope.getState()) audioScope.render(); #endif - if (displayHeadMouse && !displayHead && statsOn) { + if (displayHeadMouse && !::lookingInMirror && statsOn) { // Display small target box at center or head mouse target that can also be used to measure LOD glColor3f(1.0, 1.0, 1.0); glDisable(GL_LINE_SMOOTH); @@ -1058,7 +1056,7 @@ int setValue(int state, bool *value) { } int setHead(int state) { - return setValue(state, &displayHead); + return setValue(state, &::lookingInMirror); } int setField(int state) { @@ -1091,10 +1089,6 @@ int setMenu(int state) { return setValue(state, &::menuOn); } -int setMirror(int state) { - return setValue(state, &headMirror); -} - int setDisplayFrustum(int state) { return setValue(state, &::frustumOn); } @@ -1200,10 +1194,9 @@ void initMenu() { MenuColumn *menuColumnOptions, *menuColumnTools, *menuColumnDebug, *menuColumnFrustum; // Options menuColumnOptions = menu.addColumn("Options"); - menuColumnOptions->addRow("(H)ead", setHead); + menuColumnOptions->addRow("Mirror (h)", setHead); menuColumnOptions->addRow("Field (f)", setField); menuColumnOptions->addRow("(N)oise", setNoise); - menuColumnOptions->addRow("Mirror", setMirror); menuColumnOptions->addRow("(V)oxels", setVoxels); menuColumnOptions->addRow("Stars (*)", setStars); menuColumnOptions->addRow("(Q)uit", quitApp); @@ -1273,7 +1266,7 @@ void shiftPaintingColor() } void setupPaintingVoxel() { - glm::vec3 avatarPos = myAvatar.getBodyPosition(); + glm::vec3 avatarPos = myAvatar.getPosition(); ::paintingVoxel.x = avatarPos.z/-10.0; // voxel space x is negative z head space ::paintingVoxel.y = avatarPos.y/-10.0; // voxel space y is negative y head space @@ -1412,9 +1405,9 @@ void key(unsigned char k, int x, int y) } if (k == 'h') { - displayHead = !displayHead; + ::lookingInMirror = !::lookingInMirror; #ifndef _WIN32 - audio.setMixerLoopbackFlag(displayHead); + audio.setMixerLoopbackFlag(::lookingInMirror); #endif } @@ -1502,7 +1495,7 @@ void idle(void) { // updateAvatar(deltaTime); - //loop through all the other avatars and simulate them. + //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++) { @@ -1520,7 +1513,6 @@ void idle(void) { glutPostRedisplay(); lastTimeIdle = check; - } // Read serial data diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index d644937464..fd20e099c0 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -34,9 +34,14 @@ int unpackFloatAngleFromTwoByte(uint16_t* byteAnglePointer, float* destinationPo } AvatarData::AvatarData() : + _handPosition(0,0,0), _bodyYaw(-90.0), _bodyPitch(0.0), _bodyRoll(0.0), + _headYaw(0), + _headPitch(0), + _headRoll(0), + _handState(0), _cameraPosition(0,0,0), _cameraDirection(0,0,0), _cameraUp(0,0,0), @@ -63,15 +68,31 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { // that can pack any type given the number of bytes // and return the number of bytes to push the pointer - memcpy(destinationBuffer, &_bodyPosition, sizeof(float) * 3); + // Body world position + memcpy(destinationBuffer, &_position, sizeof(float) * 3); destinationBuffer += sizeof(float) * 3; + // Body rotation (NOTE: This needs to become a quaternion to save two bytes) destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _bodyYaw); destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _bodyPitch); destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _bodyRoll); + // Head rotation (NOTE: This needs to become a quaternion to save two bytes) + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headYaw); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headPitch); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headRoll); + + // Hand Position memcpy(destinationBuffer, &_handPosition, sizeof(float) * 3); destinationBuffer += sizeof(float) * 3; + + // Hand State (0 = not grabbing, 1 = grabbing) + memcpy(destinationBuffer, &_handState, sizeof(char)); + destinationBuffer += sizeof(char); + + // Instantaneous audio loudness (used to drive facial animation) + memcpy(destinationBuffer, &_audioLoudness, sizeof(float)); + destinationBuffer += sizeof(float); // camera details memcpy(destinationBuffer, &_cameraPosition, sizeof(_cameraPosition)); @@ -91,6 +112,7 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { memcpy(destinationBuffer, &_cameraFarClip, sizeof(_cameraFarClip)); destinationBuffer += sizeof(_cameraFarClip); + return destinationBuffer - bufferStart; } @@ -102,16 +124,32 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { unsigned char* startPosition = sourceBuffer; - memcpy(&_bodyPosition, sourceBuffer, sizeof(float) * 3); + // Body world position + memcpy(&_position, sourceBuffer, sizeof(float) * 3); sourceBuffer += sizeof(float) * 3; + // Body rotation (NOTE: This needs to become a quaternion to save two bytes) sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t *)sourceBuffer, &_bodyYaw); sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t *)sourceBuffer, &_bodyPitch); sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t *)sourceBuffer, &_bodyRoll); + + // Head rotation (NOTE: This needs to become a quaternion to save two bytes) + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t *)sourceBuffer, &_headYaw); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t *)sourceBuffer, &_headPitch); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t *)sourceBuffer, &_headRoll); + // Hand Position memcpy(&_handPosition, sourceBuffer, sizeof(float) * 3); sourceBuffer += sizeof(float) * 3; + // Hand State + memcpy(&_handState, sourceBuffer, sizeof(char)); + sourceBuffer += sizeof(char); + + // Instantaneous audio loudness (used to drive facial animation) + memcpy(&_audioLoudness, sourceBuffer, sizeof(float)); + sourceBuffer += sizeof(float); + // camera details memcpy(&_cameraPosition, sourceBuffer, sizeof(_cameraPosition)); sourceBuffer += sizeof(_cameraPosition); @@ -133,14 +171,14 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { return sourceBuffer - startPosition; } -glm::vec3 AvatarData::getBodyPosition() { - return glm::vec3(_bodyPosition.x, - _bodyPosition.y, - _bodyPosition.z); +glm::vec3 AvatarData::getPosition() { + return glm::vec3(_position.x, + _position.y, + _position.z); } -void AvatarData::setBodyPosition(glm::vec3 bodyPosition) { - _bodyPosition = bodyPosition; +void AvatarData::setPosition(glm::vec3 position) { + _position = position; } void AvatarData::setHandPosition(glm::vec3 handPosition) { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index ea735c62fe..c403a1683a 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -20,23 +20,41 @@ public: AvatarData* clone() const; - glm::vec3 getBodyPosition(); - void setBodyPosition(glm::vec3 bodyPosition); + glm::vec3 getPosition(); + void setPosition(glm::vec3 position); void setHandPosition(glm::vec3 handPosition); int getBroadcastData(unsigned char* destinationBuffer); int parseData(unsigned char* sourceBuffer, int numBytes); + // Body Rotation float getBodyYaw(); - void setBodyYaw(float bodyYaw); - float getBodyPitch(); - void setBodyPitch(float bodyPitch); - float getBodyRoll(); + void setBodyYaw(float bodyYaw); + void setBodyPitch(float bodyPitch); void setBodyRoll(float bodyRoll); - // getters for camera details + // Head Rotation + void setHeadPitch(float p) {_headPitch = p; } + void setHeadYaw(float y) {_headYaw = y; } + void setHeadRoll(float r) {_headRoll = r; }; + const float getHeadPitch() const { return _headPitch; }; + const float getHeadYaw() const { return _headYaw; }; + const float getHeadRoll() const { return _headRoll; }; + void addHeadPitch(float p) {_headPitch -= p; } + void addHeadYaw(float y){_headYaw -= y; } + void addHeadRoll(float r){_headRoll += r; } + + // Hand State + void setHandState(char s) { _handState = s; }; + const float getHandState() const {return _handState; }; //@Philip - shouldn't this be an int or a char? + + // Instantaneous audio loudness to drive mouth/facial animation + void setLoudness(float l) { _audioLoudness = l; }; + const float getLoudness() const {return _audioLoudness; }; + + // getters for camera details const glm::vec3& getCameraPosition() const { return _cameraPosition; }; const glm::vec3& getCameraDirection() const { return _cameraDirection; } const glm::vec3& getCameraUp() const { return _cameraUp; } @@ -57,13 +75,25 @@ public: void setCameraFarClip(float farClip) { _cameraFarClip = farClip; } protected: - glm::vec3 _bodyPosition; + glm::vec3 _position; glm::vec3 _handPosition; + // Body rotation float _bodyYaw; float _bodyPitch; float _bodyRoll; + + // Head rotation (relative to body) + float _headYaw; + float _headPitch; + float _headRoll; + // Audio loudness (used to drive facial animation) + float _audioLoudness; + + // Hand state (are we grabbing something or not) + char _handState; + // camera details for the avatar glm::vec3 _cameraPosition; diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 5744c0780a..15c4abdd85 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -24,7 +24,7 @@ using shared_lib::printLog; -const char SOLO_AGENT_TYPES_STRING[] = { +const char SOLO_AGENT_TYPES[3] = { AGENT_TYPE_AVATAR_MIXER, AGENT_TYPE_AUDIO_MIXER, AGENT_TYPE_VOXEL @@ -305,8 +305,8 @@ void AgentList::handlePingReply(sockaddr *agentAddress) { } } -Agent* AgentList::soloAgentOfType(char agentType) { - if (memchr(SOLO_AGENT_TYPES_STRING, agentType, 1)) { +Agent* AgentList::soloAgentOfType(char agentType) { + if (memchr(SOLO_AGENT_TYPES, agentType, sizeof(SOLO_AGENT_TYPES)) != NULL) { for(std::vector::iterator agent = agents.begin(); agent != agents.end(); agent++) { if (agent->getType() == agentType) { return &*agent; @@ -428,7 +428,7 @@ void *checkInWithDomainServer(void *args) { sockaddr_in tempAddress; memcpy(&tempAddress.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length); strcpy(DOMAIN_IP, inet_ntoa(tempAddress.sin_addr)); - printLog("Domain server: %s \n", DOMAIN_HOSTNAME); + printLog("Domain server: %s - %s\n", DOMAIN_HOSTNAME, DOMAIN_IP); } else { printLog("Failed lookup domainserver\n"); diff --git a/libraries/shared/src/AgentList.h b/libraries/shared/src/AgentList.h index f62d527116..76d6917168 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[3]; extern char DOMAIN_HOSTNAME[]; extern char DOMAIN_IP[100]; // IP Address will be re-set by lookup on startup diff --git a/libraries/shared/src/AudioInjector.cpp b/libraries/shared/src/AudioInjector.cpp new file mode 100644 index 0000000000..6e65c168d0 --- /dev/null +++ b/libraries/shared/src/AudioInjector.cpp @@ -0,0 +1,103 @@ +// +// AudioInjector.cpp +// hifi +// +// Created by Stephen Birarda on 4/23/13. +// +// + +#include +#include +#include + +#include "SharedUtil.h" +#include "PacketHeaders.h" + +#include "AudioInjector.h" + +const int BUFFER_LENGTH_BYTES = 512; +const int BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t); +const float SAMPLE_RATE = 22050.0f; +const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES / SAMPLE_RATE) * 1000000; + +AudioInjector::AudioInjector(const char* filename) : + _numTotalBytesAudio(0), + _bearing(0), + _attenuationModifier(255) +{ + _position[0] = 0.0f; + _position[1] = 0.0f; + _position[2] = 0.0f; + + std::fstream sourceFile; + + sourceFile.open(filename, std::ios::in | std::ios::binary); + sourceFile.seekg(0, std::ios::end); + + _numTotalBytesAudio = sourceFile.tellg(); + if (_numTotalBytesAudio == -1) { + printf("Error reading audio data from file %s\n", filename); + _audioSampleArray = NULL; + } else { + printf("Read %d bytes from audio file\n", _numTotalBytesAudio); + sourceFile.seekg(0, std::ios::beg); + long sizeOfShortArray = _numTotalBytesAudio / 2; + _audioSampleArray = new int16_t[sizeOfShortArray]; + + sourceFile.read((char *)_audioSampleArray, _numTotalBytesAudio); + } +} + +AudioInjector::~AudioInjector() { + delete[] _audioSampleArray; +} + +void AudioInjector::setPosition(float* position) { + _position[0] = position[0]; + _position[1] = position[1]; + _position[2] = position[2]; +} + +void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destinationSocket) const { + if (_audioSampleArray != NULL) { + timeval startTime; + + // one byte for header, 3 positional floats, 1 bearing float, 1 attenuation modifier byte + int leadingBytes = 1 + (sizeof(float) * 4) + 1; + unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes]; + + dataPacket[0] = PACKET_HEADER_INJECT_AUDIO; + unsigned char *currentPacketPtr = dataPacket + 1; + + for (int i = 0; i < 3; i++) { + memcpy(currentPacketPtr, &_position[i], sizeof(float)); + currentPacketPtr += sizeof(float); + } + + *currentPacketPtr = _attenuationModifier; + currentPacketPtr++; + + memcpy(currentPacketPtr, &_bearing, sizeof(float)); + currentPacketPtr += sizeof(float); + + for (int i = 0; i < _numTotalBytesAudio; i += BUFFER_LENGTH_BYTES) { + gettimeofday(&startTime, NULL); + + int numBytesToCopy = BUFFER_LENGTH_BYTES; + + if (_numTotalBytesAudio - i < BUFFER_LENGTH_BYTES) { + numBytesToCopy = _numTotalBytesAudio - i; + memset(currentPacketPtr + numBytesToCopy, 0, BUFFER_LENGTH_BYTES - numBytesToCopy); + } + + memcpy(currentPacketPtr, _audioSampleArray + (i / 2), numBytesToCopy); + + injectorSocket->send(destinationSocket, dataPacket, sizeof(dataPacket)); + + double usecToSleep = BUFFER_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&startTime)); + if (usecToSleep > 0) { + usleep(usecToSleep); + } + } + } +} diff --git a/libraries/shared/src/AudioInjector.h b/libraries/shared/src/AudioInjector.h new file mode 100644 index 0000000000..2515dcfcdc --- /dev/null +++ b/libraries/shared/src/AudioInjector.h @@ -0,0 +1,35 @@ +// +// AudioInjector.h +// hifi +// +// Created by Stephen Birarda on 4/23/13. +// +// + +#ifndef __hifi__AudioInjector__ +#define __hifi__AudioInjector__ + +#include +#include + +#include "UDPSocket.h" + +class AudioInjector { +public: + AudioInjector(const char* filename); + ~AudioInjector(); + + void setPosition(float* position); + void setBearing(float bearing) { _bearing = bearing; } + void setAttenuationModifier(unsigned char attenuationModifier) { _attenuationModifier = attenuationModifier; } + + void injectAudio(UDPSocket* injectorSocket, sockaddr* destinationSocket) const; +private: + int16_t* _audioSampleArray; + int _numTotalBytesAudio; + float _position[3]; + float _bearing; + unsigned char _attenuationModifier; +}; + +#endif /* defined(__hifi__AudioInjector__) */ diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index 4476cff056..e01ae90a69 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -19,7 +19,7 @@ VoxelAgentData::~VoxelAgentData() { } VoxelAgentData::VoxelAgentData(const VoxelAgentData &otherAgentData) { - memcpy(&_bodyPosition, &otherAgentData._bodyPosition, sizeof(_bodyPosition)); + memcpy(&_position, &otherAgentData._position, sizeof(_position)); rootMarkerNode = new MarkerNode(); } diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 91fa2fd596..1d2b961d93 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -199,7 +199,7 @@ void *distributeVoxelsToListeners(void *args) { stopOctal = randomTree.loadBitstreamBuffer(voxelPacketEnd, randomTree.rootNode, agentData->rootMarkerNode, - agentData->getBodyPosition(), + agentData->getPosition(), treeRoot, viewFrustum, ::viewFrustumCulling,