From 1e58f6fd40f1395b585d17cf52ee0d9f6f73cd33 Mon Sep 17 00:00:00 2001 From: tosh Date: Thu, 18 Apr 2013 20:02:24 +0200 Subject: [PATCH 01/11] fixes upside down aspect ratio --- interface/src/starfield/renderer/Renderer.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/src/starfield/renderer/Renderer.h b/interface/src/starfield/renderer/Renderer.h index a09226ed85..5148c5fa01 100644 --- a/interface/src/starfield/renderer/Renderer.h +++ b/interface/src/starfield/renderer/Renderer.h @@ -133,14 +133,14 @@ namespace starfield { // determine dimensions based on a sought screen diagonal // // ww + hh = dd - // a = h / w => h = wa - // ww + ww aa = dd - // ww = dd / (1 + aa) + // a = w / h => w = ha + // hh + hh aa = dd + // hh = dd / (1 + aa) float diag = 2.0f * std::sin(halfPersp); float nearClip = std::cos(halfPersp); - float hw = 0.5f * sqrt(diag * diag / (1.0f + aspect * aspect)); - float hh = hw * aspect; + float hh = 0.5f * sqrt(diag * diag / (1.0f + aspect * aspect)); + float hw = hh * aspect; // cancel all translation mat4 matrix = orientation; From 715534154e02ab5f7567f2bbef0b70a87ec5c577 Mon Sep 17 00:00:00 2001 From: tosh Date: Fri, 19 Apr 2013 02:46:34 +0200 Subject: [PATCH 02/11] numerous starfield fixes --- interface/src/Stars.cpp | 12 ++- interface/src/Stars.h | 80 +++++++-------- interface/src/main.cpp | 7 +- interface/src/starfield/renderer/Renderer.h | 105 ++++++++++++-------- interface/src/starfield/renderer/Tiling.h | 3 +- libraries/shared/src/FloodFill.h | 101 ++++++++----------- 6 files changed, 164 insertions(+), 144 deletions(-) diff --git a/interface/src/Stars.cpp b/interface/src/Stars.cpp index 97d68bc61d..a049269305 100644 --- a/interface/src/Stars.cpp +++ b/interface/src/Stars.cpp @@ -34,7 +34,17 @@ float Stars::changeLOD(float fraction, float overalloc, float realloc) { return float(_ptrController->changeLOD(fraction, overalloc, realloc)); } -void Stars::render(float fovDiagonal, float aspect, glm::mat4 const& view) { +void Stars::render(float fovY, float aspect, float nearZ) { + + // determine length of screen diagonal from quadrant height and aspect ratio + float quadrantHeight = nearZ * tan(angleConvert(fovY) * 0.5f); + float halfDiagonal = sqrt(quadrantHeight * quadrantHeight * (1.0f + aspect * aspect)); + + // determine fov angle in respect to the diagonal + float fovDiagonal = atan(halfDiagonal / nearZ) * 2.0f; + + // pull the modelview matrix off the GL stack + glm::mat4 view; glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view)); _ptrController->render(fovDiagonal, aspect, glm::affineInverse(view)); } diff --git a/interface/src/Stars.h b/interface/src/Stars.h index 92c7b0f806..caca215444 100644 --- a/interface/src/Stars.h +++ b/interface/src/Stars.h @@ -13,9 +13,9 @@ namespace starfield { class Controller; } -/** - * Starfield rendering component. - */ +// +// Starfield rendering component. +// class Stars { starfield::Controller* _ptrController; @@ -25,49 +25,49 @@ class Stars { Stars(); ~Stars(); - /** - * Reads input file from URL. Returns true upon success. - * - * The limit parameter allows to reduce the number of stars - * that are loaded, keeping the brightest ones. - */ + // + // Reads input file from URL. Returns true upon success. + // + // The limit parameter allows to reduce the number of stars + // that are loaded, keeping the brightest ones. + // bool readInput(const char* url, const char* cacheFile = 0l, unsigned limit = 200000); - /** - * Renders the starfield from a local viewer's perspective. - * The parameter specifies the field of view. - */ - void render(float fovDiagonal, float aspect, glm::mat4 const& view); + // + // Renders the starfield from a local viewer's perspective. + // The parameters specifiy the field of view. + // + void render(float fovY, float aspect, float nearZ); - /** - * Sets the resolution for FOV culling. - * - * The parameter determines the number of tiles in azimuthal - * and altitudinal directions. - * - * GPU resources are updated upon change in which case 'true' - * is returned. - */ + // + // Sets the resolution for FOV culling. + // + // The parameter determines the number of tiles in azimuthal + // and altitudinal directions. + // + // GPU resources are updated upon change in which case 'true' + // is returned. + // bool setResolution(unsigned k); - /** - * Allows to alter the number of stars to be rendered given a - * factor. The least brightest ones are omitted first. - * - * The further parameters determine when GPU resources should - * be reallocated. Its value is fractional in respect to the - * last number of stars 'n' that caused 'n * (1+overalloc)' to - * be allocated. When the next call to setLOD causes the total - * number of stars that could be rendered to drop below 'n * - * (1-realloc)' or rises above 'n * (1+realloc)' GPU resources - * are updated. Note that all parameters must be fractions, - * that is within the range [0;1] and that 'overalloc' must be - * greater than or equal to 'realloc'. - * - * The current level of detail is returned as a float in [0;1]. - */ + // + // Allows to alter the number of stars to be rendered given a + // factor. The least brightest ones are omitted first. + // + // The further parameters determine when GPU resources should + // be reallocated. Its value is fractional in respect to the + // last number of stars 'n' that caused 'n * (1+overalloc)' to + // be allocated. When the next call to setLOD causes the total + // number of stars that could be rendered to drop below 'n * + // (1-realloc)' or rises above 'n * (1+realloc)' GPU resources + // are updated. Note that all parameters must be fractions, + // that is within the range [0;1] and that 'overalloc' must be + // greater than or equal to 'realloc'. + // + // The current level of detail is returned as a float in [0;1]. + // float changeLOD(float factor, - float overalloc = 0.25, float realloc = 0.15); + float overalloc = 0.25, float realloc = 0.15); private: // don't copy/assign diff --git a/interface/src/main.cpp b/interface/src/main.cpp index c44aeea168..a413a0cedf 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -762,9 +762,10 @@ void display(void) if (::starsOn) { // should be the first rendering pass - w/o depth buffer / lighting - glm::mat4 view; - glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view)); - stars.render(angleConvert(whichCamera.getFieldOfView()), aspectRatio, view); + + // finally render the starfield + stars.render(whichCamera.getFieldOfView(), aspectRatio, whichCamera.getNearClip()); + } glEnable(GL_LIGHTING); diff --git a/interface/src/starfield/renderer/Renderer.h b/interface/src/starfield/renderer/Renderer.h index 5148c5fa01..c0ffff2ce2 100644 --- a/interface/src/starfield/renderer/Renderer.h +++ b/interface/src/starfield/renderer/Renderer.h @@ -130,16 +130,17 @@ namespace starfield { float halfPersp = perspective * 0.5f; - // determine dimensions based on a sought screen diagonal + // define diagonal and near distance + float halfDiag = std::sin(halfPersp); + float nearClip = std::cos(halfPersp); + + // determine half dimensions based on the screen diagonal // // ww + hh = dd // a = w / h => w = ha // hh + hh aa = dd // hh = dd / (1 + aa) - float diag = 2.0f * std::sin(halfPersp); - float nearClip = std::cos(halfPersp); - - float hh = 0.5f * sqrt(diag * diag / (1.0f + aspect * aspect)); + float hh = sqrt(halfDiag * halfDiag / (1.0f + aspect * aspect)); float hw = hh * aspect; // cancel all translation @@ -154,32 +155,34 @@ namespace starfield { float azimuth = atan2(ahead.x,-ahead.z) + Radians::pi(); float altitude = atan2(-ahead.y, hypotf(ahead.x, ahead.z)); angleHorizontalPolar(azimuth, altitude); + float const eps = 0.002f; + altitude = glm::clamp(altitude, + -Radians::halfPi() + eps, Radians::halfPi() - eps); #if STARFIELD_HEMISPHERE_ONLY altitude = std::max(0.0f, altitude); #endif - unsigned tileIndex = - _objTiling.getTileIndex(azimuth, altitude); - // fprintf(stderr, "Stars.cpp: starting on tile #%d\n", tileIndex); #if STARFIELD_DEBUG_CULLING - mat4 matrix_debug = glm::translate( - glm::frustum(-hw, hw, -hh, hh, nearClip, 10.0f), - vec3(0.0f, 0.0f, -4.0f)) * glm::affineInverse(matrix); + mat4 matrix_debug = glm::translate(glm::frustum(-hw, hw, -hh, hh, nearClip, 10.0f), + vec3(0.0f, 0.0f, -4.0f)) * + glm::affineInverse(matrix); #endif - matrix = glm::frustum(-hw,hw, -hh,hh, nearClip,10.0f) - * glm::affineInverse(matrix); + matrix = glm::frustum(-hw,hw, -hh,hh, nearClip,10.0f) * glm::affineInverse(matrix); this->_itrOutIndex = (unsigned*) _arrBatchOffs; this->_vecWxform = vec3(row(matrix, 3)); this->_valHalfPersp = halfPersp; this->_valMinBright = minBright; - floodFill(_arrTile + tileIndex, TileSelection(*this, - _arrTile, _arrTile + _objTiling.getTileCount(), - (Tile**) _arrBatchCount)); + TileSelection::Cursor cursor; + cursor.current = _arrTile + _objTiling.getTileIndex(azimuth, altitude); + cursor.firstInRow = _arrTile + _objTiling.getTileIndex(0.0f, altitude); + + floodFill(cursor, TileSelection(*this, _arrTile, _arrTile + _objTiling.getTileCount(), + (TileSelection::Cursor*) _arrBatchCount)); #if STARFIELD_DEBUG_CULLING # define matrix matrix_debug @@ -269,31 +272,35 @@ namespace starfield { class TileSelection { + public: + struct Cursor { Tile* current, * firstInRow; }; + private: Renderer& _refRenderer; - Tile** const _arrStack; - Tile** _itrStack; + Cursor* const _arrStack; + Cursor* _itrStack; Tile const* const _arrTile; - Tile const* const _itrTilesEnd; + Tile const* const _ptrTilesEnd; public: TileSelection(Renderer& renderer, Tile const* tiles, - Tile const* tiles_end, Tile** stack) : + Tile const* tiles_end, Cursor* stack) : _refRenderer(renderer), _arrStack(stack), _itrStack(stack), _arrTile(tiles), - _itrTilesEnd(tiles_end) { + _ptrTilesEnd(tiles_end) { } protected: // flood fill strategy - bool select(Tile* t) { + bool select(Cursor const& c) { + Tile* t = c.current; - if (t < _arrTile || t >= _itrTilesEnd || + if (t < _arrTile || t >= _ptrTilesEnd || !! (t->flags & Tile::checked)) { // out of bounds or been here already @@ -311,7 +318,8 @@ namespace starfield { return false; } - bool process(Tile* t) { + bool process(Cursor const& c) { + Tile* t = c.current; if (! (t->flags & Tile::visited)) { @@ -321,14 +329,39 @@ namespace starfield { return false; } - void right(Tile*& cursor) const { cursor += 1; } - void left(Tile*& cursor) const { cursor -= 1; } - void up(Tile*& cursor) const { cursor += yStride(); } - void down(Tile*& cursor) const { cursor -= yStride(); } + void right(Cursor& c) const { - void defer(Tile* t) { *_itrStack++ = t; } + c.current += 1; + if (c.current == c.firstInRow + _refRenderer._objTiling.getAzimuthalTiles()) { + c.current = c.firstInRow; + } + } + void left(Cursor& c) const { + + if (c.current == c.firstInRow) { + c.current = c.firstInRow + _refRenderer._objTiling.getAzimuthalTiles(); + } + c.current -= 1; + } + void up(Cursor& c) const { - bool deferred(Tile*& cursor) { + unsigned d = _refRenderer._objTiling.getAzimuthalTiles(); + c.current += d; + c.firstInRow += d; + } + void down(Cursor& c) const { + + unsigned d = _refRenderer._objTiling.getAzimuthalTiles(); + c.current -= d; + c.firstInRow -= d; + } + + void defer(Cursor const& t) { + + *_itrStack++ = t; + } + + bool deferred(Cursor& cursor) { if (_itrStack != _arrStack) { cursor = *--_itrStack; @@ -336,12 +369,6 @@ namespace starfield { } return false; } - - private: - unsigned yStride() const { - - return _refRenderer._objTiling.getAzimuthalTiles(); - } }; bool visitTile(Tile* t) { @@ -362,6 +389,7 @@ namespace starfield { bool tileVisible(Tile* t, unsigned i) { float slice = _objTiling.getSliceAngle(); + float halfSlice = 0.5f * slice; unsigned stride = _objTiling.getAzimuthalTiles(); float azimuth = (i % stride) * slice; float altitude = (i / stride) * slice - Radians::halfPi(); @@ -371,14 +399,13 @@ namespace starfield { vec3 tileCenter = vec3(gx * exz, sin(altitude), gz * exz); float w = dot(_vecWxform, tileCenter); - float halfSlice = 0.5f * slice; - float daz = halfSlice * cos(abs(altitude) - halfSlice); + float daz = halfSlice * cos(std::max(0.0f, abs(altitude) - halfSlice)); float dal = halfSlice; float adjustedNear = cos(_valHalfPersp + sqrt(daz * daz + dal * dal)); // fprintf(stderr, "Stars.cpp: checking tile #%d, w = %f, near = %f\n", i, w, nearClip); - return w > adjustedNear; + return w >= adjustedNear; } void updateVertexCount(Tile* t, BrightnessLevel minBright) { diff --git a/interface/src/starfield/renderer/Tiling.h b/interface/src/starfield/renderer/Tiling.h index 1df4dd1956..56df23f30c 100644 --- a/interface/src/starfield/renderer/Tiling.h +++ b/interface/src/starfield/renderer/Tiling.h @@ -1,5 +1,5 @@ // -// starfield/renderer/ +// starfield/renderer/Tiling.h // interface // // Created by Tobias Schwinger on 3/22/13. @@ -51,6 +51,7 @@ namespace starfield { private: unsigned discreteAngle(float unsigned_angle) const { + return unsigned(floor(unsigned_angle * _valRcpSlice + 0.5f)); } diff --git a/libraries/shared/src/FloodFill.h b/libraries/shared/src/FloodFill.h index 273c1c4f6e..40a89bfd1b 100644 --- a/libraries/shared/src/FloodFill.h +++ b/libraries/shared/src/FloodFill.h @@ -9,32 +9,31 @@ #ifndef __hifi__FloodFill__ #define __hifi__FloodFill__ -/** - * Line scanning, iterative flood fill algorithm. - * - * The strategy must obey the following contract: - * - * There is an associated cursor that represents a position on the image. - * The member functions 'left(C&)', 'right(C&)', 'up(C&)', and 'down(C&)' - * move it. - * The state of a cursor can be deferred to temporary storage (typically a - * stack or a queue) using the 'defer(C const&)' member function. - * Calling 'deferred(C&)' restores a cursor's state from temporary storage - * and removes it there. - * The 'select(C const&)' and 'process(C const&)' functions control the - * algorithm. The former is called to determine where to go. It may be - * called multiple times but does not have to (and should not) return - * 'true' more than once for a pixel to be selected (will cause memory - * overuse, otherwise). The latter will never be called for a given pixel - * unless previously selected. It may be called multiple times, in which - * case it should return 'true' upon successful processing and 'false' - * when an already processed pixel has been visited. - * - * Note: The terms "image" and "pixel" are used for illustratory purposes - * and mean "undirected graph with 4-connected 2D grid topology" and "node", - * respectively. - * - */ +// +// Line scanning, iterative flood fill algorithm. +// +// The strategy must obey the following contract: +// +// There is an associated cursor that represents a position on the image. +// The member functions 'left(C&)', 'right(C&)', 'up(C&)', and 'down(C&)' +// move it. +// The state of a cursor can be deferred to temporary storage (typically a +// stack or a queue) using the 'defer(C const&)' member function. +// Calling 'deferred(C&)' restores a cursor's state from temporary storage +// and removes it there. +// The 'select(C const&)' and 'process(C const&)' functions control the +// algorithm. The former is called to determine where to go. It may be +// called multiple times but does not have to (and should not) return +// 'true' more than once for a pixel to be selected (will cause memory +// overuse, otherwise). The latter will never be called for a given pixel +// unless previously selected. It may be called multiple times, in which +// case it should return 'true' upon successful processing and 'false' +// when an already processed pixel has been visited. +// +// Note: The terms "image" and "pixel" are used for illustratory purposes +// and mean "undirected graph with 4-connected 2D grid topology" and "node", +// respectively. +// template< class Strategy, typename Cursor > void floodFill(Cursor const& position, Strategy const& strategy = Strategy()); @@ -63,57 +62,39 @@ struct floodFill_impl : Strategy { } Cursor higher, lower, h,l, i; - bool higherFound, lowerFound, hf, lf; do { if (! process(position)) { continue; } - higher = position; higherFound = false; - up(higher); yTest(higher, higherFound); - lower = position; lowerFound = false; - down(lower); yTest(lower, lowerFound); + higher = position; + up(higher); + if (select(higher)) { defer(higher); } + + lower = position; + down(lower); + if (select(lower)) { defer(lower); } i = position, h = higher, l = lower; - hf = higherFound, lf = lowerFound; do { - right(i), right(h), right(l); yTest(h,hf); yTest(l,lf); - } while (selectAndProcess(i)); + right(i), right(h), right(l); + if (select(h)) { defer(h); } + if (select(l)) { defer(l); } + + } while (select(i) && process(i)); i = position, h = higher, l = lower; - hf = higherFound, lf = lowerFound; do { - left(i); left(h); left(l); yTest(h,hf); yTest(l,lf); + left(i); left(h); left(l); + if (select(h)) { defer(h); } + if (select(l)) { defer(l); } - } while (selectAndProcess(i)); + } while (select(i) && process(i)); } while (deferred(position)); } - - bool selectAndProcess(Cursor const& i) { - - if (select(i)) { - - process(i); - return true; - } - return false; - } - - void yTest(Cursor const& i, bool& state) { - - if (! select(i)) { - - state = false; - - } else if (! state) { - - state = true; - defer(i); - } - } }; template< class Strategy, typename Cursor > From 0332b455cbe986e5fced4c847e50bca0c82cfada Mon Sep 17 00:00:00 2001 From: tosh Date: Wed, 24 Apr 2013 13:33:53 +0200 Subject: [PATCH 03/11] removes leftover something and misplaced const-qualification that keeps it from compiling --- injector/src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/injector/src/main.cpp b/injector/src/main.cpp index 61327ec41b..028de6cb04 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -42,7 +42,7 @@ void usage(void) std::cout << " -c FLOAT,FLOAT,FLOAT,FLOAT X,Y,Z,YAW position in universe where audio will be originating from and direction. Defaults to 0,0,0,0" << std::endl; std::cout << " -a 0-255 Attenuation curve modifier, defaults to 255" << std::endl; std::cout << " -f FILENAME Name of audio source file. Required - RAW format, 22050hz 16bit signed mono" << std::endl; -}; +} bool processParameters(int parameterCount, char* parameterData[]) { @@ -91,9 +91,9 @@ bool processParameters(int parameterCount, char* parameterData[]) } } return true; -};_Position +}; -int main(int argc, const char* argv[]) { +int main(int argc, char* argv[]) { srand(time(0)); int AUDIO_UDP_SEND_PORT = 1500 + (rand() % (int)(1500 - 2000 + 1)); From eca6999c2c6d040cd971d7e56d1046ee5688b4c6 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 24 Apr 2013 11:02:23 -0700 Subject: [PATCH 04/11] added behavior in Eve for alternating between grasping and ungrasping hand (tho unable to test transmission). Also, improved readability of hand grasping logic in Head.cpp --- eve/src/main.cpp | 15 ++++++++++++++- injector/src/main.cpp | 2 +- interface/src/Head.cpp | 32 ++++++++++++++++++++++++-------- interface/src/Head.h | 4 +--- 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/eve/src/main.cpp b/eve/src/main.cpp index 3e075f7ba0..0166f8e615 100644 --- a/eve/src/main.cpp +++ b/eve/src/main.cpp @@ -27,6 +27,7 @@ const float MAX_ITERATIONS_BETWEEN_AUDIO_SENDS = (MAX_AUDIO_SEND_INTERVAL_SECS * bool stopReceiveAgentDataThread; bool injectAudioThreadRunning = false; +int handStateTimer = 0; int TEMP_AUDIO_LISTEN_PORT = 55439; // UDPSocket audioSocket(TEMP_AUDIO_LISTEN_PORT); @@ -124,7 +125,19 @@ int main(int argc, const char* argv[]) { eve.setHandPosition(glm::vec3(eve.getPosition()[0] - 0.2, 0.25, eve.getPosition()[2] + 0.1)); - + + // simulate the effect of pressing and un-pressing the mouse button/pad + handStateTimer ++; + if ( handStateTimer == 100 ) { + eve.setHandState(1); + } + if ( handStateTimer == 150 ) { + eve.setHandState(0); + } + if ( handStateTimer >= 200 ) { + handStateTimer = 0; + } + // read eve's audio data AudioInjector eveAudioInjector("eve.raw"); diff --git a/injector/src/main.cpp b/injector/src/main.cpp index 61327ec41b..b110f7553c 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -91,7 +91,7 @@ bool processParameters(int parameterCount, char* parameterData[]) } } return true; -};_Position +}; int main(int argc, const char* argv[]) { diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 9770bcbce1..a34d061ab5 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -48,7 +48,6 @@ Head::Head(bool isMine) { _velocity = glm::vec3( 0.0, 0.0, 0.0 ); _thrust = glm::vec3( 0.0, 0.0, 0.0 ); _rotation = glm::quat( 0.0f, 0.0f, 0.0f, 0.0f ); - _nearOtherAvatar = false; _bodyYaw = -90.0; _bodyPitch = 0.0; _bodyRoll = 0.0; @@ -130,6 +129,7 @@ Head::Head(bool isMine) { } } + _otherAvatar.nearby = false; _otherAvatar.handPosition = glm::vec3( 0.0f, 0.0f, 0.0f ); _otherAvatar.handState = 0; } @@ -141,7 +141,7 @@ Head::Head(const Head &otherAvatar) { _velocity = otherAvatar._velocity; _thrust = otherAvatar._thrust; _rotation = otherAvatar._rotation; - _nearOtherAvatar = otherAvatar._nearOtherAvatar; + _otherAvatar.nearby = otherAvatar._otherAvatar.nearby; _bodyYaw = otherAvatar._bodyYaw; _bodyPitch = otherAvatar._bodyPitch; _bodyRoll = otherAvatar._bodyRoll; @@ -303,7 +303,7 @@ void Head::simulate(float deltaTime) { //------------------------------------------------------------- if ( _isMine ) { - _nearOtherAvatar = false; + _otherAvatar.nearby = false; float closestDistance = 10000.0f; AgentList * agentList = AgentList::getInstance(); @@ -341,7 +341,7 @@ void Head::simulate(float deltaTime) { if ( distance < _maxArmLength ) { if ( distance < closestDistance ) { closestDistance = distance; - _nearOtherAvatar = true; + _otherAvatar.nearby = true; _otherAvatar.handPosition = otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); _otherAvatar.handState = (int)otherAvatar->getHandState(); } @@ -669,7 +669,7 @@ void Head::render(bool lookingInMirror) { if ( _isMine ) { if (_usingBodySprings) { - if ( _nearOtherAvatar ) { + if ( _otherAvatar.nearby ) { glm::vec3 v1( _bone[ AVATAR_BONE_RIGHT_HAND ].position ); glm::vec3 v2( _otherAvatar.handPosition ); @@ -1130,12 +1130,28 @@ void Head::updateHandMovement( float deltaTime ) { setHandState(_mousePressed); + if ( _otherAvatar.nearby ) { + if ( _otherAvatar.handState == 1 ) { + printf( "(1)" ); + } + //else { + // printf( "(0)" ); + //} + + if ( _handState == 1 ) { + printf( "1" ); + } + else { + printf( "0" ); + } + } + //--------------------------------------------------------------------- // if holding hands with another avatar, add a force to the hand... //--------------------------------------------------------------------- - if (( getHandState() == 1 ) + if (( _handState == 1 ) || ( _otherAvatar.handState == 1 )) { - if ( _nearOtherAvatar ) { + if ( _otherAvatar.nearby ) { glm::vec3 vectorToOtherHand = _otherAvatar.handPosition - _handHolding.position; glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHolding.position; @@ -1151,7 +1167,7 @@ void Head::updateHandMovement( float deltaTime ) { _handHolding.position = _bone[ AVATAR_BONE_RIGHT_HAND ].position; _handHolding.velocity = glm::vec3( 0.0, 0.0, 0.0 ); } - + //------------------------------------------------------------------------------- // determine the arm vector //------------------------------------------------------------------------------- diff --git a/interface/src/Head.h b/interface/src/Head.h index 428ba2228a..1e0a346a35 100644 --- a/interface/src/Head.h +++ b/interface/src/Head.h @@ -102,11 +102,11 @@ struct AvatarHandHolding struct OtherAvatar { + bool nearby; glm::vec3 handPosition; int handState; }; - struct AvatarBone { AvatarBoneID parent; // which bone is this bone connected to? @@ -191,7 +191,6 @@ class Head : public AvatarData { glm::vec3 getHeadPosition(); glm::vec3 getBonePosition( AvatarBoneID b ); glm::vec3 getBodyUpDirection(); - //int getHandState(); float getGirth(); float getHeight(); @@ -233,7 +232,6 @@ class Head : public AvatarData { OtherAvatar _otherAvatar; bool _mousePressed; float _bodyYawDelta; - bool _nearOtherAvatar; bool _usingBodySprings; glm::vec3 _movedHandOffset; float _springVelocityDecay; From 4e7f1ee4227f3fd573e4bf7eaa152c9cd8d4c28b Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 24 Apr 2013 11:39:43 -0700 Subject: [PATCH 05/11] more cleanup of hand holding code --- eve/src/main.cpp | 2 +- interface/src/Head.cpp | 102 ++++++++++++++++++++--------------------- 2 files changed, 51 insertions(+), 53 deletions(-) diff --git a/eve/src/main.cpp b/eve/src/main.cpp index 0166f8e615..903a2e6c96 100644 --- a/eve/src/main.cpp +++ b/eve/src/main.cpp @@ -137,7 +137,7 @@ int main(int argc, const char* argv[]) { if ( handStateTimer >= 200 ) { handStateTimer = 0; } - + // read eve's audio data AudioInjector eveAudioInjector("eve.raw"); diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index a34d061ab5..cf78625d4f 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -59,7 +59,6 @@ Head::Head(bool isMine) { //_transmitterTimer = 0; _transmitterHz = 0.0; _transmitterPackets = 0; - //_numOtherAvatars = 0; initializeSkeleton(); @@ -307,8 +306,6 @@ void Head::simulate(float deltaTime) { float closestDistance = 10000.0f; AgentList * agentList = AgentList::getInstance(); - - //_numOtherAvatars = 0; for(std::vector::iterator agent = agentList->getAgents().begin(); agent != agentList->getAgents().end(); @@ -316,35 +313,31 @@ void Head::simulate(float deltaTime) { if (( agent->getLinkedData() != NULL && ( agent->getType() == AGENT_TYPE_AVATAR ) )) { Head *otherAvatar = (Head *)agent->getLinkedData(); - // if ( _numOtherAvatars < MAX_OTHER_AVATARS ) - { - - //------------------------------------------------------ - // check for collisions with other avatars and respond - //------------------------------------------------------ - updateAvatarCollisionDetectionAndResponse - ( - otherAvatar->getPosition(), - otherAvatar->getGirth(), - otherAvatar->getHeight(), - otherAvatar->getBodyUpDirection(), - deltaTime - ); - - //------------------------------------------------- - // test other avatar hand position for proximity - //------------------------------------------------ - glm::vec3 v( _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position ); - v -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); - - float distance = glm::length( v ); - if ( distance < _maxArmLength ) { - if ( distance < closestDistance ) { - closestDistance = distance; - _otherAvatar.nearby = true; - _otherAvatar.handPosition = otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); - _otherAvatar.handState = (int)otherAvatar->getHandState(); - } + //------------------------------------------------------ + // check for collisions with other avatars and respond + //------------------------------------------------------ + updateAvatarCollisionDetectionAndResponse + ( + otherAvatar->getPosition(), + otherAvatar->getGirth(), + otherAvatar->getHeight(), + otherAvatar->getBodyUpDirection(), + deltaTime + ); + + //------------------------------------------------- + // test other avatar hand position for proximity + //------------------------------------------------ + glm::vec3 v( _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position ); + v -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); + + float distance = glm::length( v ); + if ( distance < _maxArmLength ) { + if ( distance < closestDistance ) { + closestDistance = distance; + _otherAvatar.nearby = true; + _otherAvatar.handPosition = otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); + _otherAvatar.handState = (int)otherAvatar->getHandState(); } } } @@ -1130,13 +1123,14 @@ void Head::updateHandMovement( float deltaTime ) { setHandState(_mousePressed); + /* if ( _otherAvatar.nearby ) { if ( _otherAvatar.handState == 1 ) { printf( "(1)" ); } - //else { - // printf( "(0)" ); - //} + else { + printf( "(0)" ); + } if ( _handState == 1 ) { printf( "1" ); @@ -1145,27 +1139,31 @@ void Head::updateHandMovement( float deltaTime ) { printf( "0" ); } } + */ //--------------------------------------------------------------------- - // if holding hands with another avatar, add a force to the hand... + // if I am holding hands with another avatar, a force is added + // to my hand, causing it to move closer to the other avatar's hand... //--------------------------------------------------------------------- - if (( _handState == 1 ) - || ( _otherAvatar.handState == 1 )) { + if ( _isMine ) + { if ( _otherAvatar.nearby ) { - - glm::vec3 vectorToOtherHand = _otherAvatar.handPosition - _handHolding.position; - glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHolding.position; - - _handHolding.velocity *= 0.7; - _handHolding.velocity += ( vectorToOtherHand + vectorToMyHand ) * _handHolding.force * deltaTime; - _handHolding.position += _handHolding.velocity; - - _bone[ AVATAR_BONE_RIGHT_HAND ].position = _handHolding.position; - } - } - else { - _handHolding.position = _bone[ AVATAR_BONE_RIGHT_HAND ].position; - _handHolding.velocity = glm::vec3( 0.0, 0.0, 0.0 ); + if (( getHandState() == 1 ) + || ( _otherAvatar.handState == 1 )) { + glm::vec3 vectorToOtherHand = _otherAvatar.handPosition - _handHolding.position; + glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHolding.position; + + _handHolding.velocity *= 0.7; + _handHolding.velocity += ( vectorToOtherHand + vectorToMyHand ) * _handHolding.force * deltaTime; + _handHolding.position += _handHolding.velocity; + + _bone[ AVATAR_BONE_RIGHT_HAND ].position = _handHolding.position; + } + } + else { + _handHolding.position = _bone[ AVATAR_BONE_RIGHT_HAND ].position; + _handHolding.velocity = glm::vec3( 0.0, 0.0, 0.0 ); + } } //------------------------------------------------------------------------------- From 86086ef20c2d43617434eea8fcb16ef67d262edc Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 24 Apr 2013 14:52:04 -0700 Subject: [PATCH 06/11] just did a fairly major re-ordering of avatar interaction logic in Head.cpp --- interface/src/Head.cpp | 315 +++++++++++++++++++---------------------- interface/src/Head.h | 10 +- 2 files changed, 153 insertions(+), 172 deletions(-) diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index cf78625d4f..f736850d4b 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -67,54 +67,51 @@ Head::Head(bool isMine) { for (int i = 0; i < MAX_DRIVE_KEYS; i++) _driveKeys[i] = false; - _head.pupilSize = 0.10; - _head.interPupilDistance = 0.6; - _head.interBrowDistance = 0.75; - _head.nominalPupilSize = 0.10; - //_head.yaw = 0.0; - //_head.pitch = 0.0; - //_head.roll = 0.0; - _head.pitchRate = 0.0; - _head.yawRate = 0.0; - _head.rollRate = 0.0; - _head.eyebrowPitch[0] = -30; - _head.eyebrowPitch[1] = -30; - _head.eyebrowRoll [0] = 20; - _head.eyebrowRoll [1] = -20; - _head.mouthPitch = 0; - _head.mouthYaw = 0; - _head.mouthWidth = 1.0; - _head.mouthHeight = 0.2; - _head.eyeballPitch[0] = 0; - _head.eyeballPitch[1] = 0; - _head.eyeballScaleX = 1.2; - _head.eyeballScaleY = 1.5; - _head.eyeballScaleZ = 1.0; - _head.eyeballYaw[0] = 0; - _head.eyeballYaw[1] = 0; - _head.pitchTarget = 0; - _head.yawTarget = 0; - _head.noiseEnvelope = 1.0; - _head.pupilConverge = 10.0; - _head.leanForward = 0.0; - _head.leanSideways = 0.0; - _head.eyeContact = 1; - _head.eyeContactTarget = LEFT_EYE; - _head.scale = 1.0; - _head.audioAttack = 0.0; - _head.averageLoudness = 0.0; - _head.lastLoudness = 0.0; - _head.browAudioLift = 0.0; - _head.noise = 0; - - _movedHandOffset = glm::vec3( 0.0, 0.0, 0.0 ); - _usingBodySprings = true; - _springForce = 6.0f; - _springVelocityDecay = 16.0f; - _renderYaw = 0.0; - _renderPitch = 0.0; - - _sphere = NULL; + _head.pupilSize = 0.10; + _head.interPupilDistance = 0.6; + _head.interBrowDistance = 0.75; + _head.nominalPupilSize = 0.10; + _head.pitchRate = 0.0; + _head.yawRate = 0.0; + _head.rollRate = 0.0; + _head.eyebrowPitch[0] = -30; + _head.eyebrowPitch[1] = -30; + _head.eyebrowRoll [0] = 20; + _head.eyebrowRoll [1] = -20; + _head.mouthPitch = 0; + _head.mouthYaw = 0; + _head.mouthWidth = 1.0; + _head.mouthHeight = 0.2; + _head.eyeballPitch[0] = 0; + _head.eyeballPitch[1] = 0; + _head.eyeballScaleX = 1.2; + _head.eyeballScaleY = 1.5; + _head.eyeballScaleZ = 1.0; + _head.eyeballYaw[0] = 0; + _head.eyeballYaw[1] = 0; + _head.pitchTarget = 0; + _head.yawTarget = 0; + _head.noiseEnvelope = 1.0; + _head.pupilConverge = 10.0; + _head.leanForward = 0.0; + _head.leanSideways = 0.0; + _head.eyeContact = 1; + _head.eyeContactTarget = LEFT_EYE; + _head.scale = 1.0; + _head.audioAttack = 0.0; + _head.averageLoudness = 0.0; + _head.lastLoudness = 0.0; + _head.browAudioLift = 0.0; + _head.noise = 0; + _movedHandOffset = glm::vec3( 0.0, 0.0, 0.0 ); + _usingBodySprings = true; + _springForce = 6.0f; + _springVelocityDecay = 16.0f; + _renderYaw = 0.0; + _renderPitch = 0.0; + _sphere = NULL; + _interactingOther = NULL; + _interactingOtherIsNearby = false; _handHolding.position = glm::vec3( 0.0, 0.0, 0.0 ); _handHolding.velocity = glm::vec3( 0.0, 0.0, 0.0 ); @@ -127,39 +124,35 @@ Head::Head(bool isMine) { printLog("error %u: %s\n", error, lodepng_error_text(error)); } } - - _otherAvatar.nearby = false; - _otherAvatar.handPosition = glm::vec3( 0.0f, 0.0f, 0.0f ); - _otherAvatar.handState = 0; } Head::Head(const Head &otherAvatar) { - _velocity = otherAvatar._velocity; - _thrust = otherAvatar._thrust; - _rotation = otherAvatar._rotation; - _otherAvatar.nearby = otherAvatar._otherAvatar.nearby; - _bodyYaw = otherAvatar._bodyYaw; - _bodyPitch = otherAvatar._bodyPitch; - _bodyRoll = otherAvatar._bodyRoll; - _bodyYawDelta = otherAvatar._bodyYawDelta; - _mousePressed = otherAvatar._mousePressed; - _mode = otherAvatar._mode; - _isMine = otherAvatar._isMine; - _renderYaw = otherAvatar._renderYaw; - _renderPitch = otherAvatar._renderPitch; - _maxArmLength = otherAvatar._maxArmLength; - _transmitterTimer = otherAvatar._transmitterTimer; - _transmitterHz = otherAvatar._transmitterHz; - _transmitterPackets = otherAvatar._transmitterPackets; - _TEST_bigSphereRadius = otherAvatar._TEST_bigSphereRadius; - _TEST_bigSpherePosition = otherAvatar._TEST_bigSpherePosition; - _movedHandOffset = otherAvatar._movedHandOffset; - _usingBodySprings = otherAvatar._usingBodySprings; - _springForce = otherAvatar._springForce; - _springVelocityDecay = otherAvatar._springVelocityDecay; + _velocity = otherAvatar._velocity; + _thrust = otherAvatar._thrust; + _rotation = otherAvatar._rotation; + _interactingOtherIsNearby = otherAvatar._interactingOtherIsNearby; + _bodyYaw = otherAvatar._bodyYaw; + _bodyPitch = otherAvatar._bodyPitch; + _bodyRoll = otherAvatar._bodyRoll; + _bodyYawDelta = otherAvatar._bodyYawDelta; + _mousePressed = otherAvatar._mousePressed; + _mode = otherAvatar._mode; + _isMine = otherAvatar._isMine; + _renderYaw = otherAvatar._renderYaw; + _renderPitch = otherAvatar._renderPitch; + _maxArmLength = otherAvatar._maxArmLength; + _transmitterTimer = otherAvatar._transmitterTimer; + _transmitterHz = otherAvatar._transmitterHz; + _transmitterPackets = otherAvatar._transmitterPackets; + _TEST_bigSphereRadius = otherAvatar._TEST_bigSphereRadius; + _TEST_bigSpherePosition = otherAvatar._TEST_bigSpherePosition; + _movedHandOffset = otherAvatar._movedHandOffset; + _usingBodySprings = otherAvatar._usingBodySprings; + _springForce = otherAvatar._springForce; + _springVelocityDecay = otherAvatar._springVelocityDecay; _orientation.set( otherAvatar._orientation ); _sphere = NULL; @@ -172,9 +165,6 @@ Head::Head(const Head &otherAvatar) { _head.interPupilDistance = otherAvatar._head.interPupilDistance; _head.interBrowDistance = otherAvatar._head.interBrowDistance; _head.nominalPupilSize = otherAvatar._head.nominalPupilSize; - //_head.yaw = otherAvatar._head.yaw; - //_head.pitch = otherAvatar._head.pitch; - //_head.roll = otherAvatar._head.roll; _head.yawRate = otherAvatar._head.yawRate; _head.pitchRate = otherAvatar._head.pitchRate; _head.rollRate = otherAvatar._head.rollRate; @@ -208,7 +198,6 @@ Head::Head(const Head &otherAvatar) { _head.browAudioLift = otherAvatar._head.browAudioLift; _head.noise = otherAvatar._head.noise; - if (iris_texture.size() == 0) { switchToResourcesParentIfRequired(); unsigned error = lodepng::decode(iris_texture, iris_texture_width, iris_texture_height, iris_texture_file); @@ -295,16 +284,33 @@ void Head::setMousePressed( bool d ) { } void Head::simulate(float deltaTime) { + + //------------------------ + // update avatar skeleton + //------------------------ + updateSkeleton(); + + //------------------------------------------------------------ + // reset hand and arm positions according to hand movement + //------------------------------------------------------------ + updateHandMovement( deltaTime ); + + if ( !_interactingOtherIsNearby ) { + //initialize _handHolding + _handHolding.position = _bone[ AVATAR_BONE_RIGHT_HAND ].position; + _handHolding.velocity = glm::vec3( 0.0, 0.0, 0.0 ); + } + + _interactingOtherIsNearby = false; //------------------------------------------------------------- // if the avatar being simulated is mine, then loop through - // all the other avatars to get information about them... + // all the other avatars for potential interactions... //------------------------------------------------------------- if ( _isMine ) { - _otherAvatar.nearby = false; float closestDistance = 10000.0f; - + AgentList * agentList = AgentList::getInstance(); for(std::vector::iterator agent = agentList->getAgents().begin(); @@ -333,18 +339,44 @@ void Head::simulate(float deltaTime) { float distance = glm::length( v ); if ( distance < _maxArmLength ) { - if ( distance < closestDistance ) { + + //if ( distance < closestDistance ) { // perhaps I don't need this if we want to allow multi-avatar interactions + { closestDistance = distance; - _otherAvatar.nearby = true; - _otherAvatar.handPosition = otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); - _otherAvatar.handState = (int)otherAvatar->getHandState(); + _interactingOther = otherAvatar; + _interactingOtherIsNearby = true; + + //--------------------------------------------------------------------- + // if I am holding hands with another avatar, a force is applied + //--------------------------------------------------------------------- + if (( getHandState() == 1 ) + || ( _interactingOther->_handState == 1 )) { + glm::vec3 vectorToOtherHand = _interactingOther->_handPosition - _handHolding.position; + glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHolding.position; + + _handHolding.velocity *= 0.7; + _handHolding.velocity += ( vectorToOtherHand + vectorToMyHand ) * _handHolding.force * deltaTime; + _handHolding.position += _handHolding.velocity; + + _bone[ AVATAR_BONE_RIGHT_HAND ].position = _handHolding.position; + } } } } } - }//if ( _isMine ) + // Set the vector we send for hand position to other people to be our right hand + setHandPosition(_bone[ AVATAR_BONE_RIGHT_HAND ].position); + }//if ( _isMine ) + + + updateArmIKAndConstraints( deltaTime ); + + if ( ! _interactingOtherIsNearby ) { + _interactingOther = NULL; + } + if ( usingBigSphereCollisionTest ) { //-------------------------------------------------------------- // test for avatar collision response (using a big sphere :) @@ -371,19 +403,10 @@ void Head::simulate(float deltaTime) { } } - //------------------------ - // update avatar skeleton - //------------------------ - updateSkeleton(); - - //------------------------------------------------------------ - // reset hand and arm positions according to hand movement - //------------------------------------------------------------ - if (_usingBodySprings) { - updateHandMovement( deltaTime ); - updateBodySprings( deltaTime ); - } - + // update body springs + updateBodySprings( deltaTime ); + + if ( _isMine ) { // driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely) //------------------------------------------------- // this handles the avatar being driven around... @@ -442,7 +465,6 @@ void Head::simulate(float deltaTime) { _bodyYaw += _bodyYawDelta * deltaTime; } - //---------------------------------------------------------- // decay body yaw delta //---------------------------------------------------------- @@ -620,8 +642,6 @@ void Head::updateAvatarCollisionDetectionAndResponse } - - void Head::render(bool lookingInMirror) { //--------------------------------------------------- @@ -646,9 +666,9 @@ void Head::render(bool lookingInMirror) { glPopMatrix(); } - //--------------------------------------------------- + //--------------- // render body - //--------------------------------------------------- + //--------------- renderBody(); //--------------------------------------------------- @@ -657,28 +677,25 @@ void Head::render(bool lookingInMirror) { renderHead(lookingInMirror); //--------------------------------------------------------------------------- - // if this is my avatar, then render my interactions with the other avatars + // if this is my avatar, then render my interactions with the other avatar //--------------------------------------------------------------------------- if ( _isMine ) { - if (_usingBodySprings) { - if ( _otherAvatar.nearby ) { + if ( _interactingOtherIsNearby ) { - glm::vec3 v1( _bone[ AVATAR_BONE_RIGHT_HAND ].position ); - glm::vec3 v2( _otherAvatar.handPosition ); - - glLineWidth( 8.0 ); - glColor4f( 0.7f, 0.4f, 0.1f, 0.6 ); - glBegin( GL_LINE_STRIP ); - glVertex3f( v1.x, v1.y, v1.z ); - glVertex3f( v2.x, v2.y, v2.z ); - glEnd(); - } + glm::vec3 v1( _bone[ AVATAR_BONE_RIGHT_HAND ].position ); + glm::vec3 v2( _interactingOther->_handPosition ); + + glLineWidth( 8.0 ); + glColor4f( 0.7f, 0.4f, 0.1f, 0.6 ); + glBegin( GL_LINE_STRIP ); + glVertex3f( v1.x, v1.y, v1.z ); + glVertex3f( v2.x, v2.y, v2.z ); + glEnd(); } } } - void Head::renderHead(bool lookingInMirror) { int side = 0; @@ -962,9 +979,9 @@ void Head::initializeSkeleton() { //---------------------------------------------------------------------------- calculateBoneLengths(); - //---------------------------------------------------------------------------- + //--------------------------- // generate world positions - //---------------------------------------------------------------------------- + //--------------------------- updateSkeleton(); } @@ -1121,51 +1138,14 @@ void Head::updateHandMovement( float deltaTime ) { _bone[ AVATAR_BONE_RIGHT_HAND ].position += transformedHandMovement; - setHandState(_mousePressed); - - /* - if ( _otherAvatar.nearby ) { - if ( _otherAvatar.handState == 1 ) { - printf( "(1)" ); - } - else { - printf( "(0)" ); - } + if (_isMine) { + setHandState(_mousePressed); + } +} + + +void Head::updateArmIKAndConstraints( float deltaTime ) { - if ( _handState == 1 ) { - printf( "1" ); - } - else { - printf( "0" ); - } - } - */ - - //--------------------------------------------------------------------- - // if I am holding hands with another avatar, a force is added - // to my hand, causing it to move closer to the other avatar's hand... - //--------------------------------------------------------------------- - if ( _isMine ) - { - if ( _otherAvatar.nearby ) { - if (( getHandState() == 1 ) - || ( _otherAvatar.handState == 1 )) { - glm::vec3 vectorToOtherHand = _otherAvatar.handPosition - _handHolding.position; - glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHolding.position; - - _handHolding.velocity *= 0.7; - _handHolding.velocity += ( vectorToOtherHand + vectorToMyHand ) * _handHolding.force * deltaTime; - _handHolding.position += _handHolding.velocity; - - _bone[ AVATAR_BONE_RIGHT_HAND ].position = _handHolding.position; - } - } - else { - _handHolding.position = _bone[ AVATAR_BONE_RIGHT_HAND ].position; - _handHolding.velocity = glm::vec3( 0.0, 0.0, 0.0 ); - } - } - //------------------------------------------------------------------------------- // determine the arm vector //------------------------------------------------------------------------------- @@ -1210,14 +1190,11 @@ void Head::updateHandMovement( float deltaTime ) { glm::vec3 newWristPosition = _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position; newWristPosition += vv * 0.7f; _bone[ AVATAR_BONE_RIGHT_FOREARM ].position = newWristPosition; - - // Set the vector we send for hand position to other people to be our right hand - setHandPosition(_bone[ AVATAR_BONE_RIGHT_HAND ].position); - } + void Head::renderBody() { //----------------------------------------- // Render bone positions as spheres diff --git a/interface/src/Head.h b/interface/src/Head.h index 1e0a346a35..377228986d 100644 --- a/interface/src/Head.h +++ b/interface/src/Head.h @@ -100,12 +100,14 @@ struct AvatarHandHolding float force; }; +/* struct OtherAvatar { bool nearby; - glm::vec3 handPosition; - int handState; + //glm::vec3 handPosition; + //int handState; }; +*/ struct AvatarBone { @@ -205,6 +207,7 @@ class Head : public AvatarData { void stopHandMovement(); void setHandMovementValues( glm::vec3 movement ); void updateHandMovement( float deltaTime ); + void updateArmIKAndConstraints( float deltaTime ); float getAverageLoudness() {return _head.averageLoudness;}; void setAverageLoudness(float al) {_head.averageLoudness = al;}; @@ -229,7 +232,6 @@ class Head : public AvatarData { bool _isMine; glm::vec3 _TEST_bigSpherePosition; float _TEST_bigSphereRadius; - OtherAvatar _otherAvatar; bool _mousePressed; float _bodyYawDelta; bool _usingBodySprings; @@ -251,6 +253,8 @@ class Head : public AvatarData { timeval _transmitterTimer; float _transmitterHz; int _transmitterPackets; + Head* _interactingOther; + bool _interactingOtherIsNearby; //----------------------------- // private methods... From e93430d553e5193319d49dd168def882e40baba5 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 24 Apr 2013 14:56:29 -0700 Subject: [PATCH 07/11] fix --- interface/src/Head.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index f9a4a51dab..94e36c5673 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -1148,7 +1148,8 @@ void Head::updateHandMovement( float deltaTime ) { _bone[ AVATAR_BONE_RIGHT_HAND ].position += transformedHandMovement; if (_isMine) { - setHandState(_mousePressed); + //setHandState(_mousePressed); + _handState = _mousePressed; } } From a9ff483d3d03f6db08827dbe73a502602aa3309b Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 24 Apr 2013 15:35:11 -0700 Subject: [PATCH 08/11] fix --- interface/src/Head.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 94e36c5673..1e6e78fef2 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -349,7 +349,7 @@ void Head::simulate(float deltaTime) { //--------------------------------------------------------------------- // if I am holding hands with another avatar, a force is applied //--------------------------------------------------------------------- - if (( getHandState() == 1 ) + if (( _handState == 1 ) || ( _interactingOther->_handState == 1 )) { glm::vec3 vectorToOtherHand = _interactingOther->_handPosition - _handHolding.position; glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHolding.position; @@ -1148,7 +1148,6 @@ void Head::updateHandMovement( float deltaTime ) { _bone[ AVATAR_BONE_RIGHT_HAND ].position += transformedHandMovement; if (_isMine) { - //setHandState(_mousePressed); _handState = _mousePressed; } } From e54fd0dd7d84d798efcddb04d0668948d50cf047 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 24 Apr 2013 16:54:07 -0700 Subject: [PATCH 09/11] renamed "Head" to "Avatar" and did a bunch a cleanups, including removing the three-lined comments --- eve/src/main.cpp | 32 +- interface/src/Audio.cpp | 10 +- interface/src/Audio.h | 4 +- interface/src/AudioData.h | 4 +- interface/src/Head.cpp | 1348 --------------------------------- interface/src/Head.h | 279 ------- interface/src/VoxelSystem.cpp | 6 +- interface/src/VoxelSystem.h | 6 +- interface/src/main.cpp | 12 +- 9 files changed, 37 insertions(+), 1664 deletions(-) delete mode 100644 interface/src/Head.cpp delete mode 100644 interface/src/Head.h diff --git a/eve/src/main.cpp b/eve/src/main.cpp index 903a2e6c96..2da001b368 100644 --- a/eve/src/main.cpp +++ b/eve/src/main.cpp @@ -27,7 +27,6 @@ const float MAX_ITERATIONS_BETWEEN_AUDIO_SENDS = (MAX_AUDIO_SEND_INTERVAL_SECS * bool stopReceiveAgentDataThread; bool injectAudioThreadRunning = false; -int handStateTimer = 0; int TEMP_AUDIO_LISTEN_PORT = 55439; // UDPSocket audioSocket(TEMP_AUDIO_LISTEN_PORT); @@ -124,20 +123,7 @@ int main(int argc, const char* argv[]) { // put her hand out so somebody can shake it eve.setHandPosition(glm::vec3(eve.getPosition()[0] - 0.2, 0.25, - eve.getPosition()[2] + 0.1)); - - // simulate the effect of pressing and un-pressing the mouse button/pad - handStateTimer ++; - if ( handStateTimer == 100 ) { - eve.setHandState(1); - } - if ( handStateTimer == 150 ) { - eve.setHandState(0); - } - if ( handStateTimer >= 200 ) { - handStateTimer = 0; - } - + eve.getPosition()[2] + 0.1)); // read eve's audio data AudioInjector eveAudioInjector("eve.raw"); @@ -152,6 +138,8 @@ int main(int argc, const char* argv[]) { // int numIterationsLeftBeforeAudioSend = 0; // pthread_t injectAudioThread; + int handStateTimer = 0; + while (true) { // update the thisSend timeval to the current time gettimeofday(&thisSend, NULL); @@ -183,7 +171,19 @@ int main(int argc, const char* argv[]) { // sleep for the correct amount of time to have data send be consistently timed if ((numMicrosecondsSleep = (DATA_SEND_INTERVAL_MSECS * 1000) - (usecTimestampNow() - usecTimestamp(&thisSend))) > 0) { usleep(numMicrosecondsSleep); - } + } + + // simulate the effect of pressing and un-pressing the mouse button/pad + handStateTimer++; + if ( handStateTimer == 100 ) { + eve.setHandState(1); + } + if ( handStateTimer == 150 ) { + eve.setHandState(0); + } + if ( handStateTimer >= 200 ) { + handStateTimer = 0; + } } // stop the receive agent data thread diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 287325c090..4b522d5823 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -157,7 +157,7 @@ int audioCallback (const void *inputBuffer, // memcpy the three float positions for (int p = 0; p < 3; p++) { - memcpy(currentPacketPtr, &data->linkedHead->getPosition()[p], sizeof(float)); + memcpy(currentPacketPtr, &data->linkedAvatar->getPosition()[p], sizeof(float)); currentPacketPtr += sizeof(float); } @@ -165,7 +165,7 @@ int audioCallback (const void *inputBuffer, *(currentPacketPtr++) = 255; // memcpy the corrected render yaw - float correctedYaw = fmodf(data->linkedHead->getRenderYaw(), 360); + float correctedYaw = fmodf(data->linkedAvatar->getRenderYaw(), 360); if (correctedYaw > 180) { correctedYaw -= 360; @@ -259,7 +259,7 @@ int audioCallback (const void *inputBuffer, // rotation of the head relative to body, this may effect flange effect! // // - int lastYawMeasured = fabsf(data->linkedHead->getLastMeasuredHeadYaw()); + int lastYawMeasured = fabsf(data->linkedAvatar->getLastMeasuredHeadYaw()); if (!samplesLeftForFlange && lastYawMeasured > MIN_FLANGE_EFFECT_THRESHOLD) { // we should flange for one second @@ -448,7 +448,7 @@ void Audio::setWalkingState(bool newWalkState) { * @return Returns true if successful or false if an error occurred. Use Audio::getError() to retrieve the error code. */ -Audio::Audio(Oscilloscope *s, Head *linkedHead) +Audio::Audio(Oscilloscope *s, Avatar *linkedAvatar) { // read the walking sound from the raw file and store it // in the in memory array @@ -472,7 +472,7 @@ Audio::Audio(Oscilloscope *s, Head *linkedHead) audioData = new AudioData(); - audioData->linkedHead = linkedHead; + audioData->linkedAvatar = linkedAvatar; // setup a UDPSocket audioData->audioSocket = new UDPSocket(AUDIO_UDP_LISTEN_PORT); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index f4bf594b0c..73ff7f32d1 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -12,12 +12,12 @@ #include #include "AudioData.h" #include "Oscilloscope.h" -#include "Head.h" +#include "Avatar.h" class Audio { public: // initializes audio I/O - Audio(Oscilloscope *s, Head *linkedHead); + Audio(Oscilloscope *s, Avatar *linkedAvatar); void render(); void render(int screenWidth, int screenHeight); diff --git a/interface/src/AudioData.h b/interface/src/AudioData.h index fdc15998f0..520291e3e6 100644 --- a/interface/src/AudioData.h +++ b/interface/src/AudioData.h @@ -13,7 +13,7 @@ #include #include "AudioRingBuffer.h" #include "UDPSocket.h" -#include "Head.h" +#include "Avatar.h" class AudioData { public: @@ -23,7 +23,7 @@ class AudioData { UDPSocket *audioSocket; - Head *linkedHead; + Avatar *linkedAvatar; // store current mixer address and port in_addr_t mixerAddress; diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp deleted file mode 100644 index 1e6e78fef2..0000000000 --- a/interface/src/Head.cpp +++ /dev/null @@ -1,1348 +0,0 @@ -// -// Head.cpp -// interface -// -// Created by Philip Rosedale on 9/11/12. -// adapted by Jeffrey Ventrella -// Copyright (c) 2012 Physical, Inc.. All rights reserved. -// - -#include -#include -#include -#include -#include "Head.h" -#include "Log.h" -#include -#include -#include - -using namespace std; - -float skinColor[] = {1.0, 0.84, 0.66}; -float lightBlue[] = { 0.7, 0.8, 1.0 }; -float browColor[] = {210.0/255.0, 105.0/255.0, 30.0/255.0}; -float mouthColor[] = {1, 0, 0}; - -float BrowRollAngle[5] = {0, 15, 30, -30, -15}; -float BrowPitchAngle[3] = {-70, -60, -50}; -float eyeColor[3] = {1,1,1}; - -float MouthWidthChoices[3] = {0.5, 0.77, 0.3}; - -float browWidth = 0.8; -float browThickness = 0.16; - -bool usingBigSphereCollisionTest = true; - -char iris_texture_file[] = "resources/images/green_eye.png"; - -vector iris_texture; -unsigned int iris_texture_width = 512; -unsigned int iris_texture_height = 256; - -Head::Head(bool isMine) { - - _orientation.setToIdentity(); - - _velocity = glm::vec3( 0.0, 0.0, 0.0 ); - _thrust = glm::vec3( 0.0, 0.0, 0.0 ); - _rotation = glm::quat( 0.0f, 0.0f, 0.0f, 0.0f ); - _bodyYaw = -90.0; - _bodyPitch = 0.0; - _bodyRoll = 0.0; - _bodyYawDelta = 0.0; - _mousePressed = false; - _mode = AVATAR_MODE_STANDING; - _isMine = isMine; - _maxArmLength = 0.0; - //_transmitterTimer = 0; - _transmitterHz = 0.0; - _transmitterPackets = 0; - - initializeSkeleton(); - - _TEST_bigSphereRadius = 0.3f; - _TEST_bigSpherePosition = glm::vec3( 0.0f, _TEST_bigSphereRadius, 2.0f ); - - for (int i = 0; i < MAX_DRIVE_KEYS; i++) _driveKeys[i] = false; - - _head.pupilSize = 0.10; - _head.interPupilDistance = 0.6; - _head.interBrowDistance = 0.75; - _head.nominalPupilSize = 0.10; - _head.pitchRate = 0.0; - _head.yawRate = 0.0; - _head.rollRate = 0.0; - _head.eyebrowPitch[0] = -30; - _head.eyebrowPitch[1] = -30; - _head.eyebrowRoll [0] = 20; - _head.eyebrowRoll [1] = -20; - _head.mouthPitch = 0; - _head.mouthYaw = 0; - _head.mouthWidth = 1.0; - _head.mouthHeight = 0.2; - _head.eyeballPitch[0] = 0; - _head.eyeballPitch[1] = 0; - _head.eyeballScaleX = 1.2; - _head.eyeballScaleY = 1.5; - _head.eyeballScaleZ = 1.0; - _head.eyeballYaw[0] = 0; - _head.eyeballYaw[1] = 0; - _head.pitchTarget = 0; - _head.yawTarget = 0; - _head.noiseEnvelope = 1.0; - _head.pupilConverge = 10.0; - _head.leanForward = 0.0; - _head.leanSideways = 0.0; - _head.eyeContact = 1; - _head.eyeContactTarget = LEFT_EYE; - _head.scale = 1.0; - _head.audioAttack = 0.0; - _head.averageLoudness = 0.0; - _head.lastLoudness = 0.0; - _head.browAudioLift = 0.0; - _head.noise = 0; - _movedHandOffset = glm::vec3( 0.0, 0.0, 0.0 ); - _usingBodySprings = true; - _springForce = 6.0f; - _springVelocityDecay = 16.0f; - _renderYaw = 0.0; - _renderPitch = 0.0; - _sphere = NULL; - _interactingOther = NULL; - _interactingOtherIsNearby = false; - - _handHolding.position = glm::vec3( 0.0, 0.0, 0.0 ); - _handHolding.velocity = glm::vec3( 0.0, 0.0, 0.0 ); - _handHolding.force = 10.0f; - - if (iris_texture.size() == 0) { - switchToResourcesParentIfRequired(); - unsigned error = lodepng::decode(iris_texture, iris_texture_width, iris_texture_height, iris_texture_file); - if (error != 0) { - printLog("error %u: %s\n", error, lodepng_error_text(error)); - } - } -} - - - -Head::Head(const Head &otherAvatar) { - - _velocity = otherAvatar._velocity; - _thrust = otherAvatar._thrust; - _rotation = otherAvatar._rotation; - _interactingOtherIsNearby = otherAvatar._interactingOtherIsNearby; - _bodyYaw = otherAvatar._bodyYaw; - _bodyPitch = otherAvatar._bodyPitch; - _bodyRoll = otherAvatar._bodyRoll; - _bodyYawDelta = otherAvatar._bodyYawDelta; - _mousePressed = otherAvatar._mousePressed; - _mode = otherAvatar._mode; - _isMine = otherAvatar._isMine; - _renderYaw = otherAvatar._renderYaw; - _renderPitch = otherAvatar._renderPitch; - _maxArmLength = otherAvatar._maxArmLength; - _transmitterTimer = otherAvatar._transmitterTimer; - _transmitterHz = otherAvatar._transmitterHz; - _transmitterPackets = otherAvatar._transmitterPackets; - _TEST_bigSphereRadius = otherAvatar._TEST_bigSphereRadius; - _TEST_bigSpherePosition = otherAvatar._TEST_bigSpherePosition; - _movedHandOffset = otherAvatar._movedHandOffset; - _usingBodySprings = otherAvatar._usingBodySprings; - _springForce = otherAvatar._springForce; - _springVelocityDecay = otherAvatar._springVelocityDecay; - _orientation.set( otherAvatar._orientation ); - - _sphere = NULL; - - initializeSkeleton(); - - for (int i = 0; i < MAX_DRIVE_KEYS; i++) _driveKeys[i] = otherAvatar._driveKeys[i]; - - _head.pupilSize = otherAvatar._head.pupilSize; - _head.interPupilDistance = otherAvatar._head.interPupilDistance; - _head.interBrowDistance = otherAvatar._head.interBrowDistance; - _head.nominalPupilSize = otherAvatar._head.nominalPupilSize; - _head.yawRate = otherAvatar._head.yawRate; - _head.pitchRate = otherAvatar._head.pitchRate; - _head.rollRate = otherAvatar._head.rollRate; - _head.eyebrowPitch[0] = otherAvatar._head.eyebrowPitch[0]; - _head.eyebrowPitch[1] = otherAvatar._head.eyebrowPitch[1]; - _head.eyebrowRoll [0] = otherAvatar._head.eyebrowRoll [0]; - _head.eyebrowRoll [1] = otherAvatar._head.eyebrowRoll [1]; - _head.mouthPitch = otherAvatar._head.mouthPitch; - _head.mouthYaw = otherAvatar._head.mouthYaw; - _head.mouthWidth = otherAvatar._head.mouthWidth; - _head.mouthHeight = otherAvatar._head.mouthHeight; - _head.eyeballPitch[0] = otherAvatar._head.eyeballPitch[0]; - _head.eyeballPitch[1] = otherAvatar._head.eyeballPitch[1]; - _head.eyeballScaleX = otherAvatar._head.eyeballScaleX; - _head.eyeballScaleY = otherAvatar._head.eyeballScaleY; - _head.eyeballScaleZ = otherAvatar._head.eyeballScaleZ; - _head.eyeballYaw[0] = otherAvatar._head.eyeballYaw[0]; - _head.eyeballYaw[1] = otherAvatar._head.eyeballYaw[1]; - _head.pitchTarget = otherAvatar._head.pitchTarget; - _head.yawTarget = otherAvatar._head.yawTarget; - _head.noiseEnvelope = otherAvatar._head.noiseEnvelope; - _head.pupilConverge = otherAvatar._head.pupilConverge; - _head.leanForward = otherAvatar._head.leanForward; - _head.leanSideways = otherAvatar._head.leanSideways; - _head.eyeContact = otherAvatar._head.eyeContact; - _head.eyeContactTarget = otherAvatar._head.eyeContactTarget; - _head.scale = otherAvatar._head.scale; - _head.audioAttack = otherAvatar._head.audioAttack; - _head.averageLoudness = otherAvatar._head.averageLoudness; - _head.lastLoudness = otherAvatar._head.lastLoudness; - _head.browAudioLift = otherAvatar._head.browAudioLift; - _head.noise = otherAvatar._head.noise; - - if (iris_texture.size() == 0) { - switchToResourcesParentIfRequired(); - unsigned error = lodepng::decode(iris_texture, iris_texture_width, iris_texture_height, iris_texture_file); - if (error != 0) { - printLog("error %u: %s\n", error, lodepng_error_text(error)); - } - } -} - -Head::~Head() { - if (_sphere != NULL) { - gluDeleteQuadric(_sphere); - } -} - -Head* Head::clone() const { - return new Head(*this); -} - -void Head::reset() { - _headPitch = _headYaw = _headRoll = 0; - _head.leanForward = _head.leanSideways = 0; -} - - -//this pertains to moving the head with the glasses -//--------------------------------------------------- -void Head::UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity) -// Using serial data, update avatar/render position and angles -{ - const float PITCH_ACCEL_COUPLING = 0.5; - const float ROLL_ACCEL_COUPLING = -1.0; - float measured_pitch_rate = serialInterface->getRelativeValue(HEAD_PITCH_RATE); - _head.yawRate = serialInterface->getRelativeValue(HEAD_YAW_RATE); - float measured_lateral_accel = serialInterface->getRelativeValue(ACCEL_X) - - ROLL_ACCEL_COUPLING*serialInterface->getRelativeValue(HEAD_ROLL_RATE); - float measured_fwd_accel = serialInterface->getRelativeValue(ACCEL_Z) - - PITCH_ACCEL_COUPLING*serialInterface->getRelativeValue(HEAD_PITCH_RATE); - float measured_roll_rate = serialInterface->getRelativeValue(HEAD_ROLL_RATE); - - //printLog("Pitch Rate: %d ACCEL_Z: %d\n", serialInterface->getRelativeValue(PITCH_RATE), - // serialInterface->getRelativeValue(ACCEL_Z)); - //printLog("Pitch Rate: %d ACCEL_X: %d\n", serialInterface->getRelativeValue(PITCH_RATE), - // serialInterface->getRelativeValue(ACCEL_Z)); - //printLog("Pitch: %f\n", Pitch); - - // Update avatar head position based on measured gyro rates - const float HEAD_ROTATION_SCALE = 0.70; - const float HEAD_ROLL_SCALE = 0.40; - const float HEAD_LEAN_SCALE = 0.01; - const float MAX_PITCH = 45; - const float MIN_PITCH = -45; - const float MAX_YAW = 85; - const float MIN_YAW = -85; - - if ((_headPitch < MAX_PITCH) && (_headPitch > MIN_PITCH)) - addHeadPitch(measured_pitch_rate * -HEAD_ROTATION_SCALE * frametime); - - addHeadRoll(measured_roll_rate * HEAD_ROLL_SCALE * frametime); - - if ((_headYaw < MAX_YAW) && (_headYaw > MIN_YAW)) - addHeadYaw(_head.yawRate * HEAD_ROTATION_SCALE * frametime); - - addLean(-measured_lateral_accel * frametime * HEAD_LEAN_SCALE, -measured_fwd_accel*frametime * HEAD_LEAN_SCALE); -} - -void Head::addLean(float x, float z) { - // Add Body lean as impulse - _head.leanSideways += x; - _head.leanForward += z; -} - - -void Head::setLeanForward(float dist){ - _head.leanForward = dist; -} - -void Head::setLeanSideways(float dist){ - _head.leanSideways = dist; -} - -void Head::setMousePressed( bool d ) { - _mousePressed = d; -} - -void Head::simulate(float deltaTime) { - - //------------------------ - // update avatar skeleton - //------------------------ - updateSkeleton(); - - //------------------------------------------------------------ - // reset hand and arm positions according to hand movement - //------------------------------------------------------------ - updateHandMovement( deltaTime ); - - if ( !_interactingOtherIsNearby ) { - //initialize _handHolding - _handHolding.position = _bone[ AVATAR_BONE_RIGHT_HAND ].position; - _handHolding.velocity = glm::vec3( 0.0, 0.0, 0.0 ); - } - - _interactingOtherIsNearby = false; - - //------------------------------------------------------------- - // if the avatar being simulated is mine, then loop through - // all the other avatars for potential interactions... - //------------------------------------------------------------- - if ( _isMine ) - { - float closestDistance = 10000.0f; - - AgentList * agentList = AgentList::getInstance(); - - for(std::vector::iterator agent = agentList->getAgents().begin(); - agent != agentList->getAgents().end(); - agent++) { - if (( agent->getLinkedData() != NULL && ( agent->getType() == AGENT_TYPE_AVATAR ) )) { - Head *otherAvatar = (Head *)agent->getLinkedData(); - - //------------------------------------------------------ - // check for collisions with other avatars and respond - //------------------------------------------------------ - updateAvatarCollisionDetectionAndResponse - ( - otherAvatar->getPosition(), - otherAvatar->getGirth(), - otherAvatar->getHeight(), - otherAvatar->getBodyUpDirection(), - deltaTime - ); - - //------------------------------------------------- - // test other avatar hand position for proximity - //------------------------------------------------ - glm::vec3 v( _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position ); - v -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); - - float distance = glm::length( v ); - if ( distance < _maxArmLength ) { - - //if ( distance < closestDistance ) { // perhaps I don't need this if we want to allow multi-avatar interactions - { - closestDistance = distance; - _interactingOther = otherAvatar; - _interactingOtherIsNearby = true; - - //--------------------------------------------------------------------- - // if I am holding hands with another avatar, a force is applied - //--------------------------------------------------------------------- - if (( _handState == 1 ) - || ( _interactingOther->_handState == 1 )) { - glm::vec3 vectorToOtherHand = _interactingOther->_handPosition - _handHolding.position; - glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHolding.position; - - _handHolding.velocity *= 0.7; - _handHolding.velocity += ( vectorToOtherHand + vectorToMyHand ) * _handHolding.force * deltaTime; - _handHolding.position += _handHolding.velocity; - - _bone[ AVATAR_BONE_RIGHT_HAND ].position = _handHolding.position; - } - } - } - } - } - - // Set the vector we send for hand position to other people to be our right hand - setHandPosition(_bone[ AVATAR_BONE_RIGHT_HAND ].position); - - }//if ( _isMine ) - - - updateArmIKAndConstraints( deltaTime ); - - if ( ! _interactingOtherIsNearby ) { - _interactingOther = NULL; - } - - if ( usingBigSphereCollisionTest ) { - //-------------------------------------------------------------- - // test for avatar collision response (using a big sphere :) - //-------------------------------------------------------------- - updateAvatarCollisionDetectionAndResponse - ( - _TEST_bigSpherePosition, - _TEST_bigSphereRadius, - _TEST_bigSphereRadius, - glm::vec3( 0.0, 1.0, 0.0 ), - deltaTime - ); - } - - if ( AVATAR_GRAVITY ) { - if ( _position.y > _bone[ AVATAR_BONE_RIGHT_FOOT ].radius * 2.0 ) { - _velocity += glm::dvec3( 0.0, -1.0, 0.0 ) * ( 6.0 * deltaTime ); - } - else { - if ( _position.y < _bone[ AVATAR_BONE_RIGHT_FOOT ].radius ) { - _position.y = _bone[ AVATAR_BONE_RIGHT_FOOT ].radius; - _velocity.y = 0.0; - } - } - } - - // update body springs - updateBodySprings( deltaTime ); - - - if ( _isMine ) { // driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely) - //------------------------------------------------- - // this handles the avatar being driven around... - //------------------------------------------------- - _thrust = glm::vec3( 0.0, 0.0, 0.0 ); - - if (_driveKeys[FWD]) { - glm::vec3 front( _orientation.getFront().x, _orientation.getFront().y, _orientation.getFront().z ); - _thrust += front * THRUST_MAG; - } - if (_driveKeys[BACK]) { - glm::vec3 front( _orientation.getFront().x, _orientation.getFront().y, _orientation.getFront().z ); - _thrust -= front * THRUST_MAG; - } - if (_driveKeys[RIGHT]) { - glm::vec3 right( _orientation.getRight().x, _orientation.getRight().y, _orientation.getRight().z ); - _thrust += right * THRUST_MAG; - } - if (_driveKeys[LEFT]) { - glm::vec3 right( _orientation.getRight().x, _orientation.getRight().y, _orientation.getRight().z ); - _thrust -= right * THRUST_MAG; - } - if (_driveKeys[UP]) { - glm::vec3 up( _orientation.getUp().x, _orientation.getUp().y, _orientation.getUp().z ); - _thrust += up * THRUST_MAG; - } - if (_driveKeys[DOWN]) { - glm::vec3 up( _orientation.getUp().x, _orientation.getUp().y, _orientation.getUp().z ); - _thrust -= up * THRUST_MAG; - } - if (_driveKeys[ROT_RIGHT]) { - _bodyYawDelta -= YAW_MAG * deltaTime; - } - if (_driveKeys[ROT_LEFT]) { - _bodyYawDelta += YAW_MAG * deltaTime; - } - } - - - //---------------------------------------------------------- - float translationalSpeed = glm::length( _velocity ); - float rotationalSpeed = fabs( _bodyYawDelta ); - if ( translationalSpeed + rotationalSpeed > 0.2 ) - { - _mode = AVATAR_MODE_WALKING; - } - else - { - _mode = AVATAR_MODE_INTERACTING; - } - - //---------------------------------------------------------- - // update body yaw by body yaw delta - //---------------------------------------------------------- - if (_isMine) { - _bodyYaw += _bodyYawDelta * deltaTime; - } - - //---------------------------------------------------------- - // decay body yaw delta - //---------------------------------------------------------- - _bodyYawDelta *= (1.0 - TEST_YAW_DECAY * deltaTime); - - //---------------------------------------------------------- - // add thrust to velocity - //---------------------------------------------------------- - _velocity += glm::dvec3(_thrust * deltaTime); - - //---------------------------------------------------------- - // update position by velocity - //---------------------------------------------------------- - _position += (glm::vec3)_velocity * deltaTime; - - //---------------------------------------------------------- - // decay velocity - //---------------------------------------------------------- - _velocity *= ( 1.0 - LIN_VEL_DECAY * deltaTime ); - - // - // Update Head information - // - - // we will be eventually getting head rotation from elsewhere. For now, just setting it to body rotation - //_head.yaw = _bodyYaw; - //_head.pitch = _bodyPitch; - //_head.roll = _bodyRoll; - - if (!_head.noise) { - // Decay back toward center - _headPitch *= (1.0f - DECAY * 2 * deltaTime); - _headYaw *= (1.0f - DECAY * 2 * deltaTime); - _headRoll *= (1.0f - DECAY * 2 * deltaTime); - } - else { - // Move toward new target - _headPitch += (_head.pitchTarget - _headPitch) * 10 * deltaTime; // (1.f - DECAY*deltaTime)*Pitch + ; - _headYaw += (_head.yawTarget - _headYaw ) * 10 * deltaTime; // (1.f - DECAY*deltaTime); - _headRoll *= 1.f - (DECAY * deltaTime); - } - - _head.leanForward *= (1.f - DECAY * 30 * deltaTime); - _head.leanSideways *= (1.f - DECAY * 30 * deltaTime); - - // Update where the avatar's eyes are - // - // First, decide if we are making eye contact or not - if (randFloat() < 0.005) { - _head.eyeContact = !_head.eyeContact; - _head.eyeContact = 1; - if (!_head.eyeContact) { - // If we just stopped making eye contact,move the eyes markedly away - _head.eyeballPitch[0] = _head.eyeballPitch[1] = _head.eyeballPitch[0] + 5.0 + (randFloat() - 0.5) * 10; - _head.eyeballYaw [0] = _head.eyeballYaw [1] = _head.eyeballYaw [0] + 5.0 + (randFloat() - 0.5) * 5; - } else { - // If now making eye contact, turn head to look right at viewer - SetNewHeadTarget(0,0); - } - } - - const float DEGREES_BETWEEN_VIEWER_EYES = 3; - const float DEGREES_TO_VIEWER_MOUTH = 7; - - if (_head.eyeContact) { - // Should we pick a new eye contact target? - if (randFloat() < 0.01) { - // Choose where to look next - if (randFloat() < 0.1) { - _head.eyeContactTarget = MOUTH; - } else { - if (randFloat() < 0.5) _head.eyeContactTarget = LEFT_EYE; else _head.eyeContactTarget = RIGHT_EYE; - } - } - // Set eyeball pitch and yaw to make contact - float eye_target_yaw_adjust = 0; - float eye_target_pitch_adjust = 0; - if (_head.eyeContactTarget == LEFT_EYE) eye_target_yaw_adjust = DEGREES_BETWEEN_VIEWER_EYES; - if (_head.eyeContactTarget == RIGHT_EYE) eye_target_yaw_adjust = -DEGREES_BETWEEN_VIEWER_EYES; - if (_head.eyeContactTarget == MOUTH) eye_target_pitch_adjust = DEGREES_TO_VIEWER_MOUTH; - - _head.eyeballPitch[0] = _head.eyeballPitch[1] = -_headPitch + eye_target_pitch_adjust; - _head.eyeballYaw[0] = _head.eyeballYaw[1] = -_headYaw + eye_target_yaw_adjust; - } - - - if (_head.noise) - { - _headPitch += (randFloat() - 0.5) * 0.2 * _head.noiseEnvelope; - _headYaw += (randFloat() - 0.5) * 0.3 *_head.noiseEnvelope; - //PupilSize += (randFloat() - 0.5) * 0.001*NoiseEnvelope; - - if (randFloat() < 0.005) _head.mouthWidth = MouthWidthChoices[rand()%3]; - - if (!_head.eyeContact) { - if (randFloat() < 0.01) _head.eyeballPitch[0] = _head.eyeballPitch[1] = (randFloat() - 0.5) * 20; - if (randFloat() < 0.01) _head.eyeballYaw[0] = _head.eyeballYaw[1] = (randFloat()- 0.5) * 10; - } - - if ((randFloat() < 0.005) && (fabs(_head.pitchTarget - _headPitch) < 1.0) && (fabs(_head.yawTarget - _headYaw) < 1.0)) { - SetNewHeadTarget((randFloat()-0.5) * 20.0, (randFloat()-0.5) * 45.0); - } - - if (0) { - - // Pick new target - _head.pitchTarget = (randFloat() - 0.5) * 45; - _head.yawTarget = (randFloat() - 0.5) * 22; - } - if (randFloat() < 0.01) - { - _head.eyebrowPitch[0] = _head.eyebrowPitch[1] = BrowPitchAngle[rand()%3]; - _head.eyebrowRoll [0] = _head.eyebrowRoll[1] = BrowRollAngle[rand()%5]; - _head.eyebrowRoll [1] *=-1; - } - } - - // Update audio trailing average for rendering facial animations - const float AUDIO_AVERAGING_SECS = 0.05; - _head.averageLoudness = (1.f - deltaTime / AUDIO_AVERAGING_SECS) * _head.averageLoudness + - (deltaTime / AUDIO_AVERAGING_SECS) * _audioLoudness; -} - - -float Head::getGirth() { - return COLLISION_BODY_RADIUS; -} - -float Head::getHeight() { - return COLLISION_HEIGHT; -} - - -glm::vec3 Head::getBodyUpDirection() { - return _orientation.getUp(); -} - -//-------------------------------------------------------------------------------- -// This is a workspace for testing avatar body collision detection and response -//-------------------------------------------------------------------------------- -void Head::updateAvatarCollisionDetectionAndResponse -( glm::vec3 collisionPosition, float collisionGirth, float collisionHeight, glm::vec3 collisionUpVector, float deltaTime ) { - - float myBodyApproximateBoundingRadius = 1.0f; - glm::vec3 vectorFromMyBodyToBigSphere(_position - collisionPosition); - bool jointCollision = false; - - float distanceToBigSphere = glm::length(vectorFromMyBodyToBigSphere); - if ( distanceToBigSphere < myBodyApproximateBoundingRadius + collisionGirth ) - { - for (int b=0; b 0.0) - { - glm::vec3 directionVector = vectorFromJointToBigSphereCenter / distanceToBigSphereCenter; - - float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius); - glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration; - - _bone[b].springyVelocity += collisionForce * 30.0f * deltaTime; - _velocity += collisionForce * 100.0f * deltaTime; - _bone[b].springyPosition = collisionPosition + directionVector * combinedRadius; - } - } - } - - if ( jointCollision ) { - if (!_usingBodySprings) { - _usingBodySprings = true; - initializeBodySprings(); - } - } - } -} - - -void Head::render(bool lookingInMirror) { - - //--------------------------------------------------- - // show avatar position - //--------------------------------------------------- - glColor4f( 0.5f, 0.5f, 0.5f, 0.6 ); - glPushMatrix(); - glTranslatef(_position.x, _position.y, _position.z); - glScalef( 0.03, 0.03, 0.03 ); - glutSolidSphere( 1, 10, 10 ); - glPopMatrix(); - - if ( usingBigSphereCollisionTest ) { - //--------------------------------------------------- - // show TEST big sphere - //--------------------------------------------------- - glColor4f( 0.5f, 0.6f, 0.8f, 0.7 ); - glPushMatrix(); - glTranslatef(_TEST_bigSpherePosition.x, _TEST_bigSpherePosition.y, _TEST_bigSpherePosition.z); - glScalef( _TEST_bigSphereRadius, _TEST_bigSphereRadius, _TEST_bigSphereRadius ); - glutSolidSphere( 1, 20, 20 ); - glPopMatrix(); - } - - //--------------- - // render body - //--------------- - renderBody(); - - //--------------------------------------------------- - // render head - //--------------------------------------------------- - renderHead(lookingInMirror); - - //--------------------------------------------------------------------------- - // if this is my avatar, then render my interactions with the other avatar - //--------------------------------------------------------------------------- - if ( _isMine ) - { - if ( _interactingOtherIsNearby ) { - - glm::vec3 v1( _bone[ AVATAR_BONE_RIGHT_HAND ].position ); - glm::vec3 v2( _interactingOther->_handPosition ); - - glLineWidth( 8.0 ); - glColor4f( 0.7f, 0.4f, 0.1f, 0.6 ); - glBegin( GL_LINE_STRIP ); - glVertex3f( v1.x, v1.y, v1.z ); - glVertex3f( v2.x, v2.y, v2.z ); - glEnd(); - } - } -} - - -void Head::renderHead(bool lookingInMirror) { - int side = 0; - - glEnable(GL_DEPTH_TEST); - glEnable(GL_RESCALE_NORMAL); - - //--------------------------------------------------- - // show head orientation - //--------------------------------------------------- - //renderOrientationDirections( _bone[ AVATAR_BONE_HEAD ].position, _bone[ AVATAR_BONE_HEAD ].orientation, 0.2f ); - - glPushMatrix(); - - if (_usingBodySprings) { - glTranslatef(_bone[ AVATAR_BONE_HEAD ].springyPosition.x, - _bone[ AVATAR_BONE_HEAD ].springyPosition.y, - _bone[ AVATAR_BONE_HEAD ].springyPosition.z); - } - else { - glTranslatef(_bone[ AVATAR_BONE_HEAD ].position.x, - _bone[ AVATAR_BONE_HEAD ].position.y, - _bone[ AVATAR_BONE_HEAD ].position.z); - } - - glScalef( 0.03, 0.03, 0.03 ); - - if (lookingInMirror) { - glRotatef(_bodyYaw - _headYaw, 0, 1, 0); - glRotatef(_bodyPitch + _headPitch, 1, 0, 0); - glRotatef(_bodyRoll - _headRoll, 0, 0, 1); - } else { - glRotatef(_bodyYaw + _headYaw, 0, 1, 0); - glRotatef(_bodyPitch + _headPitch, 1, 0, 0); - glRotatef(_bodyRoll + _headRoll, 0, 0, 1); - } - - glScalef(2.0, 2.0, 2.0); - glColor3fv(skinColor); - - glutSolidSphere(1, 30, 30); - - // Ears - glPushMatrix(); - glTranslatef(1.0, 0, 0); - for(side = 0; side < 2; side++) { - glPushMatrix(); - glScalef(0.3, 0.65, .65); - glutSolidSphere(0.5, 30, 30); - glPopMatrix(); - glTranslatef(-2.0, 0, 0); - } - glPopMatrix(); - - - // Update audio attack data for facial animation (eyebrows and mouth) - _head.audioAttack = 0.9 * _head.audioAttack + 0.1 * fabs(_audioLoudness - _head.lastLoudness); - _head.lastLoudness = _audioLoudness; - - - const float BROW_LIFT_THRESHOLD = 100; - if (_head.audioAttack > BROW_LIFT_THRESHOLD) - _head.browAudioLift += sqrt(_head.audioAttack) / 1000.0; - - _head.browAudioLift *= .90; - - - // Render Eyebrows - glPushMatrix(); - glTranslatef(-_head.interBrowDistance / 2.0,0.4,0.45); - for(side = 0; side < 2; side++) { - glColor3fv(browColor); - glPushMatrix(); - glTranslatef(0, 0.35 + _head.browAudioLift, 0); - glRotatef(_head.eyebrowPitch[side]/2.0, 1, 0, 0); - glRotatef(_head.eyebrowRoll[side]/2.0, 0, 0, 1); - glScalef(browWidth, browThickness, 1); - glutSolidCube(0.5); - glPopMatrix(); - glTranslatef(_head.interBrowDistance, 0, 0); - } - glPopMatrix(); - - - // Mouth - - glPushMatrix(); - glTranslatef(0,-0.35,0.75); - glColor3f(0,0,0); - glRotatef(_head.mouthPitch, 1, 0, 0); - glRotatef(_head.mouthYaw, 0, 0, 1); - glScalef(_head.mouthWidth*(.7 + sqrt(_head.averageLoudness)/60.0), _head.mouthHeight*(1.0 + sqrt(_head.averageLoudness)/30.0), 1); - glutSolidCube(0.5); - glPopMatrix(); - - glTranslatef(0, 1.0, 0); - - glTranslatef(-_head.interPupilDistance/2.0,-0.68,0.7); - // Right Eye - glRotatef(-10, 1, 0, 0); - glColor3fv(eyeColor); - glPushMatrix(); - { - glTranslatef(_head.interPupilDistance/10.0, 0, 0.05); - glRotatef(20, 0, 0, 1); - glScalef(_head.eyeballScaleX, _head.eyeballScaleY, _head.eyeballScaleZ); - glutSolidSphere(0.25, 30, 30); - } - glPopMatrix(); - - // Right Pupil - if (_sphere == NULL) { - _sphere = gluNewQuadric(); - gluQuadricTexture(_sphere, GL_TRUE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gluQuadricOrientation(_sphere, GLU_OUTSIDE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iris_texture_width, iris_texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &iris_texture[0]); - } - - glPushMatrix(); - { - glRotatef(_head.eyeballPitch[1], 1, 0, 0); - glRotatef(_head.eyeballYaw[1] + _headYaw + _head.pupilConverge, 0, 1, 0); - glTranslatef(0,0,.35); - glRotatef(-75,1,0,0); - glScalef(1.0, 0.4, 1.0); - - glEnable(GL_TEXTURE_2D); - gluSphere(_sphere, _head.pupilSize, 15, 15); - glDisable(GL_TEXTURE_2D); - } - - glPopMatrix(); - // Left Eye - glColor3fv(eyeColor); - glTranslatef(_head.interPupilDistance, 0, 0); - glPushMatrix(); - { - glTranslatef(-_head.interPupilDistance/10.0, 0, .05); - glRotatef(-20, 0, 0, 1); - glScalef(_head.eyeballScaleX, _head.eyeballScaleY, _head.eyeballScaleZ); - glutSolidSphere(0.25, 30, 30); - } - glPopMatrix(); - // Left Pupil - glPushMatrix(); - { - glRotatef(_head.eyeballPitch[0], 1, 0, 0); - glRotatef(_head.eyeballYaw[0] + _headYaw - _head.pupilConverge, 0, 1, 0); - glTranslatef(0, 0, .35); - glRotatef(-75, 1, 0, 0); - glScalef(1.0, 0.4, 1.0); - - glEnable(GL_TEXTURE_2D); - gluSphere(_sphere, _head.pupilSize, 15, 15); - glDisable(GL_TEXTURE_2D); - } - - glPopMatrix(); - - - glPopMatrix(); - } - -void Head::startHandMovement() { - - if (!_usingBodySprings) { - initializeBodySprings(); - _usingBodySprings = true; - } -} - -void Head::stopHandMovement() { -//_usingBodySprings = false; -} - -void Head::setHandMovementValues( glm::vec3 handOffset ) { - _movedHandOffset = handOffset; -} - -AvatarMode Head::getMode() { - return _mode; -} - -void Head::initializeSkeleton() { - - for (int b=0; b 0.0f ) { - glm::vec3 springDirection = springVector / length; - - float force = ( length - _bone[b].length ) * _springForce * deltaTime; - - _bone[b].springyVelocity -= springDirection * force; - - if ( _bone[b].parent != AVATAR_BONE_NULL ) { - _bone[ _bone[b].parent ].springyVelocity += springDirection * force; - } - } - - _bone[b].springyVelocity += ( _bone[b].position - _bone[b].springyPosition ) * _bone[b].springBodyTightness * deltaTime; - - float decay = 1.0 - _springVelocityDecay * deltaTime; - - if ( decay > 0.0 ) { - _bone[b].springyVelocity *= decay; - } - else { - _bone[b].springyVelocity = glm::vec3( 0.0f, 0.0f, 0.0f ); - } - - _bone[b].springyPosition += _bone[b].springyVelocity; - } -} - -glm::vec3 Head::getHeadLookatDirection() { - return glm::vec3 - ( - _orientation.getFront().x, - _orientation.getFront().y, - _orientation.getFront().z - ); -} - -glm::vec3 Head::getHeadLookatDirectionUp() { - return glm::vec3 - ( - _orientation.getUp().x, - _orientation.getUp().y, - _orientation.getUp().z - ); -} - -glm::vec3 Head::getHeadLookatDirectionRight() { - return glm::vec3 - ( - _orientation.getRight().x, - _orientation.getRight().y, - _orientation.getRight().z - ); -} - -glm::vec3 Head::getHeadPosition() { - - if ( _usingBodySprings ) { - return _bone[ AVATAR_BONE_HEAD ].springyPosition; - } - - return _bone[ AVATAR_BONE_HEAD ].position; -} - - -glm::vec3 Head::getBonePosition( AvatarBoneID b ) { - return _bone[b].position; -} - - - -void Head::updateHandMovement( float deltaTime ) { - glm::vec3 transformedHandMovement; - - transformedHandMovement - = _orientation.getRight() * _movedHandOffset.x - + _orientation.getUp() * -_movedHandOffset.y * 0.5f - + _orientation.getFront() * -_movedHandOffset.y; - - _bone[ AVATAR_BONE_RIGHT_HAND ].position += transformedHandMovement; - - if (_isMine) { - _handState = _mousePressed; - } -} - - -void Head::updateArmIKAndConstraints( float deltaTime ) { - - //------------------------------------------------------------------------------- - // determine the arm vector - //------------------------------------------------------------------------------- - glm::vec3 armVector = _bone[ AVATAR_BONE_RIGHT_HAND ].position; - armVector -= _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; - - //------------------------------------------------------------------------------- - // test to see if right hand is being dragged beyond maximum arm length - //------------------------------------------------------------------------------- - float distance = glm::length( armVector ); - - //------------------------------------------------------------------------------- - // if right hand is being dragged beyond maximum arm length... - //------------------------------------------------------------------------------- - if ( distance > _maxArmLength ) { - //------------------------------------------------------------------------------- - // reset right hand to be constrained to maximum arm length - //------------------------------------------------------------------------------- - _bone[ AVATAR_BONE_RIGHT_HAND ].position = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; - glm::vec3 armNormal = armVector / distance; - armVector = armNormal * _maxArmLength; - distance = _maxArmLength; - glm::vec3 constrainedPosition = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; - constrainedPosition += armVector; - _bone[ AVATAR_BONE_RIGHT_HAND ].position = constrainedPosition; - } - - //----------------------------------------------------------------------------- - // set elbow position - //----------------------------------------------------------------------------- - glm::vec3 newElbowPosition = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; - newElbowPosition += armVector * ONE_HALF; - glm::vec3 perpendicular = glm::cross( _orientation.getFront(), armVector ); - newElbowPosition += perpendicular * ( 1.0f - ( _maxArmLength / distance ) ) * ONE_HALF; - _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position = newElbowPosition; - - //----------------------------------------------------------------------------- - // set wrist position - //----------------------------------------------------------------------------- - glm::vec3 vv( _bone[ AVATAR_BONE_RIGHT_HAND ].position ); - vv -= _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position; - glm::vec3 newWristPosition = _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position; - newWristPosition += vv * 0.7f; - _bone[ AVATAR_BONE_RIGHT_FOREARM ].position = newWristPosition; -} - - - - -void Head::renderBody() { - //----------------------------------------- - // Render bone positions as spheres - //----------------------------------------- - for (int b=0; b( (double)TRANSMITTER_COUNT/(msecsElapsed/1000.0) ); - _transmitterTimer = now; - } - /* NOTE: PR: Will add back in when ready to animate avatar hand - - // Add rotational forces to the hand - const float ANG_VEL_SENSITIVITY = 4.0; - const float ANG_VEL_THRESHOLD = 0.0; - float angVelScale = ANG_VEL_SENSITIVITY*(1.0f/getTransmitterHz()); - - addAngularVelocity(fabs(gyrX*angVelScale)>ANG_VEL_THRESHOLD?gyrX*angVelScale:0, - fabs(gyrZ*angVelScale)>ANG_VEL_THRESHOLD?gyrZ*angVelScale:0, - fabs(-gyrY*angVelScale)>ANG_VEL_THRESHOLD?-gyrY*angVelScale:0); - - // Add linear forces to the hand - //const float LINEAR_VEL_SENSITIVITY = 50.0; - const float LINEAR_VEL_SENSITIVITY = 5.0; - float linVelScale = LINEAR_VEL_SENSITIVITY*(1.0f/getTransmitterHz()); - glm::vec3 linVel(linX*linVelScale, linZ*linVelScale, -linY*linVelScale); - addVelocity(linVel); - */ - -} - diff --git a/interface/src/Head.h b/interface/src/Head.h deleted file mode 100644 index 377228986d..0000000000 --- a/interface/src/Head.h +++ /dev/null @@ -1,279 +0,0 @@ -// -// Head.h -// interface -// -// Created by Philip Rosedale on 9/11/12. -// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__head__ -#define __interface__head__ - -#include -#include - -#include "Field.h" -#include "world.h" - -#include "InterfaceConfig.h" -#include "SerialInterface.h" - -#include -#include -#include //looks like we might not need this - -const bool AVATAR_GRAVITY = true; -const float DECAY = 0.1; -const float THRUST_MAG = 10.0; -const float YAW_MAG = 300.0; -const float TEST_YAW_DECAY = 5.0; -const float LIN_VEL_DECAY = 5.0; - -const float COLLISION_BODY_RADIUS = 0.1; -const float COLLISION_HEIGHT = 1.5; - -enum eyeContactTargets {LEFT_EYE, RIGHT_EYE, MOUTH}; - -#define FWD 0 -#define BACK 1 -#define LEFT 2 -#define RIGHT 3 -#define UP 4 -#define DOWN 5 -#define ROT_LEFT 6 -#define ROT_RIGHT 7 -#define MAX_DRIVE_KEYS 8 - -#define MAX_OTHER_AVATARS 10 // temporary - for testing purposes! - -enum AvatarMode -{ - AVATAR_MODE_STANDING = 0, - AVATAR_MODE_WALKING, - AVATAR_MODE_INTERACTING, - NUM_AVATAR_MODES -}; - -enum AvatarBoneID -{ - AVATAR_BONE_NULL = -1, - AVATAR_BONE_PELVIS_SPINE, // connects pelvis joint with torso joint (not supposed to be rotated) - AVATAR_BONE_MID_SPINE, // connects torso joint with chest joint - AVATAR_BONE_CHEST_SPINE, // connects chest joint with neckBase joint (not supposed to be rotated) - AVATAR_BONE_NECK, // connects neckBase joint with headBase joint - AVATAR_BONE_HEAD, // connects headBase joint with headTop joint - AVATAR_BONE_LEFT_CHEST, // connects chest joint with left clavicle joint (not supposed to be rotated) - AVATAR_BONE_LEFT_SHOULDER, // connects left clavicle joint with left shoulder joint - AVATAR_BONE_LEFT_UPPER_ARM, // connects left shoulder joint with left elbow joint - AVATAR_BONE_LEFT_FOREARM, // connects left elbow joint with left wrist joint - AVATAR_BONE_LEFT_HAND, // connects left wrist joint with left fingertips joint - AVATAR_BONE_RIGHT_CHEST, // connects chest joint with right clavicle joint (not supposed to be rotated) - AVATAR_BONE_RIGHT_SHOULDER, // connects right clavicle joint with right shoulder joint - AVATAR_BONE_RIGHT_UPPER_ARM, // connects right shoulder joint with right elbow joint - AVATAR_BONE_RIGHT_FOREARM, // connects right elbow joint with right wrist joint - AVATAR_BONE_RIGHT_HAND, // connects right wrist joint with right fingertips joint - AVATAR_BONE_LEFT_PELVIS, // connects pelvis joint with left hip joint (not supposed to be rotated) - AVATAR_BONE_LEFT_THIGH, // connects left hip joint with left knee joint - AVATAR_BONE_LEFT_SHIN, // connects left knee joint with left heel joint - AVATAR_BONE_LEFT_FOOT, // connects left heel joint with left toes joint - AVATAR_BONE_RIGHT_PELVIS, // connects pelvis joint with right hip joint (not supposed to be rotated) - AVATAR_BONE_RIGHT_THIGH, // connects right hip joint with right knee joint - AVATAR_BONE_RIGHT_SHIN, // connects right knee joint with right heel joint - AVATAR_BONE_RIGHT_FOOT, // connects right heel joint with right toes joint - - NUM_AVATAR_BONES -}; - -struct AvatarCollisionElipsoid -{ - bool colliding; - glm::vec3 position; - float girth; - float height; - glm::vec3 upVector; -}; - -struct AvatarHandHolding -{ - glm::vec3 position; - glm::vec3 velocity; - float force; -}; - -/* -struct OtherAvatar -{ - bool nearby; - //glm::vec3 handPosition; - //int handState; -}; -*/ - -struct AvatarBone -{ - AvatarBoneID parent; // which bone is this bone connected to? - glm::vec3 position; // the position at the "end" of the bone - glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" - glm::vec3 springyPosition; // used for special effects (a 'flexible' variant of position) - glm::dvec3 springyVelocity; // used for special effects ( the velocity of the springy position) - float springBodyTightness; // how tightly the springy position tries to stay on the position - glm::quat rotation; // this will eventually replace yaw, pitch and roll (and maybe orientation) - float yaw; // the yaw Euler angle of the bone rotation off the parent - float pitch; // the pitch Euler angle of the bone rotation off the parent - float roll; // the roll Euler angle of the bone rotation off the parent - Orientation orientation; // three orthogonal normals determined by yaw, pitch, roll - float length; // the length of the bone - float radius; // used for detecting collisions for certain physical effects -}; - -struct AvatarHead -{ - float pitchRate; - float yawRate; - float rollRate; - float noise; - float eyeballPitch[2]; - float eyeballYaw [2]; - float eyebrowPitch[2]; - float eyebrowRoll [2]; - float eyeballScaleX; - float eyeballScaleY; - float eyeballScaleZ; - float interPupilDistance; - float interBrowDistance; - float nominalPupilSize; - float pupilSize; - float mouthPitch; - float mouthYaw; - float mouthWidth; - float mouthHeight; - float leanForward; - float leanSideways; - float pitchTarget; - float yawTarget; - float noiseEnvelope; - float pupilConverge; - float scale; - int eyeContact; - float browAudioLift; - eyeContactTargets eyeContactTarget; - - // Sound loudness information - float lastLoudness; - float averageLoudness; - float audioAttack; -}; - - -class Head : public AvatarData { - public: - Head(bool isMine); - ~Head(); - Head(const Head &otherHead); - Head* clone() const; - - void reset(); - void UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity); - void setNoise (float mag) { _head.noise = mag; } - void setScale(float s) {_head.scale = s; }; - void setRenderYaw(float y) {_renderYaw = y;} - void setRenderPitch(float p) {_renderPitch = p;} - float getRenderYaw() {return _renderYaw;} - float getRenderPitch() {return _renderPitch;} - void setLeanForward(float dist); - void setLeanSideways(float dist); - void addLean(float x, float z); - float getLastMeasuredHeadYaw() const {return _head.yawRate;} - float getBodyYaw() {return _bodyYaw;}; - void addBodyYaw(float y) {_bodyYaw += y;}; - - glm::vec3 getHeadLookatDirection(); - glm::vec3 getHeadLookatDirectionUp(); - glm::vec3 getHeadLookatDirectionRight(); - glm::vec3 getHeadPosition(); - glm::vec3 getBonePosition( AvatarBoneID b ); - glm::vec3 getBodyUpDirection(); - float getGirth(); - float getHeight(); - - AvatarMode getMode(); - - void setMousePressed( bool pressed ); - void render(bool lookingInMirror); - void renderBody(); - void renderHead(bool lookingInMirror); - void simulate(float); - void startHandMovement(); - void stopHandMovement(); - void setHandMovementValues( glm::vec3 movement ); - void updateHandMovement( float deltaTime ); - void updateArmIKAndConstraints( float deltaTime ); - - float getAverageLoudness() {return _head.averageLoudness;}; - void setAverageLoudness(float al) {_head.averageLoudness = al;}; - - void SetNewHeadTarget(float, float); - - // Set what driving keys are being pressed to control thrust levels - void setDriveKeys(int key, bool val) { _driveKeys[key] = val; }; - bool getDriveKeys(int key) { return _driveKeys[key]; }; - - // Set/Get update the thrust that will move the avatar around - void setThrust(glm::vec3 newThrust) { _thrust = newThrust; }; - void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; - glm::vec3 getThrust() { return _thrust; }; - - // Related to getting transmitter UDP data used to animate the avatar hand - void processTransmitterData(unsigned char * packetData, int numBytes); - float getTransmitterHz() { return _transmitterHz; }; - - private: - AvatarHead _head; - bool _isMine; - glm::vec3 _TEST_bigSpherePosition; - float _TEST_bigSphereRadius; - bool _mousePressed; - float _bodyYawDelta; - bool _usingBodySprings; - glm::vec3 _movedHandOffset; - float _springVelocityDecay; - float _springForce; - glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion - AvatarBone _bone[ NUM_AVATAR_BONES ]; - AvatarMode _mode; - AvatarHandHolding _handHolding; - glm::dvec3 _velocity; - glm::vec3 _thrust; - float _maxArmLength; - Orientation _orientation; - int _driveKeys[MAX_DRIVE_KEYS]; - GLUquadric* _sphere; - float _renderYaw; - float _renderPitch; // Pitch from view frustum when this is own head - timeval _transmitterTimer; - float _transmitterHz; - int _transmitterPackets; - Head* _interactingOther; - bool _interactingOtherIsNearby; - - //----------------------------- - // private methods... - //----------------------------- - void initializeSkeleton(); - void updateSkeleton(); - void initializeBodySprings(); - void updateBodySprings( float deltaTime ); - void calculateBoneLengths(); - void readSensors(); - void renderBoneAsBlock( AvatarBoneID b ); - void updateAvatarCollisionDetectionAndResponse - ( - glm::vec3 collisionPosition, - float collisionGirth, - float collisionHeight, - glm::vec3 collisionUpVector, - float deltaTime - ); -}; - -#endif diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 8bf6222aec..e96dc5ef8b 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -60,8 +60,8 @@ VoxelSystem::~VoxelSystem() { pthread_mutex_destroy(&bufferWriteLock); } -void VoxelSystem::setViewerHead(Head *newViewerHead) { - viewerHead = newViewerHead; +void VoxelSystem::setViewerAvatar(Avatar *newViewerAvatar) { + viewerAvatar = newViewerAvatar; } ////////////////////////////////////////////////////////////////////////////////////////// @@ -187,7 +187,7 @@ int VoxelSystem::treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosi int voxelsAdded = 0; float halfUnitForVoxel = powf(0.5, *currentNode->octalCode) * (0.5 * TREE_SCALE); - glm::vec3 viewerPosition = viewerHead->getPosition(); + glm::vec3 viewerPosition = viewerAvatar->getPosition(); // debug LOD code glm::vec3 debugNodePosition; diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 9d831ee5f2..ca4825121b 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -15,7 +15,7 @@ #include #include #include -#include "Head.h" +#include "Avatar.h" #include "Util.h" #include "world.h" @@ -34,7 +34,7 @@ public: void render(); void setVoxelsRendered(int v) {voxelsRendered = v;}; int getVoxelsRendered() {return voxelsRendered;}; - void setViewerHead(Head *newViewerHead); + void setViewerAvatar(Avatar *newViewerAvatar); void loadVoxelsFile(const char* fileName,bool wantColorRandomizer); void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer); @@ -67,7 +67,7 @@ private: static float _minDistance; int voxelsRendered; - Head *viewerHead; + Avatar *viewerAvatar; VoxelTree *tree; GLfloat *readVerticesArray; GLubyte *readColorsArray; diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 41ffdc1e92..b4e6545271 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -64,7 +64,7 @@ #include "MenuColumn.h" #include "Menu.h" #include "Camera.h" -#include "Head.h" +#include "Avatar.h" #include "Particle.h" #include "Texture.h" #include "Cloud.h" @@ -107,7 +107,7 @@ Oscilloscope audioScope(256,200,true); ViewFrustum viewFrustum; // current state of view frustum, perspective, orientation, etc. -Head myAvatar(true); // The rendered avatar of oneself +Avatar myAvatar(true); // The rendered avatar of oneself Camera myCamera; // My view onto the world (sometimes on myself :) Camera viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode @@ -382,7 +382,7 @@ void initDisplay(void) void init(void) { voxels.init(); - voxels.setViewerHead(&myAvatar); + voxels.setViewerAvatar(&myAvatar); myAvatar.setRenderYaw(startYaw); initializeHandController(); @@ -911,7 +911,7 @@ void display(void) agent != agentList->getAgents().end(); agent++) { if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { - Head *avatar = (Head *)agent->getLinkedData(); + Avatar *avatar = (Avatar *)agent->getLinkedData(); avatar->render(0); } } @@ -1493,7 +1493,7 @@ void idle(void) { { if (agent->getLinkedData() != NULL) { - Head *avatar = (Head *)agent->getLinkedData(); + Avatar *avatar = (Avatar *)agent->getLinkedData(); avatar->simulate(deltaTime); } } @@ -1604,7 +1604,7 @@ void mouseoverFunc( int x, int y) void attachNewHeadToAgent(Agent *newAgent) { if (newAgent->getLinkedData() == NULL) { - newAgent->setLinkedData(new Head(false)); + newAgent->setLinkedData(new Avatar(false)); } } From bc6512600479c346f3417757d816cdce6793e6b7 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 24 Apr 2013 16:58:52 -0700 Subject: [PATCH 10/11] Wider log window, log panel on by default, menu->tools->log to control. --- interface/src/Log.h | 2 +- interface/src/main.cpp | 29 ++++++++++++++++++----------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/interface/src/Log.h b/interface/src/Log.h index 7def966c32..30f9098bc9 100644 --- a/interface/src/Log.h +++ b/interface/src/Log.h @@ -55,7 +55,7 @@ class Log { public: explicit Log(FILE* tPipeTo = stdout, unsigned bufferedLines = 1024, - unsigned defaultLogWidth = 240, unsigned defaultCharWidth = 6, unsigned defaultCharHeight = 20); + unsigned defaultLogWidth = 400, unsigned defaultCharWidth = 6, unsigned defaultCharHeight = 20); ~Log(); void setLogWidth(unsigned pixels); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 41ffdc1e92..0305df5e6a 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -157,6 +157,8 @@ VoxelDetail paintingVoxel; // The voxel we're painting if we're paintin unsigned char dominantColor = 0; // The dominant color of the voxel we're painting bool perfStatsOn = false; // Do we want to display perfStats? +bool logOn = true; // Whether to show on-screen log + int noiseOn = 0; // Whether to add random noise float noise = 1.0; // Overall magnitude scaling for random noise levels @@ -919,7 +921,7 @@ void display(void) if ( !::lookingInMirror ) balls.render(); // Render the world box - if (!::lookingInMirror && statsOn) render_world_box(); + if (!::lookingInMirror && ::statsOn) { render_world_box(); } // brad's frustum for debugging if (::frustumOn) renderViewFrustum(::viewFrustum); @@ -961,13 +963,12 @@ void display(void) // Show detected levels from the serial I/O ADC channel sensors if (displayLevels) serialPort.renderLevels(WIDTH,HEIGHT); - // Display miscellaneous text stats onscreen - if (statsOn) { - glLineWidth(1.0f); - glPointSize(1.0f); - displayStats(); - logger.render(WIDTH, HEIGHT); - } + // Display stats and log text onscreen + glLineWidth(1.0f); + glPointSize(1.0f); + + if (::statsOn) { displayStats(); } + if (::logOn) { logger.render(WIDTH, HEIGHT); } // Show menu if (::menuOn) { @@ -1056,6 +1057,11 @@ int setNoise(int state) { return iRet; } +int setLog(int state) { + int iRet = setValue(state, &::logOn); + return iRet; +} + int setGyroLook(int state) { int iRet = setValue(state, &::gyroLook); return iRet; @@ -1070,7 +1076,7 @@ int setStars(int state) { } int setStats(int state) { - return setValue(state, &statsOn); + return setValue(state, &::statsOn); } int setMenu(int state) { @@ -1195,7 +1201,8 @@ void initMenu() { // Tools menuColumnTools = menu.addColumn("Tools"); - menuColumnTools->addRow("Stats (/)", setStats); + menuColumnTools->addRow("Stats (/)", setStats); + menuColumnTools->addRow("Log ", setLog); menuColumnTools->addRow("(M)enu", setMenu); // Frustum Options @@ -1353,7 +1360,7 @@ void key(unsigned char k, int x, int y) // Process keypresses if (k == 'q' || k == 'Q') ::terminate(); - if (k == '/') statsOn = !statsOn; // toggle stats + if (k == '/') ::statsOn = !::statsOn; // toggle stats if (k == '*') ::starsOn = !::starsOn; // toggle stars if (k == 'V' || k == 'v') ::showingVoxels = !::showingVoxels; // toggle voxels if (k == 'F') ::frustumOn = !::frustumOn; // toggle view frustum debugging From 2163976f067c26fb677884ccf59dfb30ace4795c Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 24 Apr 2013 17:01:59 -0700 Subject: [PATCH 11/11] adding the files --- interface/src/Avatar.cpp | 1270 ++++++++++++++++++++++++++++++++++++++ interface/src/Avatar.h | 268 ++++++++ 2 files changed, 1538 insertions(+) create mode 100644 interface/src/Avatar.cpp create mode 100644 interface/src/Avatar.h diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp new file mode 100644 index 0000000000..ae082fd71c --- /dev/null +++ b/interface/src/Avatar.cpp @@ -0,0 +1,1270 @@ +// +// Avatar.cpp +// interface +// +// Created by Philip Rosedale on 9/11/12. +// adapted by Jeffrey Ventrella +// Copyright (c) 2012 Physical, Inc.. All rights reserved. +// + +#include +#include +#include +#include +#include "Avatar.h" +#include "Log.h" +#include +#include +#include + +using namespace std; + +float skinColor[] = {1.0, 0.84, 0.66}; +float lightBlue[] = { 0.7, 0.8, 1.0 }; +float browColor[] = {210.0/255.0, 105.0/255.0, 30.0/255.0}; +float mouthColor[] = {1, 0, 0}; + +float BrowRollAngle[5] = {0, 15, 30, -30, -15}; +float BrowPitchAngle[3] = {-70, -60, -50}; +float eyeColor[3] = {1,1,1}; + +float MouthWidthChoices[3] = {0.5, 0.77, 0.3}; + +float browWidth = 0.8; +float browThickness = 0.16; + +bool usingBigSphereCollisionTest = true; + +char iris_texture_file[] = "resources/images/green_eye.png"; + +vector iris_texture; +unsigned int iris_texture_width = 512; +unsigned int iris_texture_height = 256; + +Avatar::Avatar(bool isMine) { + + _orientation.setToIdentity(); + + _velocity = glm::vec3( 0.0, 0.0, 0.0 ); + _thrust = glm::vec3( 0.0, 0.0, 0.0 ); + _rotation = glm::quat( 0.0f, 0.0f, 0.0f, 0.0f ); + _bodyYaw = -90.0; + _bodyPitch = 0.0; + _bodyRoll = 0.0; + _bodyYawDelta = 0.0; + _mousePressed = false; + _mode = AVATAR_MODE_STANDING; + _isMine = isMine; + _maxArmLength = 0.0; + //_transmitterTimer = 0; + _transmitterHz = 0.0; + _transmitterPackets = 0; + + initializeSkeleton(); + + _TEST_bigSphereRadius = 0.3f; + _TEST_bigSpherePosition = glm::vec3( 0.0f, _TEST_bigSphereRadius, 2.0f ); + + for (int i = 0; i < MAX_DRIVE_KEYS; i++) _driveKeys[i] = false; + + _head.pupilSize = 0.10; + _head.interPupilDistance = 0.6; + _head.interBrowDistance = 0.75; + _head.nominalPupilSize = 0.10; + _head.pitchRate = 0.0; + _head.yawRate = 0.0; + _head.rollRate = 0.0; + _head.eyebrowPitch[0] = -30; + _head.eyebrowPitch[1] = -30; + _head.eyebrowRoll [0] = 20; + _head.eyebrowRoll [1] = -20; + _head.mouthPitch = 0; + _head.mouthYaw = 0; + _head.mouthWidth = 1.0; + _head.mouthHeight = 0.2; + _head.eyeballPitch[0] = 0; + _head.eyeballPitch[1] = 0; + _head.eyeballScaleX = 1.2; + _head.eyeballScaleY = 1.5; + _head.eyeballScaleZ = 1.0; + _head.eyeballYaw[0] = 0; + _head.eyeballYaw[1] = 0; + _head.pitchTarget = 0; + _head.yawTarget = 0; + _head.noiseEnvelope = 1.0; + _head.pupilConverge = 10.0; + _head.leanForward = 0.0; + _head.leanSideways = 0.0; + _head.eyeContact = 1; + _head.eyeContactTarget = LEFT_EYE; + _head.scale = 1.0; + _head.audioAttack = 0.0; + _head.averageLoudness = 0.0; + _head.lastLoudness = 0.0; + _head.browAudioLift = 0.0; + _head.noise = 0; + _movedHandOffset = glm::vec3( 0.0, 0.0, 0.0 ); + _usingBodySprings = true; + _springForce = 6.0f; + _springVelocityDecay = 16.0f; + _renderYaw = 0.0; + _renderPitch = 0.0; + _sphere = NULL; + _interactingOther = NULL; + _interactingOtherIsNearby = false; + + _handHolding.position = glm::vec3( 0.0, 0.0, 0.0 ); + _handHolding.velocity = glm::vec3( 0.0, 0.0, 0.0 ); + _handHolding.force = 10.0f; + + if (iris_texture.size() == 0) { + switchToResourcesParentIfRequired(); + unsigned error = lodepng::decode(iris_texture, iris_texture_width, iris_texture_height, iris_texture_file); + if (error != 0) { + printLog("error %u: %s\n", error, lodepng_error_text(error)); + } + } +} + + + +Avatar::Avatar(const Avatar &otherAvatar) { + + _velocity = otherAvatar._velocity; + _thrust = otherAvatar._thrust; + _rotation = otherAvatar._rotation; + _interactingOtherIsNearby = otherAvatar._interactingOtherIsNearby; + _bodyYaw = otherAvatar._bodyYaw; + _bodyPitch = otherAvatar._bodyPitch; + _bodyRoll = otherAvatar._bodyRoll; + _bodyYawDelta = otherAvatar._bodyYawDelta; + _mousePressed = otherAvatar._mousePressed; + _mode = otherAvatar._mode; + _isMine = otherAvatar._isMine; + _renderYaw = otherAvatar._renderYaw; + _renderPitch = otherAvatar._renderPitch; + _maxArmLength = otherAvatar._maxArmLength; + _transmitterTimer = otherAvatar._transmitterTimer; + _transmitterHz = otherAvatar._transmitterHz; + _transmitterPackets = otherAvatar._transmitterPackets; + _TEST_bigSphereRadius = otherAvatar._TEST_bigSphereRadius; + _TEST_bigSpherePosition = otherAvatar._TEST_bigSpherePosition; + _movedHandOffset = otherAvatar._movedHandOffset; + _usingBodySprings = otherAvatar._usingBodySprings; + _springForce = otherAvatar._springForce; + _springVelocityDecay = otherAvatar._springVelocityDecay; + _orientation.set( otherAvatar._orientation ); + + _sphere = NULL; + + initializeSkeleton(); + + for (int i = 0; i < MAX_DRIVE_KEYS; i++) _driveKeys[i] = otherAvatar._driveKeys[i]; + + _head.pupilSize = otherAvatar._head.pupilSize; + _head.interPupilDistance = otherAvatar._head.interPupilDistance; + _head.interBrowDistance = otherAvatar._head.interBrowDistance; + _head.nominalPupilSize = otherAvatar._head.nominalPupilSize; + _head.yawRate = otherAvatar._head.yawRate; + _head.pitchRate = otherAvatar._head.pitchRate; + _head.rollRate = otherAvatar._head.rollRate; + _head.eyebrowPitch[0] = otherAvatar._head.eyebrowPitch[0]; + _head.eyebrowPitch[1] = otherAvatar._head.eyebrowPitch[1]; + _head.eyebrowRoll [0] = otherAvatar._head.eyebrowRoll [0]; + _head.eyebrowRoll [1] = otherAvatar._head.eyebrowRoll [1]; + _head.mouthPitch = otherAvatar._head.mouthPitch; + _head.mouthYaw = otherAvatar._head.mouthYaw; + _head.mouthWidth = otherAvatar._head.mouthWidth; + _head.mouthHeight = otherAvatar._head.mouthHeight; + _head.eyeballPitch[0] = otherAvatar._head.eyeballPitch[0]; + _head.eyeballPitch[1] = otherAvatar._head.eyeballPitch[1]; + _head.eyeballScaleX = otherAvatar._head.eyeballScaleX; + _head.eyeballScaleY = otherAvatar._head.eyeballScaleY; + _head.eyeballScaleZ = otherAvatar._head.eyeballScaleZ; + _head.eyeballYaw[0] = otherAvatar._head.eyeballYaw[0]; + _head.eyeballYaw[1] = otherAvatar._head.eyeballYaw[1]; + _head.pitchTarget = otherAvatar._head.pitchTarget; + _head.yawTarget = otherAvatar._head.yawTarget; + _head.noiseEnvelope = otherAvatar._head.noiseEnvelope; + _head.pupilConverge = otherAvatar._head.pupilConverge; + _head.leanForward = otherAvatar._head.leanForward; + _head.leanSideways = otherAvatar._head.leanSideways; + _head.eyeContact = otherAvatar._head.eyeContact; + _head.eyeContactTarget = otherAvatar._head.eyeContactTarget; + _head.scale = otherAvatar._head.scale; + _head.audioAttack = otherAvatar._head.audioAttack; + _head.averageLoudness = otherAvatar._head.averageLoudness; + _head.lastLoudness = otherAvatar._head.lastLoudness; + _head.browAudioLift = otherAvatar._head.browAudioLift; + _head.noise = otherAvatar._head.noise; + + if (iris_texture.size() == 0) { + switchToResourcesParentIfRequired(); + unsigned error = lodepng::decode(iris_texture, iris_texture_width, iris_texture_height, iris_texture_file); + if (error != 0) { + printLog("error %u: %s\n", error, lodepng_error_text(error)); + } + } +} + +Avatar::~Avatar() { + if (_sphere != NULL) { + gluDeleteQuadric(_sphere); + } +} + +Avatar* Avatar::clone() const { + return new Avatar(*this); +} + +void Avatar::reset() { + _headPitch = _headYaw = _headRoll = 0; + _head.leanForward = _head.leanSideways = 0; +} + + +//this pertains to moving the head with the glasses +void Avatar::UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity) +// Using serial data, update avatar/render position and angles +{ + const float PITCH_ACCEL_COUPLING = 0.5; + const float ROLL_ACCEL_COUPLING = -1.0; + float measured_pitch_rate = serialInterface->getRelativeValue(HEAD_PITCH_RATE); + _head.yawRate = serialInterface->getRelativeValue(HEAD_YAW_RATE); + float measured_lateral_accel = serialInterface->getRelativeValue(ACCEL_X) - + ROLL_ACCEL_COUPLING*serialInterface->getRelativeValue(HEAD_ROLL_RATE); + float measured_fwd_accel = serialInterface->getRelativeValue(ACCEL_Z) - + PITCH_ACCEL_COUPLING*serialInterface->getRelativeValue(HEAD_PITCH_RATE); + float measured_roll_rate = serialInterface->getRelativeValue(HEAD_ROLL_RATE); + + //printLog("Pitch Rate: %d ACCEL_Z: %d\n", serialInterface->getRelativeValue(PITCH_RATE), + // serialInterface->getRelativeValue(ACCEL_Z)); + //printLog("Pitch Rate: %d ACCEL_X: %d\n", serialInterface->getRelativeValue(PITCH_RATE), + // serialInterface->getRelativeValue(ACCEL_Z)); + //printLog("Pitch: %f\n", Pitch); + + // Update avatar head position based on measured gyro rates + const float HEAD_ROTATION_SCALE = 0.70; + const float HEAD_ROLL_SCALE = 0.40; + const float HEAD_LEAN_SCALE = 0.01; + const float MAX_PITCH = 45; + const float MIN_PITCH = -45; + const float MAX_YAW = 85; + const float MIN_YAW = -85; + + if ((_headPitch < MAX_PITCH) && (_headPitch > MIN_PITCH)) + addHeadPitch(measured_pitch_rate * -HEAD_ROTATION_SCALE * frametime); + + addHeadRoll(measured_roll_rate * HEAD_ROLL_SCALE * frametime); + + if ((_headYaw < MAX_YAW) && (_headYaw > MIN_YAW)) + addHeadYaw(_head.yawRate * HEAD_ROTATION_SCALE * frametime); + + addLean(-measured_lateral_accel * frametime * HEAD_LEAN_SCALE, -measured_fwd_accel*frametime * HEAD_LEAN_SCALE); +} + +void Avatar::addLean(float x, float z) { + // Add Body lean as impulse + _head.leanSideways += x; + _head.leanForward += z; +} + + +void Avatar::setLeanForward(float dist){ + _head.leanForward = dist; +} + +void Avatar::setLeanSideways(float dist){ + _head.leanSideways = dist; +} + +void Avatar::setMousePressed( bool d ) { + _mousePressed = d; +} + +void Avatar::simulate(float deltaTime) { + + // update avatar skeleton + updateSkeleton(); + + // reset hand and arm positions according to hand movement + updateHandMovement( deltaTime ); + + if ( !_interactingOtherIsNearby ) { + //initialize _handHolding + _handHolding.position = _bone[ AVATAR_BONE_RIGHT_HAND ].position; + _handHolding.velocity = glm::vec3( 0.0, 0.0, 0.0 ); + } + + _interactingOtherIsNearby = false; + + // if the avatar being simulated is mine, then loop through + // all the other avatars for potential interactions... + if ( _isMine ) + { + float closestDistance = 10000.0f; + + AgentList * agentList = AgentList::getInstance(); + + for(std::vector::iterator agent = agentList->getAgents().begin(); + agent != agentList->getAgents().end(); + agent++) { + if (( agent->getLinkedData() != NULL && ( agent->getType() == AGENT_TYPE_AVATAR ) )) { + Avatar *otherAvatar = (Avatar *)agent->getLinkedData(); + + // check for collisions with other avatars and respond + updateAvatarCollisionDetectionAndResponse + ( + otherAvatar->getPosition(), + otherAvatar->getGirth(), + otherAvatar->getHeight(), + otherAvatar->getBodyUpDirection(), + deltaTime + ); + + // test other avatar hand position for proximity + glm::vec3 v( _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position ); + v -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); + + float distance = glm::length( v ); + if ( distance < _maxArmLength ) { + + //if ( distance < closestDistance ) { // perhaps I don't need this if we want to allow multi-avatar interactions + { + closestDistance = distance; + _interactingOther = otherAvatar; + _interactingOtherIsNearby = true; + + // if I am holding hands with another avatar, a force is applied + if (( _handState == 1 ) || ( _interactingOther->_handState == 1 )) { + glm::vec3 vectorToOtherHand = _interactingOther->_handPosition - _handHolding.position; + glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHolding.position; + + _handHolding.velocity *= 0.7; + _handHolding.velocity += ( vectorToOtherHand + vectorToMyHand ) * _handHolding.force * deltaTime; + _handHolding.position += _handHolding.velocity; + + _bone[ AVATAR_BONE_RIGHT_HAND ].position = _handHolding.position; + } + } + } + } + } + + // Set the vector we send for hand position to other people to be our right hand + setHandPosition(_bone[ AVATAR_BONE_RIGHT_HAND ].position); + + }//if ( _isMine ) + + + updateArmIKAndConstraints( deltaTime ); + + if (!_interactingOtherIsNearby) { + _interactingOther = NULL; + } + + if ( usingBigSphereCollisionTest ) { + + // test for avatar collision response (using a big sphere :) + updateAvatarCollisionDetectionAndResponse + ( + _TEST_bigSpherePosition, + _TEST_bigSphereRadius, + _TEST_bigSphereRadius, + glm::vec3( 0.0, 1.0, 0.0 ), + deltaTime + ); + } + + if ( AVATAR_GRAVITY ) { + if ( _position.y > _bone[ AVATAR_BONE_RIGHT_FOOT ].radius * 2.0 ) { + _velocity += glm::dvec3( 0.0, -1.0, 0.0 ) * ( 6.0 * deltaTime ); + } + else { + if ( _position.y < _bone[ AVATAR_BONE_RIGHT_FOOT ].radius ) { + _position.y = _bone[ AVATAR_BONE_RIGHT_FOOT ].radius; + _velocity.y = 0.0; + } + } + } + + // update body springs + updateBodySprings( deltaTime ); + + // driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely) + if ( _isMine ) { + + _thrust = glm::vec3( 0.0, 0.0, 0.0 ); + + if (_driveKeys[FWD]) { + glm::vec3 front( _orientation.getFront().x, _orientation.getFront().y, _orientation.getFront().z ); + _thrust += front * THRUST_MAG; + } + if (_driveKeys[BACK]) { + glm::vec3 front( _orientation.getFront().x, _orientation.getFront().y, _orientation.getFront().z ); + _thrust -= front * THRUST_MAG; + } + if (_driveKeys[RIGHT]) { + glm::vec3 right( _orientation.getRight().x, _orientation.getRight().y, _orientation.getRight().z ); + _thrust += right * THRUST_MAG; + } + if (_driveKeys[LEFT]) { + glm::vec3 right( _orientation.getRight().x, _orientation.getRight().y, _orientation.getRight().z ); + _thrust -= right * THRUST_MAG; + } + if (_driveKeys[UP]) { + glm::vec3 up( _orientation.getUp().x, _orientation.getUp().y, _orientation.getUp().z ); + _thrust += up * THRUST_MAG; + } + if (_driveKeys[DOWN]) { + glm::vec3 up( _orientation.getUp().x, _orientation.getUp().y, _orientation.getUp().z ); + _thrust -= up * THRUST_MAG; + } + if (_driveKeys[ROT_RIGHT]) { + _bodyYawDelta -= YAW_MAG * deltaTime; + } + if (_driveKeys[ROT_LEFT]) { + _bodyYawDelta += YAW_MAG * deltaTime; + } + } + + float translationalSpeed = glm::length( _velocity ); + float rotationalSpeed = fabs( _bodyYawDelta ); + if ( translationalSpeed + rotationalSpeed > 0.2 ) + { + _mode = AVATAR_MODE_WALKING; + } + else + { + _mode = AVATAR_MODE_INTERACTING; + } + + // update body yaw by body yaw delta + if (_isMine) { + _bodyYaw += _bodyYawDelta * deltaTime; + } + + // decay body yaw delta + _bodyYawDelta *= (1.0 - TEST_YAW_DECAY * deltaTime); + + // add thrust to velocity + _velocity += glm::dvec3(_thrust * deltaTime); + + // update position by velocity + _position += (glm::vec3)_velocity * deltaTime; + + // decay velocity + _velocity *= ( 1.0 - LIN_VEL_DECAY * deltaTime ); + + // + // Update Head information + // + + if (!_head.noise) { + // Decay back toward center + _headPitch *= (1.0f - DECAY * 2 * deltaTime); + _headYaw *= (1.0f - DECAY * 2 * deltaTime); + _headRoll *= (1.0f - DECAY * 2 * deltaTime); + } + else { + // Move toward new target + _headPitch += (_head.pitchTarget - _headPitch) * 10 * deltaTime; // (1.f - DECAY*deltaTime)*Pitch + ; + _headYaw += (_head.yawTarget - _headYaw ) * 10 * deltaTime; // (1.f - DECAY*deltaTime); + _headRoll *= 1.f - (DECAY * deltaTime); + } + + _head.leanForward *= (1.f - DECAY * 30 * deltaTime); + _head.leanSideways *= (1.f - DECAY * 30 * deltaTime); + + // Update where the avatar's eyes are + // + // First, decide if we are making eye contact or not + if (randFloat() < 0.005) { + _head.eyeContact = !_head.eyeContact; + _head.eyeContact = 1; + if (!_head.eyeContact) { + // If we just stopped making eye contact,move the eyes markedly away + _head.eyeballPitch[0] = _head.eyeballPitch[1] = _head.eyeballPitch[0] + 5.0 + (randFloat() - 0.5) * 10; + _head.eyeballYaw [0] = _head.eyeballYaw [1] = _head.eyeballYaw [0] + 5.0 + (randFloat() - 0.5) * 5; + } else { + // If now making eye contact, turn head to look right at viewer + SetNewHeadTarget(0,0); + } + } + + const float DEGREES_BETWEEN_VIEWER_EYES = 3; + const float DEGREES_TO_VIEWER_MOUTH = 7; + + if (_head.eyeContact) { + // Should we pick a new eye contact target? + if (randFloat() < 0.01) { + // Choose where to look next + if (randFloat() < 0.1) { + _head.eyeContactTarget = MOUTH; + } else { + if (randFloat() < 0.5) _head.eyeContactTarget = LEFT_EYE; else _head.eyeContactTarget = RIGHT_EYE; + } + } + // Set eyeball pitch and yaw to make contact + float eye_target_yaw_adjust = 0; + float eye_target_pitch_adjust = 0; + if (_head.eyeContactTarget == LEFT_EYE) eye_target_yaw_adjust = DEGREES_BETWEEN_VIEWER_EYES; + if (_head.eyeContactTarget == RIGHT_EYE) eye_target_yaw_adjust = -DEGREES_BETWEEN_VIEWER_EYES; + if (_head.eyeContactTarget == MOUTH) eye_target_pitch_adjust = DEGREES_TO_VIEWER_MOUTH; + + _head.eyeballPitch[0] = _head.eyeballPitch[1] = -_headPitch + eye_target_pitch_adjust; + _head.eyeballYaw[0] = _head.eyeballYaw[1] = -_headYaw + eye_target_yaw_adjust; + } + + + if (_head.noise) + { + _headPitch += (randFloat() - 0.5) * 0.2 * _head.noiseEnvelope; + _headYaw += (randFloat() - 0.5) * 0.3 *_head.noiseEnvelope; + //PupilSize += (randFloat() - 0.5) * 0.001*NoiseEnvelope; + + if (randFloat() < 0.005) _head.mouthWidth = MouthWidthChoices[rand()%3]; + + if (!_head.eyeContact) { + if (randFloat() < 0.01) _head.eyeballPitch[0] = _head.eyeballPitch[1] = (randFloat() - 0.5) * 20; + if (randFloat() < 0.01) _head.eyeballYaw[0] = _head.eyeballYaw[1] = (randFloat()- 0.5) * 10; + } + + if ((randFloat() < 0.005) && (fabs(_head.pitchTarget - _headPitch) < 1.0) && (fabs(_head.yawTarget - _headYaw) < 1.0)) { + SetNewHeadTarget((randFloat()-0.5) * 20.0, (randFloat()-0.5) * 45.0); + } + + if (0) { + + // Pick new target + _head.pitchTarget = (randFloat() - 0.5) * 45; + _head.yawTarget = (randFloat() - 0.5) * 22; + } + if (randFloat() < 0.01) + { + _head.eyebrowPitch[0] = _head.eyebrowPitch[1] = BrowPitchAngle[rand()%3]; + _head.eyebrowRoll [0] = _head.eyebrowRoll[1] = BrowRollAngle[rand()%5]; + _head.eyebrowRoll [1] *=-1; + } + } + + // Update audio trailing average for rendering facial animations + const float AUDIO_AVERAGING_SECS = 0.05; + _head.averageLoudness = (1.f - deltaTime / AUDIO_AVERAGING_SECS) * _head.averageLoudness + + (deltaTime / AUDIO_AVERAGING_SECS) * _audioLoudness; +} + + +float Avatar::getGirth() { + return COLLISION_BODY_RADIUS; +} + +float Avatar::getHeight() { + return COLLISION_HEIGHT; +} + + +glm::vec3 Avatar::getBodyUpDirection() { + return _orientation.getUp(); +} + +// This is a workspace for testing avatar body collision detection and response +void Avatar::updateAvatarCollisionDetectionAndResponse +( glm::vec3 collisionPosition, float collisionGirth, float collisionHeight, glm::vec3 collisionUpVector, float deltaTime ) { + + float myBodyApproximateBoundingRadius = 1.0f; + glm::vec3 vectorFromMyBodyToBigSphere(_position - collisionPosition); + bool jointCollision = false; + + float distanceToBigSphere = glm::length(vectorFromMyBodyToBigSphere); + if ( distanceToBigSphere < myBodyApproximateBoundingRadius + collisionGirth ) + { + for (int b=0; b 0.0) + { + glm::vec3 directionVector = vectorFromJointToBigSphereCenter / distanceToBigSphereCenter; + + float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius); + glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration; + + _bone[b].springyVelocity += collisionForce * 30.0f * deltaTime; + _velocity += collisionForce * 100.0f * deltaTime; + _bone[b].springyPosition = collisionPosition + directionVector * combinedRadius; + } + } + } + + if ( jointCollision ) { + if (!_usingBodySprings) { + _usingBodySprings = true; + initializeBodySprings(); + } + } + } +} + + +void Avatar::render(bool lookingInMirror) { + + // show avatar position + glColor4f( 0.5f, 0.5f, 0.5f, 0.6 ); + glPushMatrix(); + glTranslatef(_position.x, _position.y, _position.z); + glScalef( 0.03, 0.03, 0.03 ); + glutSolidSphere( 1, 10, 10 ); + glPopMatrix(); + + if ( usingBigSphereCollisionTest ) { + + // show TEST big sphere + glColor4f( 0.5f, 0.6f, 0.8f, 0.7 ); + glPushMatrix(); + glTranslatef(_TEST_bigSpherePosition.x, _TEST_bigSpherePosition.y, _TEST_bigSpherePosition.z); + glScalef( _TEST_bigSphereRadius, _TEST_bigSphereRadius, _TEST_bigSphereRadius ); + glutSolidSphere( 1, 20, 20 ); + glPopMatrix(); + } + + // render body + renderBody(); + + // render head + renderHead(lookingInMirror); + + // if this is my avatar, then render my interactions with the other avatar + if ( _isMine ) + { + if ( _interactingOtherIsNearby ) { + + glm::vec3 v1( _bone[ AVATAR_BONE_RIGHT_HAND ].position ); + glm::vec3 v2( _interactingOther->_handPosition ); + + glLineWidth( 8.0 ); + glColor4f( 0.7f, 0.4f, 0.1f, 0.6 ); + glBegin( GL_LINE_STRIP ); + glVertex3f( v1.x, v1.y, v1.z ); + glVertex3f( v2.x, v2.y, v2.z ); + glEnd(); + } + } +} + + +void Avatar::renderHead(bool lookingInMirror) { + int side = 0; + + glEnable(GL_DEPTH_TEST); + glEnable(GL_RESCALE_NORMAL); + + // show head orientation + //renderOrientationDirections( _bone[ AVATAR_BONE_HEAD ].position, _bone[ AVATAR_BONE_HEAD ].orientation, 0.2f ); + + glPushMatrix(); + + if (_usingBodySprings) { + glTranslatef(_bone[ AVATAR_BONE_HEAD ].springyPosition.x, + _bone[ AVATAR_BONE_HEAD ].springyPosition.y, + _bone[ AVATAR_BONE_HEAD ].springyPosition.z); + } + else { + glTranslatef(_bone[ AVATAR_BONE_HEAD ].position.x, + _bone[ AVATAR_BONE_HEAD ].position.y, + _bone[ AVATAR_BONE_HEAD ].position.z); + } + + glScalef( 0.03, 0.03, 0.03 ); + + if (lookingInMirror) { + glRotatef(_bodyYaw - _headYaw, 0, 1, 0); + glRotatef(_bodyPitch + _headPitch, 1, 0, 0); + glRotatef(_bodyRoll - _headRoll, 0, 0, 1); + } else { + glRotatef(_bodyYaw + _headYaw, 0, 1, 0); + glRotatef(_bodyPitch + _headPitch, 1, 0, 0); + glRotatef(_bodyRoll + _headRoll, 0, 0, 1); + } + + glScalef(2.0, 2.0, 2.0); + glColor3fv(skinColor); + + glutSolidSphere(1, 30, 30); + + // Ears + glPushMatrix(); + glTranslatef(1.0, 0, 0); + for(side = 0; side < 2; side++) { + glPushMatrix(); + glScalef(0.3, 0.65, .65); + glutSolidSphere(0.5, 30, 30); + glPopMatrix(); + glTranslatef(-2.0, 0, 0); + } + glPopMatrix(); + + + // Update audio attack data for facial animation (eyebrows and mouth) + _head.audioAttack = 0.9 * _head.audioAttack + 0.1 * fabs(_audioLoudness - _head.lastLoudness); + _head.lastLoudness = _audioLoudness; + + + const float BROW_LIFT_THRESHOLD = 100; + if (_head.audioAttack > BROW_LIFT_THRESHOLD) + _head.browAudioLift += sqrt(_head.audioAttack) / 1000.0; + + _head.browAudioLift *= .90; + + + // Render Eyebrows + glPushMatrix(); + glTranslatef(-_head.interBrowDistance / 2.0,0.4,0.45); + for(side = 0; side < 2; side++) { + glColor3fv(browColor); + glPushMatrix(); + glTranslatef(0, 0.35 + _head.browAudioLift, 0); + glRotatef(_head.eyebrowPitch[side]/2.0, 1, 0, 0); + glRotatef(_head.eyebrowRoll[side]/2.0, 0, 0, 1); + glScalef(browWidth, browThickness, 1); + glutSolidCube(0.5); + glPopMatrix(); + glTranslatef(_head.interBrowDistance, 0, 0); + } + glPopMatrix(); + + + // Mouth + + glPushMatrix(); + glTranslatef(0,-0.35,0.75); + glColor3f(0,0,0); + glRotatef(_head.mouthPitch, 1, 0, 0); + glRotatef(_head.mouthYaw, 0, 0, 1); + glScalef(_head.mouthWidth*(.7 + sqrt(_head.averageLoudness)/60.0), _head.mouthHeight*(1.0 + sqrt(_head.averageLoudness)/30.0), 1); + glutSolidCube(0.5); + glPopMatrix(); + + glTranslatef(0, 1.0, 0); + + glTranslatef(-_head.interPupilDistance/2.0,-0.68,0.7); + // Right Eye + glRotatef(-10, 1, 0, 0); + glColor3fv(eyeColor); + glPushMatrix(); + { + glTranslatef(_head.interPupilDistance/10.0, 0, 0.05); + glRotatef(20, 0, 0, 1); + glScalef(_head.eyeballScaleX, _head.eyeballScaleY, _head.eyeballScaleZ); + glutSolidSphere(0.25, 30, 30); + } + glPopMatrix(); + + // Right Pupil + if (_sphere == NULL) { + _sphere = gluNewQuadric(); + gluQuadricTexture(_sphere, GL_TRUE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gluQuadricOrientation(_sphere, GLU_OUTSIDE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iris_texture_width, iris_texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &iris_texture[0]); + } + + glPushMatrix(); + { + glRotatef(_head.eyeballPitch[1], 1, 0, 0); + glRotatef(_head.eyeballYaw[1] + _headYaw + _head.pupilConverge, 0, 1, 0); + glTranslatef(0,0,.35); + glRotatef(-75,1,0,0); + glScalef(1.0, 0.4, 1.0); + + glEnable(GL_TEXTURE_2D); + gluSphere(_sphere, _head.pupilSize, 15, 15); + glDisable(GL_TEXTURE_2D); + } + + glPopMatrix(); + // Left Eye + glColor3fv(eyeColor); + glTranslatef(_head.interPupilDistance, 0, 0); + glPushMatrix(); + { + glTranslatef(-_head.interPupilDistance/10.0, 0, .05); + glRotatef(-20, 0, 0, 1); + glScalef(_head.eyeballScaleX, _head.eyeballScaleY, _head.eyeballScaleZ); + glutSolidSphere(0.25, 30, 30); + } + glPopMatrix(); + // Left Pupil + glPushMatrix(); + { + glRotatef(_head.eyeballPitch[0], 1, 0, 0); + glRotatef(_head.eyeballYaw[0] + _headYaw - _head.pupilConverge, 0, 1, 0); + glTranslatef(0, 0, .35); + glRotatef(-75, 1, 0, 0); + glScalef(1.0, 0.4, 1.0); + + glEnable(GL_TEXTURE_2D); + gluSphere(_sphere, _head.pupilSize, 15, 15); + glDisable(GL_TEXTURE_2D); + } + + glPopMatrix(); + + + glPopMatrix(); + } + +void Avatar::startHandMovement() { + + if (!_usingBodySprings) { + initializeBodySprings(); + _usingBodySprings = true; + } +} + +void Avatar::stopHandMovement() { +//_usingBodySprings = false; +} + +void Avatar::setHandMovementValues( glm::vec3 handOffset ) { + _movedHandOffset = handOffset; +} + +AvatarMode Avatar::getMode() { + return _mode; +} + +void Avatar::initializeSkeleton() { + + for (int b=0; b 0.0f ) { + glm::vec3 springDirection = springVector / length; + + float force = ( length - _bone[b].length ) * _springForce * deltaTime; + + _bone[b].springyVelocity -= springDirection * force; + + if ( _bone[b].parent != AVATAR_BONE_NULL ) { + _bone[ _bone[b].parent ].springyVelocity += springDirection * force; + } + } + + _bone[b].springyVelocity += ( _bone[b].position - _bone[b].springyPosition ) * _bone[b].springBodyTightness * deltaTime; + + float decay = 1.0 - _springVelocityDecay * deltaTime; + + if ( decay > 0.0 ) { + _bone[b].springyVelocity *= decay; + } + else { + _bone[b].springyVelocity = glm::vec3( 0.0f, 0.0f, 0.0f ); + } + + _bone[b].springyPosition += _bone[b].springyVelocity; + } +} + +glm::vec3 Avatar::getHeadLookatDirection() { + return glm::vec3 + ( + _orientation.getFront().x, + _orientation.getFront().y, + _orientation.getFront().z + ); +} + +glm::vec3 Avatar::getHeadLookatDirectionUp() { + return glm::vec3 + ( + _orientation.getUp().x, + _orientation.getUp().y, + _orientation.getUp().z + ); +} + +glm::vec3 Avatar::getHeadLookatDirectionRight() { + return glm::vec3 + ( + _orientation.getRight().x, + _orientation.getRight().y, + _orientation.getRight().z + ); +} + +glm::vec3 Avatar::getHeadPosition() { + + if ( _usingBodySprings ) { + return _bone[ AVATAR_BONE_HEAD ].springyPosition; + } + + return _bone[ AVATAR_BONE_HEAD ].position; +} + + +glm::vec3 Avatar::getBonePosition( AvatarBoneID b ) { + return _bone[b].position; +} + + + +void Avatar::updateHandMovement( float deltaTime ) { + glm::vec3 transformedHandMovement; + + transformedHandMovement + = _orientation.getRight() * _movedHandOffset.x + + _orientation.getUp() * -_movedHandOffset.y * 0.5f + + _orientation.getFront() * -_movedHandOffset.y; + + _bone[ AVATAR_BONE_RIGHT_HAND ].position += transformedHandMovement; + + if (_isMine) { + _handState = _mousePressed; + } +} + + +void Avatar::updateArmIKAndConstraints( float deltaTime ) { + + // determine the arm vector + glm::vec3 armVector = _bone[ AVATAR_BONE_RIGHT_HAND ].position; + armVector -= _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; + + // test to see if right hand is being dragged beyond maximum arm length + float distance = glm::length( armVector ); + + // if right hand is being dragged beyond maximum arm length... + if ( distance > _maxArmLength ) { + // reset right hand to be constrained to maximum arm length + _bone[ AVATAR_BONE_RIGHT_HAND ].position = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; + glm::vec3 armNormal = armVector / distance; + armVector = armNormal * _maxArmLength; + distance = _maxArmLength; + glm::vec3 constrainedPosition = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; + constrainedPosition += armVector; + _bone[ AVATAR_BONE_RIGHT_HAND ].position = constrainedPosition; + } + + // set elbow position + glm::vec3 newElbowPosition = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; + newElbowPosition += armVector * ONE_HALF; + glm::vec3 perpendicular = glm::cross( _orientation.getFront(), armVector ); + newElbowPosition += perpendicular * ( 1.0f - ( _maxArmLength / distance ) ) * ONE_HALF; + _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position = newElbowPosition; + + // set wrist position + glm::vec3 vv( _bone[ AVATAR_BONE_RIGHT_HAND ].position ); + vv -= _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position; + glm::vec3 newWristPosition = _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position; + newWristPosition += vv * 0.7f; + _bone[ AVATAR_BONE_RIGHT_FOREARM ].position = newWristPosition; +} + + + + +void Avatar::renderBody() { + + // Render bone positions as spheres + for (int b=0; b( (double)TRANSMITTER_COUNT/(msecsElapsed/1000.0) ); + _transmitterTimer = now; + } + /* NOTE: PR: Will add back in when ready to animate avatar hand + + // Add rotational forces to the hand + const float ANG_VEL_SENSITIVITY = 4.0; + const float ANG_VEL_THRESHOLD = 0.0; + float angVelScale = ANG_VEL_SENSITIVITY*(1.0f/getTransmitterHz()); + + addAngularVelocity(fabs(gyrX*angVelScale)>ANG_VEL_THRESHOLD?gyrX*angVelScale:0, + fabs(gyrZ*angVelScale)>ANG_VEL_THRESHOLD?gyrZ*angVelScale:0, + fabs(-gyrY*angVelScale)>ANG_VEL_THRESHOLD?-gyrY*angVelScale:0); + + // Add linear forces to the hand + //const float LINEAR_VEL_SENSITIVITY = 50.0; + const float LINEAR_VEL_SENSITIVITY = 5.0; + float linVelScale = LINEAR_VEL_SENSITIVITY*(1.0f/getTransmitterHz()); + glm::vec3 linVel(linX*linVelScale, linZ*linVelScale, -linY*linVelScale); + addVelocity(linVel); + */ + +} + diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h new file mode 100644 index 0000000000..32d31184a8 --- /dev/null +++ b/interface/src/Avatar.h @@ -0,0 +1,268 @@ +// +// Avatar.h +// interface +// +// Created by Philip Rosedale on 9/11/12. +// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__avatar__ +#define __interface__avatar__ + +#include +#include + +#include "Field.h" +#include "world.h" + +#include "InterfaceConfig.h" +#include "SerialInterface.h" + +#include +#include +#include //looks like we might not need this + +const bool AVATAR_GRAVITY = true; +const float DECAY = 0.1; +const float THRUST_MAG = 10.0; +const float YAW_MAG = 300.0; +const float TEST_YAW_DECAY = 5.0; +const float LIN_VEL_DECAY = 5.0; + +const float COLLISION_BODY_RADIUS = 0.1; +const float COLLISION_HEIGHT = 1.5; + +enum eyeContactTargets {LEFT_EYE, RIGHT_EYE, MOUTH}; + +#define FWD 0 +#define BACK 1 +#define LEFT 2 +#define RIGHT 3 +#define UP 4 +#define DOWN 5 +#define ROT_LEFT 6 +#define ROT_RIGHT 7 +#define MAX_DRIVE_KEYS 8 + +#define MAX_OTHER_AVATARS 10 // temporary - for testing purposes! + +enum AvatarMode +{ + AVATAR_MODE_STANDING = 0, + AVATAR_MODE_WALKING, + AVATAR_MODE_INTERACTING, + NUM_AVATAR_MODES +}; + +enum AvatarBoneID +{ + AVATAR_BONE_NULL = -1, + AVATAR_BONE_PELVIS_SPINE, // connects pelvis joint with torso joint (not supposed to be rotated) + AVATAR_BONE_MID_SPINE, // connects torso joint with chest joint + AVATAR_BONE_CHEST_SPINE, // connects chest joint with neckBase joint (not supposed to be rotated) + AVATAR_BONE_NECK, // connects neckBase joint with headBase joint + AVATAR_BONE_HEAD, // connects headBase joint with headTop joint + AVATAR_BONE_LEFT_CHEST, // connects chest joint with left clavicle joint (not supposed to be rotated) + AVATAR_BONE_LEFT_SHOULDER, // connects left clavicle joint with left shoulder joint + AVATAR_BONE_LEFT_UPPER_ARM, // connects left shoulder joint with left elbow joint + AVATAR_BONE_LEFT_FOREARM, // connects left elbow joint with left wrist joint + AVATAR_BONE_LEFT_HAND, // connects left wrist joint with left fingertips joint + AVATAR_BONE_RIGHT_CHEST, // connects chest joint with right clavicle joint (not supposed to be rotated) + AVATAR_BONE_RIGHT_SHOULDER, // connects right clavicle joint with right shoulder joint + AVATAR_BONE_RIGHT_UPPER_ARM, // connects right shoulder joint with right elbow joint + AVATAR_BONE_RIGHT_FOREARM, // connects right elbow joint with right wrist joint + AVATAR_BONE_RIGHT_HAND, // connects right wrist joint with right fingertips joint + AVATAR_BONE_LEFT_PELVIS, // connects pelvis joint with left hip joint (not supposed to be rotated) + AVATAR_BONE_LEFT_THIGH, // connects left hip joint with left knee joint + AVATAR_BONE_LEFT_SHIN, // connects left knee joint with left heel joint + AVATAR_BONE_LEFT_FOOT, // connects left heel joint with left toes joint + AVATAR_BONE_RIGHT_PELVIS, // connects pelvis joint with right hip joint (not supposed to be rotated) + AVATAR_BONE_RIGHT_THIGH, // connects right hip joint with right knee joint + AVATAR_BONE_RIGHT_SHIN, // connects right knee joint with right heel joint + AVATAR_BONE_RIGHT_FOOT, // connects right heel joint with right toes joint + + NUM_AVATAR_BONES +}; + +struct AvatarCollisionElipsoid +{ + bool colliding; + glm::vec3 position; + float girth; + float height; + glm::vec3 upVector; +}; + +struct AvatarHandHolding +{ + glm::vec3 position; + glm::vec3 velocity; + float force; +}; + +struct AvatarBone +{ + AvatarBoneID parent; // which bone is this bone connected to? + glm::vec3 position; // the position at the "end" of the bone + glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" + glm::vec3 springyPosition; // used for special effects (a 'flexible' variant of position) + glm::dvec3 springyVelocity; // used for special effects ( the velocity of the springy position) + float springBodyTightness; // how tightly the springy position tries to stay on the position + glm::quat rotation; // this will eventually replace yaw, pitch and roll (and maybe orientation) + float yaw; // the yaw Euler angle of the bone rotation off the parent + float pitch; // the pitch Euler angle of the bone rotation off the parent + float roll; // the roll Euler angle of the bone rotation off the parent + Orientation orientation; // three orthogonal normals determined by yaw, pitch, roll + float length; // the length of the bone + float radius; // used for detecting collisions for certain physical effects +}; + +struct AvatarHead +{ + float pitchRate; + float yawRate; + float rollRate; + float noise; + float eyeballPitch[2]; + float eyeballYaw [2]; + float eyebrowPitch[2]; + float eyebrowRoll [2]; + float eyeballScaleX; + float eyeballScaleY; + float eyeballScaleZ; + float interPupilDistance; + float interBrowDistance; + float nominalPupilSize; + float pupilSize; + float mouthPitch; + float mouthYaw; + float mouthWidth; + float mouthHeight; + float leanForward; + float leanSideways; + float pitchTarget; + float yawTarget; + float noiseEnvelope; + float pupilConverge; + float scale; + int eyeContact; + float browAudioLift; + eyeContactTargets eyeContactTarget; + + // Sound loudness information + float lastLoudness; + float averageLoudness; + float audioAttack; +}; + + +class Avatar : public AvatarData { + public: + Avatar(bool isMine); + ~Avatar(); + Avatar(const Avatar &otherAvatar); + Avatar* clone() const; + + void reset(); + void UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity); + void setNoise (float mag) { _head.noise = mag; } + void setScale(float s) {_head.scale = s; }; + void setRenderYaw(float y) {_renderYaw = y;} + void setRenderPitch(float p) {_renderPitch = p;} + float getRenderYaw() {return _renderYaw;} + float getRenderPitch() {return _renderPitch;} + void setLeanForward(float dist); + void setLeanSideways(float dist); + void addLean(float x, float z); + float getLastMeasuredHeadYaw() const {return _head.yawRate;} + float getBodyYaw() {return _bodyYaw;}; + void addBodyYaw(float y) {_bodyYaw += y;}; + + glm::vec3 getHeadLookatDirection(); + glm::vec3 getHeadLookatDirectionUp(); + glm::vec3 getHeadLookatDirectionRight(); + glm::vec3 getHeadPosition(); + glm::vec3 getBonePosition( AvatarBoneID b ); + glm::vec3 getBodyUpDirection(); + float getGirth(); + float getHeight(); + + AvatarMode getMode(); + + void setMousePressed( bool pressed ); + void render(bool lookingInMirror); + void renderBody(); + void renderHead(bool lookingInMirror); + void simulate(float); + void startHandMovement(); + void stopHandMovement(); + void setHandMovementValues( glm::vec3 movement ); + void updateHandMovement( float deltaTime ); + void updateArmIKAndConstraints( float deltaTime ); + + float getAverageLoudness() {return _head.averageLoudness;}; + void setAverageLoudness(float al) {_head.averageLoudness = al;}; + + void SetNewHeadTarget(float, float); + + // Set what driving keys are being pressed to control thrust levels + void setDriveKeys(int key, bool val) { _driveKeys[key] = val; }; + bool getDriveKeys(int key) { return _driveKeys[key]; }; + + // Set/Get update the thrust that will move the avatar around + void setThrust(glm::vec3 newThrust) { _thrust = newThrust; }; + void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; + glm::vec3 getThrust() { return _thrust; }; + + // Related to getting transmitter UDP data used to animate the avatar hand + void processTransmitterData(unsigned char * packetData, int numBytes); + float getTransmitterHz() { return _transmitterHz; }; + + private: + AvatarHead _head; + bool _isMine; + glm::vec3 _TEST_bigSpherePosition; + float _TEST_bigSphereRadius; + bool _mousePressed; + float _bodyYawDelta; + bool _usingBodySprings; + glm::vec3 _movedHandOffset; + float _springVelocityDecay; + float _springForce; + glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion + AvatarBone _bone[ NUM_AVATAR_BONES ]; + AvatarMode _mode; + AvatarHandHolding _handHolding; + glm::dvec3 _velocity; + glm::vec3 _thrust; + float _maxArmLength; + Orientation _orientation; + int _driveKeys[MAX_DRIVE_KEYS]; + GLUquadric* _sphere; + float _renderYaw; + float _renderPitch; // Pitch from view frustum when this is own head + timeval _transmitterTimer; + float _transmitterHz; + int _transmitterPackets; + Avatar* _interactingOther; + bool _interactingOtherIsNearby; + + // private methods... + void initializeSkeleton(); + void updateSkeleton(); + void initializeBodySprings(); + void updateBodySprings( float deltaTime ); + void calculateBoneLengths(); + void readSensors(); + void renderBoneAsBlock( AvatarBoneID b ); + void updateAvatarCollisionDetectionAndResponse + ( + glm::vec3 collisionPosition, + float collisionGirth, + float collisionHeight, + glm::vec3 collisionUpVector, + float deltaTime + ); +}; + +#endif