llvoicevisualizer.cpp

Go to the documentation of this file.
00001 
00032 //----------------------------------------------------------------------
00033 // Voice Visualizer
00034 // author: JJ Ventrella
00035 // (information about this stuff can be found in "llvoicevisualizer.h")
00036 //----------------------------------------------------------------------
00037 #include "llviewerprecompiledheaders.h"
00038 #include "llviewercontrol.h"
00039 #include "llglheaders.h"
00040 #include "llsphere.h"
00041 #include "llvoicevisualizer.h"
00042 #include "llviewercamera.h"
00043 #include "llviewerobject.h"
00044 #include "llimagegl.h"
00045 #include "llviewerimage.h"
00046 #include "llviewerimagelist.h"
00047 #include "llvoiceclient.h"
00048 
00049 //brent's wave image
00050 //29de489d-0491-fb00-7dab-f9e686d31e83
00051 
00052 
00053 //--------------------------------------------------------------------------------------
00054 // sound symbol constants
00055 //--------------------------------------------------------------------------------------
00056 const F32       HEIGHT_ABOVE_HEAD       = 0.3f;         // how many meters vertically above the av's head the voice symbol will appear
00057 const F32       RED_THRESHOLD           = LLVoiceClient::OVERDRIVEN_POWER_LEVEL;                // value above which speaking amplitude causes the voice symbol to turn red
00058 const F32       GREEN_THRESHOLD         = 0.2f;         // value above which speaking amplitude causes the voice symbol to turn green
00059 const F32       FADE_OUT_DURATION       = 0.4f;         // how many seconds it takes for a pair of waves to fade away
00060 const F32       EXPANSION_RATE          = 1.0f;         // how many seconds it takes for the waves to expand to twice their original size
00061 const F32       EXPANSION_MAX           = 1.5f;         // maximum size scale to which the waves can expand before popping back to 1.0 
00062 const F32       WAVE_WIDTH_SCALE        = 0.03f;        // base width of the waves 
00063 const F32       WAVE_HEIGHT_SCALE       = 0.02f;        // base height of the waves 
00064 const F32       BASE_BRIGHTNESS         = 0.7f;         // gray level of the voice indicator when quiet (below green threshold)
00065 const F32       DOT_SIZE                        = 0.05f;        // size of the dot billboard texture
00066 const F32       DOT_OPACITY                     = 0.7f;         // how opaque the dot is
00067 const F32       WAVE_MOTION_RATE        = 1.5f;         // scalar applied to consecutive waves as a function of speaking amplitude
00068 
00069 //--------------------------------------------------------------------------------------
00070 // gesticulation constants
00071 //--------------------------------------------------------------------------------------
00072 const F32 DEFAULT_MINIMUM_GESTICULATION_AMPLITUDE       = 0.2f; 
00073 const F32 DEFAULT_MAXIMUM_GESTICULATION_AMPLITUDE       = 1.0f;
00074 
00075 //--------------------------------------------------------------------------------------
00076 // other constants
00077 //--------------------------------------------------------------------------------------
00078 const F32 ONE_HALF = 1.0f; // to clarify intent and reduce magic numbers in the code. 
00079 const LLVector3 WORLD_UPWARD_DIRECTION = LLVector3( 0.0f, 0.0f, 1.0f ); // Z is up in SL
00080 
00081 //-----------------------------------------------
00082 // constructor
00083 //-----------------------------------------------
00084 LLVoiceVisualizer::LLVoiceVisualizer( const U8 type )
00085 :LLHUDEffect( type )
00086 {
00087         mCurrentTime                                    = mTimer.getTotalSeconds();
00088         mPreviousTime                                   = mCurrentTime;
00089         mVoiceSourceWorldPosition               = LLVector3( 0.0f, 0.0f, 0.0f );
00090         mSpeakingAmplitude                              = 0.0f;
00091         mCurrentlySpeaking                              = false;
00092         mVoiceEnabled                                   = false;
00093         mMinGesticulationAmplitude              = DEFAULT_MINIMUM_GESTICULATION_AMPLITUDE;
00094         mMaxGesticulationAmplitude              = DEFAULT_MAXIMUM_GESTICULATION_AMPLITUDE;
00095         mSoundSymbol.mActive                    = true;
00096         mSoundSymbol.mPosition                  = LLVector3( 0.0f, 0.0f, 0.0f );
00097         
00098         mTimer.reset();
00099         
00100         LLUUID sound_level_img[] = 
00101         {
00102                 LLUUID(gSavedSettings.getString("VoiceImageLevel0")),
00103                 LLUUID(gSavedSettings.getString("VoiceImageLevel1")),
00104                 LLUUID(gSavedSettings.getString("VoiceImageLevel2")),
00105                 LLUUID(gSavedSettings.getString("VoiceImageLevel3")),
00106                 LLUUID(gSavedSettings.getString("VoiceImageLevel4")),
00107                 LLUUID(gSavedSettings.getString("VoiceImageLevel5")),                                                                                                                   
00108                 LLUUID(gSavedSettings.getString("VoiceImageLevel6"))
00109         };
00110 
00111         for (int i=0; i<NUM_VOICE_SYMBOL_WAVES; i++)
00112         {
00113                 mSoundSymbol.mWaveFadeOutStartTime      [i] = mCurrentTime;
00114                 mSoundSymbol.mTexture                           [i] = gImageList.getUIImageByID(sound_level_img[i]);
00115                 mSoundSymbol.mWaveActive                        [i] = false;
00116                 mSoundSymbol.mWaveOpacity                       [i] = 1.0f;
00117                 mSoundSymbol.mWaveExpansion                     [i] = 1.0f;
00118         }
00119                         
00120 }//---------------------------------------------------
00121 
00122 //---------------------------------------------------
00123 void LLVoiceVisualizer::setMinGesticulationAmplitude( F32 m )
00124 {
00125         mMinGesticulationAmplitude = m;
00126 
00127 }//---------------------------------------------------
00128 
00129 //---------------------------------------------------
00130 void LLVoiceVisualizer::setMaxGesticulationAmplitude( F32 m )
00131 {
00132         mMaxGesticulationAmplitude = m;
00133 
00134 }//---------------------------------------------------
00135 
00136 //---------------------------------------------------
00137 void LLVoiceVisualizer::setVoiceEnabled( bool v )
00138 {
00139         mVoiceEnabled = v;
00140 
00141 }//---------------------------------------------------
00142 
00143 //---------------------------------------------------
00144 void LLVoiceVisualizer::setStartSpeaking()
00145 {
00146         mCurrentlySpeaking              = true;
00147         mSoundSymbol.mActive    = true;
00148                 
00149 }//---------------------------------------------------
00150 
00151 
00152 //---------------------------------------------------
00153 bool LLVoiceVisualizer::getCurrentlySpeaking()
00154 {
00155         return mCurrentlySpeaking;
00156         
00157 }//---------------------------------------------------
00158 
00159 
00160 //---------------------------------------------------
00161 void LLVoiceVisualizer::setStopSpeaking()
00162 {
00163         mCurrentlySpeaking = false;
00164         mSpeakingAmplitude = 0.0f;
00165         
00166 }//---------------------------------------------------
00167 
00168 
00169 //---------------------------------------------------
00170 void LLVoiceVisualizer::setSpeakingAmplitude( F32 a )
00171 {
00172         mSpeakingAmplitude = a;
00173         
00174 }//---------------------------------------------------
00175 
00176 
00177 //---------------------------------------------------
00178 // this method is inherited from HUD Effect
00179 //---------------------------------------------------
00180 void LLVoiceVisualizer::render()
00181 {
00182         if ( ! mVoiceEnabled )
00183         {
00184                 return;
00185         }
00186         
00187         if ( mSoundSymbol.mActive ) 
00188         {                               
00189                 mPreviousTime = mCurrentTime;
00190                 mCurrentTime = mTimer.getTotalSeconds();
00191         
00192                 //---------------------------------------------------------------
00193                 // set the sound symbol position over the source (avatar's head)
00194                 //---------------------------------------------------------------
00195                 mSoundSymbol.mPosition = mVoiceSourceWorldPosition + WORLD_UPWARD_DIRECTION * HEIGHT_ABOVE_HEAD;
00196         
00197                 //---------------------------------------------------------------
00198                 // some gl state
00199                 //---------------------------------------------------------------
00200                 LLGLEnable tex( GL_TEXTURE_2D );
00201                 LLGLEnable blend( GL_BLEND );
00202                 
00203                 //-------------------------------------------------------------
00204                 // create coordinates of the geometry for the dot
00205                 //-------------------------------------------------------------
00206                 LLVector3 l     = gCamera->getLeftAxis() * DOT_SIZE;
00207                 LLVector3 u     = gCamera->getUpAxis()   * DOT_SIZE;
00208 
00209                 LLVector3 bottomLeft    = mSoundSymbol.mPosition + l - u;
00210                 LLVector3 bottomRight   = mSoundSymbol.mPosition - l - u;
00211                 LLVector3 topLeft               = mSoundSymbol.mPosition + l + u;
00212                 LLVector3 topRight              = mSoundSymbol.mPosition - l + u;
00213                 
00214                 //-----------------------------
00215                 // bind texture 0 (the dot)
00216                 //-----------------------------
00217                 mSoundSymbol.mTexture[0]->bind(); 
00218                 
00219                 //-------------------------------------------------------------
00220                 // now render the dot
00221                 //-------------------------------------------------------------
00222                 glColor4fv( LLColor4( 1.0f, 1.0f, 1.0f, DOT_OPACITY ).mV );     
00223                 
00224                 glBegin( GL_TRIANGLE_STRIP );
00225                         glTexCoord2i( 0,        0       ); glVertex3fv( bottomLeft.mV );
00226                         glTexCoord2i( 1,        0       ); glVertex3fv( bottomRight.mV );
00227                         glTexCoord2i( 0,        1       ); glVertex3fv( topLeft.mV );
00228                 glEnd();
00229 
00230                 glBegin( GL_TRIANGLE_STRIP );
00231                         glTexCoord2i( 1,        0       ); glVertex3fv( bottomRight.mV );
00232                         glTexCoord2i( 1,        1       ); glVertex3fv( topRight.mV );
00233                         glTexCoord2i( 0,        1       ); glVertex3fv( topLeft.mV );
00234                 glEnd();
00235                 
00236                 
00237                 
00238                 //--------------------------------------------------------------------------------------
00239                 // if currently speaking, trigger waves (1 through 6) based on speaking amplitude
00240                 //--------------------------------------------------------------------------------------
00241                 if ( mCurrentlySpeaking )
00242                 {
00243                         F32 min = 0.2f;
00244                         F32 max = 0.7f;
00245                         F32 fraction = ( mSpeakingAmplitude - min ) / ( max - min );
00246                 
00247                         // in case mSpeakingAmplitude > max....
00248                         if ( fraction > 1.0f )
00249                         {
00250                                 fraction = 1.0f;
00251                         }
00252                                                                                                                 
00253                         S32 level = 1 + (int)( fraction * ( NUM_VOICE_SYMBOL_WAVES - 2 ) );
00254                                                                                                                                                                                                                 
00255                         for (int i=0; i<level+1; i++)
00256                         {
00257                                 mSoundSymbol.mWaveActive                        [i] = true;
00258                                 mSoundSymbol.mWaveOpacity                       [i] = 1.0f;
00259                                 mSoundSymbol.mWaveFadeOutStartTime      [i] = mCurrentTime;
00260                         }                       
00261                         
00262                 } // if currently speaking
00263                                                                 
00264                 //---------------------------------------------------
00265                 // determine color
00266                 //---------------------------------------------------
00267                 F32 red         = 0.0f;
00268                 F32 green       = 0.0f;
00269                 F32 blue        = 0.0f;
00270         if ( mSpeakingAmplitude < RED_THRESHOLD )
00271         {
00272                         if ( mSpeakingAmplitude < GREEN_THRESHOLD )
00273                         {
00274                                 red             = BASE_BRIGHTNESS;
00275                                 green   = BASE_BRIGHTNESS;
00276                                 blue    = BASE_BRIGHTNESS;
00277                         }
00278                         else
00279                         {
00280                                 //---------------------------------------------------
00281                                 // fade from gray to bright green
00282                                 //---------------------------------------------------
00283                                 F32 fraction = ( mSpeakingAmplitude - GREEN_THRESHOLD ) / ( 1.0f - GREEN_THRESHOLD );
00284                                 red             = BASE_BRIGHTNESS - ( fraction * BASE_BRIGHTNESS );
00285                                 green   = BASE_BRIGHTNESS +   fraction * ( 1.0f - BASE_BRIGHTNESS );
00286                                 blue    = BASE_BRIGHTNESS - ( fraction * BASE_BRIGHTNESS );
00287                         }
00288         }
00289         else
00290         {
00291                         //---------------------------------------------------
00292                         // redish
00293                         //---------------------------------------------------
00294                         red             = 1.0f;
00295                         green   = 0.2f;
00296                         blue    = 0.2f;
00297         }
00298                                                                                                                 
00299                 for (int i=0; i<NUM_VOICE_SYMBOL_WAVES; i++)
00300                 {
00301                         if ( mSoundSymbol.mWaveActive[i] ) 
00302                         {
00303                                 F32 fadeOutFraction = (F32)( mCurrentTime - mSoundSymbol.mWaveFadeOutStartTime[i] ) / FADE_OUT_DURATION;
00304 
00305                                 mSoundSymbol.mWaveOpacity[i] = 1.0f - fadeOutFraction;
00306                                 
00307                                 if ( mSoundSymbol.mWaveOpacity[i] < 0.0f )
00308                                 {
00309                                         mSoundSymbol.mWaveFadeOutStartTime      [i] = mCurrentTime;
00310                                         mSoundSymbol.mWaveOpacity                       [i] = 0.0f;
00311                                         mSoundSymbol.mWaveActive                        [i] = false;
00312                                 }
00313                                 
00314                                 //----------------------------------------------------------------------------------
00315                                 // This is where we calculate the expansion of the waves - that is, the
00316                                 // rate at which they are scaled greater than 1.0 so that they grow over time.
00317                                 //----------------------------------------------------------------------------------
00318                                 F32 timeSlice = (F32)( mCurrentTime - mPreviousTime );
00319                                 F32 waveSpeed = mSpeakingAmplitude * WAVE_MOTION_RATE;
00320                                 mSoundSymbol.mWaveExpansion[i] *= ( 1.0f + EXPANSION_RATE * timeSlice * waveSpeed );
00321                                 
00322                                 if ( mSoundSymbol.mWaveExpansion[i] > EXPANSION_MAX )
00323                                 {
00324                                         mSoundSymbol.mWaveExpansion[i] = 1.0f;
00325                                 }                       
00326                                                                 
00327                                 //----------------------------------------------------------------------------------
00328                                 // create geometry for the wave billboard textures
00329                                 //----------------------------------------------------------------------------------
00330                                 F32 width       = i * WAVE_WIDTH_SCALE  * mSoundSymbol.mWaveExpansion[i];
00331                                 F32 height      = i * WAVE_HEIGHT_SCALE * mSoundSymbol.mWaveExpansion[i];
00332 
00333                                 LLVector3 l     = gCamera->getLeftAxis() * width;
00334                                 LLVector3 u     = gCamera->getUpAxis()   * height;
00335 
00336                                 LLVector3 bottomLeft    = mSoundSymbol.mPosition + l - u;
00337                                 LLVector3 bottomRight   = mSoundSymbol.mPosition - l - u;
00338                                 LLVector3 topLeft               = mSoundSymbol.mPosition + l + u;
00339                                 LLVector3 topRight              = mSoundSymbol.mPosition - l + u;
00340                                                         
00341                                 glColor4fv( LLColor4( red, green, blue, mSoundSymbol.mWaveOpacity[i] ).mV );            
00342                                 mSoundSymbol.mTexture[i]->bind();
00343                                 
00344                                 //---------------------------------------------------
00345                                 // now, render the mofo
00346                                 //---------------------------------------------------
00347                                 glBegin( GL_TRIANGLE_STRIP );
00348                                         glTexCoord2i( 0, 0 ); glVertex3fv( bottomLeft.mV );
00349                                         glTexCoord2i( 1, 0 ); glVertex3fv( bottomRight.mV );
00350                                         glTexCoord2i( 0, 1 ); glVertex3fv( topLeft.mV );
00351                                 glEnd();
00352 
00353                                 glBegin( GL_TRIANGLE_STRIP );
00354                                         glTexCoord2i( 1, 0 ); glVertex3fv( bottomRight.mV );
00355                                         glTexCoord2i( 1, 1 ); glVertex3fv( topRight.mV );
00356                                         glTexCoord2i( 0, 1 ); glVertex3fv( topLeft.mV );
00357                                 glEnd();
00358                                 
00359                         } //if ( mSoundSymbol.mWaveActive[i] ) 
00360                         
00361                 }// for loop
00362                                                                                         
00363         }//if ( mSoundSymbol.mActive ) 
00364 
00365 }//---------------------------------------------------
00366 
00367 
00368 
00369 
00370 
00371 //---------------------------------------------------
00372 void LLVoiceVisualizer::setVoiceSourceWorldPosition( const LLVector3 &p )
00373 {
00374         mVoiceSourceWorldPosition       = p;
00375 
00376 }//---------------------------------------------------
00377 
00378 //---------------------------------------------------
00379 VoiceGesticulationLevel LLVoiceVisualizer::getCurrentGesticulationLevel()
00380 {
00381         VoiceGesticulationLevel gesticulationLevel = VOICE_GESTICULATION_LEVEL_OFF; //default
00382         
00383         //-----------------------------------------------------------------------------------------
00384         // Within the range of gesticulation amplitudes, the sound signal is split into
00385         // three equal amplitude regimes, each specifying one of three gesticulation levels.
00386         //-----------------------------------------------------------------------------------------
00387         F32 range = mMaxGesticulationAmplitude - mMinGesticulationAmplitude;
00388         
00389                         if ( mSpeakingAmplitude > mMinGesticulationAmplitude + range * 0.66666f )       { gesticulationLevel = VOICE_GESTICULATION_LEVEL_HIGH;          }
00390         else    if ( mSpeakingAmplitude > mMinGesticulationAmplitude + range * 0.33333f )       { gesticulationLevel = VOICE_GESTICULATION_LEVEL_MEDIUM;        }
00391         else    if ( mSpeakingAmplitude > mMinGesticulationAmplitude + range * 0.00000f )       { gesticulationLevel = VOICE_GESTICULATION_LEVEL_LOW;           }
00392 
00393         return gesticulationLevel;
00394 
00395 }//---------------------------------------------------
00396 
00397 
00398 
00399 //------------------------------------
00400 // Destructor
00401 //------------------------------------
00402 LLVoiceVisualizer::~LLVoiceVisualizer()
00403 {
00404 }//----------------------------------------------
00405 
00406 
00407 //---------------------------------------------------
00408 // "packData" is inherited from HUDEffect
00409 //---------------------------------------------------
00410 void LLVoiceVisualizer::packData(LLMessageSystem *mesgsys)
00411 {
00412         // Pack the default data
00413         LLHUDEffect::packData(mesgsys);
00414 
00415         // TODO -- pack the relevant data for voice effects
00416         // we'll come up with some cool configurations....TBD
00417         //U8 packed_data[41];
00418         //mesgsys->addBinaryDataFast(_PREHASH_TypeData, packed_data, 41);
00419         U8 packed_data = 0;
00420         mesgsys->addBinaryDataFast(_PREHASH_TypeData, &packed_data, 1);
00421 }
00422 
00423 
00424 //---------------------------------------------------
00425 // "unpackData" is inherited from HUDEffect
00426 //---------------------------------------------------
00427 void LLVoiceVisualizer::unpackData(LLMessageSystem *mesgsys, S32 blocknum)
00428 {
00429         // TODO -- find the speaker, unpack binary data, set the properties of this effect
00430         /*
00431         LLHUDEffect::unpackData(mesgsys, blocknum);
00432         LLUUID source_id;
00433         LLUUID target_id;
00434         S32 size = mesgsys->getSizeFast(_PREHASH_Effect, blocknum, _PREHASH_TypeData);
00435         if (size != 1)
00436         {
00437                 llwarns << "Voice effect with bad size " << size << llendl;
00438                 return;
00439         }
00440         mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, 1, blocknum);
00441         */
00442 }
00443 
00444 
00445 //------------------------------------------------------------------
00446 // this method is inherited from HUD Effect
00447 //------------------------------------------------------------------
00448 void LLVoiceVisualizer::markDead()
00449 {
00450         mCurrentlySpeaking              = false;
00451         mVoiceEnabled                   = false;
00452         mSoundSymbol.mActive    = false;
00453 
00454 }//------------------------------------------------------------------
00455 
00456 
00457 
00458 
00459 
00460 
00461 
00462 

Generated on Thu Jul 1 06:09:38 2010 for Second Life Viewer by  doxygen 1.4.7