00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llhudtext.h"
00035
00036 #include "llglimmediate.h"
00037
00038 #include "llagent.h"
00039 #include "llviewercontrol.h"
00040 #include "llchatbar.h"
00041 #include "llcriticaldamp.h"
00042 #include "lldrawable.h"
00043 #include "llfontgl.h"
00044 #include "llglheaders.h"
00045 #include "llhudrender.h"
00046 #include "llimagegl.h"
00047 #include "llui.h"
00048 #include "llviewercamera.h"
00049 #include "llviewerimagelist.h"
00050 #include "llviewerobject.h"
00051 #include "llvovolume.h"
00052 #include "llviewerwindow.h"
00053 #include "llstatusbar.h"
00054 #include "llmenugl.h"
00055 #include "pipeline.h"
00056 #include <boost/tokenizer.hpp>
00057
00058
00059 const F32 SPRING_STRENGTH = 0.7f;
00060 const F32 RESTORATION_SPRING_TIME_CONSTANT = 0.1f;
00061 const F32 HORIZONTAL_PADDING = 15.f;
00062 const F32 VERTICAL_PADDING = 12.f;
00063 const F32 BUFFER_SIZE = 2.f;
00064 const F32 MIN_EDGE_OVERLAP = 3.f;
00065 F32 HUD_TEXT_MAX_WIDTH = 190.f;
00066 const F32 HUD_TEXT_MAX_WIDTH_NO_BUBBLE = 1000.f;
00067 const F32 RESIZE_TIME = 0.f;
00068 const S32 NUM_OVERLAP_ITERATIONS = 10;
00069 const F32 NEIGHBOR_FORCE_FRACTION = 1.f;
00070 const F32 POSITION_DAMPING_TC = 0.2f;
00071 const F32 MAX_STABLE_CAMERA_VELOCITY = 0.1f;
00072 const F32 LOD_0_SCREEN_COVERAGE = 0.15f;
00073 const F32 LOD_1_SCREEN_COVERAGE = 0.30f;
00074 const F32 LOD_2_SCREEN_COVERAGE = 0.40f;
00075
00076 std::set<LLPointer<LLHUDText> > LLHUDText::sTextObjects;
00077 std::vector<LLPointer<LLHUDText> > LLHUDText::sVisibleTextObjects;
00078 std::vector<LLPointer<LLHUDText> > LLHUDText::sVisibleHUDTextObjects;
00079 BOOL LLHUDText::sDisplayText = TRUE ;
00080
00081 bool lltextobject_further_away::operator()(const LLPointer<LLHUDText>& lhs, const LLPointer<LLHUDText>& rhs) const
00082 {
00083 return (lhs->getDistance() > rhs->getDistance()) ? true : false;
00084 }
00085
00086
00087 LLHUDText::LLHUDText(const U8 type) :
00088 LLHUDObject(type),
00089 mUseBubble(FALSE),
00090 mUsePixelSize(TRUE),
00091 mVisibleOffScreen(FALSE),
00092 mWidth(0.f),
00093 mHeight(0.f),
00094 mFontp(LLFontGL::sSansSerifSmall),
00095 mBoldFontp(LLFontGL::sSansSerifBold),
00096 mMass(1.f),
00097 mMaxLines(10),
00098 mOffsetY(0),
00099 mTextAlignment(ALIGN_TEXT_CENTER),
00100 mVertAlignment(ALIGN_VERT_CENTER),
00101 mLOD(0),
00102 mHidden(FALSE)
00103 {
00104 mColor = LLColor4(1.f, 1.f, 1.f, 1.f);
00105 mDoFade = TRUE;
00106 mFadeDistance = 8.f;
00107 mFadeRange = 4.f;
00108 mZCompare = TRUE;
00109 mDropShadow = TRUE;
00110 mOffscreen = FALSE;
00111 mRadius = 0.1f;
00112 LLPointer<LLHUDText> ptr(this);
00113 sTextObjects.insert(ptr);
00114
00115 }
00116
00117 LLHUDText::~LLHUDText()
00118 {
00119 }
00120
00121
00122 void LLHUDText::render()
00123 {
00124 if (!mOnHUDAttachment && sDisplayText)
00125 {
00126 LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
00127 renderText(FALSE);
00128 }
00129 }
00130
00131 void LLHUDText::renderForSelect()
00132 {
00133 if (!mOnHUDAttachment)
00134 {
00135 LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
00136 renderText(TRUE);
00137 }
00138 }
00139
00140 void LLHUDText::renderText(BOOL for_select)
00141 {
00142 if (!mVisible || mHidden)
00143 {
00144 return;
00145 }
00146
00147
00148 if (for_select &&
00149 (!mSourceObject || mSourceObject->mDrawable.isNull() || !mUseBubble))
00150 {
00151 return;
00152 }
00153
00154 LLGLState gls_tex(GL_TEXTURE_2D, for_select ? FALSE : TRUE);
00155 LLGLState gls_blend(GL_BLEND, for_select ? FALSE : TRUE);
00156 LLGLState gls_alpha(GL_ALPHA_TEST, for_select ? FALSE : TRUE);
00157
00158 LLColor4 shadow_color(0.f, 0.f, 0.f, 1.f);
00159 F32 alpha_factor = 1.f;
00160 LLColor4 text_color = mColor;
00161 if (mDoFade)
00162 {
00163 if (mLastDistance > mFadeDistance)
00164 {
00165 alpha_factor = llmax(0.f, 1.f - (mLastDistance - mFadeDistance)/mFadeRange);
00166 text_color.mV[3] = text_color.mV[3]*alpha_factor;
00167 }
00168 }
00169 if (text_color.mV[3] < 0.01f)
00170 {
00171 return;
00172 }
00173 shadow_color.mV[3] = text_color.mV[3];
00174
00175 mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f));
00176
00177
00178 LLUIImagePtr imagep = LLUI::getUIImage("rounded_square.tga");
00179
00180
00181 LLColor4 bg_color = gSavedSettings.getColor4("BackgroundChatColor");
00182 bg_color.setAlpha(gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor);
00183
00184 const S32 border_height = 16;
00185 const S32 border_width = 16;
00186
00187
00188 F32 border_scale = 1.f;
00189
00190 if (border_height * 2 > mHeight)
00191 {
00192 border_scale = (F32)mHeight / ((F32)border_height * 2.f);
00193 }
00194 if (border_width * 2 > mWidth)
00195 {
00196 border_scale = llmin(border_scale, (F32)mWidth / ((F32)border_width * 2.f));
00197 }
00198
00199
00200
00201
00202 LLVector3 x_pixel_vec;
00203 LLVector3 y_pixel_vec;
00204
00205 if (mOnHUDAttachment)
00206 {
00207 x_pixel_vec = LLVector3::y_axis / (F32)gViewerWindow->getWindowWidth();
00208 y_pixel_vec = LLVector3::z_axis / (F32)gViewerWindow->getWindowHeight();
00209 }
00210 else
00211 {
00212 LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
00213 }
00214
00215 LLVector2 border_scale_vec((F32)border_width / (F32)imagep->getTextureWidth(), (F32)border_height / (F32)imagep->getTextureHeight());
00216 LLVector3 width_vec = mWidth * x_pixel_vec;
00217 LLVector3 height_vec = mHeight * y_pixel_vec;
00218 LLVector3 scaled_border_width = (F32)llfloor(border_scale * (F32)border_width) * x_pixel_vec;
00219 LLVector3 scaled_border_height = (F32)llfloor(border_scale * (F32)border_height) * y_pixel_vec;
00220
00221 mRadius = (width_vec + height_vec).magVec() * 0.5f;
00222
00223 LLCoordGL screen_pos;
00224 LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, FALSE);
00225
00226 LLVector2 screen_offset;
00227 if (!mUseBubble)
00228 {
00229 screen_offset = mPositionOffset;
00230 }
00231 else
00232 {
00233 screen_offset = updateScreenPos(mPositionOffset);
00234 }
00235
00236 LLVector3 render_position = mPositionAgent
00237 + (x_pixel_vec * screen_offset.mV[VX])
00238 + (y_pixel_vec * screen_offset.mV[VY]);
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250 if (mUseBubble)
00251 {
00252 LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
00253 LLUI::pushMatrix();
00254 {
00255 LLVector3 bg_pos = render_position
00256 + (F32)mOffsetY * y_pixel_vec
00257 - (width_vec / 2.f)
00258 - (height_vec);
00259 LLUI::translate(bg_pos.mV[VX], bg_pos.mV[VY], bg_pos.mV[VZ]);
00260
00261 if (for_select)
00262 {
00263 LLGLSNoTexture no_texture_state;
00264 S32 name = mSourceObject->mGLName;
00265 LLColor4U coloru((U8)(name >> 16), (U8)(name >> 8), (U8)name);
00266 gGL.color4ubv(coloru.mV);
00267 gl_segmented_rect_3d_tex(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, height_vec);
00268 LLUI::popMatrix();
00269 return;
00270 }
00271 else
00272 {
00273 LLViewerImage::bindTexture(imagep->getImage());
00274
00275 gGL.color4fv(bg_color.mV);
00276 gl_segmented_rect_3d_tex(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, height_vec);
00277
00278 if ( mLabelSegments.size())
00279 {
00280 LLUI::pushMatrix();
00281 {
00282 gGL.color4f(text_color.mV[VX], text_color.mV[VY], text_color.mV[VZ], gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor);
00283 LLVector3 label_height = (mFontp->getLineHeight() * mLabelSegments.size() + (VERTICAL_PADDING / 3.f)) * y_pixel_vec;
00284 LLVector3 label_offset = height_vec - label_height;
00285 LLUI::translate(label_offset.mV[VX], label_offset.mV[VY], label_offset.mV[VZ]);
00286 gl_segmented_rect_3d_tex_top(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, label_height);
00287 }
00288 LLUI::popMatrix();
00289 }
00290 }
00291
00292 BOOL outside_width = llabs(mPositionOffset.mV[VX]) > mWidth * 0.5f;
00293 BOOL outside_height = llabs(mPositionOffset.mV[VY] + (mVertAlignment == ALIGN_VERT_TOP ? mHeight * 0.5f : 0.f)) > mHeight * (mVertAlignment == ALIGN_VERT_TOP ? mHeight * 0.75f : 0.5f);
00294
00295
00296 if (!mOffscreen && (outside_width || outside_height))
00297 {
00298 LLUI::pushMatrix();
00299 {
00300 gGL.color4fv(bg_color.mV);
00301 LLVector3 target_pos = -1.f * (mPositionOffset.mV[VX] * x_pixel_vec + mPositionOffset.mV[VY] * y_pixel_vec);
00302 target_pos += (width_vec / 2.f);
00303 target_pos += mVertAlignment == ALIGN_VERT_CENTER ? (height_vec * 0.5f) : LLVector3::zero;
00304 target_pos -= 3.f * x_pixel_vec;
00305 target_pos -= 6.f * y_pixel_vec;
00306 LLUI::translate(target_pos.mV[VX], target_pos.mV[VY], target_pos.mV[VZ]);
00307 gl_segmented_rect_3d_tex(border_scale_vec, 3.f * x_pixel_vec, 3.f * y_pixel_vec, 6.f * x_pixel_vec, 6.f * y_pixel_vec);
00308 }
00309 LLUI::popMatrix();
00310
00311
00312 LLImageGL::unbindTexture(0);
00313 LLGLDepthTest gls_depth(mZCompare ? GL_TRUE : GL_FALSE, GL_FALSE);
00314
00315 LLVector3 box_center_offset;
00316 box_center_offset = (width_vec * 0.5f) + (height_vec * 0.5f);
00317 LLUI::translate(box_center_offset.mV[VX], box_center_offset.mV[VY], box_center_offset.mV[VZ]);
00318 gGL.color4fv(bg_color.mV);
00319 LLUI::setLineWidth(2.0);
00320 gGL.begin(LLVertexBuffer::LINES);
00321 {
00322 if (outside_width)
00323 {
00324 LLVector3 vert;
00325
00326 if (mPositionOffset.mV[VX] < 0.f)
00327 {
00328
00329 vert = width_vec * 0.5f;
00330 gGL.vertex3fv(vert.mV);
00331 }
00332 else
00333 {
00334
00335 vert = width_vec * -0.5f;
00336 gGL.vertex3fv(vert.mV);
00337 }
00338 vert = -mPositionOffset.mV[VX] * x_pixel_vec;
00339 gGL.vertex3fv(vert.mV);
00340 gGL.vertex3fv(vert.mV);
00341 vert -= mPositionOffset.mV[VY] * y_pixel_vec;
00342 vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero);
00343 gGL.vertex3fv(vert.mV);
00344 }
00345 else
00346 {
00347 LLVector3 vert;
00348
00349 if (mPositionOffset.mV[VY] < 0.f)
00350 {
00351
00352 vert = (height_vec * 0.5f) - (mPositionOffset.mV[VX] * x_pixel_vec);
00353 gGL.vertex3fv(vert.mV);
00354 }
00355 else
00356 {
00357
00358 vert = (height_vec * -0.5f) - (mPositionOffset.mV[VX] * x_pixel_vec);
00359 gGL.vertex3fv(vert.mV);
00360 }
00361 vert = -mPositionOffset.mV[VY] * y_pixel_vec - mPositionOffset.mV[VX] * x_pixel_vec;
00362 vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero);
00363 gGL.vertex3fv(vert.mV);
00364 }
00365 }
00366 gGL.end();
00367 LLUI::setLineWidth(1.0);
00368
00369 }
00370 }
00371 LLUI::popMatrix();
00372 }
00373
00374 F32 y_offset = (F32)mOffsetY;
00375
00376
00377 {
00378 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00379
00380 for(std::vector<LLHUDTextSegment>::iterator segment_iter = mLabelSegments.begin();
00381 segment_iter != mLabelSegments.end(); ++segment_iter )
00382 {
00383 const LLFontGL* fontp = (segment_iter->mStyle == LLFontGL::BOLD) ? mBoldFontp : mFontp;
00384 y_offset -= fontp->getLineHeight();
00385
00386 F32 x_offset;
00387 if (mTextAlignment == ALIGN_TEXT_CENTER)
00388 {
00389 x_offset = -0.5f*segment_iter->getWidth(fontp);
00390 }
00391 else
00392 {
00393 x_offset = -0.5f * mWidth + (HORIZONTAL_PADDING / 2.f);
00394 }
00395
00396 LLColor4 label_color(0.f, 0.f, 0.f, 1.f);
00397 label_color.mV[VALPHA] = alpha_factor;
00398 hud_render_text(segment_iter->getText(), render_position, *fontp, segment_iter->mStyle, x_offset, y_offset, label_color, mOnHUDAttachment);
00399 }
00400 }
00401
00402
00403 {
00404
00405 S32 start_segment;
00406 S32 max_lines = getMaxLines();
00407
00408 if (max_lines < 0)
00409 {
00410 start_segment = 0;
00411 }
00412 else
00413 {
00414 start_segment = llmax((S32)0, (S32)mTextSegments.size() - max_lines);
00415 }
00416
00417 for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin() + start_segment;
00418 segment_iter != mTextSegments.end(); ++segment_iter )
00419 {
00420 const LLFontGL* fontp = (segment_iter->mStyle == LLFontGL::BOLD) ? mBoldFontp : mFontp;
00421 y_offset -= fontp->getLineHeight();
00422
00423 U8 style = segment_iter->mStyle;
00424 if (mDropShadow)
00425 {
00426 style |= LLFontGL::DROP_SHADOW;
00427 }
00428
00429 F32 x_offset;
00430 if (mTextAlignment== ALIGN_TEXT_CENTER)
00431 {
00432 x_offset = -0.5f*segment_iter->getWidth(fontp);
00433 }
00434 else
00435 {
00436 x_offset = -0.5f * mWidth + (HORIZONTAL_PADDING / 2.f);
00437 }
00438
00439 text_color = segment_iter->mColor;
00440 text_color.mV[VALPHA] *= alpha_factor;
00441
00442 hud_render_text(segment_iter->getText(), render_position, *fontp, style, x_offset, y_offset, text_color, mOnHUDAttachment);
00443 }
00444 }
00446 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
00447 }
00448
00449 void LLHUDText::setStringUTF8(const std::string &wtext)
00450 {
00451 setString(utf8str_to_wstring(wtext));
00452 }
00453
00454 void LLHUDText::setString(const LLWString &wtext)
00455 {
00456 mTextSegments.clear();
00457 addLine(wtext, mColor);
00458 }
00459
00460 void LLHUDText::clearString()
00461 {
00462 mTextSegments.clear();
00463 }
00464
00465
00466 void LLHUDText::addLine(const std::string &str, const LLColor4& color, const LLFontGL::StyleFlags style)
00467 {
00468 addLine(utf8str_to_wstring(str), color, style);
00469 }
00470
00471
00472 void LLHUDText::addLine(const LLWString &wstr, const LLColor4& color, const LLFontGL::StyleFlags style)
00473 {
00474 if (gNoRender)
00475 {
00476 return;
00477 }
00478 if (!wstr.empty())
00479 {
00480 LLWString wline(wstr);
00481 typedef boost::tokenizer<boost::char_separator<llwchar>, LLWString::const_iterator, LLWString > tokenizer;
00482 LLWString seps(utf8str_to_wstring("\r\n"));
00483 boost::char_separator<llwchar> sep(seps.c_str());
00484
00485 tokenizer tokens(wline, sep);
00486 tokenizer::iterator iter = tokens.begin();
00487
00488 while (iter != tokens.end())
00489 {
00490 U32 line_length = 0;
00491 do
00492 {
00493 S32 segment_length = mFontp->maxDrawableChars(iter->substr(line_length).c_str(), mUseBubble ? HUD_TEXT_MAX_WIDTH : HUD_TEXT_MAX_WIDTH_NO_BUBBLE, wline.length(), TRUE);
00494 mTextSegments.push_back(LLHUDTextSegment(iter->substr(line_length, segment_length), style, color));
00495 line_length += segment_length;
00496 }
00497 while (line_length != iter->size());
00498 ++iter;
00499 }
00500 }
00501 }
00502
00503 void LLHUDText::setLabel(const std::string &label)
00504 {
00505 setLabel(utf8str_to_wstring(label));
00506 }
00507
00508 void LLHUDText::setLabel(const LLWString &wlabel)
00509 {
00510 mLabelSegments.clear();
00511
00512 if (!wlabel.empty())
00513 {
00514 LLWString wstr(wlabel);
00515 LLWString seps(utf8str_to_wstring("\r\n"));
00516 LLWString empty;
00517
00518 typedef boost::tokenizer<boost::char_separator<llwchar>, LLWString::const_iterator, LLWString > tokenizer;
00519 boost::char_separator<llwchar> sep(seps.c_str(), empty.c_str(), boost::keep_empty_tokens);
00520
00521 tokenizer tokens(wstr, sep);
00522 tokenizer::iterator iter = tokens.begin();
00523
00524 while (iter != tokens.end())
00525 {
00526 U32 line_length = 0;
00527 do
00528 {
00529 S32 segment_length = mFontp->maxDrawableChars(iter->substr(line_length).c_str(), mUseBubble ? HUD_TEXT_MAX_WIDTH : HUD_TEXT_MAX_WIDTH_NO_BUBBLE, wstr.length(), TRUE);
00530 mLabelSegments.push_back(LLHUDTextSegment(iter->substr(line_length, segment_length), LLFontGL::NORMAL, mColor));
00531 line_length += segment_length;
00532 }
00533 while (line_length != iter->size());
00534 ++iter;
00535 }
00536 }
00537 }
00538
00539 void LLHUDText::setDropShadow(const BOOL do_shadow)
00540 {
00541 mDropShadow = do_shadow;
00542 }
00543
00544 void LLHUDText::setZCompare(const BOOL zcompare)
00545 {
00546 mZCompare = zcompare;
00547 }
00548
00549 void LLHUDText::setFont(const LLFontGL* font)
00550 {
00551 mFontp = font;
00552 }
00553
00554
00555 void LLHUDText::setColor(const LLColor4 &color)
00556 {
00557 mColor = color;
00558 for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin();
00559 segment_iter != mTextSegments.end(); ++segment_iter )
00560 {
00561 segment_iter->mColor = color;
00562 }
00563 }
00564
00565
00566 void LLHUDText::setUsePixelSize(const BOOL use_pixel_size)
00567 {
00568 mUsePixelSize = use_pixel_size;
00569 }
00570
00571 void LLHUDText::setDoFade(const BOOL do_fade)
00572 {
00573 mDoFade = do_fade;
00574 }
00575
00576 void LLHUDText::updateVisibility()
00577 {
00578 if (mSourceObject)
00579 {
00580 mSourceObject->updateText();
00581 }
00582
00583 mPositionAgent = gAgent.getPosAgentFromGlobal(mPositionGlobal);
00584
00585 if (!mSourceObject)
00586 {
00587
00588 mVisible = TRUE;
00589 if (mOnHUDAttachment)
00590 {
00591 sVisibleHUDTextObjects.push_back(LLPointer<LLHUDText> (this));
00592 }
00593 else
00594 {
00595 sVisibleTextObjects.push_back(LLPointer<LLHUDText> (this));
00596 }
00597 return;
00598 }
00599
00600
00601 if (mSourceObject->isDead())
00602 {
00603 mVisible = FALSE;
00604 return;
00605 }
00606
00607
00608 if (mOnHUDAttachment)
00609 {
00610 mVisible = TRUE;
00611 sVisibleHUDTextObjects.push_back(LLPointer<LLHUDText> (this));
00612 mLastDistance = mPositionAgent.mV[VX];
00613 return;
00614 }
00615
00616
00617 LLVector3 vec_from_camera = mPositionAgent - LLViewerCamera::getInstance()->getOrigin();
00618 LLVector3 dir_from_camera = vec_from_camera;
00619 dir_from_camera.normVec();
00620
00621 if (dir_from_camera * LLViewerCamera::getInstance()->getAtAxis() <= 0.f)
00622 {
00623 mPositionAgent -= projected_vec(vec_from_camera, LLViewerCamera::getInstance()->getAtAxis()) * 1.f;
00624 mPositionAgent += LLViewerCamera::getInstance()->getAtAxis() * (LLViewerCamera::getInstance()->getNear() + 0.1f);
00625 }
00626 else if (vec_from_camera * LLViewerCamera::getInstance()->getAtAxis() <= LLViewerCamera::getInstance()->getNear() + 0.1f + mSourceObject->getVObjRadius())
00627 {
00628 mPositionAgent = LLViewerCamera::getInstance()->getOrigin() + vec_from_camera * ((LLViewerCamera::getInstance()->getNear() + 0.1f) / (vec_from_camera * LLViewerCamera::getInstance()->getAtAxis()));
00629 }
00630 else
00631 {
00632 mPositionAgent -= dir_from_camera * mSourceObject->getVObjRadius();
00633 }
00634
00635 mLastDistance = (mPositionAgent - LLViewerCamera::getInstance()->getOrigin()).magVec();
00636
00637 if (mLOD >= 3 || !mTextSegments.size() || (mDoFade && (mLastDistance > mFadeDistance + mFadeRange)))
00638 {
00639 mVisible = FALSE;
00640 return;
00641 }
00642
00643 LLVector3 x_pixel_vec;
00644 LLVector3 y_pixel_vec;
00645
00646 LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
00647
00648 LLVector3 render_position = mPositionAgent +
00649 (x_pixel_vec * mPositionOffset.mV[VX]) +
00650 (y_pixel_vec * mPositionOffset.mV[VY]);
00651
00652 mOffscreen = FALSE;
00653 if (!LLViewerCamera::getInstance()->sphereInFrustum(render_position, mRadius))
00654 {
00655 if (!mVisibleOffScreen)
00656 {
00657 mVisible = FALSE;
00658 return;
00659 }
00660 else
00661 {
00662 mOffscreen = TRUE;
00663 }
00664 }
00665
00666 mVisible = TRUE;
00667 sVisibleTextObjects.push_back(LLPointer<LLHUDText> (this));
00668 }
00669
00670 LLVector2 LLHUDText::updateScreenPos(LLVector2 &offset)
00671 {
00672 LLCoordGL screen_pos;
00673 LLVector2 screen_pos_vec;
00674 LLVector3 x_pixel_vec;
00675 LLVector3 y_pixel_vec;
00676 LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
00677 LLVector3 world_pos = mPositionAgent + (offset.mV[VX] * x_pixel_vec) + (offset.mV[VY] * y_pixel_vec);
00678 if (!LLViewerCamera::getInstance()->projectPosAgentToScreen(world_pos, screen_pos, FALSE) && mVisibleOffScreen)
00679 {
00680
00681 LLVector2 window_center(gViewerWindow->getWindowDisplayWidth() * 0.5f, gViewerWindow->getWindowDisplayHeight() * 0.5f);
00682 LLVector2 delta_from_center(screen_pos.mX - window_center.mV[VX],
00683 screen_pos.mY - window_center.mV[VY]);
00684 delta_from_center.normVec();
00685
00686 F32 camera_aspect = LLViewerCamera::getInstance()->getAspect();
00687 F32 delta_aspect = llabs(delta_from_center.mV[VX] / delta_from_center.mV[VY]);
00688 if (camera_aspect / llmax(delta_aspect, 0.001f) > 1.f)
00689 {
00690
00691 delta_from_center *= llabs(window_center.mV[VY] / delta_from_center.mV[VY]);
00692 }
00693 else
00694 {
00695
00696 delta_from_center *= llabs(window_center.mV[VX] / delta_from_center.mV[VX]);
00697 }
00698
00699 screen_pos_vec = window_center + delta_from_center;
00700 }
00701 else
00702 {
00703 screen_pos_vec.setVec((F32)screen_pos.mX, (F32)screen_pos.mY);
00704 }
00705 S32 bottom = STATUS_BAR_HEIGHT;
00706 if (gChatBar->getVisible())
00707 {
00708 bottom += CHAT_BAR_HEIGHT;
00709 }
00710
00711 LLVector2 screen_center;
00712 screen_center.mV[VX] = llclamp((F32)screen_pos_vec.mV[VX], mWidth * 0.5f, (F32)gViewerWindow->getWindowDisplayWidth() - mWidth * 0.5f);
00713
00714 if(mVertAlignment == ALIGN_VERT_TOP)
00715 {
00716 screen_center.mV[VY] = llclamp((F32)screen_pos_vec.mV[VY],
00717 (F32)bottom,
00718 (F32)gViewerWindow->getWindowDisplayHeight() - mHeight - (F32)MENU_BAR_HEIGHT);
00719 mSoftScreenRect.setLeftTopAndSize(screen_center.mV[VX] - (mWidth + BUFFER_SIZE) * 0.5f,
00720 screen_center.mV[VY] + (mHeight + BUFFER_SIZE), mWidth + BUFFER_SIZE, mHeight + BUFFER_SIZE);
00721 }
00722 else
00723 {
00724 screen_center.mV[VY] = llclamp((F32)screen_pos_vec.mV[VY],
00725 (F32)bottom + mHeight * 0.5f,
00726 (F32)gViewerWindow->getWindowDisplayHeight() - mHeight * 0.5f - (F32)MENU_BAR_HEIGHT);
00727 mSoftScreenRect.setCenterAndSize(screen_center.mV[VX], screen_center.mV[VY], mWidth + BUFFER_SIZE, mHeight + BUFFER_SIZE);
00728 }
00729
00730 return offset + (screen_center - LLVector2((F32)screen_pos.mX, (F32)screen_pos.mY));
00731 }
00732
00733 void LLHUDText::updateSize()
00734 {
00735 F32 width = 0.f;
00736
00737 S32 max_lines = getMaxLines();
00738 S32 lines = (max_lines < 0) ? (S32)mTextSegments.size() : llmin((S32)mTextSegments.size(), max_lines);
00739
00740 F32 height = (F32)mFontp->getLineHeight() * (lines + mLabelSegments.size());
00741
00742 S32 start_segment;
00743 if (max_lines < 0) start_segment = 0;
00744 else start_segment = llmax((S32)0, (S32)mTextSegments.size() - max_lines);
00745
00746 std::vector<LLHUDTextSegment>::iterator iter = mTextSegments.begin() + start_segment;
00747 while (iter != mTextSegments.end())
00748 {
00749 width = llmax(width, llmin(iter->getWidth(mFontp), HUD_TEXT_MAX_WIDTH));
00750 ++iter;
00751 }
00752
00753 iter = mLabelSegments.begin();
00754 while (iter != mLabelSegments.end())
00755 {
00756 width = llmax(width, llmin(iter->getWidth(mFontp), HUD_TEXT_MAX_WIDTH));
00757 ++iter;
00758 }
00759
00760 if (width == 0.f)
00761 {
00762 return;
00763 }
00764
00765 width += HORIZONTAL_PADDING;
00766 height += VERTICAL_PADDING;
00767
00768 if (!mResizeTimer.getStarted() && (width != mWidth || height != mHeight))
00769 {
00770 mResizeTimer.start();
00771 }
00772
00773
00774 F32 u = 1.f;
00775 if (u == 1.f)
00776 {
00777 mResizeTimer.stop();
00778 }
00779
00780 mWidth = llmax(width, lerp(mWidth, (F32)width, u));
00781 mHeight = llmax(height, lerp(mHeight, (F32)height, u));
00782 }
00783
00784 void LLHUDText::updateAll()
00785 {
00786
00787
00788 sVisibleTextObjects.clear();
00789 sVisibleHUDTextObjects.clear();
00790
00791 TextObjectIterator text_it;
00792 for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it)
00793 {
00794 LLHUDText* textp = (*text_it);
00795 textp->mTargetPositionOffset.clearVec();
00796 textp->updateSize();
00797 textp->updateVisibility();
00798 }
00799
00800
00801 std::sort(sVisibleTextObjects.begin(), sVisibleTextObjects.end(), lltextobject_further_away());
00802 std::sort(sVisibleHUDTextObjects.begin(), sVisibleHUDTextObjects.end(), lltextobject_further_away());
00803
00804
00805 F32 screen_area = (F32)(gViewerWindow->getWindowWidth() * gViewerWindow->getWindowHeight());
00806 F32 current_screen_area = 0.f;
00807 std::vector<LLPointer<LLHUDText> >::reverse_iterator r_it;
00808 for (r_it = sVisibleTextObjects.rbegin(); r_it != sVisibleTextObjects.rend(); ++r_it)
00809 {
00810 LLHUDText* textp = (*r_it);
00811 if (textp->mUseBubble)
00812 {
00813 if (current_screen_area / screen_area > LOD_2_SCREEN_COVERAGE)
00814 {
00815 textp->setLOD(3);
00816 }
00817 else if (current_screen_area / screen_area > LOD_1_SCREEN_COVERAGE)
00818 {
00819 textp->setLOD(2);
00820 }
00821 else if (current_screen_area / screen_area > LOD_0_SCREEN_COVERAGE)
00822 {
00823 textp->setLOD(1);
00824 }
00825 else
00826 {
00827 textp->setLOD(0);
00828 }
00829 textp->updateSize();
00830
00831 textp->mTargetPositionOffset = textp->updateScreenPos(LLVector2::zero);
00832 current_screen_area += (F32)(textp->mSoftScreenRect.getWidth() * textp->mSoftScreenRect.getHeight());
00833 }
00834 }
00835
00836 LLStat* camera_vel_stat = LLViewerCamera::getInstance()->getVelocityStat();
00837 F32 camera_vel = camera_vel_stat->getCurrent();
00838 if (camera_vel > MAX_STABLE_CAMERA_VELOCITY)
00839 {
00840 return;
00841 }
00842
00843 VisibleTextObjectIterator src_it;
00844
00845 for (S32 i = 0; i < NUM_OVERLAP_ITERATIONS; i++)
00846 {
00847 for (src_it = sVisibleTextObjects.begin(); src_it != sVisibleTextObjects.end(); ++src_it)
00848 {
00849 LLHUDText* src_textp = (*src_it);
00850
00851 if (!src_textp->mUseBubble)
00852 {
00853 continue;
00854 }
00855 VisibleTextObjectIterator dst_it = src_it;
00856 ++dst_it;
00857 for (; dst_it != sVisibleTextObjects.end(); ++dst_it)
00858 {
00859 LLHUDText* dst_textp = (*dst_it);
00860
00861 if (!dst_textp->mUseBubble)
00862 {
00863 continue;
00864 }
00865 if (src_textp->mSoftScreenRect.rectInRect(&dst_textp->mSoftScreenRect))
00866 {
00867 LLRectf intersect_rect = src_textp->mSoftScreenRect;
00868 intersect_rect.intersectWith(dst_textp->mSoftScreenRect);
00869 intersect_rect.stretch(-BUFFER_SIZE * 0.5f);
00870
00871 F32 src_center_x = src_textp->mSoftScreenRect.getCenterX();
00872 F32 src_center_y = src_textp->mSoftScreenRect.getCenterY();
00873 F32 dst_center_x = dst_textp->mSoftScreenRect.getCenterX();
00874 F32 dst_center_y = dst_textp->mSoftScreenRect.getCenterY();
00875 F32 intersect_center_x = intersect_rect.getCenterX();
00876 F32 intersect_center_y = intersect_rect.getCenterY();
00877 LLVector2 force = lerp(LLVector2(dst_center_x - intersect_center_x, dst_center_y - intersect_center_y),
00878 LLVector2(intersect_center_x - src_center_x, intersect_center_y - src_center_y),
00879 0.5f);
00880 force.setVec(dst_center_x - src_center_x, dst_center_y - src_center_y);
00881 force.normVec();
00882
00883 LLVector2 src_force = -1.f * force;
00884 LLVector2 dst_force = force;
00885
00886 LLVector2 force_strength;
00887 F32 src_mult = dst_textp->mMass / (dst_textp->mMass + src_textp->mMass);
00888 F32 dst_mult = 1.f - src_mult;
00889 F32 src_aspect_ratio = src_textp->mSoftScreenRect.getWidth() / src_textp->mSoftScreenRect.getHeight();
00890 F32 dst_aspect_ratio = dst_textp->mSoftScreenRect.getWidth() / dst_textp->mSoftScreenRect.getHeight();
00891 src_force.mV[VY] *= src_aspect_ratio;
00892 src_force.normVec();
00893 dst_force.mV[VY] *= dst_aspect_ratio;
00894 dst_force.normVec();
00895
00896 src_force.mV[VX] *= llmin(intersect_rect.getWidth() * src_mult, intersect_rect.getHeight() * SPRING_STRENGTH);
00897 src_force.mV[VY] *= llmin(intersect_rect.getHeight() * src_mult, intersect_rect.getWidth() * SPRING_STRENGTH);
00898 dst_force.mV[VX] *= llmin(intersect_rect.getWidth() * dst_mult, intersect_rect.getHeight() * SPRING_STRENGTH);
00899 dst_force.mV[VY] *= llmin(intersect_rect.getHeight() * dst_mult, intersect_rect.getWidth() * SPRING_STRENGTH);
00900
00901 src_textp->mTargetPositionOffset += src_force;
00902 dst_textp->mTargetPositionOffset += dst_force;
00903 src_textp->mTargetPositionOffset = src_textp->updateScreenPos(src_textp->mTargetPositionOffset);
00904 dst_textp->mTargetPositionOffset = dst_textp->updateScreenPos(dst_textp->mTargetPositionOffset);
00905 }
00906 }
00907 }
00908 }
00909
00910 VisibleTextObjectIterator this_object_it;
00911 for (this_object_it = sVisibleTextObjects.begin(); this_object_it != sVisibleTextObjects.end(); ++this_object_it)
00912 {
00913 if (!(*this_object_it)->mUseBubble)
00914 {
00915 continue;
00916 }
00917 (*this_object_it)->mPositionOffset = lerp((*this_object_it)->mPositionOffset, (*this_object_it)->mTargetPositionOffset, LLCriticalDamp::getInterpolant(POSITION_DAMPING_TC));
00918 }
00919 }
00920
00921 void LLHUDText::setLOD(S32 lod)
00922 {
00923 mLOD = lod;
00924
00925
00926
00927
00928 }
00929
00930 S32 LLHUDText::getMaxLines()
00931 {
00932 switch(mLOD)
00933 {
00934 case 0:
00935 return mMaxLines;
00936 case 1:
00937 return mMaxLines > 0 ? mMaxLines / 2 : 5;
00938 case 2:
00939 return mMaxLines > 0 ? mMaxLines / 3 : 2;
00940 default:
00941
00942 return 0;
00943 }
00944 }
00945
00946 void LLHUDText::markDead()
00947 {
00948 sTextObjects.erase(LLPointer<LLHUDText>(this));
00949 LLHUDObject::markDead();
00950 }
00951
00952 void LLHUDText::renderAllHUD()
00953 {
00954 LLGLEnable color_mat(GL_COLOR_MATERIAL);
00955 LLGLDepthTest depth(GL_FALSE, GL_FALSE);
00956
00957 VisibleTextObjectIterator text_it;
00958
00959 for (text_it = sVisibleHUDTextObjects.begin(); text_it != sVisibleHUDTextObjects.end(); ++text_it)
00960 {
00961 (*text_it)->renderText(FALSE);
00962 }
00963 }
00964
00965
00966 void LLHUDText::addPickable(std::set<LLViewerObject*> &pick_list)
00967 {
00968
00969
00970 VisibleTextObjectIterator text_it;
00971 for (text_it = sVisibleTextObjects.begin(); text_it != sVisibleTextObjects.end(); ++text_it)
00972 {
00973 if (!(*text_it)->mUseBubble)
00974 {
00975 continue;
00976 }
00977 pick_list.insert((*text_it)->mSourceObject);
00978 }
00979 }
00980
00981
00982
00983 void LLHUDText::reshape()
00984 {
00985 TextObjectIterator text_it;
00986 for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it)
00987 {
00988 LLHUDText* textp = (*text_it);
00989 std::vector<LLHUDTextSegment>::iterator segment_iter;
00990 for (segment_iter = textp->mTextSegments.begin();
00991 segment_iter != textp->mTextSegments.end(); ++segment_iter )
00992 {
00993 segment_iter->clearFontWidthMap();
00994 }
00995 for(segment_iter = textp->mLabelSegments.begin();
00996 segment_iter != textp->mLabelSegments.end(); ++segment_iter )
00997 {
00998 segment_iter->clearFontWidthMap();
00999 }
01000 }
01001 }
01002
01003
01004
01005 F32 LLHUDText::LLHUDTextSegment::getWidth(const LLFontGL* font)
01006 {
01007 std::map<const LLFontGL*, F32>::iterator iter = mFontWidthMap.find(font);
01008 if (iter != mFontWidthMap.end())
01009 {
01010 return iter->second;
01011 }
01012 else
01013 {
01014 F32 width = font->getWidthF32(mText.c_str());
01015 mFontWidthMap[font] = width;
01016 return width;
01017 }
01018 }