llhudtext.cpp

Go to the documentation of this file.
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         //LLDebugVarMessageBox::show("max width", &HUD_TEXT_MAX_WIDTH, 500.f, 1.f);
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         // don't pick text that isn't bound to a viewerobject or isn't in a bubble
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         // *TODO: cache this image
00178         LLUIImagePtr imagep = LLUI::getUIImage("rounded_square.tga");
00179 
00180         // *TODO: make this a per-text setting
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         // *TODO move this into helper function
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         // scale screen size of borders down
00200         //RN: for now, text on hud objects is never occluded
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         //if (mOnHUD)
00241         //{
00242         //      render_position.mV[VY] -= fmodf(render_position.mV[VY], 1.f / (F32)gViewerWindow->getWindowWidth());
00243         //      render_position.mV[VZ] -= fmodf(render_position.mV[VZ], 1.f / (F32)gViewerWindow->getWindowHeight());
00244         //}
00245         //else
00246         //{
00247         //      render_position = LLViewerCamera::getInstance()->roundToPixel(render_position);
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                         // draw line segments pointing to parent object
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                                                 // draw line in x then y
00326                                                 if (mPositionOffset.mV[VX] < 0.f)
00327                                                 {
00328                                                         // start at right edge
00329                                                         vert = width_vec * 0.5f;
00330                                                         gGL.vertex3fv(vert.mV);
00331                                                 }
00332                                                 else
00333                                                 {
00334                                                         // start at left edge
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                                                 // draw line in y then x
00349                                                 if (mPositionOffset.mV[VY] < 0.f)
00350                                                 {
00351                                                         // start at top edge
00352                                                         vert = (height_vec * 0.5f) - (mPositionOffset.mV[VX] * x_pixel_vec);
00353                                                         gGL.vertex3fv(vert.mV);
00354                                                 }
00355                                                 else
00356                                                 {
00357                                                         // start at bottom edge
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         // Render label
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 // ALIGN_LEFT
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         // Render text
00403         {
00404                 // -1 mMaxLines means unlimited lines.
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 // ALIGN_LEFT
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                 //llwarns << "LLHUDText::updateScreenPos -- mSourceObject is NULL!" << llendl;
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         // Not visible if parent object is dead
00601         if (mSourceObject->isDead())
00602         {
00603                 mVisible = FALSE;
00604                 return;
00605         }
00606 
00607         // for now, all text on hud objects is visible
00608         if (mOnHUDAttachment)
00609         {
00610                 mVisible = TRUE;
00611                 sVisibleHUDTextObjects.push_back(LLPointer<LLHUDText> (this));
00612                 mLastDistance = mPositionAgent.mV[VX];
00613                 return;
00614         }
00615 
00616         // push text towards camera by radius of object, but not past camera
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                 // bubble off-screen, so find a spot for it along screen edge
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                         // camera has wider aspect ratio than offset vector, so clamp to height
00691                         delta_from_center *= llabs(window_center.mV[VY] / delta_from_center.mV[VY]);
00692                 }
00693                 else
00694                 {
00695                         // camera has narrower aspect ratio than offset vector, so clamp to width
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         // *NOTE: removed logic which did a divide by zero.
00774         F32 u = 1.f;//llclamp(mResizeTimer.getElapsedTimeF32() / RESIZE_TIME, 0.f, 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         // iterate over all text objects, calculate their restoration forces,
00787         // and add them to the visible set if they are on screen and close enough
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         // sort back to front for rendering purposes
00801         std::sort(sVisibleTextObjects.begin(), sVisibleTextObjects.end(), lltextobject_further_away());
00802         std::sort(sVisibleHUDTextObjects.begin(), sVisibleHUDTextObjects.end(), lltextobject_further_away());
00803 
00804         // iterate from front to back, and set LOD based on current screen coverage
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                         // find on-screen position and initialize collision rectangle
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         //RN: uncomment this to visualize LOD levels
00925         //char label[255];
00926         //sprintf(label, "%d", lod);
00927         //setLabel(label);
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                 // label only
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 //static 
00966 void LLHUDText::addPickable(std::set<LLViewerObject*> &pick_list)
00967 {
00968         //this might put an object on the pick list a second time, overriding it's mGLName, which is ok
00969         // *FIX: we should probably cull against pick frustum
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 //static
00982 // called when UI scale changes, to flush font width caches
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 }

Generated on Fri May 16 08:33:40 2008 for SecondLife by  doxygen 1.5.5