00001
00032
00033
00034
00035
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 #include "llglimmediate.h"
00049
00050
00051
00052
00053
00054
00055
00056
00057 const F32 HEIGHT_ABOVE_HEAD = 0.3f;
00058 const F32 RED_THRESHOLD = LLVoiceClient::OVERDRIVEN_POWER_LEVEL;
00059 const F32 GREEN_THRESHOLD = 0.2f;
00060 const F32 FADE_OUT_DURATION = 0.4f;
00061 const F32 EXPANSION_RATE = 1.0f;
00062 const F32 EXPANSION_MAX = 1.5f;
00063 const F32 WAVE_WIDTH_SCALE = 0.03f;
00064 const F32 WAVE_HEIGHT_SCALE = 0.02f;
00065 const F32 BASE_BRIGHTNESS = 0.7f;
00066 const F32 DOT_SIZE = 0.05f;
00067 const F32 DOT_OPACITY = 0.7f;
00068 const F32 WAVE_MOTION_RATE = 1.5f;
00069
00070
00071
00072
00073 const F32 DEFAULT_MINIMUM_GESTICULATION_AMPLITUDE = 0.2f;
00074 const F32 DEFAULT_MAXIMUM_GESTICULATION_AMPLITUDE = 1.0f;
00075
00076
00077
00078
00079 const F32 ONE_HALF = 1.0f;
00080 const LLVector3 WORLD_UPWARD_DIRECTION = LLVector3( 0.0f, 0.0f, 1.0f );
00081
00082
00083
00084
00085
00086 static bool handleVoiceVisualizerPrefsChanged(const LLSD& newvalue)
00087 {
00088
00089 LLVoiceVisualizer::setPreferences();
00090 return true;
00091 }
00092
00093
00094
00095
00096 bool LLVoiceVisualizer::sPrefsInitialized = false;
00097 U32 LLVoiceVisualizer::sLipSyncEnabled = 0;
00098 F32* LLVoiceVisualizer::sOoh = NULL;
00099 F32* LLVoiceVisualizer::sAah = NULL;
00100 U32 LLVoiceVisualizer::sOohs = 0;
00101 U32 LLVoiceVisualizer::sAahs = 0;
00102 F32 LLVoiceVisualizer::sOohAahRate = 0.0f;
00103 F32* LLVoiceVisualizer::sOohPowerTransfer = NULL;
00104 U32 LLVoiceVisualizer::sOohPowerTransfers = 0;
00105 F32 LLVoiceVisualizer::sOohPowerTransfersf = 0.0f;
00106 F32* LLVoiceVisualizer::sAahPowerTransfer = NULL;
00107 U32 LLVoiceVisualizer::sAahPowerTransfers = 0;
00108 F32 LLVoiceVisualizer::sAahPowerTransfersf = 0.0f;
00109
00110
00111
00112
00113
00114 LLVoiceVisualizer::LLVoiceVisualizer( const U8 type )
00115 :LLHUDEffect( type )
00116 {
00117 mCurrentTime = mTimer.getTotalSeconds();
00118 mPreviousTime = mCurrentTime;
00119 mStartTime = mCurrentTime;
00120 mVoiceSourceWorldPosition = LLVector3( 0.0f, 0.0f, 0.0f );
00121 mSpeakingAmplitude = 0.0f;
00122 mCurrentlySpeaking = false;
00123 mVoiceEnabled = false;
00124 mMinGesticulationAmplitude = DEFAULT_MINIMUM_GESTICULATION_AMPLITUDE;
00125 mMaxGesticulationAmplitude = DEFAULT_MAXIMUM_GESTICULATION_AMPLITUDE;
00126 mSoundSymbol.mActive = true;
00127 mSoundSymbol.mPosition = LLVector3( 0.0f, 0.0f, 0.0f );
00128
00129 mTimer.reset();
00130
00131 const char* sound_level_img[] =
00132 {
00133 "041ee5a0-cb6a-9ac5-6e49-41e9320507d5.j2c",
00134 "29de489d-0491-fb00-7dab-f9e686d31e83.j2c",
00135 "29de489d-0491-fb00-7dab-f9e686d31e83.j2c",
00136 "29de489d-0491-fb00-7dab-f9e686d31e83.j2c",
00137 "29de489d-0491-fb00-7dab-f9e686d31e83.j2c",
00138 "29de489d-0491-fb00-7dab-f9e686d31e83.j2c",
00139 "29de489d-0491-fb00-7dab-f9e686d31e83.j2c"
00140 };
00141
00142 for (int i=0; i<NUM_VOICE_SYMBOL_WAVES; i++)
00143 {
00144 mSoundSymbol.mWaveFadeOutStartTime [i] = mCurrentTime;
00145 mSoundSymbol.mTexture [i] = gImageList.getImageFromFile(sound_level_img[i], FALSE, TRUE);
00146 mSoundSymbol.mWaveActive [i] = false;
00147 mSoundSymbol.mWaveOpacity [i] = 1.0f;
00148 mSoundSymbol.mWaveExpansion [i] = 1.0f;
00149 }
00150
00151
00152 if (!sPrefsInitialized)
00153 {
00154 setPreferences();
00155
00156
00157 gSavedSettings.getControl("LipSyncEnabled")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1));
00158 gSavedSettings.getControl("LipSyncOohAahRate")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1));
00159 gSavedSettings.getControl("LipSyncOoh")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1));
00160 gSavedSettings.getControl("LipSyncAah")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1));
00161 gSavedSettings.getControl("LipSyncOohPowerTransfer")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1));
00162 gSavedSettings.getControl("LipSyncAahPowerTransfer")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1));
00163
00164 sPrefsInitialized = true;
00165 }
00166
00167 }
00168
00169
00170 void LLVoiceVisualizer::setMinGesticulationAmplitude( F32 m )
00171 {
00172 mMinGesticulationAmplitude = m;
00173
00174 }
00175
00176
00177 void LLVoiceVisualizer::setMaxGesticulationAmplitude( F32 m )
00178 {
00179 mMaxGesticulationAmplitude = m;
00180
00181 }
00182
00183
00184 void LLVoiceVisualizer::setVoiceEnabled( bool v )
00185 {
00186 mVoiceEnabled = v;
00187
00188 }
00189
00190
00191 void LLVoiceVisualizer::setStartSpeaking()
00192 {
00193 mStartTime = mTimer.getTotalSeconds();
00194 mCurrentlySpeaking = true;
00195 mSoundSymbol.mActive = true;
00196
00197 }
00198
00199
00200
00201 bool LLVoiceVisualizer::getCurrentlySpeaking()
00202 {
00203 return mCurrentlySpeaking;
00204
00205 }
00206
00207
00208
00209 void LLVoiceVisualizer::setStopSpeaking()
00210 {
00211 mCurrentlySpeaking = false;
00212 mSpeakingAmplitude = 0.0f;
00213
00214 }
00215
00216
00217
00218 void LLVoiceVisualizer::setSpeakingAmplitude( F32 a )
00219 {
00220 mSpeakingAmplitude = a;
00221
00222 }
00223
00224
00225
00226 void LLVoiceVisualizer::setPreferences( )
00227 {
00228 sLipSyncEnabled = gSavedSettings.getU32("LipSyncEnabled");
00229 sOohAahRate = gSavedSettings.getF32("LipSyncOohAahRate");
00230
00231 std::string oohString = gSavedSettings.getString("LipSyncOoh");
00232 lipStringToF32s (oohString, sOoh, sOohs);
00233
00234 std::string aahString = gSavedSettings.getString("LipSyncAah");
00235 lipStringToF32s (aahString, sAah, sAahs);
00236
00237 std::string oohPowerString = gSavedSettings.getString("LipSyncOohPowerTransfer");
00238 lipStringToF32s (oohPowerString, sOohPowerTransfer, sOohPowerTransfers);
00239 sOohPowerTransfersf = (F32) sOohPowerTransfers;
00240
00241 std::string aahPowerString = gSavedSettings.getString("LipSyncAahPowerTransfer");
00242 lipStringToF32s (aahPowerString, sAahPowerTransfer, sAahPowerTransfers);
00243 sAahPowerTransfersf = (F32) sAahPowerTransfers;
00244
00245 }
00246
00247
00248
00249
00250
00251
00252
00253 void LLVoiceVisualizer::lipStringToF32s ( std::string& in_string, F32*& out_F32s, U32& count_F32s )
00254 {
00255 delete[] out_F32s;
00256
00257 count_F32s = in_string.length();
00258 if (count_F32s == 0)
00259 {
00260
00261
00262 count_F32s = 1;
00263 out_F32s = new F32[1];
00264 out_F32s[0] = 0.0f;
00265 }
00266 else
00267 {
00268 out_F32s = new F32[count_F32s];
00269
00270 for (U32 i=0; i<count_F32s; i++)
00271 {
00272
00273
00274
00275 U8 digit = in_string[i];
00276 U8 four_bits = digit % 16;
00277 if (four_bits > 9)
00278 {
00279 four_bits = 9;
00280 }
00281 out_F32s[i] = 0.11f * (F32) four_bits;
00282 }
00283 }
00284
00285 }
00286
00287
00288
00289
00290
00291 void LLVoiceVisualizer::lipSyncOohAah( F32& ooh, F32& aah )
00292 {
00293 if( ( sLipSyncEnabled == 1 ) && mCurrentlySpeaking )
00294 {
00295 U32 transfer_index = (U32) (sOohPowerTransfersf * mSpeakingAmplitude);
00296 if (transfer_index < 0)
00297 {
00298 transfer_index = 0;
00299 }
00300 if (transfer_index >= sOohPowerTransfers)
00301 {
00302 transfer_index = sOohPowerTransfers - 1;
00303 }
00304 F32 transfer_ooh = sOohPowerTransfer[transfer_index];
00305
00306 transfer_index = (U32) (sAahPowerTransfersf * mSpeakingAmplitude);
00307 if (transfer_index < 0)
00308 {
00309 transfer_index = 0;
00310 }
00311 if (transfer_index >= sAahPowerTransfers)
00312 {
00313 transfer_index = sAahPowerTransfers - 1;
00314 }
00315 F32 transfer_aah = sAahPowerTransfer[transfer_index];
00316
00317 F64 current_time = mTimer.getTotalSeconds();
00318 F64 elapsed_time = current_time - mStartTime;
00319 U32 elapsed_frames = (U32) (elapsed_time * sOohAahRate);
00320 U32 elapsed_oohs = elapsed_frames % sOohs;
00321 U32 elapsed_aahs = elapsed_frames % sAahs;
00322
00323 ooh = transfer_ooh * sOoh[elapsed_oohs];
00324 aah = transfer_aah * sAah[elapsed_aahs];
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339 }
00340 else
00341 {
00342 ooh = 0.0f;
00343 aah = 0.0f;
00344 }
00345
00346 }
00347
00348
00349
00350
00351
00352 void LLVoiceVisualizer::render()
00353 {
00354 if ( ! mVoiceEnabled )
00355 {
00356 return;
00357 }
00358
00359 if ( mSoundSymbol.mActive )
00360 {
00361 mPreviousTime = mCurrentTime;
00362 mCurrentTime = mTimer.getTotalSeconds();
00363
00364
00365
00366
00367 mSoundSymbol.mPosition = mVoiceSourceWorldPosition + WORLD_UPWARD_DIRECTION * HEIGHT_ABOVE_HEAD;
00368
00369
00370
00371
00372 LLGLSPipelineAlpha alpha_blend;
00373 LLGLDepthTest depth(GL_TRUE, GL_FALSE);
00374
00375
00376
00377
00378 LLVector3 l = LLViewerCamera::getInstance()->getLeftAxis() * DOT_SIZE;
00379 LLVector3 u = LLViewerCamera::getInstance()->getUpAxis() * DOT_SIZE;
00380
00381 LLVector3 bottomLeft = mSoundSymbol.mPosition + l - u;
00382 LLVector3 bottomRight = mSoundSymbol.mPosition - l - u;
00383 LLVector3 topLeft = mSoundSymbol.mPosition + l + u;
00384 LLVector3 topRight = mSoundSymbol.mPosition - l + u;
00385
00386
00387
00388
00389 mSoundSymbol.mTexture[0]->bind();
00390
00391
00392
00393
00394 gGL.color4fv( LLColor4( 1.0f, 1.0f, 1.0f, DOT_OPACITY ).mV );
00395
00396 gGL.begin( LLVertexBuffer::TRIANGLE_STRIP );
00397 gGL.texCoord2i( 0, 0 ); gGL.vertex3fv( bottomLeft.mV );
00398 gGL.texCoord2i( 1, 0 ); gGL.vertex3fv( bottomRight.mV );
00399 gGL.texCoord2i( 0, 1 ); gGL.vertex3fv( topLeft.mV );
00400 gGL.end();
00401
00402 gGL.begin( LLVertexBuffer::TRIANGLE_STRIP );
00403 gGL.texCoord2i( 1, 0 ); gGL.vertex3fv( bottomRight.mV );
00404 gGL.texCoord2i( 1, 1 ); gGL.vertex3fv( topRight.mV );
00405 gGL.texCoord2i( 0, 1 ); gGL.vertex3fv( topLeft.mV );
00406 gGL.end();
00407
00408
00409
00410
00411
00412
00413 if ( mCurrentlySpeaking )
00414 {
00415 F32 min = 0.2f;
00416 F32 max = 0.7f;
00417 F32 fraction = ( mSpeakingAmplitude - min ) / ( max - min );
00418
00419
00420 if ( fraction > 1.0f )
00421 {
00422 fraction = 1.0f;
00423 }
00424
00425 S32 level = 1 + (int)( fraction * ( NUM_VOICE_SYMBOL_WAVES - 2 ) );
00426
00427 for (int i=0; i<level+1; i++)
00428 {
00429 mSoundSymbol.mWaveActive [i] = true;
00430 mSoundSymbol.mWaveOpacity [i] = 1.0f;
00431 mSoundSymbol.mWaveFadeOutStartTime [i] = mCurrentTime;
00432 }
00433
00434 }
00435
00436
00437
00438
00439 F32 red = 0.0f;
00440 F32 green = 0.0f;
00441 F32 blue = 0.0f;
00442 if ( mSpeakingAmplitude < RED_THRESHOLD )
00443 {
00444 if ( mSpeakingAmplitude < GREEN_THRESHOLD )
00445 {
00446 red = BASE_BRIGHTNESS;
00447 green = BASE_BRIGHTNESS;
00448 blue = BASE_BRIGHTNESS;
00449 }
00450 else
00451 {
00452
00453
00454
00455 F32 fraction = ( mSpeakingAmplitude - GREEN_THRESHOLD ) / ( 1.0f - GREEN_THRESHOLD );
00456 red = BASE_BRIGHTNESS - ( fraction * BASE_BRIGHTNESS );
00457 green = BASE_BRIGHTNESS + fraction * ( 1.0f - BASE_BRIGHTNESS );
00458 blue = BASE_BRIGHTNESS - ( fraction * BASE_BRIGHTNESS );
00459 }
00460 }
00461 else
00462 {
00463
00464
00465
00466 red = 1.0f;
00467 green = 0.2f;
00468 blue = 0.2f;
00469 }
00470
00471 for (int i=0; i<NUM_VOICE_SYMBOL_WAVES; i++)
00472 {
00473 if ( mSoundSymbol.mWaveActive[i] )
00474 {
00475 F32 fadeOutFraction = (F32)( mCurrentTime - mSoundSymbol.mWaveFadeOutStartTime[i] ) / FADE_OUT_DURATION;
00476
00477 mSoundSymbol.mWaveOpacity[i] = 1.0f - fadeOutFraction;
00478
00479 if ( mSoundSymbol.mWaveOpacity[i] < 0.0f )
00480 {
00481 mSoundSymbol.mWaveFadeOutStartTime [i] = mCurrentTime;
00482 mSoundSymbol.mWaveOpacity [i] = 0.0f;
00483 mSoundSymbol.mWaveActive [i] = false;
00484 }
00485
00486
00487
00488
00489
00490 F32 timeSlice = (F32)( mCurrentTime - mPreviousTime );
00491 F32 waveSpeed = mSpeakingAmplitude * WAVE_MOTION_RATE;
00492 mSoundSymbol.mWaveExpansion[i] *= ( 1.0f + EXPANSION_RATE * timeSlice * waveSpeed );
00493
00494 if ( mSoundSymbol.mWaveExpansion[i] > EXPANSION_MAX )
00495 {
00496 mSoundSymbol.mWaveExpansion[i] = 1.0f;
00497 }
00498
00499
00500
00501
00502 F32 width = i * WAVE_WIDTH_SCALE * mSoundSymbol.mWaveExpansion[i];
00503 F32 height = i * WAVE_HEIGHT_SCALE * mSoundSymbol.mWaveExpansion[i];
00504
00505 LLVector3 l = LLViewerCamera::getInstance()->getLeftAxis() * width;
00506 LLVector3 u = LLViewerCamera::getInstance()->getUpAxis() * height;
00507
00508 LLVector3 bottomLeft = mSoundSymbol.mPosition + l - u;
00509 LLVector3 bottomRight = mSoundSymbol.mPosition - l - u;
00510 LLVector3 topLeft = mSoundSymbol.mPosition + l + u;
00511 LLVector3 topRight = mSoundSymbol.mPosition - l + u;
00512
00513 gGL.color4fv( LLColor4( red, green, blue, mSoundSymbol.mWaveOpacity[i] ).mV );
00514 mSoundSymbol.mTexture[i]->bind();
00515
00516
00517
00518
00519 gGL.begin( LLVertexBuffer::TRIANGLE_STRIP );
00520 gGL.texCoord2i( 0, 0 ); gGL.vertex3fv( bottomLeft.mV );
00521 gGL.texCoord2i( 1, 0 ); gGL.vertex3fv( bottomRight.mV );
00522 gGL.texCoord2i( 0, 1 ); gGL.vertex3fv( topLeft.mV );
00523 gGL.end();
00524
00525 gGL.begin( LLVertexBuffer::TRIANGLE_STRIP );
00526 gGL.texCoord2i( 1, 0 ); gGL.vertex3fv( bottomRight.mV );
00527 gGL.texCoord2i( 1, 1 ); gGL.vertex3fv( topRight.mV );
00528 gGL.texCoord2i( 0, 1 ); gGL.vertex3fv( topLeft.mV );
00529 gGL.end();
00530
00531 }
00532
00533 }
00534
00535 }
00536
00537 }
00538
00539
00540
00541
00542
00543
00544 void LLVoiceVisualizer::setVoiceSourceWorldPosition( const LLVector3 &p )
00545 {
00546 mVoiceSourceWorldPosition = p;
00547
00548 }
00549
00550
00551 VoiceGesticulationLevel LLVoiceVisualizer::getCurrentGesticulationLevel()
00552 {
00553 VoiceGesticulationLevel gesticulationLevel = VOICE_GESTICULATION_LEVEL_OFF;
00554
00555
00556
00557
00558
00559 F32 range = mMaxGesticulationAmplitude - mMinGesticulationAmplitude;
00560
00561 if ( mSpeakingAmplitude > mMinGesticulationAmplitude + range * 0.66666f ) { gesticulationLevel = VOICE_GESTICULATION_LEVEL_HIGH; }
00562 else if ( mSpeakingAmplitude > mMinGesticulationAmplitude + range * 0.33333f ) { gesticulationLevel = VOICE_GESTICULATION_LEVEL_MEDIUM; }
00563 else if ( mSpeakingAmplitude > mMinGesticulationAmplitude + range * 0.00000f ) { gesticulationLevel = VOICE_GESTICULATION_LEVEL_LOW; }
00564
00565 return gesticulationLevel;
00566
00567 }
00568
00569
00570
00571
00572
00573
00574 LLVoiceVisualizer::~LLVoiceVisualizer()
00575 {
00576 }
00577
00578
00579
00580
00581
00582 void LLVoiceVisualizer::packData(LLMessageSystem *mesgsys)
00583 {
00584
00585 LLHUDEffect::packData(mesgsys);
00586
00587
00588
00589
00590
00591 U8 packed_data = 0;
00592 mesgsys->addBinaryDataFast(_PREHASH_TypeData, &packed_data, 1);
00593 }
00594
00595
00596
00597
00598
00599 void LLVoiceVisualizer::unpackData(LLMessageSystem *mesgsys, S32 blocknum)
00600 {
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614 }
00615
00616
00617
00618
00619
00620 void LLVoiceVisualizer::markDead()
00621 {
00622 mCurrentlySpeaking = false;
00623 mVoiceEnabled = false;
00624 mSoundSymbol.mActive = false;
00625
00626 LLHUDEffect::markDead();
00627 }
00628
00629
00630
00631
00632
00633
00634
00635