Jeffrey Ventrellacleaned up some codeab9fa0a13 years agoHistory
1629 lines · 65.6 KB · C++
RawDownload
////  Avatar.cpp//  interface////  Created by Philip Rosedale on 9/11/12.//	adapted by Jeffrey Ventrella//  Copyright (c) 2013 Physical, Inc.. All rights reserved. #include <glm/glm.hpp>#include <vector>#include <lodepng.h>#include <SharedUtil.h>#include "Avatar.h"#include "Head.h"#include "Log.h"#include "ui/TextRenderer.h"#include <AgentList.h>#include <AgentTypes.h>#include <PacketHeaders.h> using namespace std; const bool  BALLS_ON                      = false;const bool  USING_AVATAR_GRAVITY          = true;const float GRAVITY_SCALE                 = 10.0f;const float BOUNCE                        = 0.3f;const float THRUST_MAG                    = 1200.0;const float YAW_MAG                       = 500.0;const float BODY_SPIN_FRICTION            = 5.0;const float BODY_UPRIGHT_FORCE            = 10.0;const float BODY_PITCH_WHILE_WALKING      = 40.0;const float BODY_ROLL_WHILE_TURNING       = 0.1;const float VELOCITY_DECAY                = 5.0;const float MY_HAND_HOLDING_PULL          = 0.2;const float YOUR_HAND_HOLDING_PULL        = 1.0;const float BODY_SPRING_DEFAULT_TIGHTNESS = 1500.0f;const float BODY_SPRING_FORCE             = 300.0f;const float BODY_SPRING_DECAY             = 16.0f;const float COLLISION_RADIUS_SCALAR       = 1.8;const float COLLISION_BALL_FORCE          = 1.0;const float COLLISION_BODY_FORCE          = 6.0;const float COLLISION_BALL_FRICTION       = 60.0;const float COLLISION_BODY_FRICTION       = 0.5;const float HEAD_ROTATION_SCALE           = 0.70;const float HEAD_ROLL_SCALE               = 0.40;const float HEAD_MAX_PITCH                = 45;const float HEAD_MIN_PITCH                = -45;const float HEAD_MAX_YAW                  = 85;const float HEAD_MIN_YAW                  = -85;const float AVATAR_BRAKING_RANGE          = 1.6f;const float AVATAR_BRAKING_STRENGTH       = 30.0f; float skinColor [] = {1.0, 0.84, 0.66};float lightBlue [] = {0.7, 0.8, 1.0}; /*float browColor [] = {210.0/255.0, 105.0/255.0, 30.0/255.0};float mouthColor[] = {1, 0, 0}; float BrowRollAngle [5] = {0, 15, 30, -30, -15};float BrowPitchAngle[3] = {-70, -60, -50};float eyeColor      [3] = {1,1,1}; float MouthWidthChoices[3] = {0.5, 0.77, 0.3}; float browWidth = 0.8;float browThickness = 0.16;  //char iris_texture_file[] = "resources/images/green_eye.png";*/bool usingBigSphereCollisionTest = true; float chatMessageScale = 0.0015;float chatMessageHeight = 0.45; /*vector<unsigned char> iris_texture;unsigned int iris_texture_width = 512;unsigned int iris_texture_height = 256;*/ Avatar::Avatar(bool isMine) {        _orientation.setToIdentity();        _velocity                   = glm::vec3(0.0f, 0.0f, 0.0f);    _thrust                     = glm::vec3(0.0f, 0.0f, 0.0f);    _rotation                   = glm::quat(0.0f, 0.0f, 0.0f, 0.0f);    _bodyYaw                    = -90.0;    _bodyPitch                  = 0.0;    _bodyRoll                   = 0.0;    _bodyPitchDelta             = 0.0;    _bodyYawDelta               = 0.0;    _bodyRollDelta              = 0.0;    _mousePressed               = false;    _mode                       = AVATAR_MODE_STANDING;    _isMine                     = isMine;    _maxArmLength               = 0.0;    _transmitterHz              = 0.0;    _transmitterPackets         = 0;    _transmitterIsFirstData     = true;    _transmitterInitialReading  = glm::vec3(0.f, 0.f, 0.f);    _speed                      = 0.0;    _pelvisStandingHeight       = 0.0f;    _displayingHead             = true;    _TEST_bigSphereRadius       = 0.4f;    _TEST_bigSpherePosition     = glm::vec3(5.0f, _TEST_bigSphereRadius, 5.0f);        for (int i = 0; i < MAX_DRIVE_KEYS; i++) _driveKeys[i] = false;        _head.initialize();            _movedHandOffset            = glm::vec3(0.0f, 0.0f, 0.0f);    _renderYaw                  = 0.0;    _renderPitch                = 0.0;    _sphere                     = NULL;    _handHoldingPosition        = glm::vec3(0.0f, 0.0f, 0.0f);    _distanceToNearestAvatar    = std::numeric_limits<float>::max();    _gravity                    = glm::vec3(0.0f, -1.0f, 0.0f); // default     initializeSkeleton();        _avatarTouch.setReachableRadius(0.6);      /*      if (iris_texture.size() == 0) {        switchToResourcesParentIfRequired();        unsigned error = lodepng::decode(iris_texture, iris_texture_width, iris_texture_height, iris_texture_file);        if (error != 0) {            printLog("error %u: %s\n", error, lodepng_error_text(error));        }    }*/        if (BALLS_ON)   { _balls = new Balls(100); }    else            { _balls = NULL; }} Avatar::Avatar(const Avatar &otherAvatar) {        _velocity                    = otherAvatar._velocity;    _thrust                      = otherAvatar._thrust;    _rotation                    = otherAvatar._rotation;    _bodyYaw                     = otherAvatar._bodyYaw;    _bodyPitch                   = otherAvatar._bodyPitch;    _bodyRoll                    = otherAvatar._bodyRoll;    _bodyPitchDelta              = otherAvatar._bodyPitchDelta;    _bodyYawDelta                = otherAvatar._bodyYawDelta;    _bodyRollDelta               = otherAvatar._bodyRollDelta;    _mousePressed                = otherAvatar._mousePressed;    _mode                        = otherAvatar._mode;    _isMine                      = otherAvatar._isMine;    _renderYaw                   = otherAvatar._renderYaw;    _renderPitch                 = otherAvatar._renderPitch;    _maxArmLength                = otherAvatar._maxArmLength;    _transmitterTimer            = otherAvatar._transmitterTimer;    _transmitterIsFirstData      = otherAvatar._transmitterIsFirstData;    _transmitterTimeLastReceived = otherAvatar._transmitterTimeLastReceived;    _transmitterHz               = otherAvatar._transmitterHz;    _transmitterInitialReading   = otherAvatar._transmitterInitialReading;    _transmitterPackets          = otherAvatar._transmitterPackets;    _TEST_bigSphereRadius        = otherAvatar._TEST_bigSphereRadius;    _TEST_bigSpherePosition      = otherAvatar._TEST_bigSpherePosition;    _movedHandOffset             = otherAvatar._movedHandOffset;        _orientation.set(otherAvatar._orientation);        _sphere = NULL;        initializeSkeleton();        for (int i = 0; i < MAX_DRIVE_KEYS; i++) _driveKeys[i] = otherAvatar._driveKeys[i];        _head.pupilSize          = otherAvatar._head.pupilSize;    _head.interPupilDistance = otherAvatar._head.interPupilDistance;    _head.interBrowDistance  = otherAvatar._head.interBrowDistance;    _head.nominalPupilSize   = otherAvatar._head.nominalPupilSize;    _head.yawRate            = otherAvatar._head.yawRate;    _head.pitchRate          = otherAvatar._head.pitchRate;    _head.rollRate           = otherAvatar._head.rollRate;    _head.eyebrowPitch[0]    = otherAvatar._head.eyebrowPitch[0];    _head.eyebrowPitch[1]    = otherAvatar._head.eyebrowPitch[1];    _head.eyebrowRoll [0]    = otherAvatar._head.eyebrowRoll [0];    _head.eyebrowRoll [1]    = otherAvatar._head.eyebrowRoll [1];    _head.mouthPitch         = otherAvatar._head.mouthPitch;    _head.mouthYaw           = otherAvatar._head.mouthYaw;    _head.mouthWidth         = otherAvatar._head.mouthWidth;    _head.mouthHeight        = otherAvatar._head.mouthHeight;    _head.eyeballPitch[0]    = otherAvatar._head.eyeballPitch[0];    _head.eyeballPitch[1]    = otherAvatar._head.eyeballPitch[1];    _head.eyeballScaleX      = otherAvatar._head.eyeballScaleX;    _head.eyeballScaleY      = otherAvatar._head.eyeballScaleY;    _head.eyeballScaleZ      = otherAvatar._head.eyeballScaleZ;    _head.eyeballYaw[0]      = otherAvatar._head.eyeballYaw[0];    _head.eyeballYaw[1]      = otherAvatar._head.eyeballYaw[1];    _head.pitchTarget        = otherAvatar._head.pitchTarget;    _head.yawTarget          = otherAvatar._head.yawTarget;    _head.noiseEnvelope      = otherAvatar._head.noiseEnvelope;    _head.pupilConverge      = otherAvatar._head.pupilConverge;    _head.leanForward        = otherAvatar._head.leanForward;    _head.leanSideways       = otherAvatar._head.leanSideways;    _head.eyeContact         = otherAvatar._head.eyeContact;    _head.eyeContactTarget   = otherAvatar._head.eyeContactTarget;    _head.scale              = otherAvatar._head.scale;    _head.audioAttack        = otherAvatar._head.audioAttack;    _head.averageLoudness    = otherAvatar._head.averageLoudness;    _head.lastLoudness       = otherAvatar._head.lastLoudness;    _head.browAudioLift      = otherAvatar._head.browAudioLift;    _head.noise              = otherAvatar._head.noise;    _distanceToNearestAvatar = otherAvatar._distanceToNearestAvatar;        initializeSkeleton(); /*    if (iris_texture.size() == 0) {        switchToResourcesParentIfRequired();        unsigned error = lodepng::decode(iris_texture, iris_texture_width, iris_texture_height, iris_texture_file);        if (error != 0) {            printLog("error %u: %s\n", error, lodepng_error_text(error));        }    }*/} Avatar::~Avatar()  {    if (_sphere != NULL) {        gluDeleteQuadric(_sphere);    }} Avatar* Avatar::clone() const {    return new Avatar(*this);} void Avatar::reset() {    _headPitch = _headYaw = _headRoll = 0;    _head.leanForward = _head.leanSideways = 0;}  //  Update avatar head rotation with sensor datavoid Avatar::updateHeadFromGyros(float deltaTime, SerialInterface* serialInterface, glm::vec3* gravity) {    float measuredPitchRate = 0.0f;    float measuredRollRate = 0.0f;    float measuredYawRate = 0.0f;        measuredPitchRate = serialInterface->getLastPitchRate();    measuredYawRate = serialInterface->getLastYawRate();    measuredRollRate = serialInterface->getLastRollRate();       //  Update avatar head position based on measured gyro rates    const float MAX_PITCH = 45;    const float MIN_PITCH = -45;    const float MAX_YAW = 85;    const float MIN_YAW = -85;    const float MAX_ROLL = 50;    const float MIN_ROLL = -50;        addHeadPitch(measuredPitchRate * deltaTime);    addHeadYaw(measuredYawRate * deltaTime);    addHeadRoll(measuredRollRate * deltaTime);        setHeadPitch(glm::clamp(getHeadPitch(), MIN_PITCH, MAX_PITCH));    setHeadYaw(glm::clamp(getHeadYaw(), MIN_YAW, MAX_YAW));    setHeadRoll(glm::clamp(getHeadRoll(), MIN_ROLL, MAX_ROLL));        //  Update head lean distance based on accelerometer data    const float LEAN_SENSITIVITY = 0.15;    const float LEAN_MAX = 0.45;    const float LEAN_AVERAGING = 10.0;    glm::vec3 headRotationRates(getHeadPitch(), getHeadYaw(), getHeadRoll());    float headRateMax = 50.f;            glm::vec3 leaning = (serialInterface->getLastAcceleration() -  serialInterface->getGravity())                        * LEAN_SENSITIVITY                        * (1.f - fminf(glm::length(headRotationRates), headRateMax) / headRateMax);    leaning.y = 0.f;    if (glm::length(leaning) < LEAN_MAX) {        _head.leanForward = _head.leanForward * (1.f - LEAN_AVERAGING * deltaTime) +                                (LEAN_AVERAGING * deltaTime) * leaning.z * LEAN_SENSITIVITY;        _head.leanSideways = _head.leanSideways * (1.f - LEAN_AVERAGING * deltaTime) +                                (LEAN_AVERAGING * deltaTime) * leaning.x * LEAN_SENSITIVITY;    }    setHeadLeanSideways(_head.leanSideways);    setHeadLeanForward(_head.leanForward); } float Avatar::getAbsoluteHeadYaw() const {    return _bodyYaw + _headYaw;} float Avatar::getAbsoluteHeadPitch() const {    return _bodyPitch + _headPitch;} void Avatar::addLean(float x, float z) {    //Add lean as impulse    _head.leanSideways += x;    _head.leanForward  += z;} void Avatar::setLeanForward(float dist){    _head.leanForward = dist;} void Avatar::setLeanSideways(float dist){    _head.leanSideways = dist;} void Avatar::setMousePressed(bool mousePressed) {	_mousePressed = mousePressed;} bool Avatar::getIsNearInteractingOther() {     return _avatarTouch.getAbleToReachOtherAvatar(); } void Avatar::simulate(float deltaTime) {        // update balls    if (_balls) { _balls->simulate(deltaTime); }        // if other avatar, update head position from network data    	// update avatar skeleton	updateSkeleton();	    //detect and respond to collisions with other avatars...     if (_isMine) {        updateAvatarCollisions(deltaTime);    }        //update the movement of the hand and process handshaking with other avatars...     updateHandMovementAndTouching(deltaTime);        _avatarTouch.simulate(deltaTime);                // apply gravity and collision with the ground/floor    if (USING_AVATAR_GRAVITY) {        if (_position.y > _pelvisStandingHeight + 0.01f) {            _velocity += _gravity * (GRAVITY_SCALE * deltaTime);        } else if (_position.y < _pelvisStandingHeight) {            _position.y = _pelvisStandingHeight;            _velocity.y = -_velocity.y * BOUNCE;        }    }    	// update body springs    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)    if (_isMine) {                _thrust = glm::vec3(0.0f, 0.0f, 0.0f);                     if (_driveKeys[FWD      ]) {_thrust       += THRUST_MAG * deltaTime * _orientation.getFront();}        if (_driveKeys[BACK     ]) {_thrust       -= THRUST_MAG * deltaTime * _orientation.getFront();}        if (_driveKeys[RIGHT    ]) {_thrust       += THRUST_MAG * deltaTime * _orientation.getRight();}        if (_driveKeys[LEFT     ]) {_thrust       -= THRUST_MAG * deltaTime * _orientation.getRight();}        if (_driveKeys[UP       ]) {_thrust       += THRUST_MAG * deltaTime * _orientation.getUp();}        if (_driveKeys[DOWN     ]) {_thrust       -= THRUST_MAG * deltaTime * _orientation.getUp();}        if (_driveKeys[ROT_RIGHT]) {_bodyYawDelta -= YAW_MAG    * deltaTime;}        if (_driveKeys[ROT_LEFT ]) {_bodyYawDelta += YAW_MAG    * deltaTime;}	}            // update body yaw by body yaw delta    if (_isMine) {        _bodyPitch += _bodyPitchDelta * deltaTime;        _bodyYaw   += _bodyYawDelta   * deltaTime;        _bodyRoll  += _bodyRollDelta  * deltaTime;    }    	// decay body rotation momentum    float bodySpinMomentum = 1.0 - BODY_SPIN_FRICTION * deltaTime;    if  (bodySpinMomentum < 0.0f) { bodySpinMomentum = 0.0f; }     _bodyPitchDelta *= bodySpinMomentum;    _bodyYawDelta   *= bodySpinMomentum;    _bodyRollDelta  *= bodySpinMomentum;        	// add thrust to velocity	_velocity += _thrust * deltaTime;        // calculate speed                                 _speed = glm::length(_velocity);        //pitch and roll the body as a function of forward speed and turning delta    float forwardComponentOfVelocity = glm::dot(_orientation.getFront(), _velocity);    _bodyPitch += BODY_PITCH_WHILE_WALKING * deltaTime * forwardComponentOfVelocity;    _bodyRoll  += BODY_ROLL_WHILE_TURNING  * deltaTime * _speed * _bodyYawDelta;        	// these forces keep the body upright...         float tiltDecay = 1.0 - BODY_UPRIGHT_FORCE * deltaTime;    if  (tiltDecay < 0.0f) {tiltDecay = 0.0f;}         _bodyPitch *= tiltDecay;    _bodyRoll  *= tiltDecay;        //the following will be used to make the avatar upright no matter what gravity is    //float f = angleBetween(_orientation.getUp(), _gravity);        // update position by velocity    _position += _velocity * deltaTime; 	// decay velocity    float decay = 1.0 - VELOCITY_DECAY * deltaTime;    if ( decay < 0.0 ) {        _velocity = glm::vec3( 0.0f, 0.0f, 0.0f );    } else {        _velocity *= decay;    }        // If another avatar is near, dampen velocity as a function of closeness    if (_isMine && (_distanceToNearestAvatar < AVATAR_BRAKING_RANGE)) {            float closeness = 1.0f - (_distanceToNearestAvatar / AVATAR_BRAKING_RANGE);        float drag = 1.0f - closeness * AVATAR_BRAKING_STRENGTH * deltaTime;        if ( drag > 0.0f ) {            _velocity *= drag;        } else {            _velocity = glm::vec3( 0.0f, 0.0f, 0.0f );        }    }                     // Get head position data from network for other people    if (!_isMine) {        _head.leanSideways = getHeadLeanSideways();        _head.leanForward = getHeadLeanForward();     }        //apply the head lean values to the springy position...    if (fabs(_head.leanSideways + _head.leanForward) > 0.0f) {        glm::vec3 headLean =             _orientation.getRight() * _head.leanSideways +            _orientation.getFront() * _head.leanForward;         // this is not a long-term solution, but it works ok for initial purposes of making the avatar lean        _joint[ AVATAR_JOINT_TORSO            ].springyPosition += headLean * 0.1f;        _joint[ AVATAR_JOINT_CHEST            ].springyPosition += headLean * 0.4f;        _joint[ AVATAR_JOINT_NECK_BASE        ].springyPosition += headLean * 0.7f;        _joint[ AVATAR_JOINT_HEAD_BASE        ].springyPosition += headLean * 1.0f;                _joint[ AVATAR_JOINT_LEFT_COLLAR      ].springyPosition += headLean * 0.6f;        _joint[ AVATAR_JOINT_LEFT_SHOULDER    ].springyPosition += headLean * 0.6f;        _joint[ AVATAR_JOINT_LEFT_ELBOW       ].springyPosition += headLean * 0.2f;        _joint[ AVATAR_JOINT_LEFT_WRIST       ].springyPosition += headLean * 0.1f;        _joint[ AVATAR_JOINT_LEFT_FINGERTIPS  ].springyPosition += headLean * 0.0f;                _joint[ AVATAR_JOINT_RIGHT_COLLAR     ].springyPosition += headLean * 0.6f;        _joint[ AVATAR_JOINT_RIGHT_SHOULDER   ].springyPosition += headLean * 0.6f;        _joint[ AVATAR_JOINT_RIGHT_ELBOW      ].springyPosition += headLean * 0.2f;        _joint[ AVATAR_JOINT_RIGHT_WRIST      ].springyPosition += headLean * 0.1f;        _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].springyPosition += headLean * 0.0f;    }         // update head state    _head.setPositionRotationAndScale(        _joint[ AVATAR_JOINT_HEAD_BASE ].springyPosition,         glm::vec3(_headYaw, _headPitch, _headRoll),         _joint[ AVATAR_JOINT_HEAD_BASE ].radius     );        _head.setAudioLoudness(_audioLoudness);    _head.setSkinColor(glm::vec3(skinColor[0], skinColor[1], skinColor[2]));    _head.simulate(deltaTime, _isMine);        // use speed and angular velocity to determine walking vs. standing                                	if (_speed + fabs(_bodyYawDelta) > 0.2) {		_mode = AVATAR_MODE_WALKING;	} else {		_mode = AVATAR_MODE_INTERACTING;	}} void Avatar::updateHandMovementAndTouching(float deltaTime) {     // reset hand and arm positions according to hand movement    glm::vec3 transformedHandMovement    = _orientation.getRight() *  _movedHandOffset.x * 2.0f    + _orientation.getUp()	  * -_movedHandOffset.y * 1.0f    + _orientation.getFront() * -_movedHandOffset.y * 1.0f;        _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position += transformedHandMovement;                if (_isMine)    {        _avatarTouch.setMyBodyPosition(_position);                Avatar * _interactingOther = NULL;        float closestDistance = std::numeric_limits<float>::max();    

Lines 1–500 of 1629.