00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llhudtext.h"
00035
00036 #include "llagent.h"
00037 #include "llviewercontrol.h"
00038 #include "llchatbar.h"
00039 #include "llcriticaldamp.h"
00040 #include "lldrawable.h"
00041 #include "llfontgl.h"
00042 #include "llglheaders.h"
00043 #include "llhudrender.h"
00044 #include "llimagegl.h"
00045 #include "llui.h"
00046 #include "llviewercamera.h"
00047 #include "llviewerimagelist.h"
00048 #include "llviewerobject.h"
00049 #include "llvovolume.h"
00050 #include "llviewerwindow.h"
00051 #include "viewer.h"
00052 #include "llstatusbar.h"
00053 #include "llmenugl.h"
00054 #include "pipeline.h"
00055 #include <boost/tokenizer.hpp>
00056
00057
00058 const F32 SPRING_STRENGTH = 0.7f;
00059 const F32 RESTORATION_SPRING_TIME_CONSTANT = 0.1f;
00060 const F32 HORIZONTAL_PADDING = 15.f;
00061 const F32 VERTICAL_PADDING = 12.f;
00062 const F32 BUFFER_SIZE = 2.f;
00063 const F32 MIN_EDGE_OVERLAP = 3.f;
00064 F32 HUD_TEXT_MAX_WIDTH = 190.f;
00065 const F32 HUD_TEXT_MAX_WIDTH_NO_BUBBLE = 1000.f;
00066 const F32 RESIZE_TIME = 0.f;
00067 const S32 NUM_OVERLAP_ITERATIONS = 10;
00068 const F32 NEIGHBOR_FORCE_FRACTION = 1.f;
00069 const F32 POSITION_DAMPING_TC = 0.2f;
00070 const F32 MAX_STABLE_CAMERA_VELOCITY = 0.1f;
00071 const F32 LOD_0_SCREEN_COVERAGE = 0.15f;
00072 const F32 LOD_1_SCREEN_COVERAGE = 0.30f;
00073 const F32 LOD_2_SCREEN_COVERAGE = 0.40f;
00074
00075 std::set<LLPointer<LLHUDText> > LLHUDText::sTextObjects;
00076 std::vector<LLPointer<LLHUDText> > LLHUDText::sVisibleTextObjects;
00077 std::vector<LLPointer<LLHUDText> > LLHUDText::sVisibleHUDTextObjects;
00078
00079 bool lltextobject_further_away::operator()(const LLPointer<LLHUDText>& lhs, const LLPointer<LLHUDText>& rhs) const
00080 {
00081 return (lhs->getDistance() > rhs->getDistance()) ? true : false;
00082 }
00083
00084
00085 LLHUDText::LLHUDText(const U8 type) :
00086 LLHUDObject(type),
00087 mUseBubble(FALSE),
00088 mUsePixelSize(TRUE),
00089 mVisibleOffScreen(FALSE),
00090 mWidth(0.f),
00091 mHeight(0.f),
00092 mFontp(LLFontGL::sSansSerifSmall),
00093 mBoldFontp(LLFontGL::sSansSerifBold),
00094 mMass(1.f),
00095 mMaxLines(10),
00096 mOffsetY(0),
00097 mTextAlignment(ALIGN_TEXT_CENTER),
00098 mVertAlignment(ALIGN_VERT_CENTER),
00099 mLOD(0),
00100 mHidden(FALSE)
00101 {
00102 mColor = LLColor4(1.f, 1.f, 1.f, 1.f);
00103 mBackgroundColor = gSavedSettings.getColor4("BackgroundChatColor");
00104 mDoFade = TRUE;
00105 mFadeDistance = 8.f;
00106 mFadeRange = 4.f;
00107 mZCompare = TRUE;
00108 mDropShadow = TRUE;
00109 mOffscreen = FALSE;
00110 mRadius = 0.1f;
00111 LLPointer<LLHUDText> ptr(this);
00112 sTextObjects.insert(ptr);
00113
00114 }
00115
00116 LLHUDText::~LLHUDText()
00117 {
00118 }
00119
00120
00121 void LLHUDText::render()
00122 {
00123 if (!mOnHUDAttachment)
00124 {
00125 LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
00126 renderText(FALSE);
00127 }
00128 }
00129
00130 void LLHUDText::renderForSelect()
00131 {
00132 if (!mOnHUDAttachment)
00133 {
00134 LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
00135 renderText(TRUE);
00136 }
00137 }
00138
00139 void LLHUDText::renderText(BOOL for_select)
00140 {
00141 if (!mVisible || mHidden)
00142 {
00143 return;
00144 }
00145
00146
00147 if (for_select &&
00148 (!mSourceObject || mSourceObject->mDrawable.isNull() || !mUseBubble))
00149 {
00150 return;
00151 }
00152
00153 LLGLState gls_tex(GL_TEXTURE_2D, for_select ? FALSE : TRUE);
00154 LLGLState gls_blend(GL_BLEND, for_select ? FALSE : TRUE);
00155 LLGLState gls_alpha(GL_ALPHA_TEST, for_select ? FALSE : TRUE);
00156
00157 LLColor4 shadow_color(0.f, 0.f, 0.f, 1.f);
00158 F32 alpha_factor = 1.f;
00159 LLColor4 text_color = mColor;
00160 if (mDoFade)
00161 {
00162 if (mLastDistance > mFadeDistance)
00163 {
00164 alpha_factor = llmax(0.f, 1.f - (mLastDistance - mFadeDistance)/mFadeRange);
00165 text_color.mV[3] = text_color.mV[3]*alpha_factor;
00166 }
00167 }
00168 if (text_color.mV[3] < 0.01f)
00169 {
00170 return;
00171 }
00172 shadow_color.mV[3] = text_color.mV[3];
00173
00174 mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f));
00175
00176
00177 LLUUID image_id;
00178 image_id.set(gViewerArt.getString("rounded_square.tga"));
00179 LLViewerImage* imagep = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
00180
00181 LLColor4 bg_color = mBackgroundColor;
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 gCamera->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
00213 }
00214
00215 LLVector2 border_scale_vec((F32)border_width / (F32)imagep->getWidth(), (F32)border_height / (F32)imagep->getHeight());
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 gCamera->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 glColor4ubv(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);
00274
00275 glColor4fv(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 glColor4f(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 glColor4fv(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 LLGLDisable gls_texture_2d(GL_TEXTURE_2D);
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 glColor4fv(bg_color.mV);
00319 LLUI::setLineWidth(2.0);
00320 glBegin(GL_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 glVertex3fv(vert.mV);
00331 }
00332 else
00333 {
00334
00335 vert = width_vec * -0.5f;
00336 glVertex3fv(vert.mV);
00337 }
00338 vert = -mPositionOffset.mV[VX] * x_pixel_vec;
00339 glVertex3fv(vert.mV);
00340 glVertex3fv(vert.mV);
00341 vert -= mPositionOffset.mV[VY] * y_pixel_vec;
00342 vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero);
00343 glVertex3fv(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 glVertex3fv(vert.mV);
00354 }
00355 else
00356 {
00357
00358 vert = (height_vec * -0.5f) - (mPositionOffset.mV[VX] * x_pixel_vec);
00359 glVertex3fv(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 glVertex3fv(vert.mV);
00364 }
00365 }
00366 glEnd();
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 }
00445 }
00446
00447 void LLHUDText::setStringUTF8(const std::string &wtext)
00448 {
00449 setString(utf8str_to_wstring(wtext));
00450 }
00451
00452 void LLHUDText::setString(const LLWString &wtext)
00453 {
00454 mTextSegments.clear();
00455 addLine(wtext, mColor);
00456 }
00457
00458 void LLHUDText::clearString()
00459 {
00460 mTextSegments.clear();
00461 }
00462
00463
00464 void LLHUDText::addLine(const std::string &str, const LLColor4& color, const LLFontGL::StyleFlags style)
00465 {
00466 addLine(utf8str_to_wstring(str), color, style);
00467 }
00468
00469
00470 void LLHUDText::addLine(const LLWString &wstr, const LLColor4& color, const LLFontGL::StyleFlags style)
00471 {
00472 if (gNoRender)
00473 {
00474 return;
00475 }
00476 if (!wstr.empty())
00477 {
00478 LLWString wline(wstr);
00479 typedef boost::tokenizer<boost::char_separator<llwchar>, LLWString::const_iterator, LLWString > tokenizer;
00480 LLWString seps(utf8str_to_wstring("\r\n"));
00481 boost::char_separator<llwchar> sep(seps.c_str());
00482
00483 tokenizer tokens(wline, sep);
00484 tokenizer::iterator iter = tokens.begin();
00485
00486 while (iter != tokens.end())
00487 {
00488 U32 line_length = 0;
00489 do
00490 {
00491 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);
00492 mTextSegments.push_back(LLHUDTextSegment(iter->substr(line_length, segment_length), style, color));
00493 line_length += segment_length;
00494 }
00495 while (line_length != iter->size());
00496 ++iter;
00497 }
00498 }
00499 }
00500
00501 void LLHUDText::setLabel(const std::string &label)
00502 {
00503 setLabel(utf8str_to_wstring(label));
00504 }
00505
00506 void LLHUDText::setLabel(const LLWString &wlabel)
00507 {
00508 mLabelSegments.clear();
00509
00510 if (!wlabel.empty())
00511 {
00512 LLWString wstr(wlabel);
00513 LLWString seps(utf8str_to_wstring("\r\n"));
00514 LLWString empty;
00515
00516 typedef boost::tokenizer<boost::char_separator<llwchar>, LLWString::const_iterator, LLWString > tokenizer;
00517 boost::char_separator<llwchar> sep(seps.c_str(), empty.c_str(), boost::keep_empty_tokens);
00518
00519 tokenizer tokens(wstr, sep);
00520 tokenizer::iterator iter = tokens.begin();
00521
00522 while (iter != tokens.end())
00523 {
00524 U32 line_length = 0;
00525 do
00526 {
00527 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);
00528 mLabelSegments.push_back(LLHUDTextSegment(iter->substr(line_length, segment_length), LLFontGL::NORMAL, mColor));
00529 line_length += segment_length;
00530 }
00531 while (line_length != iter->size());
00532 ++iter;
00533 }
00534 }
00535 }
00536
00537 void LLHUDText::setDropShadow(const BOOL do_shadow)
00538 {
00539 mDropShadow = do_shadow;
00540 }
00541
00542 void LLHUDText::setZCompare(const BOOL zcompare)
00543 {
00544 mZCompare = zcompare;
00545 }
00546
00547 void LLHUDText::setFont(const LLFontGL* font)
00548 {
00549 mFontp = font;
00550 }
00551
00552
00553 void LLHUDText::setColor(const LLColor4 &color)
00554 {
00555 mColor = color;
00556 for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin();
00557 segment_iter != mTextSegments.end(); ++segment_iter )
00558 {
00559 segment_iter->mColor = color;
00560 }
00561 }
00562
00563 void LLHUDText::setBackgroundColor(const LLColor4 &color)
00564 {
00565 mBackgroundColor = color;
00566 }
00567
00568 void LLHUDText::setUsePixelSize(const BOOL use_pixel_size)
00569 {
00570 mUsePixelSize = use_pixel_size;
00571 }
00572
00573 void LLHUDText::setDoFade(const BOOL do_fade)
00574 {
00575 mDoFade = do_fade;
00576 }
00577
00578 void LLHUDText::updateVisibility()
00579 {
00580 if (mSourceObject)
00581 {
00582 mSourceObject->updateText();
00583 }
00584
00585 mPositionAgent = gAgent.getPosAgentFromGlobal(mPositionGlobal);
00586
00587 if (!mSourceObject)
00588 {
00589
00590 mVisible = TRUE;
00591 if (mOnHUDAttachment)
00592 {
00593 sVisibleHUDTextObjects.push_back(LLPointer<LLHUDText> (this));
00594 }
00595 else
00596 {
00597 sVisibleTextObjects.push_back(LLPointer<LLHUDText> (this));
00598 }
00599 return;
00600 }
00601
00602
00603 if (mSourceObject->isDead())
00604 {
00605 mVisible = FALSE;
00606 return;
00607 }
00608
00609
00610 if (mOnHUDAttachment)
00611 {
00612 mVisible = TRUE;
00613 sVisibleHUDTextObjects.push_back(LLPointer<LLHUDText> (this));
00614 mLastDistance = mPositionAgent.mV[VX];
00615 return;
00616 }
00617
00618
00619 LLVector3 vec_from_camera = mPositionAgent - gCamera->getOrigin();
00620 LLVector3 dir_from_camera = vec_from_camera;
00621 dir_from_camera.normVec();
00622
00623 if (dir_from_camera * gCamera->getAtAxis() <= 0.f)
00624 {
00625 mPositionAgent -= projected_vec(vec_from_camera, gCamera->getAtAxis()) * 1.f;
00626 mPositionAgent += gCamera->getAtAxis() * (gCamera->getNear() + 0.1f);
00627 }
00628 else if (vec_from_camera * gCamera->getAtAxis() <= gCamera->getNear() + 0.1f + mSourceObject->getVObjRadius())
00629 {
00630 mPositionAgent = gCamera->getOrigin() + vec_from_camera * ((gCamera->getNear() + 0.1f) / (vec_from_camera * gCamera->getAtAxis()));
00631 }
00632 else
00633 {
00634 mPositionAgent -= dir_from_camera * mSourceObject->getVObjRadius();
00635 }
00636
00637 mLastDistance = (mPositionAgent - gCamera->getOrigin()).magVec();
00638
00639 if (mLOD >= 3 || !mTextSegments.size() || (mDoFade && (mLastDistance > mFadeDistance + mFadeRange)))
00640 {
00641 mVisible = FALSE;
00642 return;
00643 }
00644
00645 LLVector3 x_pixel_vec;
00646 LLVector3 y_pixel_vec;
00647
00648 gCamera->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
00649
00650 LLVector3 render_position = mPositionAgent +
00651 (x_pixel_vec * mPositionOffset.mV[VX]) +
00652 (y_pixel_vec * mPositionOffset.mV[VY]);
00653
00654 mOffscreen = FALSE;
00655 if (!gCamera->sphereInFrustum(render_position, mRadius))
00656 {
00657 if (!mVisibleOffScreen)
00658 {
00659 mVisible = FALSE;
00660 return;
00661 }
00662 else
00663 {
00664 mOffscreen = TRUE;
00665 }
00666 }
00667
00668 mVisible = TRUE;
00669 sVisibleTextObjects.push_back(LLPointer<LLHUDText> (this));
00670 }
00671
00672 LLVector2 LLHUDText::updateScreenPos(LLVector2 &offset)
00673 {
00674 LLCoordGL screen_pos;
00675 LLVector2 screen_pos_vec;
00676 LLVector3 x_pixel_vec;
00677 LLVector3 y_pixel_vec;
00678 gCamera->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
00679 LLVector3 world_pos = mPositionAgent + (offset.mV[VX] * x_pixel_vec) + (offset.mV[VY] * y_pixel_vec);
00680 if (!gCamera->projectPosAgentToScreen(world_pos, screen_pos, FALSE) && mVisibleOffScreen)
00681 {
00682
00683 LLVector2 window_center(gViewerWindow->getWindowDisplayWidth() * 0.5f, gViewerWindow->getWindowDisplayHeight() * 0.5f);
00684 LLVector2 delta_from_center(screen_pos.mX - window_center.mV[VX],
00685 screen_pos.mY - window_center.mV[VY]);
00686 delta_from_center.normVec();
00687
00688 F32 camera_aspect = gCamera->getAspect();
00689 F32 delta_aspect = llabs(delta_from_center.mV[VX] / delta_from_center.mV[VY]);
00690 if (camera_aspect / llmax(delta_aspect, 0.001f) > 1.f)
00691 {
00692
00693 delta_from_center *= llabs(window_center.mV[VY] / delta_from_center.mV[VY]);
00694 }
00695 else
00696 {
00697
00698 delta_from_center *= llabs(window_center.mV[VX] / delta_from_center.mV[VX]);
00699 }
00700
00701 screen_pos_vec = window_center + delta_from_center;
00702 }
00703 else
00704 {
00705 screen_pos_vec.setVec((F32)screen_pos.mX, (F32)screen_pos.mY);
00706 }
00707 S32 bottom = STATUS_BAR_HEIGHT;
00708 if (gChatBar->getVisible())
00709 {
00710 bottom += CHAT_BAR_HEIGHT;
00711 }
00712
00713 LLVector2 screen_center;
00714 screen_center.mV[VX] = llclamp((F32)screen_pos_vec.mV[VX], mWidth * 0.5f, (F32)gViewerWindow->getWindowDisplayWidth() - mWidth * 0.5f);
00715
00716 if(mVertAlignment == ALIGN_VERT_TOP)
00717 {
00718 screen_center.mV[VY] = llclamp((F32)screen_pos_vec.mV[VY],
00719 (F32)bottom,
00720 (F32)gViewerWindow->getWindowDisplayHeight() - mHeight - (F32)MENU_BAR_HEIGHT);
00721 mSoftScreenRect.setLeftTopAndSize(screen_center.mV[VX] - (mWidth + BUFFER_SIZE) * 0.5f,
00722 screen_center.mV[VY] + (mHeight + BUFFER_SIZE), mWidth + BUFFER_SIZE, mHeight + BUFFER_SIZE);
00723 }
00724 else
00725 {
00726 screen_center.mV[VY] = llclamp((F32)screen_pos_vec.mV[VY],
00727 (F32)bottom + mHeight * 0.5f,
00728 (F32)gViewerWindow->getWindowDisplayHeight() - mHeight * 0.5f - (F32)MENU_BAR_HEIGHT);
00729 mSoftScreenRect.setCenterAndSize(screen_center.mV[VX], screen_center.mV[VY], mWidth + BUFFER_SIZE, mHeight + BUFFER_SIZE);
00730 }
00731
00732 return offset + (screen_center - LLVector2((F32)screen_pos.mX, (F32)screen_pos.mY));
00733 }
00734
00735 void LLHUDText::updateSize()
00736 {
00737 F32 width = 0.f;
00738
00739 S32 max_lines = getMaxLines();
00740 S32 lines = (max_lines < 0) ? (S32)mTextSegments.size() : llmin((S32)mTextSegments.size(), max_lines);
00741
00742 F32 height = (F32)mFontp->getLineHeight() * (lines + mLabelSegments.size());
00743
00744 S32 start_segment;
00745 if (max_lines < 0) start_segment = 0;
00746 else start_segment = llmax((S32)0, (S32)mTextSegments.size() - max_lines);
00747
00748 std::vector<LLHUDTextSegment>::iterator iter = mTextSegments.begin() + start_segment;
00749 while (iter != mTextSegments.end())
00750 {
00751 width = llmax(width, llmin(iter->getWidth(mFontp), HUD_TEXT_MAX_WIDTH));
00752 ++iter;
00753 }
00754
00755 iter = mLabelSegments.begin();
00756 while (iter != mLabelSegments.end())
00757 {
00758 width = llmax(width, llmin(iter->getWidth(mFontp), HUD_TEXT_MAX_WIDTH));
00759 ++iter;
00760 }
00761
00762 if (width == 0.f)
00763 {
00764 return;
00765 }
00766
00767 width += HORIZONTAL_PADDING;
00768 height += VERTICAL_PADDING;
00769
00770 if (!mResizeTimer.getStarted() && (width != mWidth || height != mHeight))
00771 {
00772 mResizeTimer.start();
00773 }
00774
00775
00776 F32 u = 1.f;
00777 if (u == 1.f)
00778 {
00779 mResizeTimer.stop();
00780 }
00781
00782 mWidth = llmax(width, lerp(mWidth, (F32)width, u));
00783 mHeight = llmax(height, lerp(mHeight, (F32)height, u));
00784 }
00785
00786 void LLHUDText::updateAll()
00787 {
00788
00789
00790 sVisibleTextObjects.clear();
00791 sVisibleHUDTextObjects.clear();
00792
00793 TextObjectIterator text_it;
00794 for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it)
00795 {
00796 LLHUDText* textp = (*text_it);
00797 textp->mTargetPositionOffset.clearVec();
00798 textp->updateSize();
00799 textp->updateVisibility();
00800 }
00801
00802
00803 std::sort(sVisibleTextObjects.begin(), sVisibleTextObjects.end(), lltextobject_further_away());
00804 std::sort(sVisibleHUDTextObjects.begin(), sVisibleHUDTextObjects.end(), lltextobject_further_away());
00805
00806
00807 F32 screen_area = (F32)(gViewerWindow->getWindowWidth() * gViewerWindow->getWindowHeight());
00808 F32 current_screen_area = 0.f;
00809 std::vector<LLPointer<LLHUDText> >::reverse_iterator r_it;
00810 for (r_it = sVisibleTextObjects.rbegin(); r_it != sVisibleTextObjects.rend(); ++r_it)
00811 {
00812 LLHUDText* textp = (*r_it);
00813 if (textp->mUseBubble)
00814 {
00815 if (current_screen_area / screen_area > LOD_2_SCREEN_COVERAGE)
00816 {
00817 textp->setLOD(3);
00818 }
00819 else if (current_screen_area / screen_area > LOD_1_SCREEN_COVERAGE)
00820 {
00821 textp->setLOD(2);
00822 }
00823 else if (current_screen_area / screen_area > LOD_0_SCREEN_COVERAGE)
00824 {
00825 textp->setLOD(1);
00826 }
00827 else
00828 {
00829 textp->setLOD(0);
00830 }
00831 textp->updateSize();
00832
00833 textp->mTargetPositionOffset = textp->updateScreenPos(LLVector2::zero);
00834 current_screen_area += (F32)(textp->mSoftScreenRect.getWidth() * textp->mSoftScreenRect.getHeight());
00835 }
00836 }
00837
00838 LLStat* camera_vel_stat = gCamera->getVelocityStat();
00839 F32 camera_vel = camera_vel_stat->getCurrent();
00840 if (camera_vel > MAX_STABLE_CAMERA_VELOCITY)
00841 {
00842 return;
00843 }
00844
00845 VisibleTextObjectIterator src_it;
00846
00847 for (S32 i = 0; i < NUM_OVERLAP_ITERATIONS; i++)
00848 {
00849 for (src_it = sVisibleTextObjects.begin(); src_it != sVisibleTextObjects.end(); ++src_it)
00850 {
00851 LLHUDText* src_textp = (*src_it);
00852
00853 if (!src_textp->mUseBubble)
00854 {
00855 continue;
00856 }
00857 VisibleTextObjectIterator dst_it = src_it;
00858 ++dst_it;
00859 for (; dst_it != sVisibleTextObjects.end(); ++dst_it)
00860 {
00861 LLHUDText* dst_textp = (*dst_it);
00862
00863 if (!dst_textp->mUseBubble)
00864 {
00865 continue;
00866 }
00867 if (src_textp->mSoftScreenRect.rectInRect(&dst_textp->mSoftScreenRect))
00868 {
00869 LLRectf intersect_rect = src_textp->mSoftScreenRect;
00870 intersect_rect.intersectWith(dst_textp->mSoftScreenRect);
00871 intersect_rect.stretch(-BUFFER_SIZE * 0.5f);
00872
00873 F32 src_center_x = src_textp->mSoftScreenRect.getCenterX();
00874 F32 src_center_y = src_textp->mSoftScreenRect.getCenterY();
00875 F32 dst_center_x = dst_textp->mSoftScreenRect.getCenterX();
00876 F32 dst_center_y = dst_textp->mSoftScreenRect.getCenterY();
00877 F32 intersect_center_x = intersect_rect.getCenterX();
00878 F32 intersect_center_y = intersect_rect.getCenterY();
00879 LLVector2 force = lerp(LLVector2(dst_center_x - intersect_center_x, dst_center_y - intersect_center_y),
00880 LLVector2(intersect_center_x - src_center_x, intersect_center_y - src_center_y),
00881 0.5f);
00882 force.setVec(dst_center_x - src_center_x, dst_center_y - src_center_y);
00883 force.normVec();
00884
00885 LLVector2 src_force = -1.f * force;
00886 LLVector2 dst_force = force;
00887
00888 LLVector2 force_strength;
00889 F32 src_mult = dst_textp->mMass / (dst_textp->mMass + src_textp->mMass);
00890 F32 dst_mult = 1.f - src_mult;
00891 F32 src_aspect_ratio = src_textp->mSoftScreenRect.getWidth() / src_textp->mSoftScreenRect.getHeight();
00892 F32 dst_aspect_ratio = dst_textp->mSoftScreenRect.getWidth() / dst_textp->mSoftScreenRect.getHeight();
00893 src_force.mV[VY] *= src_aspect_ratio;
00894 src_force.normVec();
00895 dst_force.mV[VY] *= dst_aspect_ratio;
00896 dst_force.normVec();
00897
00898 src_force.mV[VX] *= llmin(intersect_rect.getWidth() * src_mult, intersect_rect.getHeight() * SPRING_STRENGTH);
00899 src_force.mV[VY] *= llmin(intersect_rect.getHeight() * src_mult, intersect_rect.getWidth() * SPRING_STRENGTH);
00900 dst_force.mV[VX] *= llmin(intersect_rect.getWidth() * dst_mult, intersect_rect.getHeight() * SPRING_STRENGTH);
00901 dst_force.mV[VY] *= llmin(intersect_rect.getHeight() * dst_mult, intersect_rect.getWidth() * SPRING_STRENGTH);
00902
00903 src_textp->mTargetPositionOffset += src_force;
00904 dst_textp->mTargetPositionOffset += dst_force;
00905 src_textp->mTargetPositionOffset = src_textp->updateScreenPos(src_textp->mTargetPositionOffset);
00906 dst_textp->mTargetPositionOffset = dst_textp->updateScreenPos(dst_textp->mTargetPositionOffset);
00907 }
00908 }
00909 }
00910 }
00911
00912 VisibleTextObjectIterator this_object_it;
00913 for (this_object_it = sVisibleTextObjects.begin(); this_object_it != sVisibleTextObjects.end(); ++this_object_it)
00914 {
00915 if (!(*this_object_it)->mUseBubble)
00916 {
00917 continue;
00918 }
00919 (*this_object_it)->mPositionOffset = lerp((*this_object_it)->mPositionOffset, (*this_object_it)->mTargetPositionOffset, LLCriticalDamp::getInterpolant(POSITION_DAMPING_TC));
00920 }
00921 }
00922
00923 void LLHUDText::setLOD(S32 lod)
00924 {
00925 mLOD = lod;
00926
00927
00928
00929
00930 }
00931
00932 S32 LLHUDText::getMaxLines()
00933 {
00934 switch(mLOD)
00935 {
00936 case 0:
00937 return mMaxLines;
00938 case 1:
00939 return mMaxLines > 0 ? mMaxLines / 2 : 5;
00940 case 2:
00941 return mMaxLines > 0 ? mMaxLines / 3 : 2;
00942 default:
00943
00944 return 0;
00945 }
00946 }
00947
00948 void LLHUDText::markDead()
00949 {
00950 sTextObjects.erase(LLPointer<LLHUDText>(this));
00951 LLHUDObject::markDead();
00952 }
00953
00954 void LLHUDText::renderAllHUD()
00955 {
00956 LLGLEnable color_mat(GL_COLOR_MATERIAL);
00957 LLGLDepthTest depth(GL_FALSE, GL_FALSE);
00958
00959 VisibleTextObjectIterator text_it;
00960
00961 for (text_it = sVisibleHUDTextObjects.begin(); text_it != sVisibleHUDTextObjects.end(); ++text_it)
00962 {
00963 (*text_it)->renderText(FALSE);
00964 }
00965 }
00966
00967
00968 void LLHUDText::addPickable(std::set<LLViewerObject*> &pick_list)
00969 {
00970
00971
00972 VisibleTextObjectIterator text_it;
00973 for (text_it = sVisibleTextObjects.begin(); text_it != sVisibleTextObjects.end(); ++text_it)
00974 {
00975 if (!(*text_it)->mUseBubble)
00976 {
00977 continue;
00978 }
00979 pick_list.insert((*text_it)->mSourceObject);
00980 }
00981 }
00982
00983
00984
00985 void LLHUDText::reshape()
00986 {
00987 TextObjectIterator text_it;
00988 for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it)
00989 {
00990 LLHUDText* textp = (*text_it);
00991 std::vector<LLHUDTextSegment>::iterator segment_iter;
00992 for (segment_iter = textp->mTextSegments.begin();
00993 segment_iter != textp->mTextSegments.end(); ++segment_iter )
00994 {
00995 segment_iter->clearFontWidthMap();
00996 }
00997 for(segment_iter = textp->mLabelSegments.begin();
00998 segment_iter != textp->mLabelSegments.end(); ++segment_iter )
00999 {
01000 segment_iter->clearFontWidthMap();
01001 }
01002 }
01003 }
01004
01005
01006
01007 F32 LLHUDText::LLHUDTextSegment::getWidth(const LLFontGL* font)
01008 {
01009 std::map<const LLFontGL*, F32>::iterator iter = mFontWidthMap.find(font);
01010 if (iter != mFontWidthMap.end())
01011 {
01012 return iter->second;
01013 }
01014 else
01015 {
01016 F32 width = font->getWidthF32(mText.c_str());
01017 mFontWidthMap[font] = width;
01018 return width;
01019 }
01020 }