llhudtext.cpp

Go to the documentation of this file.
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         //LLDebugVarMessageBox::show("max width", &HUD_TEXT_MAX_WIDTH, 500.f, 1.f);
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         // don't pick text that isn't bound to a viewerobject or isn't in a bubble
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         // *TODO: cache this image
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         // *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                 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         //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 = gCamera->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                                 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                         // draw line segments pointing to parent object
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                                                 // 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                                                         glVertex3fv(vert.mV);
00331                                                 }
00332                                                 else
00333                                                 {
00334                                                         // start at left edge
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                                                 // 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                                                         glVertex3fv(vert.mV);
00354                                                 }
00355                                                 else
00356                                                 {
00357                                                         // start at bottom edge
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         // 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         }
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                 //llwarns << "LLHUDText::updateScreenPos -- mSourceObject is NULL!" << llendl;
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         // Not visible if parent object is dead
00603         if (mSourceObject->isDead())
00604         {
00605                 mVisible = FALSE;
00606                 return;
00607         }
00608 
00609         // for now, all text on hud objects is visible
00610         if (mOnHUDAttachment)
00611         {
00612                 mVisible = TRUE;
00613                 sVisibleHUDTextObjects.push_back(LLPointer<LLHUDText> (this));
00614                 mLastDistance = mPositionAgent.mV[VX];
00615                 return;
00616         }
00617 
00618         // push text towards camera by radius of object, but not past camera
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                 // bubble off-screen, so find a spot for it along screen edge
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                         // camera has wider aspect ratio than offset vector, so clamp to height
00693                         delta_from_center *= llabs(window_center.mV[VY] / delta_from_center.mV[VY]);
00694                 }
00695                 else
00696                 {
00697                         // camera has narrower aspect ratio than offset vector, so clamp to width
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         // *NOTE: removed logic which did a divide by zero.
00776         F32 u = 1.f;//llclamp(mResizeTimer.getElapsedTimeF32() / RESIZE_TIME, 0.f, 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         // iterate over all text objects, calculate their restoration forces,
00789         // and add them to the visible set if they are on screen and close enough
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         // sort back to front for rendering purposes
00803         std::sort(sVisibleTextObjects.begin(), sVisibleTextObjects.end(), lltextobject_further_away());
00804         std::sort(sVisibleHUDTextObjects.begin(), sVisibleHUDTextObjects.end(), lltextobject_further_away());
00805 
00806         // iterate from front to back, and set LOD based on current screen coverage
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                         // find on-screen position and initialize collision rectangle
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         //RN: uncomment this to visualize LOD levels
00927         //char label[255];
00928         //sprintf(label, "%d", lod);
00929         //setLabel(label);
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                 // label only
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 //static 
00968 void LLHUDText::addPickable(std::set<LLViewerObject*> &pick_list)
00969 {
00970         //this might put an object on the pick list a second time, overriding it's mGLName, which is ok
00971         // *FIX: we should probably cull against pick frustum
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 //static
00984 // called when UI scale changes, to flush font width caches
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 }

Generated on Thu Jul 1 06:08:43 2010 for Second Life Viewer by  doxygen 1.4.7