llhudtext.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:32k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llhudtext.cpp
  3.  * @brief LLHUDText class implementation
  4.  *
  5.  * $LicenseInfo:firstyear=2002&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2002-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llhudtext.h"
  34. #include "llrender.h"
  35. #include "llagent.h"
  36. #include "llviewercontrol.h"
  37. #include "llcriticaldamp.h"
  38. #include "lldrawable.h"
  39. #include "llfontgl.h"
  40. #include "llglheaders.h"
  41. #include "llhudrender.h"
  42. #include "llui.h"
  43. #include "llviewercamera.h"
  44. #include "llviewertexturelist.h"
  45. #include "llviewerobject.h"
  46. #include "llvovolume.h"
  47. #include "llviewerwindow.h"
  48. #include "llstatusbar.h"
  49. #include "llmenugl.h"
  50. #include "pipeline.h"
  51. #include <boost/tokenizer.hpp>
  52. const F32 SPRING_STRENGTH = 0.7f;
  53. const F32 RESTORATION_SPRING_TIME_CONSTANT = 0.1f;
  54. const F32 HORIZONTAL_PADDING = 15.f;
  55. const F32 VERTICAL_PADDING = 12.f;
  56. const F32 BUFFER_SIZE = 2.f;
  57. const F32 MIN_EDGE_OVERLAP = 3.f;
  58. F32 HUD_TEXT_MAX_WIDTH = 190.f;
  59. const F32 HUD_TEXT_MAX_WIDTH_NO_BUBBLE = 1000.f;
  60. const F32 RESIZE_TIME = 0.f;
  61. const S32 NUM_OVERLAP_ITERATIONS = 10;
  62. const F32 NEIGHBOR_FORCE_FRACTION = 1.f;
  63. const F32 POSITION_DAMPING_TC = 0.2f;
  64. const F32 MAX_STABLE_CAMERA_VELOCITY = 0.1f;
  65. const F32 LOD_0_SCREEN_COVERAGE = 0.15f;
  66. const F32 LOD_1_SCREEN_COVERAGE = 0.30f;
  67. const F32 LOD_2_SCREEN_COVERAGE = 0.40f;
  68. std::set<LLPointer<LLHUDText> > LLHUDText::sTextObjects;
  69. std::vector<LLPointer<LLHUDText> > LLHUDText::sVisibleTextObjects;
  70. std::vector<LLPointer<LLHUDText> > LLHUDText::sVisibleHUDTextObjects;
  71. BOOL LLHUDText::sDisplayText = TRUE ;
  72. bool lltextobject_further_away::operator()(const LLPointer<LLHUDText>& lhs, const LLPointer<LLHUDText>& rhs) const
  73. {
  74. return (lhs->getDistance() > rhs->getDistance()) ? true : false;
  75. }
  76. LLHUDText::LLHUDText(const U8 type) :
  77. LLHUDObject(type),
  78. mUseBubble(FALSE),
  79. mUsePixelSize(TRUE),
  80. mVisibleOffScreen(FALSE),
  81. mWidth(0.f),
  82. mHeight(0.f),
  83. mFontp(LLFontGL::getFontSansSerifSmall()),
  84. mBoldFontp(LLFontGL::getFontSansSerifBold()),
  85. mMass(1.f),
  86. mMaxLines(10),
  87. mOffsetY(0),
  88. mTextAlignment(ALIGN_TEXT_CENTER),
  89. mVertAlignment(ALIGN_VERT_CENTER),
  90. mLOD(0),
  91. mHidden(FALSE)
  92. {
  93. mColor = LLColor4(1.f, 1.f, 1.f, 1.f);
  94. mDoFade = TRUE;
  95. mFadeDistance = 8.f;
  96. mFadeRange = 4.f;
  97. mZCompare = TRUE;
  98. mDropShadow = TRUE;
  99. mOffscreen = FALSE;
  100. mRadius = 0.1f;
  101. LLPointer<LLHUDText> ptr(this);
  102. sTextObjects.insert(ptr);
  103. }
  104. LLHUDText::~LLHUDText()
  105. {
  106. }
  107. BOOL LLHUDText::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3& intersection, BOOL debug_render)
  108. {
  109. if (!mVisible || mHidden)
  110. {
  111. return FALSE;
  112. }
  113. // don't pick text that isn't bound to a viewerobject or isn't in a bubble
  114. if (!mSourceObject || mSourceObject->mDrawable.isNull() || !mUseBubble)
  115. {
  116. return FALSE;
  117. }
  118. F32 alpha_factor = 1.f;
  119. LLColor4 text_color = mColor;
  120. if (mDoFade)
  121. {
  122. if (mLastDistance > mFadeDistance)
  123. {
  124. alpha_factor = llmax(0.f, 1.f - (mLastDistance - mFadeDistance)/mFadeRange);
  125. text_color.mV[3] = text_color.mV[3]*alpha_factor;
  126. }
  127. }
  128. if (text_color.mV[3] < 0.01f)
  129. {
  130. return FALSE;
  131. }
  132. mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f));
  133. // scale screen size of borders down
  134. //RN: for now, text on hud objects is never occluded
  135. LLVector3 x_pixel_vec;
  136. LLVector3 y_pixel_vec;
  137. if (mOnHUDAttachment)
  138. {
  139. x_pixel_vec = LLVector3::y_axis / (F32)gViewerWindow->getWindowWidthScaled();
  140. y_pixel_vec = LLVector3::z_axis / (F32)gViewerWindow->getWindowHeightScaled();
  141. }
  142. else
  143. {
  144. LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
  145. }
  146. LLVector3 width_vec = mWidth * x_pixel_vec;
  147. LLVector3 height_vec = mHeight * y_pixel_vec;
  148. LLCoordGL screen_pos;
  149. LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, FALSE);
  150. LLVector2 screen_offset;
  151. screen_offset = updateScreenPos(mPositionOffset);
  152. LLVector3 render_position = mPositionAgent  
  153. + (x_pixel_vec * screen_offset.mV[VX])
  154. + (y_pixel_vec * screen_offset.mV[VY]);
  155. if (mUseBubble)
  156. {
  157. LLVector3 bg_pos = render_position
  158. + (F32)mOffsetY * y_pixel_vec
  159. - (width_vec / 2.f)
  160. - (height_vec);
  161. //LLUI::translate(bg_pos.mV[VX], bg_pos.mV[VY], bg_pos.mV[VZ]);
  162. LLVector3 v[] = 
  163. {
  164. bg_pos,
  165. bg_pos + width_vec,
  166. bg_pos + width_vec + height_vec,
  167. bg_pos + height_vec,
  168. };
  169. if (debug_render)
  170. {
  171. gGL.begin(LLRender::LINE_STRIP);
  172. gGL.vertex3fv(v[0].mV);
  173. gGL.vertex3fv(v[1].mV);
  174. gGL.vertex3fv(v[2].mV);
  175. gGL.vertex3fv(v[3].mV);
  176. gGL.vertex3fv(v[0].mV);
  177. gGL.vertex3fv(v[2].mV);
  178. gGL.end();
  179. }
  180. LLVector3 dir = end-start;
  181. F32 t = 0.f;
  182. if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, NULL, NULL, &t, FALSE) ||
  183. LLTriangleRayIntersect(v[2], v[3], v[0], start, dir, NULL, NULL, &t, FALSE) )
  184. {
  185. if (t <= 1.f)
  186. {
  187. intersection = start + dir*t;
  188. return TRUE;
  189. }
  190. }
  191. }
  192. return FALSE;
  193. }
  194. void LLHUDText::render()
  195. {
  196. if (!mOnHUDAttachment && sDisplayText)
  197. {
  198. LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
  199. renderText(FALSE);
  200. }
  201. }
  202. void LLHUDText::renderForSelect()
  203. {
  204. if (!mOnHUDAttachment)
  205. {
  206. LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
  207. renderText(TRUE);
  208. }
  209. }
  210. void LLHUDText::renderText(BOOL for_select)
  211. {
  212. if (!mVisible || mHidden)
  213. {
  214. return;
  215. }
  216. // don't pick text that isn't bound to a viewerobject or isn't in a bubble
  217. if (for_select && 
  218. (!mSourceObject || mSourceObject->mDrawable.isNull() || !mUseBubble))
  219. {
  220. return;
  221. }
  222. if (for_select)
  223. {
  224. gGL.getTexUnit(0)->disable();
  225. }
  226. else
  227. {
  228. gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
  229. }
  230. LLGLState gls_blend(GL_BLEND, for_select ? FALSE : TRUE);
  231. LLGLState gls_alpha(GL_ALPHA_TEST, for_select ? FALSE : TRUE);
  232. LLColor4 shadow_color(0.f, 0.f, 0.f, 1.f);
  233. F32 alpha_factor = 1.f;
  234. LLColor4 text_color = mColor;
  235. if (mDoFade)
  236. {
  237. if (mLastDistance > mFadeDistance)
  238. {
  239. alpha_factor = llmax(0.f, 1.f - (mLastDistance - mFadeDistance)/mFadeRange);
  240. text_color.mV[3] = text_color.mV[3]*alpha_factor;
  241. }
  242. }
  243. if (text_color.mV[3] < 0.01f)
  244. {
  245. return;
  246. }
  247. shadow_color.mV[3] = text_color.mV[3];
  248. mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f));
  249. // *TODO: cache this image
  250. LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Square");
  251. // *TODO: make this a per-text setting
  252. LLColor4 bg_color = LLUIColorTable::instance().getColor("BackgroundChatColor");
  253. bg_color.setAlpha(gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor);
  254. const S32 border_height = 16;
  255. const S32 border_width = 16;
  256. // *TODO move this into helper function
  257. F32 border_scale = 1.f;
  258. if (border_height * 2 > mHeight)
  259. {
  260. border_scale = (F32)mHeight / ((F32)border_height * 2.f);
  261. }
  262. if (border_width * 2 > mWidth)
  263. {
  264. border_scale = llmin(border_scale, (F32)mWidth / ((F32)border_width * 2.f));
  265. }
  266. // scale screen size of borders down
  267. //RN: for now, text on hud objects is never occluded
  268. LLVector3 x_pixel_vec;
  269. LLVector3 y_pixel_vec;
  270. if (mOnHUDAttachment)
  271. {
  272. x_pixel_vec = LLVector3::y_axis / (F32)gViewerWindow->getWorldViewWidthRaw();
  273. y_pixel_vec = LLVector3::z_axis / (F32)gViewerWindow->getWorldViewHeightRaw();
  274. }
  275. else
  276. {
  277. LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
  278. }
  279. LLVector2 border_scale_vec((F32)border_width / (F32)imagep->getTextureWidth(), (F32)border_height / (F32)imagep->getTextureHeight());
  280. LLVector3 width_vec = mWidth * x_pixel_vec;
  281. LLVector3 height_vec = mHeight * y_pixel_vec;
  282. LLVector3 scaled_border_width = (F32)llfloor(border_scale * (F32)border_width) * x_pixel_vec;
  283. LLVector3 scaled_border_height = (F32)llfloor(border_scale * (F32)border_height) * y_pixel_vec;
  284. mRadius = (width_vec + height_vec).magVec() * 0.5f;
  285. LLCoordGL screen_pos;
  286. LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, FALSE);
  287. LLVector2 screen_offset;
  288. if (!mUseBubble)
  289. {
  290. screen_offset = mPositionOffset;
  291. }
  292. else
  293. {
  294. screen_offset = updateScreenPos(mPositionOffset);
  295. }
  296. LLVector3 render_position = mPositionAgent  
  297. + (x_pixel_vec * screen_offset.mV[VX])
  298. + (y_pixel_vec * screen_offset.mV[VY]);
  299. //if (mOnHUD)
  300. //{
  301. // render_position.mV[VY] -= fmodf(render_position.mV[VY], 1.f / (F32)gViewerWindow->getWindowWidthScaled());
  302. // render_position.mV[VZ] -= fmodf(render_position.mV[VZ], 1.f / (F32)gViewerWindow->getWindowHeightScaled());
  303. //}
  304. //else
  305. //{
  306. // render_position = LLViewerCamera::getInstance()->roundToPixel(render_position);
  307. //}
  308. if (mUseBubble)
  309. {
  310. LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
  311. LLUI::pushMatrix();
  312. {
  313. LLVector3 bg_pos = render_position
  314. + (F32)mOffsetY * y_pixel_vec
  315. - (width_vec / 2.f)
  316. - (height_vec);
  317. LLUI::translate(bg_pos.mV[VX], bg_pos.mV[VY], bg_pos.mV[VZ]);
  318. if (for_select)
  319. {
  320. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  321. S32 name = mSourceObject->mGLName;
  322. LLColor4U coloru((U8)(name >> 16), (U8)(name >> 8), (U8)name);
  323. gGL.color4ubv(coloru.mV);
  324. gl_segmented_rect_3d_tex(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, height_vec);
  325. LLUI::popMatrix();
  326. return;
  327. }
  328. else
  329. {
  330. gGL.getTexUnit(0)->bind(imagep->getImage());
  331. gGL.color4fv(bg_color.mV);
  332. gl_segmented_rect_3d_tex(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, height_vec);
  333. if ( mLabelSegments.size())
  334. {
  335. LLUI::pushMatrix();
  336. {
  337. gGL.color4f(text_color.mV[VX], text_color.mV[VY], text_color.mV[VZ], gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor);
  338. LLVector3 label_height = (mFontp->getLineHeight() * mLabelSegments.size() + (VERTICAL_PADDING / 3.f)) * y_pixel_vec;
  339. LLVector3 label_offset = height_vec - label_height;
  340. LLUI::translate(label_offset.mV[VX], label_offset.mV[VY], label_offset.mV[VZ]);
  341. gl_segmented_rect_3d_tex_top(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, label_height);
  342. }
  343. LLUI::popMatrix();
  344. }
  345. }
  346. BOOL outside_width = llabs(mPositionOffset.mV[VX]) > mWidth * 0.5f;
  347. 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);
  348. // draw line segments pointing to parent object
  349. if (!mOffscreen && (outside_width || outside_height))
  350. {
  351. LLUI::pushMatrix();
  352. {
  353. gGL.color4fv(bg_color.mV);
  354. LLVector3 target_pos = -1.f * (mPositionOffset.mV[VX] * x_pixel_vec + mPositionOffset.mV[VY] * y_pixel_vec);
  355. target_pos += (width_vec / 2.f);
  356. target_pos += mVertAlignment == ALIGN_VERT_CENTER ? (height_vec * 0.5f) : LLVector3::zero;
  357. target_pos -= 3.f * x_pixel_vec;
  358. target_pos -= 6.f * y_pixel_vec;
  359. LLUI::translate(target_pos.mV[VX], target_pos.mV[VY], target_pos.mV[VZ]);
  360. 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);
  361. }
  362. LLUI::popMatrix();
  363. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  364. LLGLDepthTest gls_depth(mZCompare ? GL_TRUE : GL_FALSE, GL_FALSE);
  365. LLVector3 box_center_offset;
  366. box_center_offset = (width_vec * 0.5f) + (height_vec * 0.5f);
  367. LLUI::translate(box_center_offset.mV[VX], box_center_offset.mV[VY], box_center_offset.mV[VZ]);
  368. gGL.color4fv(bg_color.mV);
  369. LLUI::setLineWidth(2.0);
  370. gGL.begin(LLRender::LINES);
  371. {
  372. if (outside_width)
  373. {
  374. LLVector3 vert;
  375. // draw line in x then y
  376. if (mPositionOffset.mV[VX] < 0.f)
  377. {
  378. // start at right edge
  379. vert = width_vec * 0.5f;
  380. gGL.vertex3fv(vert.mV);
  381. }
  382. else
  383. {
  384. // start at left edge
  385. vert = width_vec * -0.5f;
  386. gGL.vertex3fv(vert.mV);
  387. }
  388. vert = -mPositionOffset.mV[VX] * x_pixel_vec;
  389. gGL.vertex3fv(vert.mV);
  390. gGL.vertex3fv(vert.mV);
  391. vert -= mPositionOffset.mV[VY] * y_pixel_vec;
  392. vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero);
  393. gGL.vertex3fv(vert.mV);
  394. }
  395. else
  396. {
  397. LLVector3 vert;
  398. // draw line in y then x
  399. if (mPositionOffset.mV[VY] < 0.f)
  400. {
  401. // start at top edge
  402. vert = (height_vec * 0.5f) - (mPositionOffset.mV[VX] * x_pixel_vec);
  403. gGL.vertex3fv(vert.mV);
  404. }
  405. else
  406. {
  407. // start at bottom edge
  408. vert = (height_vec * -0.5f)  - (mPositionOffset.mV[VX] * x_pixel_vec);
  409. gGL.vertex3fv(vert.mV);
  410. }
  411. vert = -mPositionOffset.mV[VY] * y_pixel_vec - mPositionOffset.mV[VX] * x_pixel_vec;
  412. vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero);
  413. gGL.vertex3fv(vert.mV);
  414. }
  415. }
  416. gGL.end();
  417. LLUI::setLineWidth(1.0);
  418. }
  419. }
  420. LLUI::popMatrix();
  421. }
  422. F32 y_offset = (F32)mOffsetY;
  423. // Render label
  424. {
  425. gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
  426. for(std::vector<LLHUDTextSegment>::iterator segment_iter = mLabelSegments.begin();
  427. segment_iter != mLabelSegments.end(); ++segment_iter )
  428. {
  429. const LLFontGL* fontp = (segment_iter->mStyle == LLFontGL::BOLD) ? mBoldFontp : mFontp;
  430. y_offset -= fontp->getLineHeight();
  431. F32 x_offset;
  432. if (mTextAlignment == ALIGN_TEXT_CENTER)
  433. {
  434. x_offset = -0.5f*segment_iter->getWidth(fontp);
  435. }
  436. else // ALIGN_LEFT
  437. {
  438. x_offset = -0.5f * mWidth + (HORIZONTAL_PADDING / 2.f);
  439. }
  440. LLColor4 label_color(0.f, 0.f, 0.f, 1.f);
  441. label_color.mV[VALPHA] = alpha_factor;
  442. hud_render_text(segment_iter->getText(), render_position, *fontp, segment_iter->mStyle, LLFontGL::NO_SHADOW, x_offset, y_offset, label_color, mOnHUDAttachment);
  443. }
  444. }
  445. // Render text
  446. {
  447. // -1 mMaxLines means unlimited lines.
  448. S32 start_segment;
  449. S32 max_lines = getMaxLines();
  450. if (max_lines < 0) 
  451. {
  452. start_segment = 0;
  453. }
  454. else 
  455. {
  456. start_segment = llmax((S32)0, (S32)mTextSegments.size() - max_lines);
  457. }
  458. for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin() + start_segment;
  459.  segment_iter != mTextSegments.end(); ++segment_iter )
  460. {
  461. const LLFontGL* fontp = (segment_iter->mStyle == LLFontGL::BOLD) ? mBoldFontp : mFontp;
  462. y_offset -= fontp->getLineHeight();
  463. U8 style = segment_iter->mStyle;
  464. LLFontGL::ShadowType shadow = LLFontGL::NO_SHADOW;
  465. if (mDropShadow)
  466. {
  467. shadow = LLFontGL::DROP_SHADOW;
  468. }
  469. F32 x_offset;
  470. if (mTextAlignment== ALIGN_TEXT_CENTER)
  471. {
  472. x_offset = -0.5f*segment_iter->getWidth(fontp);
  473. }
  474. else // ALIGN_LEFT
  475. {
  476. x_offset = -0.5f * mWidth + (HORIZONTAL_PADDING / 2.f);
  477. }
  478. text_color = segment_iter->mColor;
  479. text_color.mV[VALPHA] *= alpha_factor;
  480. hud_render_text(segment_iter->getText(), render_position, *fontp, style, shadow, x_offset, y_offset, text_color, mOnHUDAttachment);
  481. }
  482. }
  483. /// Reset the default color to white.  The renderer expects this to be the default. 
  484. glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  485. if (for_select)
  486. {
  487. gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
  488. }
  489. }
  490. void LLHUDText::setStringUTF8(const std::string &wtext)
  491. {
  492. setString(utf8str_to_wstring(wtext));
  493. }
  494. void LLHUDText::setString(const LLWString &wtext)
  495. {
  496. mTextSegments.clear();
  497. addLine(wtext, mColor);
  498. }
  499. void LLHUDText::clearString()
  500. {
  501. mTextSegments.clear();
  502. }
  503. void LLHUDText::addLine(const std::string &str, const LLColor4& color, const LLFontGL::StyleFlags style)
  504. {
  505. addLine(utf8str_to_wstring(str), color, style);
  506. }
  507. void LLHUDText::addLine(const LLWString &wstr, const LLColor4& color, const LLFontGL::StyleFlags style)
  508. {
  509. if (gNoRender)
  510. {
  511. return;
  512. }
  513. if (!wstr.empty())
  514. {
  515. LLWString wline(wstr);
  516. typedef boost::tokenizer<boost::char_separator<llwchar>, LLWString::const_iterator, LLWString > tokenizer;
  517. LLWString seps(utf8str_to_wstring("rn"));
  518. boost::char_separator<llwchar> sep(seps.c_str());
  519. tokenizer tokens(wline, sep);
  520. tokenizer::iterator iter = tokens.begin();
  521. while (iter != tokens.end())
  522. {
  523. U32 line_length = 0;
  524. do
  525. {
  526. S32 segment_length = mFontp->maxDrawableChars(iter->substr(line_length).c_str(), mUseBubble ? HUD_TEXT_MAX_WIDTH : HUD_TEXT_MAX_WIDTH_NO_BUBBLE, wline.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE);
  527. mTextSegments.push_back(LLHUDTextSegment(iter->substr(line_length, segment_length), style, color));
  528. line_length += segment_length;
  529. }
  530. while (line_length != iter->size());
  531. ++iter;
  532. }
  533. }
  534. }
  535. void LLHUDText::setLabel(const std::string &label)
  536. {
  537. setLabel(utf8str_to_wstring(label));
  538. }
  539. void LLHUDText::setLabel(const LLWString &wlabel)
  540. {
  541. mLabelSegments.clear();
  542. if (!wlabel.empty())
  543. {
  544. LLWString wstr(wlabel);
  545. LLWString seps(utf8str_to_wstring("rn"));
  546. LLWString empty;
  547. typedef boost::tokenizer<boost::char_separator<llwchar>, LLWString::const_iterator, LLWString > tokenizer;
  548. boost::char_separator<llwchar> sep(seps.c_str(), empty.c_str(), boost::keep_empty_tokens);
  549. tokenizer tokens(wstr, sep);
  550. tokenizer::iterator iter = tokens.begin();
  551. while (iter != tokens.end())
  552. {
  553. U32 line_length = 0;
  554. do
  555. {
  556. S32 segment_length = mFontp->maxDrawableChars(iter->substr(line_length).c_str(), mUseBubble ? HUD_TEXT_MAX_WIDTH : HUD_TEXT_MAX_WIDTH_NO_BUBBLE, wstr.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE);
  557. mLabelSegments.push_back(LLHUDTextSegment(iter->substr(line_length, segment_length), LLFontGL::NORMAL, mColor));
  558. line_length += segment_length;
  559. }
  560. while (line_length != iter->size());
  561. ++iter;
  562. }
  563. }
  564. }
  565. void LLHUDText::setDropShadow(const BOOL do_shadow)
  566. {
  567. mDropShadow = do_shadow;
  568. }
  569. void LLHUDText::setZCompare(const BOOL zcompare)
  570. {
  571. mZCompare = zcompare;
  572. }
  573. void LLHUDText::setFont(const LLFontGL* font)
  574. {
  575. mFontp = font;
  576. }
  577. void LLHUDText::setColor(const LLColor4 &color)
  578. {
  579. mColor = color;
  580. for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin();
  581.  segment_iter != mTextSegments.end(); ++segment_iter )
  582. {
  583. segment_iter->mColor = color;
  584. }
  585. }
  586. void LLHUDText::setUsePixelSize(const BOOL use_pixel_size)
  587. {
  588. mUsePixelSize = use_pixel_size;
  589. }
  590. void LLHUDText::setDoFade(const BOOL do_fade)
  591. {
  592. mDoFade = do_fade;
  593. }
  594. void LLHUDText::updateVisibility()
  595. {
  596. if (mSourceObject)
  597. {
  598. mSourceObject->updateText();
  599. }
  600. mPositionAgent = gAgent.getPosAgentFromGlobal(mPositionGlobal);
  601. if (!mSourceObject)
  602. {
  603. //llwarns << "LLHUDText::updateScreenPos -- mSourceObject is NULL!" << llendl;
  604. mVisible = TRUE;
  605. if (mOnHUDAttachment)
  606. {
  607. sVisibleHUDTextObjects.push_back(LLPointer<LLHUDText> (this));
  608. }
  609. else
  610. {
  611. sVisibleTextObjects.push_back(LLPointer<LLHUDText> (this));
  612. }
  613. return;
  614. }
  615. // Not visible if parent object is dead
  616. if (mSourceObject->isDead())
  617. {
  618. mVisible = FALSE;
  619. return;
  620. }
  621. // for now, all text on hud objects is visible
  622. if (mOnHUDAttachment)
  623. {
  624. mVisible = TRUE;
  625. sVisibleHUDTextObjects.push_back(LLPointer<LLHUDText> (this));
  626. mLastDistance = mPositionAgent.mV[VX];
  627. return;
  628. }
  629. // push text towards camera by radius of object, but not past camera
  630. LLVector3 vec_from_camera = mPositionAgent - LLViewerCamera::getInstance()->getOrigin();
  631. LLVector3 dir_from_camera = vec_from_camera;
  632. dir_from_camera.normVec();
  633. if (dir_from_camera * LLViewerCamera::getInstance()->getAtAxis() <= 0.f)
  634. { //text is behind camera, don't render
  635. mVisible = FALSE;
  636. return;
  637. }
  638. if (vec_from_camera * LLViewerCamera::getInstance()->getAtAxis() <= LLViewerCamera::getInstance()->getNear() + 0.1f + mSourceObject->getVObjRadius())
  639. {
  640. mPositionAgent = LLViewerCamera::getInstance()->getOrigin() + vec_from_camera * ((LLViewerCamera::getInstance()->getNear() + 0.1f) / (vec_from_camera * LLViewerCamera::getInstance()->getAtAxis()));
  641. }
  642. else
  643. {
  644. mPositionAgent -= dir_from_camera * mSourceObject->getVObjRadius();
  645. }
  646. mLastDistance = (mPositionAgent - LLViewerCamera::getInstance()->getOrigin()).magVec();
  647. if (mLOD >= 3 || !mTextSegments.size() || (mDoFade && (mLastDistance > mFadeDistance + mFadeRange)))
  648. {
  649. mVisible = FALSE;
  650. return;
  651. }
  652. LLVector3 x_pixel_vec;
  653. LLVector3 y_pixel_vec;
  654. LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
  655. LLVector3 render_position = mPositionAgent + 
  656. (x_pixel_vec * mPositionOffset.mV[VX]) +
  657. (y_pixel_vec * mPositionOffset.mV[VY]);
  658. mOffscreen = FALSE;
  659. if (!LLViewerCamera::getInstance()->sphereInFrustum(render_position, mRadius))
  660. {
  661. if (!mVisibleOffScreen)
  662. {
  663. mVisible = FALSE;
  664. return;
  665. }
  666. else
  667. {
  668. mOffscreen = TRUE;
  669. }
  670. }
  671. mVisible = TRUE;
  672. sVisibleTextObjects.push_back(LLPointer<LLHUDText> (this));
  673. }
  674. LLVector2 LLHUDText::updateScreenPos(LLVector2 &offset)
  675. {
  676. LLCoordGL screen_pos;
  677. LLVector2 screen_pos_vec;
  678. LLVector3 x_pixel_vec;
  679. LLVector3 y_pixel_vec;
  680. LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
  681. LLVector3 world_pos = mPositionAgent + (offset.mV[VX] * x_pixel_vec) + (offset.mV[VY] * y_pixel_vec);
  682. if (!LLViewerCamera::getInstance()->projectPosAgentToScreen(world_pos, screen_pos, FALSE) && mVisibleOffScreen)
  683. {
  684. // bubble off-screen, so find a spot for it along screen edge
  685. LLViewerCamera::getInstance()->projectPosAgentToScreenEdge(world_pos, screen_pos);
  686. }
  687. screen_pos_vec.setVec((F32)screen_pos.mX, (F32)screen_pos.mY);
  688. LLRect world_rect = gViewerWindow->getWorldViewRectScaled();
  689. S32 bottom = world_rect.mBottom + STATUS_BAR_HEIGHT;
  690. LLVector2 screen_center;
  691. 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);
  692. if(mVertAlignment == ALIGN_VERT_TOP)
  693. {
  694. screen_center.mV[VY] = llclamp((F32)screen_pos_vec.mV[VY], 
  695. (F32)bottom, 
  696. (F32)world_rect.mTop - mHeight - (F32)MENU_BAR_HEIGHT);
  697. mSoftScreenRect.setLeftTopAndSize(screen_center.mV[VX] - (mWidth + BUFFER_SIZE) * 0.5f, 
  698. screen_center.mV[VY] + (mHeight + BUFFER_SIZE), mWidth + BUFFER_SIZE, mHeight + BUFFER_SIZE);
  699. }
  700. else
  701. {
  702. screen_center.mV[VY] = llclamp((F32)screen_pos_vec.mV[VY], 
  703. (F32)bottom + mHeight * 0.5f, 
  704. (F32)world_rect.mTop - mHeight * 0.5f - (F32)MENU_BAR_HEIGHT);
  705. mSoftScreenRect.setCenterAndSize(screen_center.mV[VX], screen_center.mV[VY], mWidth + BUFFER_SIZE, mHeight + BUFFER_SIZE);
  706. }
  707. return offset + (screen_center - LLVector2((F32)screen_pos.mX, (F32)screen_pos.mY));
  708. }
  709. void LLHUDText::updateSize()
  710. {
  711. F32 width = 0.f;
  712. S32 max_lines = getMaxLines();
  713. S32 lines = (max_lines < 0) ? (S32)mTextSegments.size() : llmin((S32)mTextSegments.size(), max_lines);
  714. F32 height = (F32)mFontp->getLineHeight() * (lines + mLabelSegments.size());
  715. S32 start_segment;
  716. if (max_lines < 0) start_segment = 0;
  717. else start_segment = llmax((S32)0, (S32)mTextSegments.size() - max_lines);
  718. std::vector<LLHUDTextSegment>::iterator iter = mTextSegments.begin() + start_segment;
  719. while (iter != mTextSegments.end())
  720. {
  721. width = llmax(width, llmin(iter->getWidth(mFontp), HUD_TEXT_MAX_WIDTH));
  722. ++iter;
  723. }
  724. iter = mLabelSegments.begin();
  725. while (iter != mLabelSegments.end())
  726. {
  727. width = llmax(width, llmin(iter->getWidth(mFontp), HUD_TEXT_MAX_WIDTH));
  728. ++iter;
  729. }
  730. if (width == 0.f)
  731. {
  732. return;
  733. }
  734. width += HORIZONTAL_PADDING;
  735. height += VERTICAL_PADDING;
  736. if (!mResizeTimer.getStarted() && (width != mWidth || height != mHeight))
  737. {
  738. mResizeTimer.start();
  739. }
  740. // *NOTE: removed logic which did a divide by zero.
  741. F32 u = 1.f;//llclamp(mResizeTimer.getElapsedTimeF32() / RESIZE_TIME, 0.f, 1.f);
  742. if (u == 1.f)
  743. {
  744. mResizeTimer.stop();
  745. }
  746. mWidth = llmax(width, lerp(mWidth, (F32)width, u));
  747. mHeight = llmax(height, lerp(mHeight, (F32)height, u));
  748. }
  749. void LLHUDText::updateAll()
  750. {
  751. // iterate over all text objects, calculate their restoration forces,
  752. // and add them to the visible set if they are on screen and close enough
  753. sVisibleTextObjects.clear();
  754. sVisibleHUDTextObjects.clear();
  755. TextObjectIterator text_it;
  756. for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it)
  757. {
  758. LLHUDText* textp = (*text_it);
  759. textp->mTargetPositionOffset.clearVec();
  760. textp->updateSize();
  761. textp->updateVisibility();
  762. }
  763. // sort back to front for rendering purposes
  764. std::sort(sVisibleTextObjects.begin(), sVisibleTextObjects.end(), lltextobject_further_away());
  765. std::sort(sVisibleHUDTextObjects.begin(), sVisibleHUDTextObjects.end(), lltextobject_further_away());
  766. // iterate from front to back, and set LOD based on current screen coverage
  767. F32 screen_area = (F32)(gViewerWindow->getWindowWidthScaled() * gViewerWindow->getWindowHeightScaled());
  768. F32 current_screen_area = 0.f;
  769. std::vector<LLPointer<LLHUDText> >::reverse_iterator r_it;
  770. for (r_it = sVisibleTextObjects.rbegin(); r_it != sVisibleTextObjects.rend(); ++r_it)
  771. {
  772. LLHUDText* textp = (*r_it);
  773. if (textp->mUseBubble)
  774. {
  775. if (current_screen_area / screen_area > LOD_2_SCREEN_COVERAGE)
  776. {
  777. textp->setLOD(3);
  778. }
  779. else if (current_screen_area / screen_area > LOD_1_SCREEN_COVERAGE)
  780. {
  781. textp->setLOD(2);
  782. }
  783. else if (current_screen_area / screen_area > LOD_0_SCREEN_COVERAGE)
  784. {
  785. textp->setLOD(1);
  786. }
  787. else
  788. {
  789. textp->setLOD(0);
  790. }
  791. textp->updateSize();
  792. // find on-screen position and initialize collision rectangle
  793. textp->mTargetPositionOffset = textp->updateScreenPos(LLVector2::zero);
  794. current_screen_area += (F32)(textp->mSoftScreenRect.getWidth() * textp->mSoftScreenRect.getHeight());
  795. }
  796. }
  797. LLStat* camera_vel_stat = LLViewerCamera::getInstance()->getVelocityStat();
  798. F32 camera_vel = camera_vel_stat->getCurrent();
  799. if (camera_vel > MAX_STABLE_CAMERA_VELOCITY)
  800. {
  801. return;
  802. }
  803. VisibleTextObjectIterator src_it;
  804. for (S32 i = 0; i < NUM_OVERLAP_ITERATIONS; i++)
  805. {
  806. for (src_it = sVisibleTextObjects.begin(); src_it != sVisibleTextObjects.end(); ++src_it)
  807. {
  808. LLHUDText* src_textp = (*src_it);
  809. if (!src_textp->mUseBubble)
  810. {
  811. continue;
  812. }
  813. VisibleTextObjectIterator dst_it = src_it;
  814. ++dst_it;
  815. for (; dst_it != sVisibleTextObjects.end(); ++dst_it)
  816. {
  817. LLHUDText* dst_textp = (*dst_it);
  818. if (!dst_textp->mUseBubble)
  819. {
  820. continue;
  821. }
  822. if (src_textp->mSoftScreenRect.overlaps(dst_textp->mSoftScreenRect))
  823. {
  824. LLRectf intersect_rect = src_textp->mSoftScreenRect;
  825. intersect_rect.intersectWith(dst_textp->mSoftScreenRect);
  826. intersect_rect.stretch(-BUFFER_SIZE * 0.5f);
  827. F32 src_center_x = src_textp->mSoftScreenRect.getCenterX();
  828. F32 src_center_y = src_textp->mSoftScreenRect.getCenterY();
  829. F32 dst_center_x = dst_textp->mSoftScreenRect.getCenterX();
  830. F32 dst_center_y = dst_textp->mSoftScreenRect.getCenterY();
  831. F32 intersect_center_x = intersect_rect.getCenterX();
  832. F32 intersect_center_y = intersect_rect.getCenterY();
  833. LLVector2 force = lerp(LLVector2(dst_center_x - intersect_center_x, dst_center_y - intersect_center_y), 
  834. LLVector2(intersect_center_x - src_center_x, intersect_center_y - src_center_y),
  835. 0.5f);
  836. force.setVec(dst_center_x - src_center_x, dst_center_y - src_center_y);
  837. force.normVec();
  838. LLVector2 src_force = -1.f * force;
  839. LLVector2 dst_force = force;
  840. LLVector2 force_strength;
  841. F32 src_mult = dst_textp->mMass / (dst_textp->mMass + src_textp->mMass); 
  842. F32 dst_mult = 1.f - src_mult;
  843. F32 src_aspect_ratio = src_textp->mSoftScreenRect.getWidth() / src_textp->mSoftScreenRect.getHeight();
  844. F32 dst_aspect_ratio = dst_textp->mSoftScreenRect.getWidth() / dst_textp->mSoftScreenRect.getHeight();
  845. src_force.mV[VY] *= src_aspect_ratio;
  846. src_force.normVec();
  847. dst_force.mV[VY] *= dst_aspect_ratio;
  848. dst_force.normVec();
  849. src_force.mV[VX] *= llmin(intersect_rect.getWidth() * src_mult, intersect_rect.getHeight() * SPRING_STRENGTH);
  850. src_force.mV[VY] *= llmin(intersect_rect.getHeight() * src_mult, intersect_rect.getWidth() * SPRING_STRENGTH);
  851. dst_force.mV[VX] *=  llmin(intersect_rect.getWidth() * dst_mult, intersect_rect.getHeight() * SPRING_STRENGTH);
  852. dst_force.mV[VY] *=  llmin(intersect_rect.getHeight() * dst_mult, intersect_rect.getWidth() * SPRING_STRENGTH);
  853. src_textp->mTargetPositionOffset += src_force;
  854. dst_textp->mTargetPositionOffset += dst_force;
  855. src_textp->mTargetPositionOffset = src_textp->updateScreenPos(src_textp->mTargetPositionOffset);
  856. dst_textp->mTargetPositionOffset = dst_textp->updateScreenPos(dst_textp->mTargetPositionOffset);
  857. }
  858. }
  859. }
  860. }
  861. VisibleTextObjectIterator this_object_it;
  862. for (this_object_it = sVisibleTextObjects.begin(); this_object_it != sVisibleTextObjects.end(); ++this_object_it)
  863. {
  864. if (!(*this_object_it)->mUseBubble)
  865. {
  866. continue;
  867. }
  868. (*this_object_it)->mPositionOffset = lerp((*this_object_it)->mPositionOffset, (*this_object_it)->mTargetPositionOffset, LLCriticalDamp::getInterpolant(POSITION_DAMPING_TC));
  869. }
  870. }
  871. void LLHUDText::setLOD(S32 lod)
  872. {
  873. mLOD = lod;
  874. //RN: uncomment this to visualize LOD levels
  875. //std::string label = llformat("%d", lod);
  876. //setLabel(label);
  877. }
  878. S32 LLHUDText::getMaxLines()
  879. {
  880. switch(mLOD)
  881. {
  882. case 0:
  883. return mMaxLines;
  884. case 1:
  885. return mMaxLines > 0 ? mMaxLines / 2 : 5;
  886. case 2:
  887. return mMaxLines > 0 ? mMaxLines / 3 : 2;
  888. default:
  889. // label only
  890. return 0;
  891. }
  892. }
  893. void LLHUDText::markDead()
  894. {
  895. sTextObjects.erase(LLPointer<LLHUDText>(this));
  896. LLHUDObject::markDead();
  897. }
  898. void LLHUDText::renderAllHUD()
  899. {
  900. LLGLState::checkStates();
  901. LLGLState::checkTextureChannels();
  902. LLGLState::checkClientArrays();
  903. {
  904. LLGLEnable color_mat(GL_COLOR_MATERIAL);
  905. LLGLDepthTest depth(GL_FALSE, GL_FALSE);
  906. VisibleTextObjectIterator text_it;
  907. for (text_it = sVisibleHUDTextObjects.begin(); text_it != sVisibleHUDTextObjects.end(); ++text_it)
  908. {
  909. (*text_it)->renderText(FALSE);
  910. }
  911. }
  912. LLVertexBuffer::unbind();
  913.     LLVertexBuffer::unbind();
  914. LLGLState::checkStates();
  915. LLGLState::checkTextureChannels();
  916. LLGLState::checkClientArrays();
  917. }
  918. void LLHUDText::shiftAll(const LLVector3& offset)
  919. {
  920. TextObjectIterator text_it;
  921. for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it)
  922. {
  923. LLHUDText *textp = text_it->get();
  924. textp->shift(offset);
  925. }
  926. }
  927. void LLHUDText::shift(const LLVector3& offset)
  928. {
  929. mPositionAgent += offset;
  930. }
  931. //static 
  932. void LLHUDText::addPickable(std::set<LLViewerObject*> &pick_list)
  933. {
  934. //this might put an object on the pick list a second time, overriding it's mGLName, which is ok
  935. // *FIX: we should probably cull against pick frustum
  936. VisibleTextObjectIterator text_it;
  937. for (text_it = sVisibleTextObjects.begin(); text_it != sVisibleTextObjects.end(); ++text_it)
  938. {
  939. if (!(*text_it)->mUseBubble)
  940. {
  941. continue;
  942. }
  943. pick_list.insert((*text_it)->mSourceObject);
  944. }
  945. }
  946. //static
  947. // called when UI scale changes, to flush font width caches
  948. void LLHUDText::reshape()
  949. {
  950. TextObjectIterator text_it;
  951. for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it)
  952. {
  953. LLHUDText* textp = (*text_it);
  954. std::vector<LLHUDTextSegment>::iterator segment_iter; 
  955. for (segment_iter = textp->mTextSegments.begin();
  956.  segment_iter != textp->mTextSegments.end(); ++segment_iter )
  957. {
  958. segment_iter->clearFontWidthMap();
  959. }
  960. for(segment_iter = textp->mLabelSegments.begin();
  961. segment_iter != textp->mLabelSegments.end(); ++segment_iter )
  962. {
  963. segment_iter->clearFontWidthMap();
  964. }
  965. }
  966. }
  967. //============================================================================
  968. F32 LLHUDText::LLHUDTextSegment::getWidth(const LLFontGL* font)
  969. {
  970. std::map<const LLFontGL*, F32>::iterator iter = mFontWidthMap.find(font);
  971. if (iter != mFontWidthMap.end())
  972. {
  973. return iter->second;
  974. }
  975. else
  976. {
  977. F32 width = font->getWidthF32(mText.c_str());
  978. mFontWidthMap[font] = width;
  979. return width;
  980. }
  981. }