diff --git a/eve/src/main.cpp b/eve/src/main.cpp index a06ec4981e..9ebffec7e9 100644 --- a/eve/src/main.cpp +++ b/eve/src/main.cpp @@ -113,7 +113,8 @@ int main(int argc, const char* argv[]) { // move eve away from the origin // pick a random point inside a 10x10 grid - eve.setPosition(glm::vec3(randFloatInRange(-RANDOM_POSITION_MAX_DIMENSION, RANDOM_POSITION_MAX_DIMENSION), 0.4, + eve.setPosition(glm::vec3(randFloatInRange(-RANDOM_POSITION_MAX_DIMENSION, RANDOM_POSITION_MAX_DIMENSION), + 0.32, // this is the same as the pelvis standing height (as of 4/26/13) randFloatInRange(-RANDOM_POSITION_MAX_DIMENSION, RANDOM_POSITION_MAX_DIMENSION))); // face any instance of eve down the z-axis @@ -121,7 +122,7 @@ int main(int argc, const char* argv[]) { // put her hand out so somebody can shake it eve.setHandPosition(glm::vec3(eve.getPosition()[0] - 0.2, - 0.32, // this is the same as the pelvis standing height (as of 4/26/13) + 0.25, eve.getPosition()[2] + 0.1)); // read eve's audio data AudioInjector eveAudioInjector("/etc/highfidelity/eve/resources/eve.raw"); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index b52e7484e1..cfb6fb9f6a 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -4,7 +4,7 @@ // // Created by Philip Rosedale on 9/11/12. // adapted by Jeffrey Ventrella -// Copyright (c) 2012 Physical, Inc.. All rights reserved. +// Copyright (c) 2013 Physical, Inc.. All rights reserved. // #include @@ -20,11 +20,15 @@ using namespace std; +/* const bool BALLS_ON = false; const bool AVATAR_GRAVITY = true; const float DECAY = 0.1; -const float THRUST_MAG = 1200.0; + +//const float THRUST_MAG = 1200.0; +const float THRUST_MAG = 0.0; + const float YAW_MAG = 500.0; //JJV - changed from 300.0; const float TEST_YAW_DECAY = 5.0; const float LIN_VEL_DECAY = 5.0; @@ -32,17 +36,13 @@ const float MY_HAND_HOLDING_PULL = 0.2; const float YOUR_HAND_HOLDING_PULL = 1.0; const float BODY_SPRING_FORCE = 6.0f; const float BODY_SPRING_DECAY = 16.0f; -//const float COLLISION_FRICTION = 0.5; -//const float COLLISION_RADIUS_SCALAR = 1.8; -//const float COLLISION_BALL_FORCE = 0.1; -//const float COLLISION_BODY_FORCE = 3.0; - const float COLLISION_RADIUS_SCALAR = 1.8; const float COLLISION_BALL_FORCE = 0.6; const float COLLISION_BODY_FORCE = 6.0; const float COLLISION_BALL_FRICTION = 200.0; const float COLLISION_BODY_FRICTION = 0.5; - +*/ + 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}; @@ -78,7 +78,9 @@ Avatar::Avatar(bool isMine) { _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; @@ -138,9 +140,9 @@ Avatar::Avatar(bool isMine) { _renderPitch = 0.0; _sphere = NULL; _interactingOther = NULL; - _interactingOtherIsNearby = false; + //_canReachToOtherAvatar = false; _handHoldingPosition = glm::vec3( 0.0, 0.0, 0.0 ); - + initializeSkeleton(); if (iris_texture.size() == 0) { @@ -155,17 +157,18 @@ Avatar::Avatar(bool isMine) { else { _balls = NULL; } } - Avatar::Avatar(const Avatar &otherAvatar) { _velocity = otherAvatar._velocity; _thrust = otherAvatar._thrust; _rotation = otherAvatar._rotation; - _interactingOtherIsNearby = otherAvatar._interactingOtherIsNearby; + //_canReachToOtherAvatar = otherAvatar._canReachToOtherAvatar; _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; @@ -182,6 +185,7 @@ Avatar::Avatar(const Avatar &otherAvatar) { _TEST_bigSpherePosition = otherAvatar._TEST_bigSpherePosition; _movedHandOffset = otherAvatar._movedHandOffset; _usingBodySprings = otherAvatar._usingBodySprings; + _orientation.set( otherAvatar._orientation ); _sphere = NULL; @@ -227,7 +231,6 @@ Avatar::Avatar(const Avatar &otherAvatar) { _head.browAudioLift = otherAvatar._head.browAudioLift; _head.noise = otherAvatar._head.noise; - initializeSkeleton(); if (iris_texture.size() == 0) { @@ -318,8 +321,22 @@ void Avatar::setMousePressed( bool d ) { } +bool Avatar::getIsNearInteractingOther() { + return _avatarTouch.getAbleToReachOtherAvatar(); +} + + void Avatar::simulate(float deltaTime) { - + +//keep this - I'm still using it to test things.... +/* +//TEST +static float tt = 0.0f; +tt += deltaTime * 2.0f; +//_head.leanSideways = 0.01 * sin( tt ); +_head.leanForward = 0.02 * sin( tt * 0.8 ); +*/ + // update balls if (_balls) { _balls->simulate(deltaTime); } @@ -329,19 +346,19 @@ void Avatar::simulate(float deltaTime) { // reset hand and arm positions according to hand movement updateHandMovement( deltaTime ); - if ( !_interactingOtherIsNearby ) { + if ( !_avatarTouch.getAbleToReachOtherAvatar() ) { //initialize _handHolding _handHoldingPosition = _bone[ AVATAR_BONE_RIGHT_HAND ].position; } - _interactingOtherIsNearby = false; + //reset these for the next go-round + _avatarTouch.setAbleToReachOtherAvatar (false); + _avatarTouch.setHandsCloseEnoughToGrasp(false); // if the avatar being simulated is mine, then loop through // all the other avatars for potential interactions... if ( _isMine ) { - float closestDistance = 10000.0f; - AgentList* agentList = AgentList::getInstance(); for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { @@ -352,25 +369,42 @@ void Avatar::simulate(float deltaTime) { // test other avatar hand position for proximity glm::vec3 v( _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position ); - v -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); + v -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_SHOULDER ); float distance = glm::length( v ); if ( distance < _maxArmLength + _maxArmLength ) { - closestDistance = distance; _interactingOther = otherAvatar; - _interactingOtherIsNearby = true; + _avatarTouch.setAbleToReachOtherAvatar(true); + glm::vec3 vectorBetweenHands( _bone[ AVATAR_BONE_RIGHT_HAND ].position ); + vectorBetweenHands -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); + float distanceBetweenHands = glm::length(vectorBetweenHands); + + if (distanceBetweenHands < _avatarTouch.HANDS_CLOSE_ENOUGH_TO_GRASP) { + _avatarTouch.setHandsCloseEnoughToGrasp(true); + } + // if I am holding hands with another avatar, a force is applied if (( _handState == 1 ) || ( _interactingOther->_handState == 1 )) { - glm::vec3 vectorToOtherHand = _interactingOther->_handPosition - _handHoldingPosition; - glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHoldingPosition; - _handHoldingPosition += vectorToOtherHand * YOUR_HAND_HOLDING_PULL; - _handHoldingPosition += vectorToMyHand * MY_HAND_HOLDING_PULL; - _bone[ AVATAR_BONE_RIGHT_HAND ].position = _handHoldingPosition; + + // if the hands are close enough to grasp... + if (distanceBetweenHands < _avatarTouch.HANDS_CLOSE_ENOUGH_TO_GRASP) + { + // apply the forces... + glm::vec3 vectorToOtherHand = _interactingOther->_handPosition - _handHoldingPosition; + glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHoldingPosition; + + _handHoldingPosition += vectorToOtherHand * YOUR_HAND_HOLDING_PULL; + _handHoldingPosition += vectorToMyHand * MY_HAND_HOLDING_PULL; + _bone[ AVATAR_BONE_RIGHT_HAND ].position = _handHoldingPosition; + + // apply a force to the avatar body + if ( glm::length(vectorToOtherHand) > _maxArmLength * 0.9 ) { + _velocity += vectorToOtherHand; + } + } } - - _avatarTouch.setYourHandPosition( _interactingOther->_handPosition ); } } } @@ -378,19 +412,23 @@ void Avatar::simulate(float deltaTime) { // Set the vector we send for hand position to other people to be our right hand setHandPosition(_bone[ AVATAR_BONE_RIGHT_HAND ].position); - //update the effects of touching another avatar - _avatarTouch.simulate(deltaTime); - }//if ( _isMine ) //constrain right arm length and re-adjust elbow position as it bends updateArmIKAndConstraints( deltaTime ); - - if (_isMine) { - _avatarTouch.setMyHandPosition( _bone[ AVATAR_BONE_RIGHT_HAND ].position ); + + // set hand positions for _avatarTouch.setMyHandPosition AFTER calling updateArmIKAndConstraints + if ( _interactingOther ) { + if (_isMine) { + _avatarTouch.setMyHandPosition ( _bone[ AVATAR_BONE_RIGHT_HAND ].position ); + _avatarTouch.setYourHandPosition( _interactingOther->_bone[ AVATAR_BONE_RIGHT_HAND ].position ); + _avatarTouch.setMyHandState ( _handState ); + _avatarTouch.setYourHandState ( _interactingOther->_handState ); + _avatarTouch.simulate(deltaTime); + } } - if (!_interactingOtherIsNearby) { + if (!_avatarTouch.getAbleToReachOtherAvatar() ) { _interactingOther = NULL; } @@ -431,8 +469,10 @@ void Avatar::simulate(float deltaTime) { _bodyYaw += _bodyYawDelta * deltaTime; } - // decay body yaw delta - _bodyYawDelta *= (1.0 - TEST_YAW_DECAY * deltaTime); + // decay body rotation deltas + _bodyPitchDelta *= (1.0 - BODY_PITCH_DECAY * deltaTime); + _bodyYawDelta *= (1.0 - BODY_YAW_DECAY * deltaTime); + _bodyRollDelta *= (1.0 - BODY_ROLL_DECAY * deltaTime); // add thrust to velocity _velocity += _thrust * deltaTime; @@ -457,11 +497,16 @@ void Avatar::simulate(float deltaTime) { } } - - - void Avatar::updateHead(float deltaTime) { + //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; + _bone[ AVATAR_BONE_HEAD ].springyPosition += headLean; + } + // Decay head back to center if turned on if (_returnHeadToCenter) { // Decay back toward center @@ -477,10 +522,9 @@ void Avatar::updateHead(float deltaTime) { _headRoll *= 1.f - (DECAY * deltaTime); } - _head.leanForward *= (1.f - DECAY * 30 * deltaTime); _head.leanSideways *= (1.f - DECAY * 30 * deltaTime); - + // Update where the avatar's eyes are // // First, decide if we are making eye contact or not @@ -520,7 +564,6 @@ void Avatar::updateHead(float deltaTime) { _head.eyeballPitch[0] = _head.eyeballPitch[1] = -_headPitch + eye_target_pitch_adjust; _head.eyeballYaw[0] = _head.eyeballYaw[1] = -_headYaw + eye_target_yaw_adjust; } - if (_head.noise) { @@ -635,18 +678,16 @@ void Avatar::updateCollisionWithOtherAvatar( Avatar * otherAvatar, float deltaTi // push balls away from each other and apply friction glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * deltaTime; - - float ballMomentum = COLLISION_BALL_FRICTION * deltaTime; + float ballMomentum = 1.0 - COLLISION_BALL_FRICTION * deltaTime; if ( ballMomentum < 0.0 ) { ballMomentum = 0.0;} - _bone[b].springyVelocity += ballPushForce; otherAvatar->_bone[o].springyVelocity -= ballPushForce; - _bone[b].springyVelocity *= 0.9; - otherAvatar->_bone[o].springyVelocity *= 0.9; + _bone[b].springyVelocity *= ballMomentum; + otherAvatar->_bone[o].springyVelocity *= ballMomentum; - // accumulate forces and frictions to the velocities of avatar bodies + // accumulate forces and frictions to apply to the velocities of avatar bodies bodyPushForce += directionVector * COLLISION_BODY_FORCE * deltaTime; bodyMomentum -= COLLISION_BODY_FRICTION * deltaTime; if ( bodyMomentum < 0.0 ) { bodyMomentum = 0.0;} @@ -669,8 +710,6 @@ void Avatar::updateCollisionWithOtherAvatar( Avatar * otherAvatar, float deltaTi } //method - - void Avatar::setDisplayingHead( bool displayingHead ) { _displayingHead = displayingHead; } @@ -694,7 +733,6 @@ void Avatar::render(bool lookingInMirror) { */ if ( usingBigSphereCollisionTest ) { - // show TEST big sphere glColor4f( 0.5f, 0.6f, 0.8f, 0.7 ); glPushMatrix(); @@ -704,7 +742,7 @@ void Avatar::render(bool lookingInMirror) { glPopMatrix(); } - // render body + //render body renderBody(); // render head @@ -713,15 +751,11 @@ void Avatar::render(bool lookingInMirror) { } // if this is my avatar, then render my interactions with the other avatar - if ( _isMine ) - { - if ( _interactingOtherIsNearby ) { - _avatarTouch.render(); - } + if ( _isMine ) { + _avatarTouch.render(); } // Render the balls - if (_balls) { glPushMatrix(); glTranslatef(_position.x, _position.y, _position.z); @@ -778,7 +812,7 @@ void Avatar::renderHead(bool lookingInMirror) { glEnable(GL_RESCALE_NORMAL); // show head orientation - //renderOrientationDirections( _bone[ AVATAR_BONE_HEAD ].position, _bone[ AVATAR_BONE_HEAD ].orientation, 0.2f ); + //renderOrientationDirections( _bone[ AVATAR_BONE_HEAD ].springyPosition, _bone[ AVATAR_BONE_HEAD ].orientation, 0.2f ); glPushMatrix(); @@ -796,13 +830,13 @@ void Avatar::renderHead(bool lookingInMirror) { glScalef( 0.03, 0.03, 0.03 ); if (lookingInMirror) { - glRotatef(_bodyYaw - _headYaw, 0, 1, 0); + glRotatef(_bodyYaw - _headYaw, 0, 1, 0); glRotatef(_bodyPitch + _headPitch, 1, 0, 0); - glRotatef(_bodyRoll - _headRoll, 0, 0, 1); + glRotatef(_bodyRoll - _headRoll, 0, 0, 1); } else { - glRotatef(_bodyYaw + _headYaw, 0, 1, 0); + glRotatef(_bodyYaw + _headYaw, 0, 1, 0); glRotatef(_bodyPitch + _headPitch, 1, 0, 0); - glRotatef(_bodyRoll + _headRoll, 0, 0, 1); + glRotatef(_bodyRoll + _headRoll, 0, 0, 1); } glScalef(2.0, 2.0, 2.0); @@ -851,9 +885,7 @@ void Avatar::renderHead(bool lookingInMirror) { } glPopMatrix(); - // Mouth - glPushMatrix(); glTranslatef(0,-0.35,0.75); glColor3f(0,0,0); @@ -956,7 +988,7 @@ void Avatar::initializeSkeleton() { _bone[b].roll = 0.0; _bone[b].length = 0.0; _bone[b].radius = 0.0; - _bone[b].springBodyTightness = 4.0; + _bone[b].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS; _bone[b].orientation.setToIdentity(); } @@ -1034,7 +1066,35 @@ void Avatar::initializeSkeleton() { _bone[ AVATAR_BONE_RIGHT_THIGH ].radius = 0.02; _bone[ AVATAR_BONE_RIGHT_SHIN ].radius = 0.015; _bone[ AVATAR_BONE_RIGHT_FOOT ].radius = 0.02; - + + // specify the tightness of the springy positions as far as attraction to rigid body + _bone[ AVATAR_BONE_PELVIS_SPINE ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 1.0; + _bone[ AVATAR_BONE_MID_SPINE ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.8; + _bone[ AVATAR_BONE_CHEST_SPINE ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5; + _bone[ AVATAR_BONE_NECK ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.4; + _bone[ AVATAR_BONE_HEAD ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3; + + _bone[ AVATAR_BONE_LEFT_CHEST ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5; + _bone[ AVATAR_BONE_LEFT_SHOULDER ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5; + _bone[ AVATAR_BONE_LEFT_UPPER_ARM ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5; + _bone[ AVATAR_BONE_LEFT_FOREARM ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3; + _bone[ AVATAR_BONE_LEFT_HAND ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3; + + _bone[ AVATAR_BONE_RIGHT_CHEST ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5; + _bone[ AVATAR_BONE_RIGHT_SHOULDER ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5; + _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5; + _bone[ AVATAR_BONE_RIGHT_FOREARM ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3; + _bone[ AVATAR_BONE_RIGHT_HAND ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3; + + _bone[ AVATAR_BONE_LEFT_PELVIS ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS; + _bone[ AVATAR_BONE_LEFT_THIGH ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS; + _bone[ AVATAR_BONE_LEFT_SHIN ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS; + _bone[ AVATAR_BONE_LEFT_FOOT ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS; + _bone[ AVATAR_BONE_RIGHT_PELVIS ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS; + _bone[ AVATAR_BONE_RIGHT_THIGH ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS; + _bone[ AVATAR_BONE_RIGHT_SHIN ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS; + _bone[ AVATAR_BONE_RIGHT_FOOT ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS; + // to aid in hand-shaking and hand-holding, the right hand is not collidable _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].isCollidable = false; _bone[ AVATAR_BONE_RIGHT_FOREARM ].isCollidable = false; @@ -1096,7 +1156,7 @@ void Avatar::updateSkeleton() { _bone[ AVATAR_BONE_RIGHT_HAND ].position = _handPosition; } - // the following will be replaced by a proper rotation... + // the following will be replaced by a proper rotation...close float xx = glm::dot( _bone[b].defaultPosePosition, _bone[b].orientation.getRight() ); float yy = glm::dot( _bone[b].defaultPosePosition, _bone[b].orientation.getUp () ); float zz = glm::dot( _bone[b].defaultPosePosition, _bone[b].orientation.getFront() ); @@ -1160,20 +1220,22 @@ void Avatar::updateBodySprings( float deltaTime ) { const glm::vec3& Avatar::getHeadPosition() const { - if (_usingBodySprings) { - return _bone[ AVATAR_BONE_HEAD ].springyPosition; - } + + //if (_usingBodySprings) { + // return _bone[ AVATAR_BONE_HEAD ].springyPosition; + //} return _bone[ AVATAR_BONE_HEAD ].position; } + void Avatar::updateHandMovement( float deltaTime ) { glm::vec3 transformedHandMovement; transformedHandMovement - = _orientation.getRight() * _movedHandOffset.x - + _orientation.getUp() * -_movedHandOffset.y * 0.5f - + _orientation.getFront() * -_movedHandOffset.y; + = _orientation.getRight() * _movedHandOffset.x * 2.0f + + _orientation.getUp() * -_movedHandOffset.y * 1.0f + + _orientation.getFront() * -_movedHandOffset.y * 1.0f; _bone[ AVATAR_BONE_RIGHT_HAND ].position += transformedHandMovement; @@ -1207,7 +1269,9 @@ void Avatar::updateArmIKAndConstraints( float deltaTime ) { // set elbow position glm::vec3 newElbowPosition = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; newElbowPosition += armVector * ONE_HALF; + glm::vec3 perpendicular = glm::cross( _orientation.getFront(), armVector ); + newElbowPosition += perpendicular * ( 1.0f - ( _maxArmLength / distance ) ) * ONE_HALF; _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position = newElbowPosition; @@ -1277,6 +1341,7 @@ void Avatar::renderBody() { } } + /* // if the hand is grasping, show it... if (( _usingBodySprings ) && ( _handState == 1 )) { glPushMatrix(); @@ -1289,6 +1354,7 @@ void Avatar::renderBody() { glPopMatrix(); } + */ } void Avatar::SetNewHeadTarget(float pitch, float yaw) { diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 202c3524ca..fec8b6e4d0 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -72,7 +72,6 @@ enum AvatarBoneID NUM_AVATAR_BONES }; - class Avatar : public AvatarData { public: Avatar(bool isMine); @@ -93,8 +92,8 @@ public: float getBodyYaw() {return _bodyYaw;}; void addBodyYaw(float y) {_bodyYaw += y;}; - bool getIsNearInteractingOther() { return _interactingOtherIsNearby; } - + bool getIsNearInteractingOther(); + float getAbsoluteHeadYaw() const; void setLeanForward(float dist); void setLeanSideways(float dist); @@ -123,7 +122,7 @@ public: void setDisplayingHead( bool displayingHead ); float getAverageLoudness() {return _head.averageLoudness;}; - void setAverageLoudness(float al) {_head.averageLoudness = al;}; + void setAverageLoudness(float al) {_head.averageLoudness = al;}; void SetNewHeadTarget(float, float); @@ -143,12 +142,32 @@ public: // Find out what the local gravity vector is at this location glm::vec3 getGravity(glm::vec3 pos); +private: + + const bool BALLS_ON = false; + const bool AVATAR_GRAVITY = true; + const float DECAY = 0.1; + const float THRUST_MAG = 1200.0; + const float YAW_MAG = 500.0; + const float BODY_PITCH_DECAY = 5.0; + const float BODY_YAW_DECAY = 5.0; + const float BODY_ROLL_DECAY = 5.0; + const float LIN_VEL_DECAY = 5.0; + const float MY_HAND_HOLDING_PULL = 0.2; + const float YOUR_HAND_HOLDING_PULL = 1.0; + const float BODY_SPRING_FORCE = 6.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_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; + // Do you want head to try to return to center (depends on interface detected) void setHeadReturnToCenter(bool r) { _returnHeadToCenter = r; }; const bool getHeadReturnToCenter() const { return _returnHeadToCenter; }; -private: - struct AvatarBone { AvatarBoneID parent; // which bone is this bone connected to? @@ -208,42 +227,43 @@ private: float returnSpringScale; }; - AvatarHead _head; - bool _isMine; - glm::vec3 _TEST_bigSpherePosition; - float _TEST_bigSphereRadius; - bool _mousePressed; - float _bodyYawDelta; - bool _usingBodySprings; - glm::vec3 _movedHandOffset; - glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion - AvatarBone _bone[ NUM_AVATAR_BONES ]; - AvatarMode _mode; - glm::vec3 _handHoldingPosition; - glm::vec3 _velocity; - glm::vec3 _thrust; - float _speed; - float _maxArmLength; - Orientation _orientation; - int _driveKeys[MAX_DRIVE_KEYS]; - GLUquadric* _sphere; - float _renderYaw; - float _renderPitch; // Pitch from view frustum when this is own head - bool _transmitterIsFirstData; - timeval _transmitterTimeLastReceived; - timeval _transmitterTimer; - float _transmitterHz; - int _transmitterPackets; - glm::vec3 _transmitterInitialReading; - Avatar* _interactingOther; - bool _interactingOtherIsNearby; - float _pelvisStandingHeight; - float _height; - Balls* _balls; - AvatarTouch _avatarTouch; - bool _displayingHead; // should be false if in first-person view - bool _returnHeadToCenter; - + AvatarHead _head; + bool _isMine; + glm::vec3 _TEST_bigSpherePosition; + float _TEST_bigSphereRadius; + bool _mousePressed; + float _bodyPitchDelta; + float _bodyYawDelta; + float _bodyRollDelta; + bool _usingBodySprings; + glm::vec3 _movedHandOffset; + glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion + AvatarBone _bone[ NUM_AVATAR_BONES ]; + AvatarMode _mode; + glm::vec3 _handHoldingPosition; + glm::vec3 _velocity; + glm::vec3 _thrust; + float _speed; + float _maxArmLength; + Orientation _orientation; + int _driveKeys[MAX_DRIVE_KEYS]; + GLUquadric* _sphere; + float _renderYaw; + float _renderPitch; // Pitch from view frustum when this is own head + bool _transmitterIsFirstData; + timeval _transmitterTimeLastReceived; + timeval _transmitterTimer; + float _transmitterHz; + int _transmitterPackets; + glm::vec3 _transmitterInitialReading; + Avatar* _interactingOther; + float _pelvisStandingHeight; + float _height; + Balls* _balls; + AvatarTouch _avatarTouch; + bool _displayingHead; // should be false if in first-person view + bool _returnHeadToCenter; + // private methods... void initializeSkeleton(); void updateSkeleton(); diff --git a/interface/src/AvatarTouch.cpp b/interface/src/AvatarTouch.cpp index b26b030b1d..37c4c7fb2f 100644 --- a/interface/src/AvatarTouch.cpp +++ b/interface/src/AvatarTouch.cpp @@ -11,13 +11,18 @@ #include "AvatarTouch.h" #include "InterfaceConfig.h" -const float THREAD_RADIUS = 0.007; +const float THREAD_RADIUS = 0.012; AvatarTouch::AvatarTouch() { _myHandPosition = glm::vec3( 0.0f, 0.0f, 0.0f ); _yourHandPosition = glm::vec3( 0.0f, 0.0f, 0.0f ); + _myHandState = 0; + _yourHandState = 0; + _canReachToOtherAvatar = false; + _handsCloseEnoughToGrasp = false; + for (int p=0; ploadVoxelsFile(fileName,wantColorRandomizer); - + _tree->loadVoxelsFile(fileName, wantColorRandomizer); copyWrittenDataToReadArrays(); } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: VoxelSystem::createSphere() -// Description: Creates a sphere of voxels in the local system at a given location/radius -// To Do: Move this function someplace better? I put it here because we need a -// mechanism to tell the system to redraw it's arrays after voxels are done -// being added. This is a concept mostly only understood by VoxelSystem. -// Complaints: Brad :) void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer) { - - tree->createSphere(r,xc,yc,zc,s,solid,wantColorRandomizer); + _tree->createSphere(r, xc, yc, zc, s, solid, wantColorRandomizer); setupNewVoxelsForDrawing(); } long int VoxelSystem::getVoxelsCreated() { - return tree->voxelsCreated; + return _tree->voxelsCreated; } float VoxelSystem::getVoxelsCreatedPerSecondAverage() { - return (1 / tree->voxelsCreatedStats.getEventDeltaAverage()); + return (1 / _tree->voxelsCreatedStats.getEventDeltaAverage()); } long int VoxelSystem::getVoxelsColored() { - return tree->voxelsColored; + return _tree->voxelsColored; } float VoxelSystem::getVoxelsColoredPerSecondAverage() { - return (1 / tree->voxelsColoredStats.getEventDeltaAverage()); + return (1 / _tree->voxelsColoredStats.getEventDeltaAverage()); } long int VoxelSystem::getVoxelsBytesRead() { - return tree->voxelsBytesRead; + return _tree->voxelsBytesRead; } float VoxelSystem::getVoxelsBytesReadPerSecondAverage() { - return tree->voxelsBytesReadStats.getAverageSampleValuePerSecond(); + return _tree->voxelsBytesReadStats.getAverageSampleValuePerSecond(); } int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { @@ -114,11 +98,11 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { switch(command) { case PACKET_HEADER_VOXEL_DATA: // ask the VoxelTree to read the bitstream into the tree - tree->readBitstreamToTree(voxelData, numBytes - 1); + _tree->readBitstreamToTree(voxelData, numBytes - 1); break; case PACKET_HEADER_ERASE_VOXEL: // ask the tree to read the "remove" bitstream - tree->processRemoveVoxelBitstream(sourceBuffer, numBytes); + _tree->processRemoveVoxelBitstream(sourceBuffer, numBytes); break; case PACKET_HEADER_Z_COMMAND: @@ -135,7 +119,8 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { while (totalLength <= numBytes) { if (0==strcmp(command,(char*)"erase all")) { printLog("got Z message == erase all\n"); - tree->eraseAllVoxels(); + _tree->eraseAllVoxels(); + _voxelsInArrays = 0; // better way to do this?? } if (0==strcmp(command,(char*)"add scene")) { printLog("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n"); @@ -150,78 +135,87 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { } void VoxelSystem::setupNewVoxelsForDrawing() { - // reset the verticesEndPointer so we're writing to the beginning of the array - writeVerticesEndPointer = writeVerticesArray; - // call recursive function to populate in memory arrays - // it will return the number of voxels added - glm::vec3 treeRoot = glm::vec3(0,0,0); - voxelsRendered = treeToArrays(tree->rootNode, treeRoot); + _voxelsUpdated = newTreeToArrays(_tree->rootNode); + if (_voxelsUpdated) { + _voxelsDirty=true; + } + // copy the newly written data to the arrays designated for reading copyWrittenDataToReadArrays(); } void VoxelSystem::copyWrittenDataToReadArrays() { - // lock on the buffer write lock so we can't modify the data when the GPU is reading it - pthread_mutex_lock(&bufferWriteLock); - // store a pointer to the current end so it doesn't change during copy - GLfloat *endOfCurrentVerticesData = writeVerticesEndPointer; - // copy the vertices and colors - memcpy(readVerticesArray, writeVerticesArray, (endOfCurrentVerticesData - writeVerticesArray) * sizeof(GLfloat)); - memcpy(readColorsArray, writeColorsArray, (endOfCurrentVerticesData - writeVerticesArray) * sizeof(GLubyte)); - // set the read vertices end pointer to the correct spot so the GPU knows how much to pull - readVerticesEndPointer = readVerticesArray + (endOfCurrentVerticesData - writeVerticesArray); - pthread_mutex_unlock(&bufferWriteLock); + if (_voxelsDirty) { + // lock on the buffer write lock so we can't modify the data when the GPU is reading it + pthread_mutex_lock(&_bufferWriteLock); + int bytesOfVertices = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat); + int bytesOfColors = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte); + memcpy(_readVerticesArray, _writeVerticesArray, bytesOfVertices); + memcpy(_readColorsArray, _writeColorsArray, bytesOfColors ); + pthread_mutex_unlock(&_bufferWriteLock); + } } -int VoxelSystem::treeToArrays(VoxelNode* currentNode, const glm::vec3& nodePosition) { - int voxelsAdded = 0; - float halfUnitForVoxel = powf(0.5, *currentNode->octalCode) * (0.5 * TREE_SCALE); - glm::vec3 viewerPosition = _camera->getPosition(); //_viewerAvatar->getPosition(); +int VoxelSystem::newTreeToArrays(VoxelNode* node) { + assert(_viewFrustum); // you must set up _viewFrustum before calling this + int voxelsUpdated = 0; + float distanceToNode = node->distanceToCamera(*_viewFrustum); + float boundary = boundaryDistanceForRenderLevel(*node->octalCode + 1); + float childBoundary = boundaryDistanceForRenderLevel(*node->octalCode + 2); + bool inBoundary = (distanceToNode <= boundary); + bool inChildBoundary = (distanceToNode <= childBoundary); + bool shouldRender = node->isColored() && ((node->isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary)); - // debug LOD code - glm::vec3 debugNodePosition; - copyFirstVertexForCode(currentNode->octalCode,(float*)&debugNodePosition); - - float distanceToVoxelCenter = sqrtf(powf(viewerPosition.x - nodePosition[0] - halfUnitForVoxel, 2) + - powf(viewerPosition.y - nodePosition[1] - halfUnitForVoxel, 2) + - powf(viewerPosition.z - nodePosition[2] - halfUnitForVoxel, 2)); - - int renderLevel = *currentNode->octalCode + 1; - int boundaryPosition = boundaryDistanceForRenderLevel(renderLevel); - bool alwaysDraw = false; // XXXBHG - temporary debug code. Flip this to true to disable LOD blurring - - if (alwaysDraw || distanceToVoxelCenter < boundaryPosition) { - for (int i = 0; i < 8; i++) { - // check if there is a child here - if (currentNode->children[i] != NULL) { - - glm::vec3 childNodePosition; - copyFirstVertexForCode(currentNode->children[i]->octalCode,(float*)&childNodePosition); - childNodePosition *= (float)TREE_SCALE; // scale it up - voxelsAdded += treeToArrays(currentNode->children[i], childNodePosition); - } + node->setShouldRender(shouldRender); + // let children figure out their renderness + for (int i = 0; i < 8; i++) { + if (node->children[i]) { + voxelsUpdated += newTreeToArrays(node->children[i]); } } + + // Now, if we've changed any attributes (our renderness, our color, etc) then update the Arrays... for us + if (node->isDirty() && (shouldRender || node->isKnownBufferIndex())) { + glm::vec3 startVertex; + float voxelScale = 0; + + // If we're should render, use our legit location and scale, + if (node->getShouldRender()) { + copyFirstVertexForCode(node->octalCode, (float*)&startVertex); + voxelScale = (1 / powf(2, *node->octalCode)); + } else { + // if we shouldn't render then set out location to some infinitely distant location, + // and our scale as infinitely small + startVertex[0] = startVertex[1] = startVertex[2] = FLT_MAX; + voxelScale = 0; + } - // if we didn't get any voxels added then we're a leaf - // add our vertex and color information to the interleaved array - if (voxelsAdded == 0 && currentNode->isColored()) { - float startVertex[3]; - copyFirstVertexForCode(currentNode->octalCode,(float*)&startVertex); - float voxelScale = 1 / powf(2, *currentNode->octalCode); + // If this node has not yet been written to the array, then add it to the end of the array. + glBufferIndex nodeIndex; + if (node->isKnownBufferIndex()) { + nodeIndex = node->getBufferIndex(); + } else { + nodeIndex = _voxelsInArrays; + } + + _voxelDirtyArray[nodeIndex] = true; // populate the array with points for the 8 vertices // and RGB color for each added vertex for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { - *writeVerticesEndPointer = startVertex[j % 3] + (identityVertices[j] * voxelScale); - *(writeColorsArray + (writeVerticesEndPointer - writeVerticesArray)) = currentNode->getColor()[j % 3]; - - writeVerticesEndPointer++; + GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); + GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); + *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); + *(writeColorsAt +j) = node->getColor()[j % 3]; } - voxelsAdded++; + if (!node->isKnownBufferIndex()) { + node->setBufferIndex(nodeIndex); + _voxelsInArrays++; // our know vertices in the arrays + } + voxelsUpdated++; + node->clearDirtyBit(); } - - return voxelsAdded; + return voxelsUpdated; } VoxelSystem* VoxelSystem::clone() const { @@ -230,20 +224,30 @@ VoxelSystem* VoxelSystem::clone() const { } void VoxelSystem::init() { - // prep the data structures for incoming voxel data - writeVerticesEndPointer = writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; - readVerticesEndPointer = readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; - writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; - readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; - GLuint *indicesArray = new GLuint[INDICES_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + // When we change voxels representations in the arrays, we'll update this + _voxelsDirty = false; + _voxelsInArrays = 0; + + // we will track individual dirty sections with this array of bools + _voxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM]; + memset(_voxelDirtyArray, false, MAX_VOXELS_PER_SYSTEM * sizeof(bool)); + + // prep the data structures for incoming voxel data + _writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + _readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + + _writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + _readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + + GLuint* indicesArray = new GLuint[INDICES_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; // populate the indicesArray // this will not change given new voxels, so we can set it all up now for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) { // fill the indices array int voxelIndexOffset = n * INDICES_PER_VOXEL; - GLuint *currentIndicesPos = indicesArray + voxelIndexOffset; + GLuint* currentIndicesPos = indicesArray + voxelIndexOffset; int startIndex = (n * VERTICES_PER_VOXEL); for (int i = 0; i < INDICES_PER_VOXEL; i++) { @@ -252,8 +256,8 @@ void VoxelSystem::init() { } } - GLfloat *normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; - GLfloat *normalsArrayEndPointer = normalsArray; + GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + GLfloat* normalsArrayEndPointer = normalsArray; // populate the normalsArray for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) { @@ -263,25 +267,25 @@ void VoxelSystem::init() { } // VBO for the verticesArray - glGenBuffers(1, &vboVerticesID); - glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID); + glGenBuffers(1, &_vboVerticesID); + glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW); // VBO for the normalsArray - glGenBuffers(1, &vboNormalsID); - glBindBuffer(GL_ARRAY_BUFFER, vboNormalsID); + glGenBuffers(1, &_vboNormalsID); + glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID); glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, normalsArray, GL_STATIC_DRAW); // VBO for colorsArray - glGenBuffers(1, &vboColorsID); - glBindBuffer(GL_ARRAY_BUFFER, vboColorsID); + glGenBuffers(1, &_vboColorsID); + glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW); // VBO for the indicesArray - glGenBuffers(1, &vboIndicesID); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndicesID); + glGenBuffers(1, &_vboIndicesID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, INDICES_PER_VOXEL * sizeof(GLuint) * MAX_VOXELS_PER_SYSTEM, indicesArray, GL_STATIC_DRAW); @@ -291,45 +295,61 @@ void VoxelSystem::init() { delete[] normalsArray; } -void VoxelSystem::render() { - - glPushMatrix(); - - if (readVerticesEndPointer != readVerticesArray) { - // try to lock on the buffer write - // just avoid pulling new data if it is currently being written - if (pthread_mutex_trylock(&bufferWriteLock) == 0) { - - glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID); - glBufferSubData(GL_ARRAY_BUFFER, 0, (readVerticesEndPointer - readVerticesArray) * sizeof(GLfloat), readVerticesArray); - - glBindBuffer(GL_ARRAY_BUFFER, vboColorsID); - glBufferSubData(GL_ARRAY_BUFFER, 0, (readVerticesEndPointer - readVerticesArray) * sizeof(GLubyte), readColorsArray); - - readVerticesEndPointer = readVerticesArray; - - pthread_mutex_unlock(&bufferWriteLock); +void VoxelSystem::updateVBOs() { + if (_voxelsDirty) { + glBufferIndex segmentStart = 0; + glBufferIndex segmentEnd = 0; + bool inSegment = false; + for (glBufferIndex i = 0; i < _voxelsInArrays; i++) { + if (!inSegment) { + if (_voxelDirtyArray[i]) { + segmentStart = i; + inSegment = true; + _voxelDirtyArray[i] = false; // consider us clean! + } + } else { + if (!_voxelDirtyArray[i] || (i == (_voxelsInArrays - 1)) ) { + segmentEnd = i; + inSegment = false; + int segmentLength = (segmentEnd - segmentStart) + 1; + GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); + segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); + } + } } + _voxelsDirty = false; } +} +void VoxelSystem::render() { + glPushMatrix(); + updateVBOs(); // tell OpenGL where to find vertex and color information glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_COLOR_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID); + glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); glVertexPointer(3, GL_FLOAT, 0, 0); - glBindBuffer(GL_ARRAY_BUFFER, vboNormalsID); + glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID); glNormalPointer(GL_FLOAT, 0, 0); - glBindBuffer(GL_ARRAY_BUFFER, vboColorsID); + glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); // draw the number of voxels we have - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndicesID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); glScalef(10, 10, 10); - glDrawElements(GL_TRIANGLES, 36 * voxelsRendered, GL_UNSIGNED_INT, 0); + glDrawElements(GL_TRIANGLES, 36 * _voxelsInArrays, GL_UNSIGNED_INT, 0); // deactivate vertex and color arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); @@ -344,25 +364,12 @@ void VoxelSystem::render() { glPopMatrix(); } -void VoxelSystem::simulate(float deltaTime) { - -} - int VoxelSystem::_nodeCount = 0; -bool VoxelSystem::randomColorOperation(VoxelNode* node, bool down, void* extraData) { - - // we do our operations on the way up! - if (down) { - return true; - } - +bool VoxelSystem::randomColorOperation(VoxelNode* node, void* extraData) { _nodeCount++; if (node->isColored()) { - nodeColor newColor = { 0,0,0,1 }; - newColor[0] = randomColorValue(150); - newColor[1] = randomColorValue(150); - newColor[1] = randomColorValue(150); + nodeColor newColor = { randomColorValue(150), randomColorValue(150), randomColorValue(150), 1 }; node->setColor(newColor); } return true; @@ -370,43 +377,26 @@ bool VoxelSystem::randomColorOperation(VoxelNode* node, bool down, void* extraDa void VoxelSystem::randomizeVoxelColors() { _nodeCount = 0; - tree->recurseTreeWithOperation(randomColorOperation); - printLog("setting randomized true color for %d nodes\n",_nodeCount); + _tree->recurseTreeWithOperation(randomColorOperation); + printLog("setting randomized true color for %d nodes\n", _nodeCount); setupNewVoxelsForDrawing(); } -bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, bool down, void* extraData) { - - // we do our operations on the way up! - if (down) { - return true; - } - +bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, void* extraData) { _nodeCount++; - // always false colorize - unsigned char newR = randomColorValue(150); - unsigned char newG = randomColorValue(150); - unsigned char newB = randomColorValue(150); - node->setFalseColor(newR,newG,newB); - + node->setFalseColor(randomColorValue(150), randomColorValue(150), randomColorValue(150)); return true; // keep going! } void VoxelSystem::falseColorizeRandom() { _nodeCount = 0; - tree->recurseTreeWithOperation(falseColorizeRandomOperation); - printLog("setting randomized false color for %d nodes\n",_nodeCount); + _tree->recurseTreeWithOperation(falseColorizeRandomOperation); + printLog("setting randomized false color for %d nodes\n", _nodeCount); setupNewVoxelsForDrawing(); } -bool VoxelSystem::trueColorizeOperation(VoxelNode* node, bool down, void* extraData) { - - // we do our operations on the way up! - if (down) { - return true; - } - +bool VoxelSystem::trueColorizeOperation(VoxelNode* node, void* extraData) { _nodeCount++; node->setFalseColored(false); return true; @@ -414,90 +404,45 @@ bool VoxelSystem::trueColorizeOperation(VoxelNode* node, bool down, void* extraD void VoxelSystem::trueColorize() { _nodeCount = 0; - tree->recurseTreeWithOperation(trueColorizeOperation); - printLog("setting true color for %d nodes\n",_nodeCount); + _tree->recurseTreeWithOperation(trueColorizeOperation); + printLog("setting true color for %d nodes\n", _nodeCount); setupNewVoxelsForDrawing(); } // Will false colorize voxels that are not in view -bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void* extraData) { - - // we do our operations on the way up! - if (down) { - return true; - } - +bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, void* extraData) { const ViewFrustum* viewFrustum = (const ViewFrustum*) extraData; - _nodeCount++; - - // only do this for truely colored voxels... if (node->isColored()) { - // If the voxel is outside of the view frustum, then false color it red if (!node->isInView(*viewFrustum)) { // Out of view voxels are colored RED - unsigned char newR = 255; - unsigned char newG = 0; - unsigned char newB = 0; - node->setFalseColor(newR,newG,newB); + node->setFalseColor(255, 0, 0); } } - return true; // keep going! } void VoxelSystem::falseColorizeInView(ViewFrustum* viewFrustum) { _nodeCount = 0; - tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum); - printLog("setting in view false color for %d nodes\n",_nodeCount); + _tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum); + printLog("setting in view false color for %d nodes\n", _nodeCount); setupNewVoxelsForDrawing(); } // Will false colorize voxels based on distance from view -bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, bool down, void* extraData) { - - // we do our operations on the way up! - if (down) { - return true; - } - +bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, void* extraData) { ViewFrustum* viewFrustum = (ViewFrustum*) extraData; - - // only do this for truly colored voxels... if (node->isColored()) { - - // We need our distance for both up and down - glm::vec3 nodePosition; - float* startVertex = firstVertexForCode(node->octalCode); - nodePosition.x = startVertex[0]; - nodePosition.y = startVertex[1]; - nodePosition.z = startVertex[2]; - delete startVertex; - - // scale up the node position - nodePosition = nodePosition*(float)TREE_SCALE; - - float halfUnitForVoxel = powf(0.5, *node->octalCode) * (0.5 * TREE_SCALE); - glm::vec3 viewerPosition = viewFrustum->getPosition(); - - float distance = sqrtf(powf(viewerPosition.x - nodePosition.x - halfUnitForVoxel, 2) + - powf(viewerPosition.y - nodePosition.y - halfUnitForVoxel, 2) + - powf(viewerPosition.z - nodePosition.z - halfUnitForVoxel, 2)); - - // actually colorize + float distance = node->distanceToCamera(*viewFrustum); _nodeCount++; - - float distanceRatio = (_minDistance==_maxDistance) ? 1 : (distance - _minDistance)/(_maxDistance - _minDistance); + float distanceRatio = (_minDistance == _maxDistance) ? 1 : (distance - _minDistance) / (_maxDistance - _minDistance); // We want to colorize this in 16 bug chunks of color const unsigned char maxColor = 255; const unsigned char colorBands = 16; const unsigned char gradientOver = 128; - unsigned char colorBand = (colorBands*distanceRatio); - unsigned char newR = (colorBand*(gradientOver/colorBands))+(maxColor-gradientOver); - unsigned char newG = 0; - unsigned char newB = 0; - node->setFalseColor(newR,newG,newB); + unsigned char colorBand = (colorBands * distanceRatio); + node->setFalseColor((colorBand * (gradientOver / colorBands)) + (maxColor - gradientOver), 0, 0); } return true; // keep going! } @@ -508,44 +453,18 @@ float VoxelSystem::_minDistance = FLT_MAX; // Helper function will get the distance from view range, would be nice if you could just keep track // of this as voxels are created and/or colored... seems like some transform math could do that so // we wouldn't need to do two passes of the tree -bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, bool down, void* extraData) { - - // we do our operations on the way up! - if (down) { - return true; - } - +bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData) { ViewFrustum* viewFrustum = (ViewFrustum*) extraData; - // only do this for truly colored voxels... if (node->isColored()) { - - // We need our distance for both up and down - glm::vec3 nodePosition; - float* startVertex = firstVertexForCode(node->octalCode); - nodePosition.x = startVertex[0]; - nodePosition.y = startVertex[1]; - nodePosition.z = startVertex[2]; - delete startVertex; - - // scale up the node position - nodePosition = nodePosition*(float)TREE_SCALE; - - float halfUnitForVoxel = powf(0.5, *node->octalCode) * (0.5 * TREE_SCALE); - glm::vec3 viewerPosition = viewFrustum->getPosition(); - - float distance = sqrtf(powf(viewerPosition.x - nodePosition.x - halfUnitForVoxel, 2) + - powf(viewerPosition.y - nodePosition.y - halfUnitForVoxel, 2) + - powf(viewerPosition.z - nodePosition.z - halfUnitForVoxel, 2)); - - // on way down, calculate the range of distances + float distance = node->distanceToCamera(*viewFrustum); + // calculate the range of distances if (distance > _maxDistance) { _maxDistance = distance; } if (distance < _minDistance) { _minDistance = distance; } - _nodeCount++; } return true; // keep going! @@ -553,15 +472,14 @@ bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, bool down, void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { _nodeCount = 0; - _maxDistance = 0.0; _minDistance = FLT_MAX; - tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum); - printLog("determining distance range for %d nodes\n",_nodeCount); - + _tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum); + printLog("determining distance range for %d nodes\n", _nodeCount); _nodeCount = 0; - - tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum); - printLog("setting in distance false color for %d nodes\n",_nodeCount); + _tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum); + printLog("setting in distance false color for %d nodes\n", _nodeCount); setupNewVoxelsForDrawing(); } + + diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index f12cc7521a..e6798f9fd1 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -29,12 +29,16 @@ public: int parseData(unsigned char* sourceBuffer, int numBytes); VoxelSystem* clone() const; + + void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; }; void init(); - void simulate(float deltaTime); + void simulate(float deltaTime) { }; void render(); - void setVoxelsRendered(int v) {voxelsRendered = v;}; - int getVoxelsRendered() {return voxelsRendered;}; + + unsigned long getVoxelsUpdated() const {return _voxelsUpdated;}; + unsigned long getVoxelsRendered() const {return _voxelsInArrays;}; + void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; }; void setCamera(Camera* newCamera) { _camera = newCamera; }; void loadVoxelsFile(const char* fileName,bool wantColorRandomizer); @@ -57,36 +61,42 @@ public: private: // Operation functions for tree recursion methods static int _nodeCount; - static bool randomColorOperation(VoxelNode* node, bool down, void* extraData); - static bool falseColorizeRandomOperation(VoxelNode* node, bool down, void* extraData); - static bool trueColorizeOperation(VoxelNode* node, bool down, void* extraData); - static bool falseColorizeInViewOperation(VoxelNode* node, bool down, void* extraData); - static bool falseColorizeDistanceFromViewOperation(VoxelNode* node, bool down, void* extraData); - static bool getDistanceFromViewRangeOperation(VoxelNode* node, bool down, void* extraData); + static bool randomColorOperation(VoxelNode* node, void* extraData); + static bool falseColorizeRandomOperation(VoxelNode* node, void* extraData); + static bool trueColorizeOperation(VoxelNode* node, void* extraData); + static bool falseColorizeInViewOperation(VoxelNode* node, void* extraData); + static bool falseColorizeDistanceFromViewOperation(VoxelNode* node, void* extraData); + static bool getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData); // these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here static float _maxDistance; static float _minDistance; - int voxelsRendered; Avatar* _viewerAvatar; Camera* _camera; - VoxelTree *tree; - GLfloat *readVerticesArray; - GLubyte *readColorsArray; - GLfloat *readVerticesEndPointer; - GLfloat *writeVerticesArray; - GLubyte *writeColorsArray; - GLfloat *writeVerticesEndPointer; - GLuint vboVerticesID; - GLuint vboNormalsID; - GLuint vboColorsID; - GLuint vboIndicesID; - pthread_mutex_t bufferWriteLock; + VoxelTree* _tree; + GLfloat* _readVerticesArray; + GLubyte* _readColorsArray; + GLfloat* _writeVerticesArray; + GLubyte* _writeColorsArray; + bool* _voxelDirtyArray; + unsigned long _voxelsUpdated; + unsigned long _voxelsInArrays; + + GLuint _vboVerticesID; + GLuint _vboNormalsID; + GLuint _vboColorsID; + GLuint _vboIndicesID; + pthread_mutex_t _bufferWriteLock; - int treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosition); + ViewFrustum* _viewFrustum; + + int newTreeToArrays(VoxelNode *currentNode); void setupNewVoxelsForDrawing(); void copyWrittenDataToReadArrays(); + void updateVBOs(); + + bool _voxelsDirty; }; #endif diff --git a/interface/src/main.cpp b/interface/src/main.cpp index c68c6aee9c..08b1666d05 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -113,11 +113,11 @@ bool wantColorRandomizer = true; // for addSphere and load file Oscilloscope audioScope(256,200,true); -ViewFrustum viewFrustum; // current state of view frustum, perspective, orientation, etc. +ViewFrustum viewFrustum; // current state of view frustum, perspective, orientation, etc. -Avatar myAvatar(true); // The rendered avatar of oneself -Camera myCamera; // My view onto the world (sometimes on myself :) -Camera viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode +Avatar myAvatar(true); // The rendered avatar of oneself +Camera myCamera; // My view onto the world (sometimes on myself :) +Camera viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode // Starfield information char starFile[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; @@ -236,7 +236,7 @@ void displayStats(void) drawtext(10, statsVerticalOffset + 49, 0.10f, 0, 1.0, 0, stats); std::stringstream voxelStats; - voxelStats << "Voxels Rendered: " << voxels.getVoxelsRendered(); + voxelStats << "Voxels Rendered: " << voxels.getVoxelsRendered() << " Updated: " << voxels.getVoxelsUpdated(); drawtext(10, statsVerticalOffset + 70, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); voxelStats.str(""); @@ -502,31 +502,19 @@ void loadViewFrustum(ViewFrustum& viewFrustum) { glm::vec3 up; glm::vec3 right; float fov, nearClip, farClip; - float yaw, pitch, roll; // Camera or Head? if (::cameraFrustum) { - position = ::myCamera.getPosition(); + position = ::myCamera.getPosition(); } else { - position = ::myAvatar.getHeadPosition(); + position = ::myAvatar.getHeadPosition(); } - // This bit of hackery is all because our Cameras report the incorrect yaw. - // For whatever reason, the camera has a yaw set to 180.0-trueYaw, so we basically - // need to get the "yaw" from the camera and adjust it to be the trueYaw - yaw = -(::myCamera.getOrientation().getYaw()-180); - pitch = ::myCamera.getOrientation().getPitch(); - roll = ::myCamera.getOrientation().getRoll(); fov = ::myCamera.getFieldOfView(); nearClip = ::myCamera.getNearClip(); farClip = ::myCamera.getFarClip(); - - // We can't use the camera's Orientation because of it's broken yaw. so we make a new - // correct orientation to get our vectors - Orientation o; - o.yaw(yaw); - o.pitch(pitch); - o.roll(roll); + + Orientation o = ::myCamera.getOrientation(); direction = o.getFront(); up = o.getUp(); @@ -716,16 +704,16 @@ void display(void) glMaterialfv(GL_FRONT, GL_SPECULAR, specular_color); glMateriali(GL_FRONT, GL_SHININESS, 96); - // camera settings - if ( ::lookingInMirror ) { - // set the camera to looking at my own face - myCamera.setTargetPosition ( myAvatar.getHeadPosition() ); - myCamera.setTargetYaw ( - myAvatar.getBodyYaw() ); - myCamera.setPitch ( 0.0 ); - myCamera.setRoll ( 0.0 ); - myCamera.setUpShift ( 0.0 ); - myCamera.setDistance ( 0.2 ); - myCamera.setTightness ( 100.0f ); + // camera settings + if ( ::lookingInMirror ) { + // set the camera to looking at my own face + myCamera.setTargetPosition ( myAvatar.getHeadPosition() ); + myCamera.setTargetYaw ( myAvatar.getBodyYaw() - 180.0f ); // 180 degrees from body yaw + myCamera.setPitch ( 0.0 ); + myCamera.setRoll ( 0.0 ); + myCamera.setUpShift ( 0.0 ); + myCamera.setDistance ( 0.2 ); + myCamera.setTightness ( 100.0f ); } else { //float firstPersonPitch = 20.0f; @@ -800,17 +788,17 @@ void display(void) */ } else { - myCamera.setPitch (thirdPersonPitch ); + myCamera.setPitch (thirdPersonPitch ); myCamera.setUpShift (thirdPersonUpShift ); myCamera.setDistance (thirdPersonDistance ); myCamera.setTightness(thirdPersonTightness); } - myCamera.setTargetPosition( myAvatar.getHeadPosition() ); - myCamera.setTargetYaw ( 180.0 - myAvatar.getBodyYaw() ); - myCamera.setRoll ( 0.0 ); + myCamera.setTargetPosition( myAvatar.getHeadPosition() ); + myCamera.setTargetYaw ( myAvatar.getBodyYaw() ); + myCamera.setRoll ( 0.0 ); } - + // important... myCamera.update( 1.f/FPS ); @@ -827,23 +815,25 @@ void display(void) if (::viewFrustumFromOffset && ::frustumOn) { - // set the camera to third-person view but offset so we can see the frustum - viewFrustumOffsetCamera.setTargetYaw( 180.0 - myAvatar.getBodyYaw() + ::viewFrustumOffsetYaw ); - viewFrustumOffsetCamera.setPitch ( ::viewFrustumOffsetPitch ); - viewFrustumOffsetCamera.setRoll ( ::viewFrustumOffsetRoll ); - viewFrustumOffsetCamera.setUpShift ( ::viewFrustumOffsetUp ); - viewFrustumOffsetCamera.setDistance ( ::viewFrustumOffsetDistance ); - viewFrustumOffsetCamera.update(1.f/FPS); - whichCamera = viewFrustumOffsetCamera; - } + // set the camera to third-person view but offset so we can see the frustum + viewFrustumOffsetCamera.setTargetYaw( ::viewFrustumOffsetYaw + myAvatar.getBodyYaw() ); + viewFrustumOffsetCamera.setPitch ( ::viewFrustumOffsetPitch ); + viewFrustumOffsetCamera.setRoll ( ::viewFrustumOffsetRoll ); + viewFrustumOffsetCamera.setUpShift ( ::viewFrustumOffsetUp ); + viewFrustumOffsetCamera.setDistance ( ::viewFrustumOffsetDistance ); + viewFrustumOffsetCamera.update(1.f/FPS); + whichCamera = viewFrustumOffsetCamera; + } // transform view according to whichCamera // could be myCamera (if in normal mode) // or could be viewFrustumOffsetCamera if in offset mode // I changed the ordering here - roll is FIRST (JJV) - glRotatef ( whichCamera.getRoll(), 0, 0, 1 ); - glRotatef ( whichCamera.getPitch(), 1, 0, 0 ); - glRotatef ( whichCamera.getYaw(), 0, 1, 0 ); + + glRotatef ( whichCamera.getRoll(), IDENTITY_FRONT.x, IDENTITY_FRONT.y, IDENTITY_FRONT.z ); + glRotatef ( whichCamera.getPitch(), IDENTITY_RIGHT.x, IDENTITY_RIGHT.y, IDENTITY_RIGHT.z ); + glRotatef ( 180.0 - whichCamera.getYaw(), IDENTITY_UP.x, IDENTITY_UP.y, IDENTITY_UP.z ); + glTranslatef( -whichCamera.getPosition().x, -whichCamera.getPosition().y, -whichCamera.getPosition().z ); if (::starsOn) { @@ -859,18 +849,18 @@ void display(void) // draw a red sphere float sphereRadius = 0.25f; glColor3f(1,0,0); - glPushMatrix(); - glutSolidSphere( sphereRadius, 15, 15 ); - glPopMatrix(); + glPushMatrix(); + glutSolidSphere( sphereRadius, 15, 15 ); + glPopMatrix(); - //draw a grid ground plane.... - drawGroundPlaneGrid( 5.0f, 9 ); + //draw a grid ground plane.... + drawGroundPlaneGrid( 5.0f, 9 ); // Draw voxels - if ( showingVoxels ) - { - voxels.render(); - } + if ( showingVoxels ) + { + voxels.render(); + } // Render avatars of other agents AgentList* agentList = AgentList::getInstance(); @@ -1619,6 +1609,8 @@ void audioMixerUpdate(in_addr_t newMixerAddress, in_port_t newMixerPort) { int main(int argc, const char * argv[]) { + voxels.setViewFrustum(&::viewFrustum); + shared_lib::printLog = & ::printLog; voxels_lib::printLog = & ::printLog; avatars_lib::printLog = & ::printLog; diff --git a/libraries/avatars/src/Orientation.cpp b/libraries/avatars/src/Orientation.cpp index 066c1edc58..fddb64d700 100755 --- a/libraries/avatars/src/Orientation.cpp +++ b/libraries/avatars/src/Orientation.cpp @@ -9,165 +9,116 @@ #include #include "avatars_Log.h" -#include -#include -//#include "Util.h" - using avatars_lib::printLog; -// XXXBHG - this test has not yet been reworked to match the correct vector orientation -// of the coordinate system, so don't use it for now. -// -// tosh - yep, I noticed... :-) -// - -static bool testingForNormalizationAndOrthogonality = false; +static const bool USING_QUATERNIONS = true; Orientation::Orientation() { setToIdentity(); } void Orientation::setToIdentity() { - _yaw = 0.0; - _pitch = 0.0; - _roll = 0.0; - right = glm::vec3( -1.0f, 0.0f, 0.0f ); - up = glm::vec3( 0.0f, 1.0f, 0.0f ); - front = glm::vec3( 0.0f, 0.0f, 1.0f ); + + quat = glm::quat(); + right = glm::vec3( IDENTITY_RIGHT ); + up = glm::vec3( IDENTITY_UP ); + front = glm::vec3( IDENTITY_FRONT ); } void Orientation::set( Orientation o ) { + + quat = o.quat; right = o.right; up = o.up; front = o.front; } -void Orientation::update() { +void Orientation::yaw( float angle ) { - float pitchRads = _pitch * PI_OVER_180; - float yawRads = _yaw * PI_OVER_180; - float rollRads = _roll * PI_OVER_180; + float radian = angle * PI_OVER_180; - glm::quat q(glm::vec3(pitchRads, -(yawRads), rollRads)); - - // Next, create a rotation matrix from that quaternion - glm::mat4 rotation; - rotation = glm::mat4_cast(q); - - // Transform the original vectors by the rotation matrix to get the new vectors - glm::vec4 qup(0,1,0,0); - glm::vec4 qright(-1,0,0,0); - glm::vec4 qfront(0,0,1,0); - glm::vec4 upNew = qup*rotation; - glm::vec4 rightNew = qright*rotation; - glm::vec4 frontNew = qfront*rotation; - - // Copy the answers to output vectors - up.x = upNew.x; - up.y = upNew.y; - up.z = upNew.z; - - right.x = rightNew.x; - right.y = rightNew.y; - right.z = rightNew.z; - - front.x = frontNew.x; - front.y = frontNew.y; - front.z = frontNew.z; - - if ( testingForNormalizationAndOrthogonality ) { testForOrthogonalAndNormalizedVectors( EPSILON ); } -} - -void Orientation::yaw(float angle) { - // remember the value for any future changes to other angles - _yaw = angle; - update(); + if ( USING_QUATERNIONS ) { + rotateAndGenerateDirections( glm::quat( glm::vec3( 0.0f, -radian, 0.0f )) ); + } else { + float s = sin(radian); + float c = cos(radian); + + glm::vec3 cosineFront = front * c; + glm::vec3 cosineRight = right * c; + glm::vec3 sineFront = front * s; + glm::vec3 sineRight = right * s; + + front = cosineFront - sineRight; + right = cosineRight + sineFront; + } } void Orientation::pitch( float angle ) { - // remember the value for any future changes to other angles - _pitch = angle; - update(); -} + float radian = angle * PI_OVER_180; + + if ( USING_QUATERNIONS ) { + rotateAndGenerateDirections( glm::quat( glm::vec3( radian, 0.0f, 0.0f ) ) ); + } else { + float s = sin(radian); + float c = cos(radian); + + glm::vec3 cosineUp = up * c; + glm::vec3 cosineFront = front * c; + glm::vec3 sineUp = up * s; + glm::vec3 sineFront = front * s; + + up = cosineUp - sineFront; + front = cosineFront + sineUp; + } +} void Orientation::roll( float angle ) { - _roll = angle; - update(); + + float radian = angle * PI_OVER_180; + + if ( USING_QUATERNIONS ) { + rotateAndGenerateDirections( glm::quat( glm::vec3( 0.0f, 0.0f, radian )) ); + } else { + float s = sin(radian); + float c = cos(radian); + + glm::vec3 cosineUp = up * c; + glm::vec3 cosineRight = right * c; + glm::vec3 sineUp = up * s; + glm::vec3 sineRight = right * s; + + up = cosineUp - sineRight; + right = cosineRight + sineUp; + } +} + +void Orientation::rotate( float p, float y, float r ) { + pitch(p); + yaw (y); + roll (r); +} + +void Orientation::rotate( glm::vec3 eulerAngles ) { + +//this needs to be optimized! + pitch(eulerAngles.x); + yaw (eulerAngles.y); + roll (eulerAngles.z); +} + +void Orientation::rotate( glm::quat rotation ) { + rotateAndGenerateDirections(rotation); } -void Orientation::setRightUpFront( const glm::vec3 &r, const glm::vec3 &u, const glm::vec3 &f ) { - right = r; - up = u; - front = f; +void Orientation::rotateAndGenerateDirections( glm::quat rotation ) { + + quat = quat * rotation; + + glm::mat4 rotationMatrix = glm::mat4_cast(quat); + + right = glm::vec3( glm::vec4( IDENTITY_RIGHT, 0.0f ) * rotationMatrix ); + up = glm::vec3( glm::vec4( IDENTITY_UP, 0.0f ) * rotationMatrix ); + front = glm::vec3( glm::vec4( IDENTITY_FRONT, 0.0f ) * rotationMatrix ); } - -void Orientation::testForOrthogonalAndNormalizedVectors( float epsilon ) { - - // XXXBHG - this test has not yet been reworked to match the correct vector orientation - // of the coordinate system - // bail for now, assume all is good - return; - - // make sure vectors are normalized (or close enough to length 1.0) - float rightLength = glm::length( right ); - float upLength = glm::length( up ); - float frontLength = glm::length( front ); - - if (( rightLength > 1.0f + epsilon ) - || ( rightLength < 1.0f - epsilon )) { - printLog( "Error in Orientation class: right direction length is %f \n", rightLength ); - } - assert ( rightLength > 1.0f - epsilon ); - assert ( rightLength < 1.0f + epsilon ); - - - if (( upLength > 1.0f + epsilon ) - || ( upLength < 1.0f - epsilon )) { - printLog( "Error in Orientation class: up direction length is %f \n", upLength ); - } - assert ( upLength > 1.0f - epsilon ); - assert ( upLength < 1.0f + epsilon ); - - - if (( frontLength > 1.0f + epsilon ) - || ( frontLength < 1.0f - epsilon )) { - printLog( "Error in Orientation class: front direction length is %f \n", frontLength ); - } - assert ( frontLength > 1.0f - epsilon ); - assert ( frontLength < 1.0f + epsilon ); - - - // make sure vectors are orthogonal (or close enough) - glm::vec3 rightCross = glm::cross( up, front ); - glm::vec3 upCross = glm::cross( front, right ); - glm::vec3 frontCross = glm::cross( right, up ); - - float rightDiff = glm::length( rightCross - right ); - float upDiff = glm::length( upCross - up ); - float frontDiff = glm::length( frontCross - front ); - - - if ( rightDiff > epsilon ) { - printLog( "Error in Orientation class: right direction not orthogonal to up and/or front. " ); - printLog( "The tested cross of up and front is off by %f \n", rightDiff ); - } - assert ( rightDiff < epsilon ); - - - if ( upDiff > epsilon ) { - printLog( "Error in Orientation class: up direction not orthogonal to front and/or right. " ); - printLog( "The tested cross of front and right is off by %f \n", upDiff ); - } - assert ( upDiff < epsilon ); - - - if ( frontDiff > epsilon ) { - printLog( "Error in Orientation class: front direction not orthogonal to right and/or up. " ); - printLog( "The tested cross of right and up is off by %f \n", frontDiff ); - } - assert ( frontDiff < epsilon ); -} - - diff --git a/libraries/avatars/src/Orientation.h b/libraries/avatars/src/Orientation.h index 1b64230812..50b400b935 100755 --- a/libraries/avatars/src/Orientation.h +++ b/libraries/avatars/src/Orientation.h @@ -1,6 +1,5 @@ //----------------------------------------------------------- // -// Created by Jeffrey Ventrella // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // //----------------------------------------------------------- @@ -8,52 +7,47 @@ #ifndef __interface__orientation__ #define __interface__orientation__ -#include // with this work? "Math.h" +#include #include +#include -enum Axis -{ - ORIENTATION_RIGHT_AXIS, - ORIENTATION_UP_AXIS, - ORIENTATION_FRONT_AXIS -}; +// this is where the coordinate system is represented +const glm::vec3 IDENTITY_RIGHT = glm::vec3( -1.0f, 0.0f, 0.0f ); +const glm::vec3 IDENTITY_UP = glm::vec3( 0.0f, 1.0f, 0.0f ); +const glm::vec3 IDENTITY_FRONT = glm::vec3( 0.0f, 0.0f, 1.0f ); class Orientation { -private: - float _yaw; - float _pitch; - float _roll; +public: + Orientation(); + + void set( Orientation ); + void setToIdentity(); + + void pitch( float p ); + void yaw ( float y ); + void roll ( float r ); + void rotate( float pitch, float yaw, float roll ); + void rotate( glm::vec3 EulerAngles ); + void rotate( glm::quat quaternion ); + + const glm::vec3 & getRight() const { return right; } + const glm::vec3 & getUp () const { return up; } + const glm::vec3 & getFront() const { return front; } + + const glm::vec3 & getIdentityRight() const { return IDENTITY_RIGHT; } + const glm::vec3 & getIdentityUp () const { return IDENTITY_UP; } + const glm::vec3 & getIdentityFront() const { return IDENTITY_FRONT; } + +private: + + glm::quat quat; glm::vec3 right; glm::vec3 up; glm::vec3 front; - void update(); // actually updates the vectors from yaw, pitch, roll - -public: - Orientation(); - - void yaw ( float ); - void pitch ( float ); - void roll ( float ); - - float getYaw() { return _yaw; }; - float getPitch(){ return _pitch; }; - float getRoll(){ return _roll; }; - - void set( Orientation ); - void setToIdentity(); - - const glm::vec3& getRight() const { return right; } - const glm::vec3& getUp() const { return up; } - const glm::vec3& getFront() const { return front; } - - void setRightUpFront( const glm::vec3 &, const glm::vec3 &, const glm::vec3 & ); - -private: - void testForOrthogonalAndNormalizedVectors( float epsilon ); + void rotateAndGenerateDirections( glm::quat rotation ); }; - #endif diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 66ddbcb915..2ba4d05e31 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -21,4 +21,7 @@ const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL; const int INDICES_PER_VOXEL = 3 * 12; const int COLOR_VALUES_PER_VOXEL = 3 * VERTICES_PER_VOXEL; +typedef unsigned long int glBufferIndex; +const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX; + #endif diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index c1527d3334..6f8f1d71f8 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -30,6 +30,10 @@ VoxelNode::VoxelNode() { for (int i = 0; i < 8; i++) { children[i] = NULL; } + + _glBufferIndex = GLBUFFER_INDEX_UNKNOWN; + _isDirty = true; + _shouldRender = false; } VoxelNode::~VoxelNode() { @@ -43,6 +47,14 @@ VoxelNode::~VoxelNode() { } } +void VoxelNode::setShouldRender(bool shouldRender) { + // if shouldRender is changing, then consider ourselves dirty + if (shouldRender != _shouldRender) { + _shouldRender = shouldRender; + _isDirty = true; + } +} + void VoxelNode::getAABox(AABox& box) const { glm::vec3 corner; @@ -59,16 +71,19 @@ void VoxelNode::getAABox(AABox& box) const { } void VoxelNode::addChildAtIndex(int childIndex) { - children[childIndex] = new VoxelNode(); + if (!children[childIndex]) { + children[childIndex] = new VoxelNode(); - // XXXBHG - When the node is constructed, it should be cleanly set up as - // true colored, but for some reason, not so much. I've added a a basecamp - // to-do to research this. But for now we'll use belt and suspenders and set - // it to not-false-colored here! - children[childIndex]->setFalseColored(false); + // XXXBHG - When the node is constructed, it should be cleanly set up as + // true colored, but for some reason, not so much. I've added a a basecamp + // to-do to research this. But for now we'll use belt and suspenders and set + // it to not-false-colored here! + children[childIndex]->setFalseColored(false); - // give this child its octal code - children[childIndex]->octalCode = childOctalCode(octalCode, childIndex); + // give this child its octal code + children[childIndex]->octalCode = childOctalCode(octalCode, childIndex); + _isDirty = true; + } } // will average the child colors... @@ -104,26 +119,35 @@ void VoxelNode::setColorFromAverageOfChildren() { // the actual NO_FALSE_COLOR version are inline in the VoxelNode.h #ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color void VoxelNode::setFalseColor(colorPart red, colorPart green, colorPart blue) { - _falseColored=true; - _currentColor[0] = red; - _currentColor[1] = green; - _currentColor[2] = blue; - _currentColor[3] = 1; // XXXBHG - False colors are always considered set + if (_falseColored != true || _currentColor[0] != red || _currentColor[1] != green || _currentColor[2] != blue) { + _falseColored=true; + _currentColor[0] = red; + _currentColor[1] = green; + _currentColor[2] = blue; + _currentColor[3] = 1; // XXXBHG - False colors are always considered set + _isDirty = true; + } } void VoxelNode::setFalseColored(bool isFalseColored) { - // if we were false colored, and are no longer false colored, then swap back - if (_falseColored && !isFalseColored) { - memcpy(&_currentColor,&_trueColor,sizeof(nodeColor)); + if (_falseColored != isFalseColored) { + // if we were false colored, and are no longer false colored, then swap back + if (_falseColored && !isFalseColored) { + memcpy(&_currentColor,&_trueColor,sizeof(nodeColor)); + } + _falseColored = isFalseColored; + _isDirty = true; } - _falseColored = isFalseColored; }; void VoxelNode::setColor(const nodeColor& color) { - memcpy(&_trueColor,&color,sizeof(nodeColor)); - if (!_falseColored) { - memcpy(&_currentColor,&color,sizeof(nodeColor)); + if (_trueColor[0] != color[0] || _trueColor[1] != color[1] || _trueColor[2] != color[2]) { + memcpy(&_trueColor,&color,sizeof(nodeColor)); + if (!_falseColored) { + memcpy(&_currentColor,&color,sizeof(nodeColor)); + } + _isDirty = true; } } #endif @@ -199,7 +223,6 @@ void VoxelNode::printDebugDetails(const char* label) const { printOctalCode(octalCode); } - bool VoxelNode::isInView(const ViewFrustum& viewFrustum) const { AABox box; getAABox(box); diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 4cda55f8a7..26edb87e79 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -11,6 +11,7 @@ #include "AABox.h" #include "ViewFrustum.h" +#include "VoxelConstants.h" typedef unsigned char colorPart; typedef unsigned char nodeColor[4]; @@ -22,6 +23,9 @@ private: nodeColor _currentColor; bool _falseColored; #endif + glBufferIndex _glBufferIndex; + bool _isDirty; + bool _shouldRender; public: VoxelNode(); ~VoxelNode(); @@ -40,7 +44,14 @@ public: bool isLeaf() const; void getAABox(AABox& box) const; void printDebugDetails(const char* label) const; - + bool isDirty() const { return _isDirty; }; + void clearDirtyBit() { _isDirty = false; }; + glBufferIndex getBufferIndex() const { return _glBufferIndex; }; + bool isKnownBufferIndex() const { return (_glBufferIndex != GLBUFFER_INDEX_UNKNOWN); }; + void setBufferIndex(glBufferIndex index) { _glBufferIndex = index; }; + void setShouldRender(bool shouldRender); + bool getShouldRender() const { return _shouldRender; } + #ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color void setFalseColor(colorPart red, colorPart green, colorPart blue); void setFalseColored(bool isFalseColored); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index cbbccedb59..3ff14b5afd 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -58,16 +58,13 @@ void VoxelTree::recurseTreeWithOperation(RecurseVoxelTreeOperation operation, vo // Recurses voxel node with an operation function void VoxelTree::recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperation operation, void* extraData) { - // call the operation function going "down" first, stop deeper recursion if function returns false - if (operation(node,true,extraData)) { - for (int i = 0; i < sizeof(node->children)/sizeof(node->children[0]); i++) { + if (operation(node, extraData)) { + for (int i = 0; i < sizeof(node->children) / sizeof(node->children[0]); i++) { VoxelNode* child = node->children[i]; if (child) { - recurseNodeWithOperation(child,operation,extraData); + recurseNodeWithOperation(child, operation, extraData); } } - // call operation on way back up - operation(node,false,extraData); } } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index ac3c762fcf..7f5a6b866b 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -16,7 +16,7 @@ #include "VoxelNodeBag.h" // Callback function, for recuseTreeWithOperation -typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, bool down, void* extraData); +typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, void* extraData); class VoxelTree { public: diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 716a4e9d7b..9ab5675d7e 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -38,7 +38,7 @@ const float DEATH_STAR_RADIUS = 4.0; const float MAX_CUBE = 0.05f; const int VOXEL_SEND_INTERVAL_USECS = 100 * 1000; -const int PACKETS_PER_CLIENT_PER_INTERVAL = 2; +const int PACKETS_PER_CLIENT_PER_INTERVAL = 20; const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4; @@ -68,11 +68,9 @@ void addSphere(VoxelTree * tree,bool random, bool wantColorRandomizer) { } int _nodeCount=0; -bool countVoxelsOperation(VoxelNode* node, bool down, void* extraData) { - if (down) { - if (node->isColored()){ - _nodeCount++; - } +bool countVoxelsOperation(VoxelNode* node, void* extraData) { + if (node->isColored()){ + _nodeCount++; } return true; // keep going } @@ -80,7 +78,7 @@ bool countVoxelsOperation(VoxelNode* node, bool down, void* extraData) { void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) { printf("adding scene of spheres...\n"); - int sphereBaseSize = 256; + int sphereBaseSize = 512; tree->createSphere(0.25, 0.5, 0.5, 0.5, (1.0 / sphereBaseSize), true, wantColorRandomizer); printf("one sphere added...\n");