diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/llhudtext.cpp | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
Diffstat (limited to 'indra/newview/llhudtext.cpp')
-rw-r--r-- | indra/newview/llhudtext.cpp | 1278 |
1 files changed, 639 insertions, 639 deletions
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index 8bbed4fc6d..6e8b7875c8 100644 --- a/indra/newview/llhudtext.cpp +++ b/indra/newview/llhudtext.cpp @@ -1,639 +1,639 @@ -/** - * @file llhudtext.cpp - * @brief Floating text above objects, set via script with llSetText() - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llhudtext.h" - -#include "llrender.h" - -#include "llagent.h" -#include "llviewercontrol.h" -#include "llcriticaldamp.h" -#include "lldrawable.h" -#include "llfontgl.h" -#include "llglheaders.h" -#include "llhudrender.h" -#include "llui.h" -#include "llviewercamera.h" -#include "llviewertexturelist.h" -#include "llviewerobject.h" -#include "llvovolume.h" -#include "llviewerwindow.h" -#include "llstatusbar.h" -#include "llmenugl.h" -#include "pipeline.h" -#include <boost/tokenizer.hpp> - -const F32 HORIZONTAL_PADDING = 15.f; -const F32 VERTICAL_PADDING = 12.f; -const F32 BUFFER_SIZE = 2.f; -const F32 HUD_TEXT_MAX_WIDTH = 190.f; -const F32 HUD_TEXT_MAX_WIDTH_NO_BUBBLE = 1000.f; -const F32 MAX_DRAW_DISTANCE = 300.f; - -std::set<LLPointer<LLHUDText> > LLHUDText::sTextObjects; -std::vector<LLPointer<LLHUDText> > LLHUDText::sVisibleTextObjects; -std::vector<LLPointer<LLHUDText> > LLHUDText::sVisibleHUDTextObjects; -bool LLHUDText::sDisplayText = true ; - -bool lltextobject_further_away::operator()(const LLPointer<LLHUDText>& lhs, const LLPointer<LLHUDText>& rhs) const -{ - return lhs->getDistance() > rhs->getDistance(); -} - - -LLHUDText::LLHUDText(const U8 type) : - LLHUDObject(type), - mOnHUDAttachment(false), -// mVisibleOffScreen(false), - mWidth(0.f), - mHeight(0.f), - mFontp(LLFontGL::getFontSansSerifSmall()), - mBoldFontp(LLFontGL::getFontSansSerifBold()), - mMass(1.f), - mMaxLines(10), - mOffsetY(0), - mTextAlignment(ALIGN_TEXT_CENTER), - mVertAlignment(ALIGN_VERT_CENTER), -// mLOD(0), - mHidden(false) -{ - mColor = LLColor4(1.f, 1.f, 1.f, 1.f); - mDoFade = true; - mFadeDistance = 8.f; - mFadeRange = 4.f; - mZCompare = true; - mOffscreen = false; - mRadius = 0.1f; - LLPointer<LLHUDText> ptr(this); - sTextObjects.insert(ptr); -} - -LLHUDText::~LLHUDText() -{ -} - -void LLHUDText::render() -{ - if (!mOnHUDAttachment && sDisplayText) - { - LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - //LLGLDisable gls_stencil(GL_STENCIL_TEST); - renderText(); - } -} - -void LLHUDText::renderText() -{ - if (!mVisible || mHidden) - { - return; - } - - gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); - - LLGLState gls_blend(GL_BLEND, true); - - LLColor4 shadow_color(0.f, 0.f, 0.f, 1.f); - F32 alpha_factor = 1.f; - LLColor4 text_color = mColor; - if (mDoFade) - { - if (mLastDistance > mFadeDistance) - { - alpha_factor = llmax(0.f, 1.f - (mLastDistance - mFadeDistance)/mFadeRange); - text_color.mV[3] = text_color.mV[3]*alpha_factor; - } - } - if (text_color.mV[3] < 0.01f) - { - return; - } - shadow_color.mV[3] = text_color.mV[3]; - - mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f)); - - // *TODO: make this a per-text setting - LLColor4 bg_color = LLUIColorTable::instance().getColor("ObjectBubbleColor"); - bg_color.setAlpha(gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor); - - const S32 border_height = 16; - const S32 border_width = 16; - - // *TODO move this into helper function - F32 border_scale = 1.f; - - if (border_height * 2 > mHeight) - { - border_scale = (F32)mHeight / ((F32)border_height * 2.f); - } - if (border_width * 2 > mWidth) - { - border_scale = llmin(border_scale, (F32)mWidth / ((F32)border_width * 2.f)); - } - - // scale screen size of borders down - //RN: for now, text on hud objects is never occluded - - LLVector3 x_pixel_vec; - LLVector3 y_pixel_vec; - - if (mOnHUDAttachment) - { - x_pixel_vec = LLVector3::y_axis / (F32)gViewerWindow->getWorldViewWidthRaw(); - y_pixel_vec = LLVector3::z_axis / (F32)gViewerWindow->getWorldViewHeightRaw(); - } - else - { - LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec); - } - - LLVector3 width_vec = mWidth * x_pixel_vec; - LLVector3 height_vec = mHeight * y_pixel_vec; - - mRadius = (width_vec + height_vec).magVec() * 0.5f; - - LLVector2 screen_offset; - screen_offset = mPositionOffset; - - LLVector3 render_position = mPositionAgent - + (x_pixel_vec * screen_offset.mV[VX]) - + (y_pixel_vec * screen_offset.mV[VY]); - - F32 y_offset = (F32)mOffsetY; - - // Render label - - // Render text - { - // -1 mMaxLines means unlimited lines. - S32 start_segment; - S32 max_lines = getMaxLines(); - - if (max_lines < 0) - { - start_segment = 0; - } - else - { - start_segment = llmax((S32)0, (S32)mTextSegments.size() - max_lines); - } - - for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin() + start_segment; - segment_iter != mTextSegments.end(); ++segment_iter ) - { - const LLFontGL* fontp = segment_iter->mFont; - y_offset -= fontp->getLineHeight() - 1; // correction factor to match legacy font metrics - - U8 style = segment_iter->mStyle; - LLFontGL::ShadowType shadow = LLFontGL::DROP_SHADOW; - - F32 x_offset; - if (mTextAlignment== ALIGN_TEXT_CENTER) - { - x_offset = -0.5f*segment_iter->getWidth(fontp); - } - else // ALIGN_LEFT - { - x_offset = -0.5f * mWidth + (HORIZONTAL_PADDING / 2.f); - } - - text_color = segment_iter->mColor; - if (mOnHUDAttachment) - { - text_color = linearColor4(text_color); - } - text_color.mV[VALPHA] *= alpha_factor; - - hud_render_text(segment_iter->getText(), render_position, *fontp, style, shadow, x_offset, y_offset, text_color, mOnHUDAttachment); - } - } - /// Reset the default color to white. The renderer expects this to be the default. - gGL.color4f(1.0f, 1.0f, 1.0f, 1.0f); -} - -void LLHUDText::setString(const std::string &text_utf8) -{ - mTextSegments.clear(); - addLine(text_utf8, mColor); -} - -void LLHUDText::clearString() -{ - mTextSegments.clear(); -} - - -void LLHUDText::addLine(const std::string &text_utf8, - const LLColor4& color, - const LLFontGL::StyleFlags style, - const LLFontGL* font) -{ - LLWString wline = utf8str_to_wstring(text_utf8); - if (!wline.empty()) - { - // use default font for segment if custom font not specified - if (!font) - { - font = mFontp; - } - typedef boost::tokenizer<boost::char_separator<llwchar>, LLWString::const_iterator, LLWString > tokenizer; - LLWString seps(utf8str_to_wstring("\r\n")); - boost::char_separator<llwchar> sep(seps.c_str()); - - tokenizer tokens(wline, sep); - tokenizer::iterator iter = tokens.begin(); - - while (iter != tokens.end()) - { - U32 line_length = 0; - do - { - F32 max_pixels = HUD_TEXT_MAX_WIDTH_NO_BUBBLE; - S32 segment_length = font->maxDrawableChars(iter->substr(line_length).c_str(), max_pixels, wline.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE); - LLHUDTextSegment segment(iter->substr(line_length, segment_length), style, color, font); - mTextSegments.push_back(segment); - line_length += segment_length; - } - while (line_length != iter->size()); - ++iter; - } - } -} - -void LLHUDText::setZCompare(const bool zcompare) -{ - mZCompare = zcompare; -} - -void LLHUDText::setFont(const LLFontGL* font) -{ - mFontp = font; -} - - -void LLHUDText::setColor(const LLColor4 &color) -{ - mColor = color; - for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin(); - segment_iter != mTextSegments.end(); ++segment_iter ) - { - segment_iter->mColor = color; - } -} - -void LLHUDText::setAlpha(F32 alpha) -{ - mColor.mV[VALPHA] = alpha; - for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin(); - segment_iter != mTextSegments.end(); ++segment_iter ) - { - segment_iter->mColor.mV[VALPHA] = alpha; - } -} - - -void LLHUDText::setDoFade(const bool do_fade) -{ - mDoFade = do_fade; -} - -void LLHUDText::updateVisibility() -{ - if (mSourceObject) - { - mSourceObject->updateText(); - } - - mPositionAgent = gAgent.getPosAgentFromGlobal(mPositionGlobal); - - if (!mSourceObject) - { - // Beacons - mVisible = true; - if (mOnHUDAttachment) - { - sVisibleHUDTextObjects.push_back(LLPointer<LLHUDText> (this)); - } - else - { - sVisibleTextObjects.push_back(LLPointer<LLHUDText> (this)); - } - return; - } - - // Not visible if parent object is dead - if (mSourceObject->isDead()) - { - mVisible = false; - return; - } - - // for now, all text on hud objects is visible - if (mOnHUDAttachment) - { - mVisible = true; - sVisibleHUDTextObjects.push_back(LLPointer<LLHUDText> (this)); - mLastDistance = mPositionAgent.mV[VX]; - return; - } - - // push text towards camera by radius of object, but not past camera - LLVector3 vec_from_camera = mPositionAgent - LLViewerCamera::getInstance()->getOrigin(); - LLVector3 dir_from_camera = vec_from_camera; - dir_from_camera.normVec(); - - if (dir_from_camera * LLViewerCamera::getInstance()->getAtAxis() <= 0.f) - { //text is behind camera, don't render - mVisible = false; - return; - } - - if (vec_from_camera * LLViewerCamera::getInstance()->getAtAxis() <= LLViewerCamera::getInstance()->getNear() + 0.1f + mSourceObject->getVObjRadius()) - { - mPositionAgent = LLViewerCamera::getInstance()->getOrigin() + vec_from_camera * ((LLViewerCamera::getInstance()->getNear() + 0.1f) / (vec_from_camera * LLViewerCamera::getInstance()->getAtAxis())); - } - else - { - mPositionAgent -= dir_from_camera * mSourceObject->getVObjRadius(); - } - - mLastDistance = (mPositionAgent - LLViewerCamera::getInstance()->getOrigin()).magVec(); - - if (!mTextSegments.size() || (mDoFade && (mLastDistance > mFadeDistance + mFadeRange))) - { - mVisible = false; - return; - } - - LLVector3 pos_agent_center = gAgent.getPosAgentFromGlobal(mPositionGlobal) - dir_from_camera; - F32 last_distance_center = (pos_agent_center - LLViewerCamera::getInstance()->getOrigin()).magVec(); - F32 max_draw_distance = gSavedSettings.getF32("PrimTextMaxDrawDistance"); - - if(max_draw_distance < 0) - { - max_draw_distance = 0; - gSavedSettings.setF32("PrimTextMaxDrawDistance", max_draw_distance); - } - else if(max_draw_distance > MAX_DRAW_DISTANCE) - { - max_draw_distance = MAX_DRAW_DISTANCE; - gSavedSettings.setF32("PrimTextMaxDrawDistance", MAX_DRAW_DISTANCE); - } - - if(last_distance_center > max_draw_distance) - { - mVisible = false; - return; - } - - - LLVector3 x_pixel_vec; - LLVector3 y_pixel_vec; - - LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec); - - LLVector3 render_position = mPositionAgent + - (x_pixel_vec * mPositionOffset.mV[VX]) + - (y_pixel_vec * mPositionOffset.mV[VY]); - - mOffscreen = false; - if (!LLViewerCamera::getInstance()->sphereInFrustum(render_position, mRadius)) - { -// if (!mVisibleOffScreen) -// { - mVisible = false; - return; -// } -// else -// { -// mOffscreen = true; -// } - } - - mVisible = true; - sVisibleTextObjects.push_back(LLPointer<LLHUDText> (this)); -} - -LLVector2 LLHUDText::updateScreenPos(LLVector2 &offset) -{ - LLCoordGL screen_pos; - LLVector2 screen_pos_vec; - LLVector3 x_pixel_vec; - LLVector3 y_pixel_vec; - LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec); -// LLVector3 world_pos = mPositionAgent + (offset.mV[VX] * x_pixel_vec) + (offset.mV[VY] * y_pixel_vec); -// if (!LLViewerCamera::getInstance()->projectPosAgentToScreen(world_pos, screen_pos, false) && mVisibleOffScreen) -// { -// // bubble off-screen, so find a spot for it along screen edge -// LLViewerCamera::getInstance()->projectPosAgentToScreenEdge(world_pos, screen_pos); -// } - - screen_pos_vec.setVec((F32)screen_pos.mX, (F32)screen_pos.mY); - - LLRect world_rect = gViewerWindow->getWorldViewRectScaled(); - S32 bottom = world_rect.mBottom + STATUS_BAR_HEIGHT; - - LLVector2 screen_center; - screen_center.mV[VX] = llclamp((F32)screen_pos_vec.mV[VX], (F32)world_rect.mLeft + mWidth * 0.5f, (F32)world_rect.mRight - mWidth * 0.5f); - - if(mVertAlignment == ALIGN_VERT_TOP) - { - screen_center.mV[VY] = llclamp((F32)screen_pos_vec.mV[VY], - (F32)bottom, - (F32)world_rect.mTop - mHeight - (F32)MENU_BAR_HEIGHT); - mSoftScreenRect.setLeftTopAndSize(screen_center.mV[VX] - (mWidth + BUFFER_SIZE) * 0.5f, - screen_center.mV[VY] + (mHeight + BUFFER_SIZE), mWidth + BUFFER_SIZE, mHeight + BUFFER_SIZE); - } - else - { - screen_center.mV[VY] = llclamp((F32)screen_pos_vec.mV[VY], - (F32)bottom + mHeight * 0.5f, - (F32)world_rect.mTop - mHeight * 0.5f - (F32)MENU_BAR_HEIGHT); - mSoftScreenRect.setCenterAndSize(screen_center.mV[VX], screen_center.mV[VY], mWidth + BUFFER_SIZE, mHeight + BUFFER_SIZE); - } - - return offset + (screen_center - LLVector2((F32)screen_pos.mX, (F32)screen_pos.mY)); -} - -void LLHUDText::updateSize() -{ - F32 height = 0.f; - F32 width = 0.f; - - S32 max_lines = getMaxLines(); - - S32 start_segment; - if (max_lines < 0) start_segment = 0; - else start_segment = llmax((S32)0, (S32)mTextSegments.size() - max_lines); - - std::vector<LLHUDTextSegment>::iterator iter = mTextSegments.begin() + start_segment; - while (iter != mTextSegments.end()) - { - const LLFontGL* fontp = iter->mFont; - height += fontp->getLineHeight() - 1; // correction factor to match legacy font metrics - width = llmax(width, llmin(iter->getWidth(fontp), HUD_TEXT_MAX_WIDTH)); - ++iter; - } - - if (width == 0.f) - { - return; - } - - width += HORIZONTAL_PADDING; - height += VERTICAL_PADDING; - - // *TODO: Could do some sort of timer-based resize logic here - F32 u = 1.f; - mWidth = llmax(width, lerp(mWidth, (F32)width, u)); - mHeight = llmax(height, lerp(mHeight, (F32)height, u)); -} - -void LLHUDText::updateAll() -{ - // iterate over all text objects, calculate their restoration forces, - // and add them to the visible set if they are on screen and close enough - sVisibleTextObjects.clear(); - sVisibleHUDTextObjects.clear(); - - TextObjectIterator text_it; - for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it) - { - LLHUDText* textp = (*text_it); - textp->mTargetPositionOffset.clearVec(); - textp->updateSize(); - textp->updateVisibility(); - } - - // sort back to front for rendering purposes - std::sort(sVisibleTextObjects.begin(), sVisibleTextObjects.end(), lltextobject_further_away()); - std::sort(sVisibleHUDTextObjects.begin(), sVisibleHUDTextObjects.end(), lltextobject_further_away()); -} - -//void LLHUDText::setLOD(S32 lod) -//{ -// mLOD = lod; -// //RN: uncomment this to visualize LOD levels -// //std::string label = llformat("%d", lod); -// //setLabel(label); -//} - -S32 LLHUDText::getMaxLines() -{ - return mMaxLines; - //switch(mLOD) - //{ - //case 0: - // return mMaxLines; - //case 1: - // return mMaxLines > 0 ? mMaxLines / 2 : 5; - //case 2: - // return mMaxLines > 0 ? mMaxLines / 3 : 2; - //default: - // // label only - // return 0; - //} -} - -void LLHUDText::markDead() -{ - // make sure we have at least one pointer - // till the end of the function - LLPointer<LLHUDText> ptr(this); - sTextObjects.erase(ptr); - LLHUDObject::markDead(); -} - -void LLHUDText::renderAllHUD() -{ - LLGLState::checkStates(); - - { - LLGLDepthTest depth(GL_FALSE, GL_FALSE); - - VisibleTextObjectIterator text_it; - - for (text_it = sVisibleHUDTextObjects.begin(); text_it != sVisibleHUDTextObjects.end(); ++text_it) - { - (*text_it)->renderText(); - } - } - - LLVertexBuffer::unbind(); - - LLGLState::checkStates(); -} - -void LLHUDText::shiftAll(const LLVector3& offset) -{ - TextObjectIterator text_it; - for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it) - { - LLHUDText *textp = text_it->get(); - textp->shift(offset); - } -} - -void LLHUDText::shift(const LLVector3& offset) -{ - mPositionAgent += offset; -} - -//static -// called when UI scale changes, to flush font width caches -void LLHUDText::reshape() -{ - TextObjectIterator text_it; - for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it) - { - LLHUDText* textp = (*text_it); - std::vector<LLHUDTextSegment>::iterator segment_iter; - for (segment_iter = textp->mTextSegments.begin(); - segment_iter != textp->mTextSegments.end(); ++segment_iter ) - { - segment_iter->clearFontWidthMap(); - } - } -} - -//============================================================================ - -F32 LLHUDText::LLHUDTextSegment::getWidth(const LLFontGL* font) -{ - std::map<const LLFontGL*, F32>::iterator iter = mFontWidthMap.find(font); - if (iter != mFontWidthMap.end()) - { - return iter->second; - } - else - { - F32 width = font->getWidthF32(mText.c_str()); - mFontWidthMap[font] = width; - return width; - } -} +/**
+ * @file llhudtext.cpp
+ * @brief Floating text above objects, set via script with llSetText()
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llhudtext.h"
+
+#include "llrender.h"
+
+#include "llagent.h"
+#include "llviewercontrol.h"
+#include "llcriticaldamp.h"
+#include "lldrawable.h"
+#include "llfontgl.h"
+#include "llglheaders.h"
+#include "llhudrender.h"
+#include "llui.h"
+#include "llviewercamera.h"
+#include "llviewertexturelist.h"
+#include "llviewerobject.h"
+#include "llvovolume.h"
+#include "llviewerwindow.h"
+#include "llstatusbar.h"
+#include "llmenugl.h"
+#include "pipeline.h"
+#include <boost/tokenizer.hpp>
+
+const F32 HORIZONTAL_PADDING = 15.f;
+const F32 VERTICAL_PADDING = 12.f;
+const F32 BUFFER_SIZE = 2.f;
+const F32 HUD_TEXT_MAX_WIDTH = 190.f;
+const F32 HUD_TEXT_MAX_WIDTH_NO_BUBBLE = 1000.f;
+const F32 MAX_DRAW_DISTANCE = 300.f;
+
+std::set<LLPointer<LLHUDText> > LLHUDText::sTextObjects;
+std::vector<LLPointer<LLHUDText> > LLHUDText::sVisibleTextObjects;
+std::vector<LLPointer<LLHUDText> > LLHUDText::sVisibleHUDTextObjects;
+bool LLHUDText::sDisplayText = true ;
+
+bool lltextobject_further_away::operator()(const LLPointer<LLHUDText>& lhs, const LLPointer<LLHUDText>& rhs) const
+{
+ return lhs->getDistance() > rhs->getDistance();
+}
+
+
+LLHUDText::LLHUDText(const U8 type) :
+ LLHUDObject(type),
+ mOnHUDAttachment(false),
+// mVisibleOffScreen(false),
+ mWidth(0.f),
+ mHeight(0.f),
+ mFontp(LLFontGL::getFontSansSerifSmall()),
+ mBoldFontp(LLFontGL::getFontSansSerifBold()),
+ mMass(1.f),
+ mMaxLines(10),
+ mOffsetY(0),
+ mTextAlignment(ALIGN_TEXT_CENTER),
+ mVertAlignment(ALIGN_VERT_CENTER),
+// mLOD(0),
+ mHidden(false)
+{
+ mColor = LLColor4(1.f, 1.f, 1.f, 1.f);
+ mDoFade = true;
+ mFadeDistance = 8.f;
+ mFadeRange = 4.f;
+ mZCompare = true;
+ mOffscreen = false;
+ mRadius = 0.1f;
+ LLPointer<LLHUDText> ptr(this);
+ sTextObjects.insert(ptr);
+}
+
+LLHUDText::~LLHUDText()
+{
+}
+
+void LLHUDText::render()
+{
+ if (!mOnHUDAttachment && sDisplayText)
+ {
+ LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
+ //LLGLDisable gls_stencil(GL_STENCIL_TEST);
+ renderText();
+ }
+}
+
+void LLHUDText::renderText()
+{
+ if (!mVisible || mHidden)
+ {
+ return;
+ }
+
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+
+ LLGLState gls_blend(GL_BLEND, true);
+
+ LLColor4 shadow_color(0.f, 0.f, 0.f, 1.f);
+ F32 alpha_factor = 1.f;
+ LLColor4 text_color = mColor;
+ if (mDoFade)
+ {
+ if (mLastDistance > mFadeDistance)
+ {
+ alpha_factor = llmax(0.f, 1.f - (mLastDistance - mFadeDistance)/mFadeRange);
+ text_color.mV[3] = text_color.mV[3]*alpha_factor;
+ }
+ }
+ if (text_color.mV[3] < 0.01f)
+ {
+ return;
+ }
+ shadow_color.mV[3] = text_color.mV[3];
+
+ mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f));
+
+ // *TODO: make this a per-text setting
+ LLColor4 bg_color = LLUIColorTable::instance().getColor("ObjectBubbleColor");
+ bg_color.setAlpha(gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor);
+
+ const S32 border_height = 16;
+ const S32 border_width = 16;
+
+ // *TODO move this into helper function
+ F32 border_scale = 1.f;
+
+ if (border_height * 2 > mHeight)
+ {
+ border_scale = (F32)mHeight / ((F32)border_height * 2.f);
+ }
+ if (border_width * 2 > mWidth)
+ {
+ border_scale = llmin(border_scale, (F32)mWidth / ((F32)border_width * 2.f));
+ }
+
+ // scale screen size of borders down
+ //RN: for now, text on hud objects is never occluded
+
+ LLVector3 x_pixel_vec;
+ LLVector3 y_pixel_vec;
+
+ if (mOnHUDAttachment)
+ {
+ x_pixel_vec = LLVector3::y_axis / (F32)gViewerWindow->getWorldViewWidthRaw();
+ y_pixel_vec = LLVector3::z_axis / (F32)gViewerWindow->getWorldViewHeightRaw();
+ }
+ else
+ {
+ LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
+ }
+
+ LLVector3 width_vec = mWidth * x_pixel_vec;
+ LLVector3 height_vec = mHeight * y_pixel_vec;
+
+ mRadius = (width_vec + height_vec).magVec() * 0.5f;
+
+ LLVector2 screen_offset;
+ screen_offset = mPositionOffset;
+
+ LLVector3 render_position = mPositionAgent
+ + (x_pixel_vec * screen_offset.mV[VX])
+ + (y_pixel_vec * screen_offset.mV[VY]);
+
+ F32 y_offset = (F32)mOffsetY;
+
+ // Render label
+
+ // Render text
+ {
+ // -1 mMaxLines means unlimited lines.
+ S32 start_segment;
+ S32 max_lines = getMaxLines();
+
+ if (max_lines < 0)
+ {
+ start_segment = 0;
+ }
+ else
+ {
+ start_segment = llmax((S32)0, (S32)mTextSegments.size() - max_lines);
+ }
+
+ for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin() + start_segment;
+ segment_iter != mTextSegments.end(); ++segment_iter )
+ {
+ const LLFontGL* fontp = segment_iter->mFont;
+ y_offset -= fontp->getLineHeight() - 1; // correction factor to match legacy font metrics
+
+ U8 style = segment_iter->mStyle;
+ LLFontGL::ShadowType shadow = LLFontGL::DROP_SHADOW;
+
+ F32 x_offset;
+ if (mTextAlignment== ALIGN_TEXT_CENTER)
+ {
+ x_offset = -0.5f*segment_iter->getWidth(fontp);
+ }
+ else // ALIGN_LEFT
+ {
+ x_offset = -0.5f * mWidth + (HORIZONTAL_PADDING / 2.f);
+ }
+
+ text_color = segment_iter->mColor;
+ if (mOnHUDAttachment)
+ {
+ text_color = linearColor4(text_color);
+ }
+ text_color.mV[VALPHA] *= alpha_factor;
+
+ hud_render_text(segment_iter->getText(), render_position, *fontp, style, shadow, x_offset, y_offset, text_color, mOnHUDAttachment);
+ }
+ }
+ /// Reset the default color to white. The renderer expects this to be the default.
+ gGL.color4f(1.0f, 1.0f, 1.0f, 1.0f);
+}
+
+void LLHUDText::setString(const std::string &text_utf8)
+{
+ mTextSegments.clear();
+ addLine(text_utf8, mColor);
+}
+
+void LLHUDText::clearString()
+{
+ mTextSegments.clear();
+}
+
+
+void LLHUDText::addLine(const std::string &text_utf8,
+ const LLColor4& color,
+ const LLFontGL::StyleFlags style,
+ const LLFontGL* font)
+{
+ LLWString wline = utf8str_to_wstring(text_utf8);
+ if (!wline.empty())
+ {
+ // use default font for segment if custom font not specified
+ if (!font)
+ {
+ font = mFontp;
+ }
+ typedef boost::tokenizer<boost::char_separator<llwchar>, LLWString::const_iterator, LLWString > tokenizer;
+ LLWString seps(utf8str_to_wstring("\r\n"));
+ boost::char_separator<llwchar> sep(seps.c_str());
+
+ tokenizer tokens(wline, sep);
+ tokenizer::iterator iter = tokens.begin();
+
+ while (iter != tokens.end())
+ {
+ U32 line_length = 0;
+ do
+ {
+ F32 max_pixels = HUD_TEXT_MAX_WIDTH_NO_BUBBLE;
+ S32 segment_length = font->maxDrawableChars(iter->substr(line_length).c_str(), max_pixels, wline.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE);
+ LLHUDTextSegment segment(iter->substr(line_length, segment_length), style, color, font);
+ mTextSegments.push_back(segment);
+ line_length += segment_length;
+ }
+ while (line_length != iter->size());
+ ++iter;
+ }
+ }
+}
+
+void LLHUDText::setZCompare(const bool zcompare)
+{
+ mZCompare = zcompare;
+}
+
+void LLHUDText::setFont(const LLFontGL* font)
+{
+ mFontp = font;
+}
+
+
+void LLHUDText::setColor(const LLColor4 &color)
+{
+ mColor = color;
+ for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin();
+ segment_iter != mTextSegments.end(); ++segment_iter )
+ {
+ segment_iter->mColor = color;
+ }
+}
+
+void LLHUDText::setAlpha(F32 alpha)
+{
+ mColor.mV[VALPHA] = alpha;
+ for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin();
+ segment_iter != mTextSegments.end(); ++segment_iter )
+ {
+ segment_iter->mColor.mV[VALPHA] = alpha;
+ }
+}
+
+
+void LLHUDText::setDoFade(const bool do_fade)
+{
+ mDoFade = do_fade;
+}
+
+void LLHUDText::updateVisibility()
+{
+ if (mSourceObject)
+ {
+ mSourceObject->updateText();
+ }
+
+ mPositionAgent = gAgent.getPosAgentFromGlobal(mPositionGlobal);
+
+ if (!mSourceObject)
+ {
+ // Beacons
+ mVisible = true;
+ if (mOnHUDAttachment)
+ {
+ sVisibleHUDTextObjects.push_back(LLPointer<LLHUDText> (this));
+ }
+ else
+ {
+ sVisibleTextObjects.push_back(LLPointer<LLHUDText> (this));
+ }
+ return;
+ }
+
+ // Not visible if parent object is dead
+ if (mSourceObject->isDead())
+ {
+ mVisible = false;
+ return;
+ }
+
+ // for now, all text on hud objects is visible
+ if (mOnHUDAttachment)
+ {
+ mVisible = true;
+ sVisibleHUDTextObjects.push_back(LLPointer<LLHUDText> (this));
+ mLastDistance = mPositionAgent.mV[VX];
+ return;
+ }
+
+ // push text towards camera by radius of object, but not past camera
+ LLVector3 vec_from_camera = mPositionAgent - LLViewerCamera::getInstance()->getOrigin();
+ LLVector3 dir_from_camera = vec_from_camera;
+ dir_from_camera.normVec();
+
+ if (dir_from_camera * LLViewerCamera::getInstance()->getAtAxis() <= 0.f)
+ { //text is behind camera, don't render
+ mVisible = false;
+ return;
+ }
+
+ if (vec_from_camera * LLViewerCamera::getInstance()->getAtAxis() <= LLViewerCamera::getInstance()->getNear() + 0.1f + mSourceObject->getVObjRadius())
+ {
+ mPositionAgent = LLViewerCamera::getInstance()->getOrigin() + vec_from_camera * ((LLViewerCamera::getInstance()->getNear() + 0.1f) / (vec_from_camera * LLViewerCamera::getInstance()->getAtAxis()));
+ }
+ else
+ {
+ mPositionAgent -= dir_from_camera * mSourceObject->getVObjRadius();
+ }
+
+ mLastDistance = (mPositionAgent - LLViewerCamera::getInstance()->getOrigin()).magVec();
+
+ if (!mTextSegments.size() || (mDoFade && (mLastDistance > mFadeDistance + mFadeRange)))
+ {
+ mVisible = false;
+ return;
+ }
+
+ LLVector3 pos_agent_center = gAgent.getPosAgentFromGlobal(mPositionGlobal) - dir_from_camera;
+ F32 last_distance_center = (pos_agent_center - LLViewerCamera::getInstance()->getOrigin()).magVec();
+ F32 max_draw_distance = gSavedSettings.getF32("PrimTextMaxDrawDistance");
+
+ if(max_draw_distance < 0)
+ {
+ max_draw_distance = 0;
+ gSavedSettings.setF32("PrimTextMaxDrawDistance", max_draw_distance);
+ }
+ else if(max_draw_distance > MAX_DRAW_DISTANCE)
+ {
+ max_draw_distance = MAX_DRAW_DISTANCE;
+ gSavedSettings.setF32("PrimTextMaxDrawDistance", MAX_DRAW_DISTANCE);
+ }
+
+ if(last_distance_center > max_draw_distance)
+ {
+ mVisible = false;
+ return;
+ }
+
+
+ LLVector3 x_pixel_vec;
+ LLVector3 y_pixel_vec;
+
+ LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
+
+ LLVector3 render_position = mPositionAgent +
+ (x_pixel_vec * mPositionOffset.mV[VX]) +
+ (y_pixel_vec * mPositionOffset.mV[VY]);
+
+ mOffscreen = false;
+ if (!LLViewerCamera::getInstance()->sphereInFrustum(render_position, mRadius))
+ {
+// if (!mVisibleOffScreen)
+// {
+ mVisible = false;
+ return;
+// }
+// else
+// {
+// mOffscreen = true;
+// }
+ }
+
+ mVisible = true;
+ sVisibleTextObjects.push_back(LLPointer<LLHUDText> (this));
+}
+
+LLVector2 LLHUDText::updateScreenPos(LLVector2 &offset)
+{
+ LLCoordGL screen_pos;
+ LLVector2 screen_pos_vec;
+ LLVector3 x_pixel_vec;
+ LLVector3 y_pixel_vec;
+ LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
+// LLVector3 world_pos = mPositionAgent + (offset.mV[VX] * x_pixel_vec) + (offset.mV[VY] * y_pixel_vec);
+// if (!LLViewerCamera::getInstance()->projectPosAgentToScreen(world_pos, screen_pos, false) && mVisibleOffScreen)
+// {
+// // bubble off-screen, so find a spot for it along screen edge
+// LLViewerCamera::getInstance()->projectPosAgentToScreenEdge(world_pos, screen_pos);
+// }
+
+ screen_pos_vec.setVec((F32)screen_pos.mX, (F32)screen_pos.mY);
+
+ LLRect world_rect = gViewerWindow->getWorldViewRectScaled();
+ S32 bottom = world_rect.mBottom + STATUS_BAR_HEIGHT;
+
+ LLVector2 screen_center;
+ screen_center.mV[VX] = llclamp((F32)screen_pos_vec.mV[VX], (F32)world_rect.mLeft + mWidth * 0.5f, (F32)world_rect.mRight - mWidth * 0.5f);
+
+ if(mVertAlignment == ALIGN_VERT_TOP)
+ {
+ screen_center.mV[VY] = llclamp((F32)screen_pos_vec.mV[VY],
+ (F32)bottom,
+ (F32)world_rect.mTop - mHeight - (F32)MENU_BAR_HEIGHT);
+ mSoftScreenRect.setLeftTopAndSize(screen_center.mV[VX] - (mWidth + BUFFER_SIZE) * 0.5f,
+ screen_center.mV[VY] + (mHeight + BUFFER_SIZE), mWidth + BUFFER_SIZE, mHeight + BUFFER_SIZE);
+ }
+ else
+ {
+ screen_center.mV[VY] = llclamp((F32)screen_pos_vec.mV[VY],
+ (F32)bottom + mHeight * 0.5f,
+ (F32)world_rect.mTop - mHeight * 0.5f - (F32)MENU_BAR_HEIGHT);
+ mSoftScreenRect.setCenterAndSize(screen_center.mV[VX], screen_center.mV[VY], mWidth + BUFFER_SIZE, mHeight + BUFFER_SIZE);
+ }
+
+ return offset + (screen_center - LLVector2((F32)screen_pos.mX, (F32)screen_pos.mY));
+}
+
+void LLHUDText::updateSize()
+{
+ F32 height = 0.f;
+ F32 width = 0.f;
+
+ S32 max_lines = getMaxLines();
+
+ S32 start_segment;
+ if (max_lines < 0) start_segment = 0;
+ else start_segment = llmax((S32)0, (S32)mTextSegments.size() - max_lines);
+
+ std::vector<LLHUDTextSegment>::iterator iter = mTextSegments.begin() + start_segment;
+ while (iter != mTextSegments.end())
+ {
+ const LLFontGL* fontp = iter->mFont;
+ height += fontp->getLineHeight() - 1; // correction factor to match legacy font metrics
+ width = llmax(width, llmin(iter->getWidth(fontp), HUD_TEXT_MAX_WIDTH));
+ ++iter;
+ }
+
+ if (width == 0.f)
+ {
+ return;
+ }
+
+ width += HORIZONTAL_PADDING;
+ height += VERTICAL_PADDING;
+
+ // *TODO: Could do some sort of timer-based resize logic here
+ F32 u = 1.f;
+ mWidth = llmax(width, lerp(mWidth, (F32)width, u));
+ mHeight = llmax(height, lerp(mHeight, (F32)height, u));
+}
+
+void LLHUDText::updateAll()
+{
+ // iterate over all text objects, calculate their restoration forces,
+ // and add them to the visible set if they are on screen and close enough
+ sVisibleTextObjects.clear();
+ sVisibleHUDTextObjects.clear();
+
+ TextObjectIterator text_it;
+ for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it)
+ {
+ LLHUDText* textp = (*text_it);
+ textp->mTargetPositionOffset.clearVec();
+ textp->updateSize();
+ textp->updateVisibility();
+ }
+
+ // sort back to front for rendering purposes
+ std::sort(sVisibleTextObjects.begin(), sVisibleTextObjects.end(), lltextobject_further_away());
+ std::sort(sVisibleHUDTextObjects.begin(), sVisibleHUDTextObjects.end(), lltextobject_further_away());
+}
+
+//void LLHUDText::setLOD(S32 lod)
+//{
+// mLOD = lod;
+// //RN: uncomment this to visualize LOD levels
+// //std::string label = llformat("%d", lod);
+// //setLabel(label);
+//}
+
+S32 LLHUDText::getMaxLines()
+{
+ return mMaxLines;
+ //switch(mLOD)
+ //{
+ //case 0:
+ // return mMaxLines;
+ //case 1:
+ // return mMaxLines > 0 ? mMaxLines / 2 : 5;
+ //case 2:
+ // return mMaxLines > 0 ? mMaxLines / 3 : 2;
+ //default:
+ // // label only
+ // return 0;
+ //}
+}
+
+void LLHUDText::markDead()
+{
+ // make sure we have at least one pointer
+ // till the end of the function
+ LLPointer<LLHUDText> ptr(this);
+ sTextObjects.erase(ptr);
+ LLHUDObject::markDead();
+}
+
+void LLHUDText::renderAllHUD()
+{
+ LLGLState::checkStates();
+
+ {
+ LLGLDepthTest depth(GL_FALSE, GL_FALSE);
+
+ VisibleTextObjectIterator text_it;
+
+ for (text_it = sVisibleHUDTextObjects.begin(); text_it != sVisibleHUDTextObjects.end(); ++text_it)
+ {
+ (*text_it)->renderText();
+ }
+ }
+
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+}
+
+void LLHUDText::shiftAll(const LLVector3& offset)
+{
+ TextObjectIterator text_it;
+ for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it)
+ {
+ LLHUDText *textp = text_it->get();
+ textp->shift(offset);
+ }
+}
+
+void LLHUDText::shift(const LLVector3& offset)
+{
+ mPositionAgent += offset;
+}
+
+//static
+// called when UI scale changes, to flush font width caches
+void LLHUDText::reshape()
+{
+ TextObjectIterator text_it;
+ for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it)
+ {
+ LLHUDText* textp = (*text_it);
+ std::vector<LLHUDTextSegment>::iterator segment_iter;
+ for (segment_iter = textp->mTextSegments.begin();
+ segment_iter != textp->mTextSegments.end(); ++segment_iter )
+ {
+ segment_iter->clearFontWidthMap();
+ }
+ }
+}
+
+//============================================================================
+
+F32 LLHUDText::LLHUDTextSegment::getWidth(const LLFontGL* font)
+{
+ std::map<const LLFontGL*, F32>::iterator iter = mFontWidthMap.find(font);
+ if (iter != mFontWidthMap.end())
+ {
+ return iter->second;
+ }
+ else
+ {
+ F32 width = font->getWidthF32(mText.c_str());
+ mFontWidthMap[font] = width;
+ return width;
+ }
+}
|