Merge branch 'master' of https://github.com/worklist/hifi into render_voxels_optimization

This commit is contained in:
ZappoMan 2013-05-06 13:36:31 -07:00
commit 043a284d4d
21 changed files with 541 additions and 346 deletions

View file

@ -10,5 +10,5 @@ add_subdirectory(interface)
add_subdirectory(injector) add_subdirectory(injector)
add_subdirectory(pairing-server) add_subdirectory(pairing-server)
add_subdirectory(space-server) add_subdirectory(space-server)
add_subdirectory(voxel-server) add_subdirectory(voxel-edit)
add_subdirectory(voxel-edit) add_subdirectory(voxel-server)

View file

@ -45,8 +45,6 @@ unsigned char packetData[MAX_PACKET_SIZE];
const int LOGOFF_CHECK_INTERVAL = 5000; const int LOGOFF_CHECK_INTERVAL = 5000;
#define DEBUG_TO_SELF 0
int lastActiveCount = 0; int lastActiveCount = 0;
unsigned char* addAgentToBroadcastPacket(unsigned char* currentPosition, Agent* agentToAdd) { unsigned char* addAgentToBroadcastPacket(unsigned char* currentPosition, Agent* agentToAdd) {
@ -81,13 +79,13 @@ int main(int argc, const char * argv[])
setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(stdout, NULL, _IOLBF, 0);
ssize_t receivedBytes = 0; ssize_t receivedBytes = 0;
char agentType; char agentType = '\0';
unsigned char *broadcastPacket = new unsigned char[MAX_PACKET_SIZE]; unsigned char broadcastPacket[MAX_PACKET_SIZE];
*broadcastPacket = PACKET_HEADER_DOMAIN; broadcastPacket[0] = PACKET_HEADER_DOMAIN;
unsigned char *currentBufferPos; unsigned char* currentBufferPos;
unsigned char *startPointer; unsigned char* startPointer;
int packetBytesWithoutLeadingChar; int packetBytesWithoutLeadingChar;
sockaddr_in agentPublicAddress, agentLocalAddress; sockaddr_in agentPublicAddress, agentLocalAddress;
@ -101,8 +99,8 @@ int main(int argc, const char * argv[])
if (agentList->getAgentSocket().receive((sockaddr *)&agentPublicAddress, packetData, &receivedBytes)) { if (agentList->getAgentSocket().receive((sockaddr *)&agentPublicAddress, packetData, &receivedBytes)) {
std::map<char, Agent *> newestSoloAgents; std::map<char, Agent *> newestSoloAgents;
agentType = packetData[0]; agentType = packetData[1];
unpackSocket(&packetData[1], (sockaddr *)&agentLocalAddress); unpackSocket(&packetData[2], (sockaddr*) &agentLocalAddress);
// check the agent public address // check the agent public address
// if it matches our local address we're on the same box // if it matches our local address we're on the same box
@ -115,21 +113,23 @@ int main(int argc, const char * argv[])
} }
} }
if (agentList->addOrUpdateAgent((sockaddr *)&agentPublicAddress, if (agentList->addOrUpdateAgent((sockaddr*) &agentPublicAddress,
(sockaddr *)&agentLocalAddress, (sockaddr*) &agentLocalAddress,
agentType, agentType,
agentList->getLastAgentId())) { agentList->getLastAgentId())) {
agentList->increaseAgentId(); agentList->increaseAgentId();
} else if (packetData[0] == PACKET_HEADER_DOMAIN_RFD) {
// if this is a previous agent, and they are re-reporting for duty
// then we need to update the first receive time
Agent* refreshedAgent = agentList->agentWithAddress((sockaddr*) &agentLocalAddress);
refreshedAgent->setWakeMicrostamp(usecTimestampNow());
} }
currentBufferPos = broadcastPacket + 1; currentBufferPos = broadcastPacket + 2;
startPointer = currentBufferPos; startPointer = currentBufferPos;
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
if (DEBUG_TO_SELF || if (!agent->matches((sockaddr*) &agentPublicAddress, (sockaddr*) &agentLocalAddress, agentType)) {
!agent->matches((sockaddr *)&agentPublicAddress, (sockaddr *)&agentLocalAddress, agentType)) {
if (memchr(SOLO_AGENT_TYPES, agent->getType(), sizeof(SOLO_AGENT_TYPES)) == 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 // 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 // don't send avatar agents to other avatars, that will come from avatar mixer
@ -140,26 +140,26 @@ int main(int argc, const char * argv[])
} else { } else {
// solo agent, we need to only send newest // solo agent, we need to only send newest
if (newestSoloAgents[agent->getType()] == NULL || if (newestSoloAgents[agent->getType()] == NULL ||
newestSoloAgents[agent->getType()]->getFirstRecvTimeUsecs() < agent->getFirstRecvTimeUsecs()) { newestSoloAgents[agent->getType()]->getWakeMicrostamp() < agent->getWakeMicrostamp()) {
// we have to set the newer solo agent to add it to the broadcast later // we have to set the newer solo agent to add it to the broadcast later
newestSoloAgents[agent->getType()] = &(*agent); newestSoloAgents[agent->getType()] = &(*agent);
} }
} }
} else { } else {
// this is the agent, just update last receive to now // this is the agent, just update last receive to now
agent->setLastRecvTimeUsecs(usecTimestampNow()); agent->setLastHeardMicrostamp(usecTimestampNow());
} }
} }
for (std::map<char, Agent *>::iterator agentIterator = newestSoloAgents.begin(); for (std::map<char, Agent *>::iterator soloAgent = newestSoloAgents.begin();
agentIterator != newestSoloAgents.end(); soloAgent != newestSoloAgents.end();
agentIterator++) { soloAgent++) {
// this is the newest alive solo agent, add them to the packet // this is the newest alive solo agent, add them to the packet
currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, agentIterator->second); currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, soloAgent->second);
} }
if ((packetBytesWithoutLeadingChar = (currentBufferPos - startPointer))) { if ((packetBytesWithoutLeadingChar = (currentBufferPos - startPointer))) {
agentList->getAgentSocket().send((sockaddr *)&agentPublicAddress, agentList->getAgentSocket().send((sockaddr*) &agentPublicAddress,
broadcastPacket, broadcastPacket,
packetBytesWithoutLeadingChar + 1); packetBytesWithoutLeadingChar + 1);
} }

View file

@ -49,7 +49,7 @@ void *receiveAgentData(void *args) {
avatarMixer = agentList->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER); avatarMixer = agentList->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER);
if (avatarMixer != NULL) { if (avatarMixer != NULL) {
avatarMixer->setLastRecvTimeUsecs(usecTimestampNow()); avatarMixer->setLastHeardMicrostamp(usecTimestampNow());
} }
break; break;

View file

@ -21,7 +21,9 @@
using namespace std; using namespace std;
const bool BALLS_ON = false; const bool BALLS_ON = false;
const bool AVATAR_GRAVITY = true; const bool USING_AVATAR_GRAVITY = true;
const float GRAVITY_SCALE = 6.0f;
const float BOUNCE = 0.3f;
const float DECAY = 0.1; const float DECAY = 0.1;
const float THRUST_MAG = 1200.0; const float THRUST_MAG = 1200.0;
const float YAW_MAG = 500.0; const float YAW_MAG = 500.0;
@ -32,23 +34,28 @@ const float BODY_ROLL_WHILE_TURNING = 0.1;
const float LIN_VEL_DECAY = 5.0; const float LIN_VEL_DECAY = 5.0;
const float MY_HAND_HOLDING_PULL = 0.2; const float MY_HAND_HOLDING_PULL = 0.2;
const float YOUR_HAND_HOLDING_PULL = 1.0; const float YOUR_HAND_HOLDING_PULL = 1.0;
const float BODY_SPRING_FORCE = 6.0f;
//const float BODY_SPRING_DEFAULT_TIGHTNESS = 20.0f;
//const float BODY_SPRING_FORCE = 6.0f;
const float BODY_SPRING_DEFAULT_TIGHTNESS = 1500.0f;
const float BODY_SPRING_FORCE = 300.0f;
const float BODY_SPRING_DECAY = 16.0f; const float BODY_SPRING_DECAY = 16.0f;
const float BODY_SPRING_DEFAULT_TIGHTNESS = 10.0f;
const float COLLISION_RADIUS_SCALAR = 1.8; const float COLLISION_RADIUS_SCALAR = 1.8;
const float COLLISION_BALL_FORCE = 1.0; const float COLLISION_BALL_FORCE = 1.0;
const float COLLISION_BODY_FORCE = 6.0; const float COLLISION_BODY_FORCE = 6.0;
const float COLLISION_BALL_FRICTION = 60.0; const float COLLISION_BALL_FRICTION = 60.0;
const float COLLISION_BODY_FRICTION = 0.5; const float COLLISION_BODY_FRICTION = 0.5;
float skinColor[] = {1.0, 0.84, 0.66}; float skinColor [] = {1.0, 0.84, 0.66};
float lightBlue[] = { 0.7, 0.8, 1.0 }; float lightBlue [] = {0.7, 0.8, 1.0};
float browColor[] = {210.0/255.0, 105.0/255.0, 30.0/255.0}; float browColor [] = {210.0/255.0, 105.0/255.0, 30.0/255.0};
float mouthColor[] = {1, 0, 0}; float mouthColor[] = {1, 0, 0};
float BrowRollAngle[5] = {0, 15, 30, -30, -15}; float BrowRollAngle [5] = {0, 15, 30, -30, -15};
float BrowPitchAngle[3] = {-70, -60, -50}; float BrowPitchAngle[3] = {-70, -60, -50};
float eyeColor[3] = {1,1,1}; float eyeColor [3] = {1,1,1};
float MouthWidthChoices[3] = {0.5, 0.77, 0.3}; float MouthWidthChoices[3] = {0.5, 0.77, 0.3};
@ -70,9 +77,9 @@ Avatar::Avatar(bool isMine) {
_orientation.setToIdentity(); _orientation.setToIdentity();
_velocity = glm::vec3( 0.0, 0.0, 0.0 ); _velocity = glm::vec3(0.0f, 0.0f, 0.0f);
_thrust = glm::vec3( 0.0, 0.0, 0.0 ); _thrust = glm::vec3(0.0f, 0.0f, 0.0f);
_rotation = glm::quat( 0.0f, 0.0f, 0.0f, 0.0f ); _rotation = glm::quat(0.0f, 0.0f, 0.0f, 0.0f);
_bodyYaw = -90.0; _bodyYaw = -90.0;
_bodyPitch = 0.0; _bodyPitch = 0.0;
_bodyRoll = 0.0; _bodyRoll = 0.0;
@ -86,12 +93,12 @@ Avatar::Avatar(bool isMine) {
_transmitterHz = 0.0; _transmitterHz = 0.0;
_transmitterPackets = 0; _transmitterPackets = 0;
_transmitterIsFirstData = true; _transmitterIsFirstData = true;
_transmitterInitialReading = glm::vec3( 0.f, 0.f, 0.f ); _transmitterInitialReading = glm::vec3(0.f, 0.f, 0.f);
_speed = 0.0; _speed = 0.0;
_pelvisStandingHeight = 0.0f; _pelvisStandingHeight = 0.0f;
_displayingHead = true; _displayingHead = true;
_TEST_bigSphereRadius = 0.4f; _TEST_bigSphereRadius = 0.4f;
_TEST_bigSpherePosition = glm::vec3( 0.0f, _TEST_bigSphereRadius, 2.0f ); _TEST_bigSpherePosition = glm::vec3(5.0f, _TEST_bigSphereRadius, 5.0f);
for (int i = 0; i < MAX_DRIVE_KEYS; i++) _driveKeys[i] = false; for (int i = 0; i < MAX_DRIVE_KEYS; i++) _driveKeys[i] = false;
@ -132,14 +139,15 @@ Avatar::Avatar(bool isMine) {
_head.browAudioLift = 0.0; _head.browAudioLift = 0.0;
_head.noise = 0; _head.noise = 0;
_head.returnSpringScale = 1.0; _head.returnSpringScale = 1.0;
_movedHandOffset = glm::vec3( 0.0, 0.0, 0.0 ); _movedHandOffset = glm::vec3(0.0f, 0.0f, 0.0f);
_usingBodySprings = true; _usingBodySprings = true;
_renderYaw = 0.0; _renderYaw = 0.0;
_renderPitch = 0.0; _renderPitch = 0.0;
_sphere = NULL; _sphere = NULL;
_interactingOther = NULL; _interactingOther = NULL;
_handHoldingPosition = glm::vec3( 0.0, 0.0, 0.0 ); _handHoldingPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_distanceToNearestAvatar = std::numeric_limits<float>::max(); _distanceToNearestAvatar = std::numeric_limits<float>::max();
_gravity = glm::vec3(0.0f, -1.0f, 0.0f); // default
initializeSkeleton(); initializeSkeleton();
@ -183,7 +191,7 @@ Avatar::Avatar(const Avatar &otherAvatar) {
_movedHandOffset = otherAvatar._movedHandOffset; _movedHandOffset = otherAvatar._movedHandOffset;
_usingBodySprings = otherAvatar._usingBodySprings; _usingBodySprings = otherAvatar._usingBodySprings;
_orientation.set( otherAvatar._orientation ); _orientation.set(otherAvatar._orientation);
_sphere = NULL; _sphere = NULL;
@ -255,45 +263,39 @@ void Avatar::reset() {
_head.leanForward = _head.leanSideways = 0; _head.leanForward = _head.leanSideways = 0;
} }
// this pertains to moving the head with the glasses
//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 // Using serial data, update avatar/render position and angles
{ void Avatar::UpdateGyros(float frametime, SerialInterface* serialInterface, glm::vec3* gravity) {
const float PITCH_ACCEL_COUPLING = 0.5; float measured_pitch_rate = 0.0f;
const float ROLL_ACCEL_COUPLING = -1.0; float measured_roll_rate = 0.0f;
float measured_pitch_rate = serialInterface->getRelativeValue(HEAD_PITCH_RATE); if (serialInterface->active && USING_INVENSENSE_MPU9150) {
_head.yawRate = serialInterface->getRelativeValue(HEAD_YAW_RATE); measured_pitch_rate = serialInterface->getLastPitch();
float measured_lateral_accel = serialInterface->getRelativeValue(ACCEL_X) - _head.yawRate = serialInterface->getLastYaw();
ROLL_ACCEL_COUPLING * serialInterface->getRelativeValue(HEAD_ROLL_RATE); measured_roll_rate = -1 * serialInterface->getLastRoll();
float measured_fwd_accel = serialInterface->getRelativeValue(ACCEL_Z) - } else {
PITCH_ACCEL_COUPLING * serialInterface->getRelativeValue(HEAD_PITCH_RATE); measured_pitch_rate = serialInterface->getRelativeValue(HEAD_PITCH_RATE);
float measured_roll_rate = serialInterface->getRelativeValue(HEAD_ROLL_RATE); _head.yawRate = serialInterface->getRelativeValue(HEAD_YAW_RATE);
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 // Update avatar head position based on measured gyro rates
const float HEAD_ROTATION_SCALE = 0.70; const float HEAD_ROTATION_SCALE = 0.70;
const float HEAD_ROLL_SCALE = 0.40; const float HEAD_ROLL_SCALE = 0.40;
const float HEAD_LEAN_SCALE = 0.01;
const float MAX_PITCH = 45; const float MAX_PITCH = 45;
const float MIN_PITCH = -45; const float MIN_PITCH = -45;
const float MAX_YAW = 85; const float MAX_YAW = 85;
const float MIN_YAW = -85; const float MIN_YAW = -85;
if ((_headPitch < MAX_PITCH) && (_headPitch > MIN_PITCH)) if ((_headPitch < MAX_PITCH) && (_headPitch > MIN_PITCH)) {
addHeadPitch(measured_pitch_rate * -HEAD_ROTATION_SCALE * frametime); addHeadPitch(measured_pitch_rate * -HEAD_ROTATION_SCALE * frametime);
}
addHeadRoll(measured_roll_rate * HEAD_ROLL_SCALE * frametime); addHeadRoll(measured_roll_rate * HEAD_ROLL_SCALE * frametime);
if ((_headYaw < MAX_YAW) && (_headYaw > MIN_YAW)) if ((_headYaw < MAX_YAW) && (_headYaw > MIN_YAW)) {
addHeadYaw(_head.yawRate * HEAD_ROTATION_SCALE * frametime); addHeadYaw(_head.yawRate * HEAD_ROTATION_SCALE * frametime);
}
addLean(-measured_lateral_accel * frametime * HEAD_LEAN_SCALE, -measured_fwd_accel*frametime * HEAD_LEAN_SCALE);
} }
float Avatar::getAbsoluteHeadYaw() const { float Avatar::getAbsoluteHeadYaw() const {
@ -314,7 +316,7 @@ void Avatar::setLeanSideways(float dist){
_head.leanSideways = dist; _head.leanSideways = dist;
} }
void Avatar::setMousePressed( bool d ) { void Avatar::setMousePressed(bool d) {
_mousePressed = d; _mousePressed = d;
} }
@ -336,28 +338,29 @@ void Avatar::simulate(float deltaTime) {
//update the movement of the hand and process handshaking with other avatars... //update the movement of the hand and process handshaking with other avatars...
updateHandMovementAndTouching(deltaTime); updateHandMovementAndTouching(deltaTime);
// test for avatar collision response with the big sphere
if (usingBigSphereCollisionTest) {
updateCollisionWithSphere( _TEST_bigSpherePosition, _TEST_bigSphereRadius, deltaTime );
}
// apply gravity and collision wiht the ground/floor // apply gravity and collision with the ground/floor
if ( AVATAR_GRAVITY ) { if (USING_AVATAR_GRAVITY) {
if ( _position.y > _pelvisStandingHeight + 0.01 ) { if (_position.y > _pelvisStandingHeight + 0.01f) {
_velocity += glm::dvec3(getGravity(getPosition())) * ( 6.0 * deltaTime ); _velocity += _gravity * (GRAVITY_SCALE * deltaTime);
} else if ( _position.y < _pelvisStandingHeight ) { } else if (_position.y < _pelvisStandingHeight) {
_position.y = _pelvisStandingHeight; _position.y = _pelvisStandingHeight;
_velocity.y = 0.0; _velocity.y = -_velocity.y * BOUNCE;
} }
} }
// update body springs // update body springs
updateBodySprings( deltaTime ); updateBodySprings(deltaTime);
// test for avatar collision response with the big sphere
if (usingBigSphereCollisionTest) {
updateCollisionWithSphere(_TEST_bigSpherePosition, _TEST_bigSphereRadius, deltaTime);
}
// driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely) // driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely)
if ( _isMine ) { if (_isMine) {
_thrust = glm::vec3( 0.0, 0.0, 0.0 ); _thrust = glm::vec3(0.0f, 0.0f, 0.0f);
if (_driveKeys[FWD ]) {_thrust += THRUST_MAG * deltaTime * _orientation.getFront();} if (_driveKeys[FWD ]) {_thrust += THRUST_MAG * deltaTime * _orientation.getFront();}
if (_driveKeys[BACK ]) {_thrust -= THRUST_MAG * deltaTime * _orientation.getFront();} if (_driveKeys[BACK ]) {_thrust -= THRUST_MAG * deltaTime * _orientation.getFront();}
@ -387,16 +390,16 @@ void Avatar::simulate(float deltaTime) {
_velocity += _thrust * deltaTime; _velocity += _thrust * deltaTime;
// calculate speed // calculate speed
_speed = glm::length( _velocity ); _speed = glm::length(_velocity);
//pitch and roll the body as a function of forward speed and turning delta //pitch and roll the body as a function of forward speed and turning delta
float forwardComponentOfVelocity = glm::dot( _orientation.getFront(), _velocity ); float forwardComponentOfVelocity = glm::dot(_orientation.getFront(), _velocity);
_bodyPitch += BODY_PITCH_WHILE_WALKING * deltaTime * forwardComponentOfVelocity; _bodyPitch += BODY_PITCH_WHILE_WALKING * deltaTime * forwardComponentOfVelocity;
_bodyRoll += BODY_ROLL_WHILE_TURNING * deltaTime * _speed * _bodyYawDelta; _bodyRoll += BODY_ROLL_WHILE_TURNING * deltaTime * _speed * _bodyYawDelta;
// these forces keep the body upright... // these forces keep the body upright...
float tiltDecay = 1.0 - BODY_UPRIGHT_FORCE * deltaTime; float tiltDecay = 1.0 - BODY_UPRIGHT_FORCE * deltaTime;
if ( tiltDecay < 0.0f ) { tiltDecay = 0.0f; } if (tiltDecay < 0.0f) {tiltDecay = 0.0f;}
_bodyPitch *= tiltDecay; _bodyPitch *= tiltDecay;
_bodyRoll *= tiltDecay; _bodyRoll *= tiltDecay;
@ -404,7 +407,7 @@ void Avatar::simulate(float deltaTime) {
_position += _velocity * deltaTime; _position += _velocity * deltaTime;
// decay velocity // decay velocity
_velocity *= ( 1.0 - LIN_VEL_DECAY * deltaTime ); _velocity *= (1.0 - LIN_VEL_DECAY * deltaTime);
// If someone is near, damp velocity as a function of closeness // If someone is near, damp velocity as a function of closeness
const float AVATAR_BRAKING_RANGE = 1.2f; const float AVATAR_BRAKING_RANGE = 1.2f;
@ -419,7 +422,7 @@ void Avatar::simulate(float deltaTime) {
updateHead(deltaTime); updateHead(deltaTime);
// use speed and angular velocity to determine walking vs. standing // use speed and angular velocity to determine walking vs. standing
if ( _speed + fabs( _bodyYawDelta ) > 0.2 ) { if (_speed + fabs(_bodyYawDelta) > 0.2) {
_mode = AVATAR_MODE_WALKING; _mode = AVATAR_MODE_WALKING;
} else { } else {
_mode = AVATAR_MODE_INTERACTING; _mode = AVATAR_MODE_INTERACTING;
@ -449,7 +452,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
// if the avatar being simulated is mine, then loop through // if the avatar being simulated is mine, then loop through
// all the other avatars for potential interactions... // all the other avatars for potential interactions...
if ( _isMine ) if (_isMine)
{ {
// Reset detector for nearest avatar // Reset detector for nearest avatar
_distanceToNearestAvatar = std::numeric_limits<float>::max(); _distanceToNearestAvatar = std::numeric_limits<float>::max();
@ -463,24 +466,24 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
updateCollisionWithOtherAvatar(otherAvatar, deltaTime ); updateCollisionWithOtherAvatar(otherAvatar, deltaTime );
// test other avatar hand position for proximity // test other avatar hand position for proximity
glm::vec3 v( _joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position ); glm::vec3 v(_joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position);
v -= otherAvatar->getJointPosition( AVATAR_JOINT_RIGHT_SHOULDER ); v -= otherAvatar->getJointPosition(AVATAR_JOINT_RIGHT_SHOULDER);
float distance = glm::length( v ); float distance = glm::length(v);
if (distance < _distanceToNearestAvatar) { _distanceToNearestAvatar = distance; } if (distance < _distanceToNearestAvatar) {_distanceToNearestAvatar = distance;}
if (distance < _maxArmLength + _maxArmLength) { if (distance < _maxArmLength + _maxArmLength) {
_interactingOther = otherAvatar; _interactingOther = otherAvatar;
if ( ! _avatarTouch.getAbleToReachOtherAvatar() ) { if (! _avatarTouch.getAbleToReachOtherAvatar()) {
//initialize _handHolding //initialize _handHolding
_handHoldingPosition = _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position; _handHoldingPosition = _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position;
_avatarTouch.setAbleToReachOtherAvatar(true); _avatarTouch.setAbleToReachOtherAvatar(true);
} }
glm::vec3 vectorBetweenHands( _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position ); glm::vec3 vectorBetweenHands(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position);
vectorBetweenHands -= otherAvatar->getJointPosition( AVATAR_JOINT_RIGHT_FINGERTIPS ); vectorBetweenHands -= otherAvatar->getJointPosition(AVATAR_JOINT_RIGHT_FINGERTIPS);
float distanceBetweenHands = glm::length(vectorBetweenHands); float distanceBetweenHands = glm::length(vectorBetweenHands);
if (distanceBetweenHands < HANDS_CLOSE_ENOUGH_TO_GRASP) { if (distanceBetweenHands < HANDS_CLOSE_ENOUGH_TO_GRASP) {
@ -488,7 +491,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
} }
// if I am holding hands with another avatar, a force is applied // if I am holding hands with another avatar, a force is applied
if (( _handState == 1 ) || ( _interactingOther->_handState == 1 )) { if ((_handState == 1) || (_interactingOther->_handState == 1)) {
// if the hands are close enough to grasp... // if the hands are close enough to grasp...
if (distanceBetweenHands < HANDS_CLOSE_ENOUGH_TO_GRASP) if (distanceBetweenHands < HANDS_CLOSE_ENOUGH_TO_GRASP)
@ -502,7 +505,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = _handHoldingPosition; _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = _handHoldingPosition;
// apply a force to the avatar body // apply a force to the avatar body
if ( glm::length(vectorToOtherHand) > _maxArmLength * 0.9 ) { if (glm::length(vectorToOtherHand) > _maxArmLength * 0.9) {
_velocity += vectorToOtherHand; _velocity += vectorToOtherHand;
} }
} }
@ -514,18 +517,18 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
// Set the vector we send for hand position to other people to be our right hand // Set the vector we send for hand position to other people to be our right hand
setHandPosition(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position); setHandPosition(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position);
}//if ( _isMine ) }//if (_isMine)
//constrain right arm length and re-adjust elbow position as it bends //constrain right arm length and re-adjust elbow position as it bends
updateArmIKAndConstraints( deltaTime ); updateArmIKAndConstraints(deltaTime);
// set hand positions for _avatarTouch.setMyHandPosition AFTER calling updateArmIKAndConstraints // set hand positions for _avatarTouch.setMyHandPosition AFTER calling updateArmIKAndConstraints
if ( _interactingOther ) { if (_interactingOther) {
if (_isMine) { if (_isMine) {
_avatarTouch.setMyHandPosition ( _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position ); _avatarTouch.setMyHandPosition (_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position);
_avatarTouch.setYourHandPosition( _interactingOther->_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position ); _avatarTouch.setYourHandPosition(_interactingOther->_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position);
_avatarTouch.setMyHandState ( _handState ); _avatarTouch.setMyHandState (_handState);
_avatarTouch.setYourHandState ( _interactingOther->_handState ); _avatarTouch.setYourHandState (_interactingOther->_handState);
_avatarTouch.simulate(deltaTime); _avatarTouch.simulate(deltaTime);
} }
} }
@ -539,7 +542,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
void Avatar::updateHead(float deltaTime) { void Avatar::updateHead(float deltaTime) {
//apply the head lean values to the springy position... //apply the head lean values to the springy position...
if ( fabs( _head.leanSideways + _head.leanForward ) > 0.0f ) { if (fabs( _head.leanSideways + _head.leanForward ) > 0.0f) {
glm::vec3 headLean = glm::vec3 headLean =
_orientation.getRight() * _head.leanSideways + _orientation.getRight() * _head.leanSideways +
_orientation.getFront() * _head.leanForward; _orientation.getFront() * _head.leanForward;
@ -650,19 +653,19 @@ float Avatar::getHeight() {
} }
void Avatar::updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ) { void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float deltaTime) {
float myBodyApproximateBoundingRadius = 1.0f; float myBodyApproximateBoundingRadius = 1.0f;
glm::vec3 vectorFromMyBodyToBigSphere(_position - position); glm::vec3 vectorFromMyBodyToBigSphere(_position - position);
bool jointCollision = false; bool jointCollision = false;
float distanceToBigSphere = glm::length(vectorFromMyBodyToBigSphere); float distanceToBigSphere = glm::length(vectorFromMyBodyToBigSphere);
if ( distanceToBigSphere < myBodyApproximateBoundingRadius + radius ) { if (distanceToBigSphere < myBodyApproximateBoundingRadius + radius) {
for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { for (int b = 0; b < NUM_AVATAR_JOINTS; b++) {
glm::vec3 vectorFromJointToBigSphereCenter(_joint[b].springyPosition - position); glm::vec3 vectorFromJointToBigSphereCenter(_joint[b].springyPosition - position);
float distanceToBigSphereCenter = glm::length(vectorFromJointToBigSphereCenter); float distanceToBigSphereCenter = glm::length(vectorFromJointToBigSphereCenter);
float combinedRadius = _joint[b].radius + radius; float combinedRadius = _joint[b].radius + radius;
if ( distanceToBigSphereCenter < combinedRadius ) { if (distanceToBigSphereCenter < combinedRadius) {
jointCollision = true; jointCollision = true;
if (distanceToBigSphereCenter > 0.0) { if (distanceToBigSphereCenter > 0.0) {
glm::vec3 directionVector = vectorFromJointToBigSphereCenter / distanceToBigSphereCenter; glm::vec3 directionVector = vectorFromJointToBigSphereCenter / distanceToBigSphereCenter;
@ -670,14 +673,14 @@ void Avatar::updateCollisionWithSphere( glm::vec3 position, float radius, float
float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius); float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius);
glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration; glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration;
_joint[b].springyVelocity += collisionForce * 30.0f * deltaTime; _joint[b].springyVelocity += collisionForce * 0.0f * deltaTime;
_velocity += collisionForce * 100.0f * deltaTime; _velocity += collisionForce * 40.0f * deltaTime;
_joint[b].springyPosition = position + directionVector * combinedRadius; _joint[b].springyPosition = position + directionVector * combinedRadius;
} }
} }
} }
if ( jointCollision ) { if (jointCollision) {
if (!_usingBodySprings) { if (!_usingBodySprings) {
_usingBodySprings = true; _usingBodySprings = true;
initializeBodySprings(); initializeBodySprings();
@ -688,37 +691,37 @@ void Avatar::updateCollisionWithSphere( glm::vec3 position, float radius, float
//detect collisions with other avatars and respond //detect collisions with other avatars and respond
void Avatar::updateCollisionWithOtherAvatar( Avatar * otherAvatar, float deltaTime ) { void Avatar::updateCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime) {
// check if the bounding spheres of the two avatars are colliding // check if the bounding spheres of the two avatars are colliding
glm::vec3 vectorBetweenBoundingSpheres(_position - otherAvatar->_position); glm::vec3 vectorBetweenBoundingSpheres(_position - otherAvatar->_position);
if ( glm::length(vectorBetweenBoundingSpheres) < _height * ONE_HALF + otherAvatar->_height * ONE_HALF ) { if (glm::length(vectorBetweenBoundingSpheres) < _height * ONE_HALF + otherAvatar->_height * ONE_HALF) {
float bodyMomentum = 1.0f; float bodyMomentum = 1.0f;
glm::vec3 bodyPushForce = glm::vec3( 0.0, 0.0, 0.0 ); glm::vec3 bodyPushForce = glm::vec3(0.0f, 0.0f, 0.0f);
// loop through the joints of each avatar to check for every possible collision // loop through the joints of each avatar to check for every possible collision
for (int b=1; b<NUM_AVATAR_JOINTS; b++) { for (int b=1; b<NUM_AVATAR_JOINTS; b++) {
if ( _joint[b].isCollidable ) { if (_joint[b].isCollidable) {
for (int o=b+1; o<NUM_AVATAR_JOINTS; o++) { for (int o=b+1; o<NUM_AVATAR_JOINTS; o++) {
if ( otherAvatar->_joint[o].isCollidable ) { if (otherAvatar->_joint[o].isCollidable) {
glm::vec3 vectorBetweenJoints(_joint[b].springyPosition - otherAvatar->_joint[o].springyPosition); glm::vec3 vectorBetweenJoints(_joint[b].springyPosition - otherAvatar->_joint[o].springyPosition);
float distanceBetweenJoints = glm::length(vectorBetweenJoints); float distanceBetweenJoints = glm::length(vectorBetweenJoints);
if ( distanceBetweenJoints > 0.0 ) { // to avoid divide by zero if (distanceBetweenJoints > 0.0 ) { // to avoid divide by zero
float combinedRadius = _joint[b].radius + otherAvatar->_joint[o].radius; float combinedRadius = _joint[b].radius + otherAvatar->_joint[o].radius;
// check for collision // check for collision
if ( distanceBetweenJoints < combinedRadius * COLLISION_RADIUS_SCALAR) { if (distanceBetweenJoints < combinedRadius * COLLISION_RADIUS_SCALAR) {
glm::vec3 directionVector = vectorBetweenJoints / distanceBetweenJoints; glm::vec3 directionVector = vectorBetweenJoints / distanceBetweenJoints;
// push balls away from each other and apply friction // push balls away from each other and apply friction
glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * deltaTime; glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * deltaTime;
float ballMomentum = 1.0 - COLLISION_BALL_FRICTION * deltaTime; float ballMomentum = 1.0 - COLLISION_BALL_FRICTION * deltaTime;
if ( ballMomentum < 0.0 ) { ballMomentum = 0.0;} if (ballMomentum < 0.0 ) { ballMomentum = 0.0;}
_joint[b].springyVelocity += ballPushForce; _joint[b].springyVelocity += ballPushForce;
otherAvatar->_joint[o].springyVelocity -= ballPushForce; otherAvatar->_joint[o].springyVelocity -= ballPushForce;
@ -729,7 +732,7 @@ void Avatar::updateCollisionWithOtherAvatar( Avatar * otherAvatar, float deltaTi
// accumulate forces and frictions to apply to the velocities of avatar bodies // accumulate forces and frictions to apply to the velocities of avatar bodies
bodyPushForce += directionVector * COLLISION_BODY_FORCE * deltaTime; bodyPushForce += directionVector * COLLISION_BODY_FORCE * deltaTime;
bodyMomentum -= COLLISION_BODY_FRICTION * deltaTime; bodyMomentum -= COLLISION_BODY_FRICTION * deltaTime;
if ( bodyMomentum < 0.0 ) { bodyMomentum = 0.0;} if (bodyMomentum < 0.0 ) { bodyMomentum = 0.0;}
}// check for collision }// check for collision
} // to avoid divide by zero } // to avoid divide by zero
@ -749,7 +752,7 @@ void Avatar::updateCollisionWithOtherAvatar( Avatar * otherAvatar, float deltaTi
} //method } //method
void Avatar::setDisplayingHead( bool displayingHead ) { void Avatar::setDisplayingHead(bool displayingHead ) {
_displayingHead = displayingHead; _displayingHead = displayingHead;
} }
@ -759,26 +762,34 @@ static TextRenderer* textRenderer() {
return renderer; return renderer;
} }
void Avatar::setGravity(glm::vec3 gravity) {
_gravity = gravity;
}
void Avatar::render(bool lookingInMirror) { void Avatar::render(bool lookingInMirror) {
// render a simple round on the ground projected down from the avatar's position
renderDiskShadow(_position, glm::vec3(0.0f, 1.0f, 0.0f ), 0.1f, 0.2f );
/* /*
// show avatar position // show avatar position
glColor4f( 0.5f, 0.5f, 0.5f, 0.6 ); glColor4f(0.5f, 0.5f, 0.5f, 0.6 );
glPushMatrix(); glPushMatrix();
glTranslatef(_position.x, _position.y, _position.z); glTranslatef(_position.x, _position.y, _position.z);
glScalef( 0.03, 0.03, 0.03 ); glScalef(0.03, 0.03, 0.03 );
glutSolidSphere( 1, 10, 10 ); glutSolidSphere(1, 10, 10 );
glPopMatrix(); glPopMatrix();
*/ */
if ( usingBigSphereCollisionTest ) { if (usingBigSphereCollisionTest ) {
// show TEST big sphere // show TEST big sphere
glColor4f( 0.5f, 0.6f, 0.8f, 0.7 ); glColor4f(0.5f, 0.6f, 0.8f, 0.7 );
glPushMatrix(); glPushMatrix();
glTranslatef(_TEST_bigSpherePosition.x, _TEST_bigSpherePosition.y, _TEST_bigSpherePosition.z); glTranslatef(_TEST_bigSpherePosition.x, _TEST_bigSpherePosition.y, _TEST_bigSpherePosition.z);
glScalef( _TEST_bigSphereRadius, _TEST_bigSphereRadius, _TEST_bigSphereRadius ); glScalef(_TEST_bigSphereRadius, _TEST_bigSphereRadius, _TEST_bigSphereRadius );
glutSolidSphere( 1, 20, 20 ); glutSolidSphere(1, 20, 20 );
glPopMatrix(); glPopMatrix();
} }
@ -791,7 +802,7 @@ void Avatar::render(bool lookingInMirror) {
} }
// if this is my avatar, then render my interactions with the other avatar // if this is my avatar, then render my interactions with the other avatar
if ( _isMine ) { if (_isMine ) {
_avatarTouch.render(); _avatarTouch.render();
} }
@ -852,7 +863,7 @@ void Avatar::renderHead(bool lookingInMirror) {
glEnable(GL_RESCALE_NORMAL); glEnable(GL_RESCALE_NORMAL);
// show head orientation // show head orientation
//renderOrientationDirections( _joint[ AVATAR_JOINT_HEAD_BASE ].springyPosition, _joint[ AVATAR_JOINT_HEAD_BASE ].orientation, 0.2f ); //renderOrientationDirections(_joint[ AVATAR_JOINT_HEAD_BASE ].springyPosition, _joint[ AVATAR_JOINT_HEAD_BASE ].orientation, 0.2f );
glPushMatrix(); glPushMatrix();
@ -868,7 +879,7 @@ void Avatar::renderHead(bool lookingInMirror) {
} }
glScalef glScalef
( (
_joint[ AVATAR_JOINT_HEAD_BASE ].radius, _joint[ AVATAR_JOINT_HEAD_BASE ].radius,
_joint[ AVATAR_JOINT_HEAD_BASE ].radius, _joint[ AVATAR_JOINT_HEAD_BASE ].radius,
_joint[ AVATAR_JOINT_HEAD_BASE ].radius _joint[ AVATAR_JOINT_HEAD_BASE ].radius
@ -880,15 +891,15 @@ void Avatar::renderHead(bool lookingInMirror) {
//glRotatef(_bodyPitch + _headPitch, 1, 0, 0); //glRotatef(_bodyPitch + _headPitch, 1, 0, 0);
//glRotatef(_bodyRoll - _headRoll, 0, 0, 1); //glRotatef(_bodyRoll - _headRoll, 0, 0, 1);
// don't let body pitch and roll affect the head.. // don't let body pitch and roll affect the head..
glRotatef( _headPitch, 1, 0, 0); glRotatef( _headPitch, 1, 0, 0);
glRotatef( -_headRoll, 0, 0, 1); glRotatef(-_headRoll, 0, 0, 1);
} else { } else {
glRotatef(_bodyYaw + _headYaw, 0, 1, 0); glRotatef(_bodyYaw + _headYaw, 0, 1, 0);
//glRotatef(_bodyPitch + _headPitch, 1, 0, 0); //glRotatef(_bodyPitch + _headPitch, 1, 0, 0);
//glRotatef(_bodyRoll + _headRoll, 0, 0, 1); //glRotatef(_bodyRoll + _headRoll, 0, 0, 1);
// don't let body pitch and roll affect the head.. // don't let body pitch and roll affect the head..
glRotatef( _headPitch, 1, 0, 0); glRotatef(_headPitch, 1, 0, 0);
glRotatef( _headRoll, 0, 0, 1); glRotatef(_headRoll, 0, 0, 1);
} }
//glScalef(2.0, 2.0, 2.0); //glScalef(2.0, 2.0, 2.0);
@ -1017,7 +1028,7 @@ void Avatar::renderHead(bool lookingInMirror) {
glPopMatrix(); glPopMatrix();
} }
void Avatar::setHandMovementValues( glm::vec3 handOffset ) { void Avatar::setHandMovementValues(glm::vec3 handOffset ) {
_movedHandOffset = handOffset; _movedHandOffset = handOffset;
} }
@ -1030,11 +1041,11 @@ void Avatar::initializeSkeleton() {
for (int b=0; b<NUM_AVATAR_JOINTS; b++) { for (int b=0; b<NUM_AVATAR_JOINTS; b++) {
_joint[b].isCollidable = true; _joint[b].isCollidable = true;
_joint[b].parent = AVATAR_JOINT_NULL; _joint[b].parent = AVATAR_JOINT_NULL;
_joint[b].position = glm::vec3( 0.0, 0.0, 0.0 ); _joint[b].position = glm::vec3(0.0, 0.0, 0.0 );
_joint[b].defaultPosePosition = glm::vec3( 0.0, 0.0, 0.0 ); _joint[b].defaultPosePosition = glm::vec3(0.0, 0.0, 0.0 );
_joint[b].springyPosition = glm::vec3( 0.0, 0.0, 0.0 ); _joint[b].springyPosition = glm::vec3(0.0, 0.0, 0.0 );
_joint[b].springyVelocity = glm::vec3( 0.0, 0.0, 0.0 ); _joint[b].springyVelocity = glm::vec3(0.0, 0.0, 0.0 );
_joint[b].rotation = glm::quat( 0.0f, 0.0f, 0.0f, 0.0f ); _joint[b].rotation = glm::quat(0.0f, 0.0f, 0.0f, 0.0f );
_joint[b].yaw = 0.0; _joint[b].yaw = 0.0;
_joint[b].pitch = 0.0; _joint[b].pitch = 0.0;
_joint[b].roll = 0.0; _joint[b].roll = 0.0;
@ -1071,19 +1082,19 @@ void Avatar::initializeSkeleton() {
_joint[ AVATAR_JOINT_RIGHT_TOES ].parent = AVATAR_JOINT_RIGHT_HEEL; _joint[ AVATAR_JOINT_RIGHT_TOES ].parent = AVATAR_JOINT_RIGHT_HEEL;
// specify the default pose position // specify the default pose position
_joint[ AVATAR_JOINT_PELVIS ].defaultPosePosition = glm::vec3( 0.0, 0.0, 0.0 ); _joint[ AVATAR_JOINT_PELVIS ].defaultPosePosition = glm::vec3( 0.0, 0.0, 0.0 );
_joint[ AVATAR_JOINT_TORSO ].defaultPosePosition = glm::vec3( 0.0, 0.08, 0.01 ); _joint[ AVATAR_JOINT_TORSO ].defaultPosePosition = glm::vec3( 0.0, 0.08, 0.01 );
_joint[ AVATAR_JOINT_CHEST ].defaultPosePosition = glm::vec3( 0.0, 0.09, 0.0 ); _joint[ AVATAR_JOINT_CHEST ].defaultPosePosition = glm::vec3( 0.0, 0.09, 0.0 );
_joint[ AVATAR_JOINT_NECK_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.1, -0.01 ); _joint[ AVATAR_JOINT_NECK_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.1, -0.01 );
_joint[ AVATAR_JOINT_HEAD_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.08, 0.01 ); _joint[ AVATAR_JOINT_HEAD_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.08, 0.01 );
_joint[ AVATAR_JOINT_LEFT_COLLAR ].defaultPosePosition = glm::vec3( -0.06, 0.04, -0.01 ); _joint[ AVATAR_JOINT_LEFT_COLLAR ].defaultPosePosition = glm::vec3(-0.06, 0.04, -0.01 );
_joint[ AVATAR_JOINT_LEFT_SHOULDER ].defaultPosePosition = glm::vec3( -0.03, 0.0, -0.01 ); _joint[ AVATAR_JOINT_LEFT_SHOULDER ].defaultPosePosition = glm::vec3(-0.03, 0.0, -0.01 );
_joint[ AVATAR_JOINT_LEFT_ELBOW ].defaultPosePosition = glm::vec3( 0.0, -0.13, 0.0 ); _joint[ AVATAR_JOINT_LEFT_ELBOW ].defaultPosePosition = glm::vec3( 0.0, -0.13, 0.0 );
_joint[ AVATAR_JOINT_LEFT_WRIST ].defaultPosePosition = glm::vec3( 0.0, -0.11, 0.0 ); _joint[ AVATAR_JOINT_LEFT_WRIST ].defaultPosePosition = glm::vec3( 0.0, -0.11, 0.0 );
_joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.07, 0.0 ); _joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.07, 0.0 );
_joint[ AVATAR_JOINT_RIGHT_COLLAR ].defaultPosePosition = glm::vec3( 0.06, 0.04, -0.01 ); _joint[ AVATAR_JOINT_RIGHT_COLLAR ].defaultPosePosition = glm::vec3( 0.06, 0.04, -0.01 );
_joint[ AVATAR_JOINT_RIGHT_SHOULDER ].defaultPosePosition = glm::vec3( 0.03, 0.0, -0.01 ); _joint[ AVATAR_JOINT_RIGHT_SHOULDER ].defaultPosePosition = glm::vec3( 0.03, 0.0, -0.01 );
_joint[ AVATAR_JOINT_RIGHT_ELBOW ].defaultPosePosition = glm::vec3( 0.0, -0.13, 0.0 ); _joint[ AVATAR_JOINT_RIGHT_ELBOW ].defaultPosePosition = glm::vec3( 0.0, -0.13, 0.0 );
_joint[ AVATAR_JOINT_RIGHT_WRIST ].defaultPosePosition = glm::vec3( 0.0, -0.11, 0.0 ); _joint[ AVATAR_JOINT_RIGHT_WRIST ].defaultPosePosition = glm::vec3( 0.0, -0.11, 0.0 );
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.07, 0.0 ); _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.07, 0.0 );
_joint[ AVATAR_JOINT_LEFT_HIP ].defaultPosePosition = glm::vec3( -0.04, 0.0, -0.02 ); _joint[ AVATAR_JOINT_LEFT_HIP ].defaultPosePosition = glm::vec3( -0.04, 0.0, -0.02 );
@ -1276,7 +1287,7 @@ void Avatar::updateBodySprings( float deltaTime ) {
_joint[b].springyVelocity = glm::vec3( 0.0f, 0.0f, 0.0f ); _joint[b].springyVelocity = glm::vec3( 0.0f, 0.0f, 0.0f );
} }
_joint[b].springyPosition += _joint[b].springyVelocity; _joint[b].springyPosition += _joint[b].springyVelocity * deltaTime;
} }
} }
@ -1520,25 +1531,7 @@ void Avatar::setHeadFromGyros(glm::vec3* eulerAngles, glm::vec3* angularVelocity
} }
} }
// Find and return the gravity vector at my location
glm::vec3 Avatar::getGravity(glm::vec3 pos) {
//
// For now, we'll test this with a simple global lookup, but soon we will add getting this
// from the domain/voxelserver (or something similar)
//
if ((pos.x > 0.f) &&
(pos.x < 10.f) &&
(pos.z > 0.f) &&
(pos.z < 10.f) &&
(pos.y > 0.f) &&
(pos.y < 3.f)) {
// If above ground plane, turn gravity on
return glm::vec3(0.f, -1.f, 0.f);
} else {
// If flying in space, turn gravity OFF
return glm::vec3(0.f, 0.f, 0.f);
}
}
const char AVATAR_DATA_FILENAME[] = "avatar.ifd"; const char AVATAR_DATA_FILENAME[] = "avatar.ifd";
@ -1568,3 +1561,4 @@ void Avatar::readAvatarDataFromFile() {
fclose(avatarFile); fclose(avatarFile);
} }
} }

View file

@ -84,7 +84,7 @@ public:
void reset(); void reset();
void UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity); void UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity);
void setNoise (float mag) { _head.noise = mag; } void setNoise (float mag) {_head.noise = mag;}
void setScale(float s) {_head.scale = s; }; void setScale(float s) {_head.scale = s; };
void setRenderYaw(float y) {_renderYaw = y;} void setRenderYaw(float y) {_renderYaw = y;}
void setRenderPitch(float p) {_renderPitch = p;} void setRenderPitch(float p) {_renderPitch = p;}
@ -93,6 +93,7 @@ public:
float getLastMeasuredHeadYaw() const {return _head.yawRate;} float getLastMeasuredHeadYaw() const {return _head.yawRate;}
float getBodyYaw() {return _bodyYaw;}; float getBodyYaw() {return _bodyYaw;};
void addBodyYaw(float y) {_bodyYaw += y;}; void addBodyYaw(float y) {_bodyYaw += y;};
void setGravity(glm::vec3 gravity);
bool getIsNearInteractingOther(); bool getIsNearInteractingOther();
@ -143,9 +144,6 @@ public:
void processTransmitterData(unsigned char * packetData, int numBytes); void processTransmitterData(unsigned char * packetData, int numBytes);
float getTransmitterHz() { return _transmitterHz; }; float getTransmitterHz() { return _transmitterHz; };
// Find out what the local gravity vector is at this location
glm::vec3 getGravity(glm::vec3 pos);
void writeAvatarDataToFile(); void writeAvatarDataToFile();
void readAvatarDataFromFile(); void readAvatarDataFromFile();
@ -251,6 +249,7 @@ private:
bool _displayingHead; // should be false if in first-person view bool _displayingHead; // should be false if in first-person view
bool _returnHeadToCenter; bool _returnHeadToCenter;
float _distanceToNearestAvatar; // How close is the nearest avatar? float _distanceToNearestAvatar; // How close is the nearest avatar?
glm::vec3 _gravity;
// private methods... // private methods...
void initializeSkeleton(); void initializeSkeleton();

View file

@ -11,13 +11,11 @@
#include "AvatarRenderer.h" #include "AvatarRenderer.h"
#include "InterfaceConfig.h" #include "InterfaceConfig.h"
AvatarRenderer::AvatarRenderer() { AvatarRenderer::AvatarRenderer() {
} }
// this method renders the avatar // this method renders the avatar
void AvatarRenderer::render(Avatar *avatar, bool lookingInMirror) { void AvatarRenderer::render(Avatar *avatar, bool lookingInMirror) {
/* /*
// show avatar position // show avatar position
glColor4f( 0.5f, 0.5f, 0.5f, 0.6 ); glColor4f( 0.5f, 0.5f, 0.5f, 0.6 );
@ -27,6 +25,4 @@ void AvatarRenderer::render(Avatar *avatar, bool lookingInMirror) {
glutSolidSphere( 1, 10, 10 ); glutSolidSphere( 1, 10, 10 );
glPopMatrix(); glPopMatrix();
*/ */
} }

View file

@ -22,7 +22,6 @@
#include <string> #include <string>
#endif #endif
int serialFd;
const int MAX_BUFFER = 255; const int MAX_BUFFER = 255;
char serialBuffer[MAX_BUFFER]; char serialBuffer[MAX_BUFFER];
int serialBufferPos = 0; int serialBufferPos = 0;
@ -32,6 +31,12 @@ const short NO_READ_MAXIMUM_MSECS = 3000;
const short SAMPLES_TO_DISCARD = 100; // Throw out the first few samples const short SAMPLES_TO_DISCARD = 100; // Throw out the first few samples
const int GRAVITY_SAMPLES = 200; // Use the first samples to compute gravity vector const int GRAVITY_SAMPLES = 200; // Use the first samples to compute gravity vector
const bool USING_INVENSENSE_MPU9150 = 1;
SerialInterface::~SerialInterface() {
close(_serialDescriptor);
}
void SerialInterface::pair() { void SerialInterface::pair() {
#ifdef __APPLE__ #ifdef __APPLE__
@ -41,43 +46,47 @@ void SerialInterface::pair() {
int matchStatus; int matchStatus;
regex_t regex; regex_t regex;
// for now this only works on OS X, where the usb serial shows up as /dev/tty.usb* if (_failedOpenAttempts < 2) {
if((devDir = opendir("/dev"))) { // if we've already failed to open the detected interface twice then don't try again
while((entry = readdir(devDir))) {
regcomp(&regex, "tty\\.usb", REG_EXTENDED|REG_NOSUB); // for now this only works on OS X, where the usb serial shows up as /dev/tty.usb*
matchStatus = regexec(&regex, entry->d_name, (size_t) 0, NULL, 0); if((devDir = opendir("/dev"))) {
if (matchStatus == 0) { while((entry = readdir(devDir))) {
char *serialPortname = new char[100]; regcomp(&regex, "tty\\.usb", REG_EXTENDED|REG_NOSUB);
sprintf(serialPortname, "/dev/%s", entry->d_name); matchStatus = regexec(&regex, entry->d_name, (size_t) 0, NULL, 0);
if (matchStatus == 0) {
initializePort(serialPortname, 115200); char *serialPortname = new char[100];
sprintf(serialPortname, "/dev/%s", entry->d_name);
delete [] serialPortname;
initializePort(serialPortname, 115200);
delete [] serialPortname;
}
regfree(&regex);
} }
regfree(&regex); closedir(devDir);
} }
closedir(devDir);
} }
#endif
#endif
} }
// Connect to the serial port // connect to the serial port
int SerialInterface::initializePort(char* portname, int baud) void SerialInterface::initializePort(char* portname, int baud) {
{
#ifdef __APPLE__ #ifdef __APPLE__
serialFd = open(portname, O_RDWR | O_NOCTTY | O_NDELAY); _serialDescriptor = open(portname, O_RDWR | O_NOCTTY | O_NDELAY);
printLog("Opening SerialUSB %s: ", portname); printLog("Opening SerialUSB %s: ", portname);
if (serialFd == -1) { if (_serialDescriptor == -1) {
printLog("Failed.\n"); printLog("Failed.\n");
return -1; // Failed to open port _failedOpenAttempts++;
return;
} }
struct termios options; struct termios options;
tcgetattr(serialFd,&options); tcgetattr(_serialDescriptor, &options);
switch(baud)
{ switch(baud) {
case 9600: cfsetispeed(&options,B9600); case 9600: cfsetispeed(&options,B9600);
cfsetospeed(&options,B9600); cfsetospeed(&options,B9600);
break; break;
@ -94,20 +103,39 @@ int SerialInterface::initializePort(char* portname, int baud)
cfsetospeed(&options,B9600); cfsetospeed(&options,B9600);
break; break;
} }
options.c_cflag |= (CLOCAL | CREAD); options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB; options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE; options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8; options.c_cflag |= CS8;
tcsetattr(serialFd,TCSANOW,&options); tcsetattr(_serialDescriptor, TCSANOW, &options);
if (USING_INVENSENSE_MPU9150) {
// block on invensense reads until there is data to read
int currentFlags = fcntl(_serialDescriptor, F_GETFL);
fcntl(_serialDescriptor, F_SETFL, currentFlags & ~O_NONBLOCK);
// there are extra commands to send to the invensense when it fires up
// this takes it out of SLEEP
write(_serialDescriptor, "WR686B01\n", 9);
// delay after the wakeup
usleep(10000);
// this disables streaming so there's no garbage data on reads
write(_serialDescriptor, "SD\n", 3);
// flush whatever was produced by the last two commands
tcflush(_serialDescriptor, TCIOFLUSH);
}
printLog("Connected.\n"); printLog("Connected.\n");
resetSerial(); resetSerial();
active = true; active = true;
#endif #endif
return 0;
} }
// Reset Trailing averages to the current measurement // Reset Trailing averages to the current measurement
@ -121,9 +149,7 @@ void SerialInterface::renderLevels(int width, int height) {
int disp_x = 10; int disp_x = 10;
const int GAP = 16; const int GAP = 16;
char val[10]; char val[10];
for(i = 0; i < NUM_CHANNELS; i++) for(i = 0; i < NUM_CHANNELS; i++) {
{
// Actual value // Actual value
glLineWidth(2.0); glLineWidth(2.0);
glColor4f(1, 1, 1, 1); glColor4f(1, 1, 1, 1);
@ -157,62 +183,89 @@ void SerialInterface::renderLevels(int width, int height) {
} }
glEnd(); glEnd();
} }
}
void convertHexToInt(unsigned char* sourceBuffer, int& destinationInt) {
unsigned int byte[2];
for(int i = 0; i < 2; i++) {
sscanf((char*) sourceBuffer + 2 * i, "%2x", &byte[i]);
}
int16_t result = (byte[0] << 8);
result += byte[1];
destinationInt = result;
} }
void SerialInterface::readData() { void SerialInterface::readData() {
#ifdef __APPLE__ #ifdef __APPLE__
// This array sets the rate of trailing averaging for each channel:
// If the sensor rate is 100Hz, 0.001 will make the long term average a 10-second average
const float AVG_RATE[] = {0.002, 0.002, 0.002, 0.002, 0.002, 0.002};
char bufchar[1];
int initialSamples = totalSamples; int initialSamples = totalSamples;
while (read(serialFd, &bufchar, 1) > 0) { if (USING_INVENSENSE_MPU9150) {
serialBuffer[serialBufferPos] = bufchar[0]; unsigned char gyroBuffer[20];
serialBufferPos++;
// Have we reached end of a line of input? // ask the invensense for raw gyro data
if ((bufchar[0] == '\n') || (serialBufferPos >= MAX_BUFFER)) { write(_serialDescriptor, "RD684306\n", 9);
std::string serialLine(serialBuffer, serialBufferPos-1); read(_serialDescriptor, gyroBuffer, 20);
//printLog("%s\n", serialLine.c_str());
int spot; convertHexToInt(gyroBuffer + 6, _lastYaw);
//int channel = 0; convertHexToInt(gyroBuffer + 10, _lastRoll);
std::string val; convertHexToInt(gyroBuffer + 14, _lastPitch);
for (int i = 0; i < NUM_CHANNELS + 2; i++) {
spot = serialLine.find_first_of(" ", 0); totalSamples++;
if (spot != std::string::npos) { } else {
val = serialLine.substr(0,spot); // This array sets the rate of trailing averaging for each channel:
//printLog("%s\n", val.c_str()); // If the sensor rate is 100Hz, 0.001 will make the long term average a 10-second average
if (i < NUM_CHANNELS) lastMeasured[i] = atoi(val.c_str()); const float AVG_RATE[] = {0.002, 0.002, 0.002, 0.002, 0.002, 0.002};
else samplesAveraged = atoi(val.c_str()); char bufchar[1];
} else LED = atoi(serialLine.c_str());
serialLine = serialLine.substr(spot+1, serialLine.length() - spot - 1); while (read(_serialDescriptor, &bufchar, 1) > 0) {
} serialBuffer[serialBufferPos] = bufchar[0];
serialBufferPos++;
// Update Trailing Averages // Have we reached end of a line of input?
for (int i = 0; i < NUM_CHANNELS; i++) { if ((bufchar[0] == '\n') || (serialBufferPos >= MAX_BUFFER)) {
if (totalSamples > SAMPLES_TO_DISCARD) { std::string serialLine(serialBuffer, serialBufferPos-1);
trailingAverage[i] = (1.f - AVG_RATE[i])*trailingAverage[i] + //printLog("%s\n", serialLine.c_str());
AVG_RATE[i]*(float)lastMeasured[i]; int spot;
} else { //int channel = 0;
trailingAverage[i] = (float)lastMeasured[i]; std::string val;
for (int i = 0; i < NUM_CHANNELS + 2; i++) {
spot = serialLine.find_first_of(" ", 0);
if (spot != std::string::npos) {
val = serialLine.substr(0,spot);
//printLog("%s\n", val.c_str());
if (i < NUM_CHANNELS) lastMeasured[i] = atoi(val.c_str());
else samplesAveraged = atoi(val.c_str());
} else LED = atoi(serialLine.c_str());
serialLine = serialLine.substr(spot+1, serialLine.length() - spot - 1);
} }
// Update Trailing Averages
for (int i = 0; i < NUM_CHANNELS; i++) {
if (totalSamples > SAMPLES_TO_DISCARD) {
trailingAverage[i] = (1.f - AVG_RATE[i])*trailingAverage[i] +
AVG_RATE[i]*(float)lastMeasured[i];
} else {
trailingAverage[i] = (float)lastMeasured[i];
}
}
// Use a set of initial samples to compute gravity
if (totalSamples < GRAVITY_SAMPLES) {
gravity.x += lastMeasured[ACCEL_X];
gravity.y += lastMeasured[ACCEL_Y];
gravity.z += lastMeasured[ACCEL_Z];
}
if (totalSamples == GRAVITY_SAMPLES) {
gravity = glm::normalize(gravity);
printLog("gravity: %f,%f,%f\n", gravity.x, gravity.y, gravity.z);
}
totalSamples++;
serialBufferPos = 0;
} }
// Use a set of initial samples to compute gravity
if (totalSamples < GRAVITY_SAMPLES) {
gravity.x += lastMeasured[ACCEL_X];
gravity.y += lastMeasured[ACCEL_Y];
gravity.z += lastMeasured[ACCEL_Z];
}
if (totalSamples == GRAVITY_SAMPLES) {
gravity = glm::normalize(gravity);
printLog("gravity: %f,%f,%f\n", gravity.x, gravity.y, gravity.z);
}
totalSamples++;
serialBufferPos = 0;
} }
} }
@ -234,19 +287,23 @@ void SerialInterface::resetSerial() {
#ifdef __APPLE__ #ifdef __APPLE__
active = false; active = false;
totalSamples = 0; totalSamples = 0;
gravity = glm::vec3(0,-1,0);
gettimeofday(&lastGoodRead, NULL); gettimeofday(&lastGoodRead, NULL);
// Clear the measured and average channel data if (!USING_INVENSENSE_MPU9150) {
for (int i = 0; i < NUM_CHANNELS; i++) { gravity = glm::vec3(0, -1, 0);
lastMeasured[i] = 0;
trailingAverage[i] = 0.0; // Clear the measured and average channel data
} for (int i = 0; i < NUM_CHANNELS; i++) {
// Clear serial input buffer lastMeasured[i] = 0;
for (int i = 1; i < MAX_BUFFER; i++) { trailingAverage[i] = 0.0;
serialBuffer[i] = ' '; }
// Clear serial input buffer
for (int i = 1; i < MAX_BUFFER; i++) {
serialBuffer[i] = ' ';
}
} }
#endif #endif
} }

View file

@ -32,24 +32,37 @@
#define HEAD_YAW_RATE 0 #define HEAD_YAW_RATE 0
#define HEAD_ROLL_RATE 2 #define HEAD_ROLL_RATE 2
extern const bool USING_INVENSENSE_MPU9150;
class SerialInterface { class SerialInterface {
public: public:
SerialInterface() { active = false; }; SerialInterface() : active(false),
_failedOpenAttempts(0) {}
~SerialInterface();
void pair(); void pair();
void readData(); void readData();
int getLastYaw() const { return _lastYaw; }
int getLastPitch() const { return _lastPitch; }
int getLastRoll() const { return _lastRoll; }
int getLED() {return LED;}; int getLED() {return LED;};
int getNumSamples() {return samplesAveraged;}; int getNumSamples() {return samplesAveraged;};
int getValue(int num) {return lastMeasured[num];}; int getValue(int num) {return lastMeasured[num];};
int getRelativeValue(int num) {return static_cast<int>(lastMeasured[num] - trailingAverage[num]);}; int getRelativeValue(int num) {return static_cast<int>(lastMeasured[num] - trailingAverage[num]);};
float getTrailingValue(int num) {return trailingAverage[num];}; float getTrailingValue(int num) {return trailingAverage[num];};
void resetTrailingAverages(); void resetTrailingAverages();
void renderLevels(int width, int height); void renderLevels(int width, int height);
bool active; bool active;
glm::vec3 getGravity() {return gravity;}; glm::vec3 getGravity() {return gravity;};
private: private:
int initializePort(char * portname, int baud); void initializePort(char* portname, int baud);
void resetSerial(); void resetSerial();
int _serialDescriptor;
int lastMeasured[NUM_CHANNELS]; int lastMeasured[NUM_CHANNELS];
float trailingAverage[NUM_CHANNELS]; float trailingAverage[NUM_CHANNELS];
int samplesAveraged; int samplesAveraged;
@ -57,6 +70,10 @@ private:
int totalSamples; int totalSamples;
timeval lastGoodRead; timeval lastGoodRead;
glm::vec3 gravity; glm::vec3 gravity;
int _lastYaw;
int _lastPitch;
int _lastRoll;
int _failedOpenAttempts;
}; };
#endif #endif

View file

@ -237,6 +237,36 @@ void drawGroundPlaneGrid(float size)
} }
void renderDiskShadow(glm::vec3 position, glm::vec3 upDirection, float radius, float darkness) {
glColor4f( 0.0f, 0.0f, 0.0f, darkness );
int num = 20;
float y = 0.001f;
float x2 = 0.0f;
float z2 = radius;
float x1;
float z1;
glBegin(GL_TRIANGLES);
for (int i=1; i<num+1; i++) {
x1 = x2;
z1 = z2;
float r = ((float)i / (float)num) * PI * 2.0;
x2 = radius * sin(r);
z2 = radius * cos(r);
glVertex3f(position.x, y, position.z );
glVertex3f(position.x + x1, y, position.z + z1);
glVertex3f(position.x + x2, y, position.z + z2);
}
glEnd();
}
void renderOrientationDirections( glm::vec3 position, Orientation orientation, float size ) { void renderOrientationDirections( glm::vec3 position, Orientation orientation, float size ) {
glm::vec3 pRight = position + orientation.getRight() * size; glm::vec3 pRight = position + orientation.getRight() * size;
glm::vec3 pUp = position + orientation.getUp() * size; glm::vec3 pUp = position + orientation.getUp() * size;

View file

@ -44,6 +44,8 @@ double diffclock(timeval *clock1,timeval *clock2);
void drawGroundPlaneGrid(float size); void drawGroundPlaneGrid(float size);
void renderDiskShadow(glm::vec3 position, glm::vec3 upDirection, float radius, float darkness);
void renderOrientationDirections( glm::vec3 position, Orientation orientation, float size ); void renderOrientationDirections( glm::vec3 position, Orientation orientation, float size );

View file

@ -69,7 +69,6 @@
#include "Camera.h" #include "Camera.h"
#include "Avatar.h" #include "Avatar.h"
#include "AvatarRenderer.h"
#include "Texture.h" #include "Texture.h"
#include <AgentList.h> #include <AgentList.h>
#include <AgentTypes.h> #include <AgentTypes.h>
@ -91,6 +90,8 @@ using namespace std;
void reshape(int width, int height); // will be defined below void reshape(int width, int height); // will be defined below
void loadViewFrustum(ViewFrustum& viewFrustum); // will be defined below void loadViewFrustum(ViewFrustum& viewFrustum); // will be defined below
glm::vec3 getGravity(glm::vec3 pos); //get the local gravity vector at this location in the universe
QApplication* app; QApplication* app;
bool enableNetworkThread = true; bool enableNetworkThread = true;
@ -120,9 +121,6 @@ Avatar myAvatar(true); // The rendered avatar of oneself
Camera myCamera; // My view onto the world (sometimes on myself :) 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 Camera viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode
AvatarRenderer avatarRenderer;
// Starfield information // Starfield information
char starFile[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; char starFile[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt";
char starCacheFile[] = "cachedStars.txt"; char starCacheFile[] = "cachedStars.txt";
@ -208,8 +206,7 @@ bool justStarted = true;
// Every second, check the frame rates and other stuff // Every second, check the frame rates and other stuff
void Timer(int extra) void Timer(int extra) {
{
gettimeofday(&timerEnd, NULL); gettimeofday(&timerEnd, NULL);
FPS = (float)frameCount / ((float)diffclock(&timerStart, &timerEnd) / 1000.f); FPS = (float)frameCount / ((float)diffclock(&timerStart, &timerEnd) / 1000.f);
packetsPerSecond = (float)packetCount / ((float)diffclock(&timerStart, &timerEnd) / 1000.f); packetsPerSecond = (float)packetCount / ((float)diffclock(&timerStart, &timerEnd) / 1000.f);
@ -227,8 +224,7 @@ void Timer(int extra)
} }
} }
void displayStats(void) void displayStats(void) {
{
int statsVerticalOffset = 50; int statsVerticalOffset = 50;
if (::menuOn == 0) { if (::menuOn == 0) {
statsVerticalOffset = 8; statsVerticalOffset = 8;
@ -269,6 +265,7 @@ void displayStats(void)
Agent *avatarMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER); Agent *avatarMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER);
char avatarMixerStats[200]; char avatarMixerStats[200];
if (avatarMixer) { if (avatarMixer) {
sprintf(avatarMixerStats, "Avatar Mixer: %.f kbps, %.f pps", sprintf(avatarMixerStats, "Avatar Mixer: %.f kbps, %.f pps",
roundf(avatarMixer->getAverageKilobitsPerSecond()), roundf(avatarMixer->getAverageKilobitsPerSecond()),
@ -276,6 +273,7 @@ void displayStats(void)
} else { } else {
sprintf(avatarMixerStats, "No Avatar Mixer"); sprintf(avatarMixerStats, "No Avatar Mixer");
} }
drawtext(10, statsVerticalOffset + 330, 0.10f, 0, 1.0, 0, avatarMixerStats); drawtext(10, statsVerticalOffset + 330, 0.10f, 0, 1.0, 0, avatarMixerStats);
if (::perfStatsOn) { if (::perfStatsOn) {
@ -293,8 +291,7 @@ void displayStats(void)
} }
} }
void initDisplay(void) void initDisplay(void) {
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@ -306,8 +303,7 @@ void initDisplay(void)
if (fullscreen) glutFullScreen(); if (fullscreen) glutFullScreen();
} }
void init(void) void init(void) {
{
voxels.init(); voxels.init();
voxels.setViewerAvatar(&myAvatar); voxels.setViewerAvatar(&myAvatar);
voxels.setCamera(&myCamera); voxels.setCamera(&myCamera);
@ -360,8 +356,7 @@ void terminate () {
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
void reset_sensors() void reset_sensors() {
{
myAvatar.setPosition(start_location); myAvatar.setPosition(start_location);
headMouseX = WIDTH/2; headMouseX = WIDTH/2;
@ -377,16 +372,13 @@ void reset_sensors()
// //
// Using gyro data, update both view frustum and avatar head position // Using gyro data, update both view frustum and avatar head position
// //
void updateAvatar(float frametime) void updateAvatar(float frametime) {
{
float gyroPitchRate = serialPort.getRelativeValue(HEAD_PITCH_RATE); float gyroPitchRate = serialPort.getRelativeValue(HEAD_PITCH_RATE);
float gyroYawRate = serialPort.getRelativeValue(HEAD_YAW_RATE ); float gyroYawRate = serialPort.getRelativeValue(HEAD_YAW_RATE );
myAvatar.UpdateGyros(frametime, &serialPort, &gravity); myAvatar.UpdateGyros(frametime, &serialPort, &gravity);
//
// Update gyro-based mouse (X,Y on screen) // Update gyro-based mouse (X,Y on screen)
//
const float MIN_MOUSE_RATE = 30.0; const float MIN_MOUSE_RATE = 30.0;
const float MOUSE_SENSITIVITY = 0.1f; const float MOUSE_SENSITIVITY = 0.1f;
if (powf(gyroYawRate*gyroYawRate + if (powf(gyroYawRate*gyroYawRate +
@ -401,7 +393,7 @@ void updateAvatar(float frametime)
headMouseY = min(headMouseY, HEIGHT); headMouseY = min(headMouseY, HEIGHT);
// Update head and body pitch and yaw based on measured gyro rates // Update head and body pitch and yaw based on measured gyro rates
if (::gyroLook) { if (::gyroLook) {
// Yaw // Yaw
const float MIN_YAW_RATE = 50; const float MIN_YAW_RATE = 50;
const float YAW_SENSITIVITY = 1.0; const float YAW_SENSITIVITY = 1.0;
@ -720,7 +712,6 @@ void displaySide(Camera& whichCamera) {
if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) {
Avatar *avatar = (Avatar *)agent->getLinkedData(); Avatar *avatar = (Avatar *)agent->getLinkedData();
avatar->render(0); avatar->render(0);
//avatarRenderer.render(avatar, 0); // this will replace the above call
} }
} }
agentList->unlock(); agentList->unlock();
@ -733,7 +724,6 @@ void displaySide(Camera& whichCamera) {
//Render my own avatar //Render my own avatar
myAvatar.render(::lookingInMirror); myAvatar.render(::lookingInMirror);
//avatarRenderer.render(&myAvatar, lookingInMirror); // this will replace the above call
glPopMatrix(); glPopMatrix();
} }
@ -1017,7 +1007,7 @@ void display(void)
float firstPersonTightness = 100.0f; float firstPersonTightness = 100.0f;
float thirdPersonPitch = 0.0f; float thirdPersonPitch = 0.0f;
float thirdPersonUpShift = -0.1f; float thirdPersonUpShift = -0.2f;
float thirdPersonDistance = 1.2f; float thirdPersonDistance = 1.2f;
float thirdPersonTightness = 8.0f; float thirdPersonTightness = 8.0f;
@ -1692,6 +1682,10 @@ void idle(void) {
handControl.stop(); handControl.stop();
} }
if (serialPort.active && USING_INVENSENSE_MPU9150) {
serialPort.readData();
}
// Sample hardware, update view frustum if needed, Lsend avatar data to mixer/agents // Sample hardware, update view frustum if needed, Lsend avatar data to mixer/agents
updateAvatar(deltaTime); updateAvatar(deltaTime);
@ -1711,6 +1705,7 @@ void idle(void) {
} }
agentList->unlock(); agentList->unlock();
myAvatar.setGravity(getGravity(myAvatar.getPosition()));
myAvatar.simulate(deltaTime); myAvatar.simulate(deltaTime);
glutPostRedisplay(); glutPostRedisplay();
@ -1718,7 +1713,7 @@ void idle(void) {
} }
// Read serial data // Read serial data
if (serialPort.active) { if (serialPort.active && !USING_INVENSENSE_MPU9150) {
serialPort.readData(); serialPort.readData();
} }
} }
@ -1773,6 +1768,30 @@ void reshape(int width, int height) {
glLoadIdentity(); glLoadIdentity();
} }
//Find and return the gravity vector at this location
glm::vec3 getGravity(glm::vec3 pos) {
//
// For now, we'll test this with a simple global lookup, but soon we will add getting this
// from the domain/voxelserver (or something similar)
//
if ((pos.x > 0.f) &&
(pos.x < 10.f) &&
(pos.z > 0.f) &&
(pos.z < 10.f) &&
(pos.y > 0.f) &&
(pos.y < 3.f)) {
// If above ground plane, turn gravity on
return glm::vec3(0.f, -1.f, 0.f);
} else {
// If flying in space, turn gravity OFF
return glm::vec3(0.f, 0.f, 0.f);
}
}
void mouseFunc(int button, int state, int x, int y) { void mouseFunc(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN ) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN ) {
if (state == GLUT_DOWN && !menu.mouseClick(x, y)) { if (state == GLUT_DOWN && !menu.mouseClick(x, y)) {

View file

@ -52,8 +52,8 @@ Agent::Agent(sockaddr *agentPublicSocket, sockaddr *agentLocalSocket, char agent
type = agentType; type = agentType;
agentId = thisAgentId; agentId = thisAgentId;
firstRecvTimeUsecs = usecTimestampNow(); _wakeMicrostamp = usecTimestampNow();
lastRecvTimeUsecs = usecTimestampNow(); _lastHeardMicrostamp = usecTimestampNow();
activeSocket = NULL; activeSocket = NULL;
linkedData = NULL; linkedData = NULL;
@ -87,8 +87,8 @@ Agent::Agent(const Agent &otherAgent) {
activeSocket = NULL; activeSocket = NULL;
} }
firstRecvTimeUsecs = otherAgent.firstRecvTimeUsecs; _wakeMicrostamp = otherAgent._wakeMicrostamp;
lastRecvTimeUsecs = otherAgent.lastRecvTimeUsecs; _lastHeardMicrostamp = otherAgent._lastHeardMicrostamp;
type = otherAgent.type; type = otherAgent.type;
if (otherAgent.linkedData != NULL) { if (otherAgent.linkedData != NULL) {
@ -120,8 +120,8 @@ void Agent::swap(Agent &first, Agent &second) {
swap(first.type, second.type); swap(first.type, second.type);
swap(first.linkedData, second.linkedData); swap(first.linkedData, second.linkedData);
swap(first.agentId, second.agentId); swap(first.agentId, second.agentId);
swap(first.firstRecvTimeUsecs, second.firstRecvTimeUsecs); swap(first._wakeMicrostamp, second._wakeMicrostamp);
swap(first.lastRecvTimeUsecs, second.lastRecvTimeUsecs); swap(first._lastHeardMicrostamp, second._lastHeardMicrostamp);
swap(first._bytesReceivedMovingAverage, second._bytesReceivedMovingAverage); swap(first._bytesReceivedMovingAverage, second._bytesReceivedMovingAverage);
} }
@ -178,22 +178,6 @@ void Agent::setAgentId(uint16_t thisAgentId) {
agentId = thisAgentId; agentId = thisAgentId;
} }
double Agent::getFirstRecvTimeUsecs() {
return firstRecvTimeUsecs;
}
void Agent::setFirstRecvTimeUsecs(double newTimeUsecs) {
firstRecvTimeUsecs = newTimeUsecs;
}
double Agent::getLastRecvTimeUsecs() {
return lastRecvTimeUsecs;
}
void Agent::setLastRecvTimeUsecs(double newTimeUsecs) {
lastRecvTimeUsecs = newTimeUsecs;
}
sockaddr* Agent::getPublicSocket() { sockaddr* Agent::getPublicSocket() {
return publicSocket; return publicSocket;
} }

View file

@ -38,11 +38,11 @@ public:
uint16_t getAgentId(); uint16_t getAgentId();
void setAgentId(uint16_t thisAgentId); void setAgentId(uint16_t thisAgentId);
double getFirstRecvTimeUsecs(); double getWakeMicrostamp() const { return _wakeMicrostamp; }
void setFirstRecvTimeUsecs(double newTimeUsecs); void setWakeMicrostamp(double wakeMicrostamp) { _wakeMicrostamp = wakeMicrostamp; }
double getLastRecvTimeUsecs(); double getLastHeardMicrostamp() const { return _lastHeardMicrostamp; }
void setLastRecvTimeUsecs(double newTimeUsecs); void setLastHeardMicrostamp(double lastHeardMicrostamp) { _lastHeardMicrostamp = lastHeardMicrostamp; }
sockaddr* getPublicSocket(); sockaddr* getPublicSocket();
void setPublicSocket(sockaddr *newSocket); void setPublicSocket(sockaddr *newSocket);
@ -70,8 +70,8 @@ private:
sockaddr *publicSocket, *localSocket, *activeSocket; sockaddr *publicSocket, *localSocket, *activeSocket;
char type; char type;
uint16_t agentId; uint16_t agentId;
double firstRecvTimeUsecs; double _wakeMicrostamp;
double lastRecvTimeUsecs; double _lastHeardMicrostamp;
SimpleMovingAverage* _bytesReceivedMovingAverage; SimpleMovingAverage* _bytesReceivedMovingAverage;
AgentData* linkedData; AgentData* linkedData;
bool _isAlive; bool _isAlive;

View file

@ -64,8 +64,7 @@ AgentList::AgentList(char newOwnerType, unsigned int newSocketListenPort) :
agentSocket(newSocketListenPort), agentSocket(newSocketListenPort),
ownerType(newOwnerType), ownerType(newOwnerType),
socketListenPort(newSocketListenPort), socketListenPort(newSocketListenPort),
lastAgentId(0) lastAgentId(0) {
{
pthread_mutex_init(&mutex, 0); pthread_mutex_init(&mutex, 0);
} }
@ -114,7 +113,7 @@ void AgentList::processBulkAgentData(sockaddr *senderAddress, unsigned char *pac
Agent* bulkSendAgent = agentWithAddress(senderAddress); Agent* bulkSendAgent = agentWithAddress(senderAddress);
if (bulkSendAgent) { if (bulkSendAgent) {
bulkSendAgent->setLastRecvTimeUsecs(usecTimestampNow()); bulkSendAgent->setLastHeardMicrostamp(usecTimestampNow());
bulkSendAgent->recordBytesReceived(numTotalBytes); bulkSendAgent->recordBytesReceived(numTotalBytes);
} }
@ -161,7 +160,7 @@ int AgentList::updateAgentWithData(sockaddr *senderAddress, unsigned char *packe
} }
int AgentList::updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes) { int AgentList::updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes) {
agent->setLastRecvTimeUsecs(usecTimestampNow()); agent->setLastHeardMicrostamp(usecTimestampNow());
if (agent->getActiveSocket() != NULL) { if (agent->getActiveSocket() != NULL) {
agent->recordBytesReceived(dataBytes); agent->recordBytesReceived(dataBytes);
@ -273,7 +272,7 @@ bool AgentList::addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket,
if (agent->getType() == AGENT_TYPE_AUDIO_MIXER || agent->getType() == AGENT_TYPE_VOXEL) { if (agent->getType() == AGENT_TYPE_AUDIO_MIXER || agent->getType() == AGENT_TYPE_VOXEL) {
// until the Audio class also uses our agentList, we need to update // until the Audio class also uses our agentList, we need to update
// the lastRecvTimeUsecs for the audio mixer so it doesn't get killed and re-added continously // the lastRecvTimeUsecs for the audio mixer so it doesn't get killed and re-added continously
agent->setLastRecvTimeUsecs(usecTimestampNow()); agent->setLastHeardMicrostamp(usecTimestampNow());
} }
// we had this agent already, do nothing for now // we had this agent already, do nothing for now
@ -383,7 +382,7 @@ void *removeSilentAgents(void *args) {
for(AgentList::iterator agent = agentList->begin(); agent != agentList->end(); ++agent) { for(AgentList::iterator agent = agentList->begin(); agent != agentList->end(); ++agent) {
if ((checkTimeUSecs - agent->getLastRecvTimeUsecs()) > AGENT_SILENCE_THRESHOLD_USECS if ((checkTimeUSecs - agent->getLastHeardMicrostamp()) > AGENT_SILENCE_THRESHOLD_USECS
&& agent->getType() != AGENT_TYPE_VOXEL) { && agent->getType() != AGENT_TYPE_VOXEL) {
printLog("Killing agent - "); printLog("Killing agent - ");
@ -418,13 +417,6 @@ void *checkInWithDomainServer(void *args) {
const int DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000; const int DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000;
AgentList* parentAgentList = (AgentList*) args;
timeval lastSend;
unsigned char output[7];
in_addr_t localAddress = getLocalAddress();
// Lookup the IP address of the domain server if we need to // Lookup the IP address of the domain server if we need to
if (atoi(DOMAIN_IP) == 0) { if (atoi(DOMAIN_IP) == 0) {
struct hostent* pHostInfo; struct hostent* pHostInfo;
@ -439,14 +431,23 @@ void *checkInWithDomainServer(void *args) {
} }
} else printLog("Using static domainserver IP: %s\n", DOMAIN_IP); } else printLog("Using static domainserver IP: %s\n", DOMAIN_IP);
AgentList* parentAgentList = (AgentList*) args;
timeval lastSend;
in_addr_t localAddress = getLocalAddress();
unsigned char packet[8];
packet[0] = PACKET_HEADER_DOMAIN_RFD;
packet[1] = parentAgentList->getOwnerType();
while (!domainServerCheckinStopFlag) { while (!domainServerCheckinStopFlag) {
gettimeofday(&lastSend, NULL); gettimeofday(&lastSend, NULL);
output[0] = parentAgentList->getOwnerType(); packSocket(packet + 2, localAddress, htons(parentAgentList->getSocketListenPort()));
packSocket(output + 1, localAddress, htons(parentAgentList->getSocketListenPort()));
parentAgentList->getAgentSocket().send(DOMAIN_IP, DOMAINSERVER_PORT, output, 7); parentAgentList->getAgentSocket().send(DOMAIN_IP, DOMAINSERVER_PORT, packet, sizeof(packet));
packet[0] = PACKET_HEADER_DOMAIN_LIST_REQUEST;
double usecToSleep = DOMAIN_SERVER_CHECK_IN_USECS - (usecTimestampNow() - usecTimestamp(&lastSend)); double usecToSleep = DOMAIN_SERVER_CHECK_IN_USECS - (usecTimestampNow() - usecTimestamp(&lastSend));
@ -481,7 +482,8 @@ AgentList::iterator AgentList::begin() const {
} }
} }
return AgentListIterator(this, 0); // there's no alive agent to start from - return the end
return end();
} }
AgentList::iterator AgentList::end() const { AgentList::iterator AgentList::end() const {

View file

@ -1,3 +1,4 @@
// //
// PacketHeaders.h // PacketHeaders.h
// hifi // hifi
@ -23,5 +24,7 @@ const char PACKET_HEADER_ERASE_VOXEL = 'E';
const char PACKET_HEADER_VOXEL_DATA = 'V'; const char PACKET_HEADER_VOXEL_DATA = 'V';
const char PACKET_HEADER_BULK_AVATAR_DATA = 'X'; const char PACKET_HEADER_BULK_AVATAR_DATA = 'X';
const char PACKET_HEADER_TRANSMITTER_DATA = 't'; const char PACKET_HEADER_TRANSMITTER_DATA = 't';
const char PACKET_HEADER_DOMAIN_LIST_REQUEST = 'L';
const char PACKET_HEADER_DOMAIN_RFD = 'C';
#endif #endif

View file

@ -8,6 +8,8 @@
// Simple axis aligned box class. // Simple axis aligned box class.
// //
#include "SharedUtil.h"
#include "AABox.h" #include "AABox.h"
@ -68,3 +70,50 @@ glm::vec3 AABox::getVertexN(const glm::vec3 &normal) const {
return(res); return(res);
} }
// determines whether a value is within the extents
static bool isWithin(float value, float corner, float size) {
return value >= corner && value <= corner + size;
}
bool AABox::contains(const glm::vec3& point) const {
return isWithin(point.x, _corner.x, _size.x) &&
isWithin(point.y, _corner.y, _size.y) &&
isWithin(point.z, _corner.z, _size.z);
}
// finds the intersection between a ray and the facing plane on one axis
static bool findIntersection(float origin, float direction, float corner, float size, float& distance) {
if (direction > EPSILON) {
distance = (corner - origin) / direction;
return true;
} else if (direction < -EPSILON) {
distance = (corner + size - origin) / direction;
return true;
}
return false;
}
bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
// handle the trivial case where the box contains the origin
if (contains(origin)) {
distance = 0;
return true;
}
// check each axis
float axisDistance;
if (findIntersection(origin.x, direction.x, _corner.x, _size.x, axisDistance) && axisDistance >= 0 &&
isWithin(origin.y + axisDistance*direction.y, _corner.y, _size.y) &&
isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z) ||
findIntersection(origin.y, direction.y, _corner.y, _size.y, axisDistance) && axisDistance >= 0 &&
isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x) &&
isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z) ||
findIntersection(origin.z, direction.z, _corner.z, _size.z, axisDistance) && axisDistance >= 0 &&
isWithin(origin.y + axisDistance*direction.y, _corner.y, _size.y) &&
isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x)) {
distance = axisDistance;
return true;
}
return false;
}

View file

@ -36,6 +36,9 @@ public:
const glm::vec3& getSize() const { return _size; }; const glm::vec3& getSize() const { return _size; };
const glm::vec3& getCenter() const { return _center; }; const glm::vec3& getCenter() const { return _center; };
bool contains(const glm::vec3& point) const;
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
private: private:
glm::vec3 _corner; glm::vec3 _corner;
glm::vec3 _center; glm::vec3 _center;
@ -43,4 +46,4 @@ private:
}; };
#endif #endif

View file

@ -238,3 +238,7 @@ bool ViewFrustum::matches(const ViewFrustum& compareTo) const {
void ViewFrustum::computePickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const {
origin = _nearTopLeft + x*(_nearTopRight - _nearTopLeft) + y*(_nearBottomLeft - _nearTopLeft);
direction = glm::normalize(origin - _position);
}

View file

@ -101,7 +101,7 @@ public:
// some frustum comparisons // some frustum comparisons
bool matches(const ViewFrustum& compareTo) const; bool matches(const ViewFrustum& compareTo) const;
bool matches(const ViewFrustum* compareTo) const { return matches(*compareTo); }; bool matches(const ViewFrustum* compareTo) const { return matches(*compareTo); };
void computePickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const;
}; };

View file

@ -546,7 +546,41 @@ int VoxelTree::searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const
return levelReached; return levelReached;
} }
// combines the ray cast arguments into a single object
class RayArgs {
public:
glm::vec3 origin;
glm::vec3 direction;
VoxelNode*& node;
float& distance;
bool found;
};
bool findRayOperation(VoxelNode* node, void* extraData) {
RayArgs* args = static_cast<RayArgs*>(extraData);
AABox box;
node->getAABox(box);
float distance;
if (!box.findRayIntersection(args->origin, args->direction, distance)) {
return false;
}
if (!node->isLeaf()) {
return true; // recurse on children
}
if (!args->found || distance < args->distance) {
args->node = node;
args->distance = distance;
args->found = true;
}
return false;
}
bool VoxelTree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, VoxelNode*& node, float& distance)
{
RayArgs args = { origin / (float)TREE_SCALE, direction, node, distance };
recurseTreeWithOperation(findRayOperation, &args);
return args.found;
}
int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel, int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel,
VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) { VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) {

View file

@ -62,6 +62,8 @@ public:
void clearDirtyBit() { _isDirty = false; }; void clearDirtyBit() { _isDirty = false; };
unsigned long int getNodesChangedFromBitstream() const { return _nodesChangedFromBitstream; }; unsigned long int getNodesChangedFromBitstream() const { return _nodesChangedFromBitstream; };
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, VoxelNode*& node, float& distance);
// Note: this assumes the fileFormat is the HIO individual voxels code files // Note: this assumes the fileFormat is the HIO individual voxels code files
void loadVoxelsFile(const char* fileName, bool wantColorRandomizer); void loadVoxelsFile(const char* fileName, bool wantColorRandomizer);