PageRenderTime 53ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llui/llui.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2191 lines | 1615 code | 408 blank | 168 comment | 132 complexity | 680b4e3d4650b32f1fc530f0b19891a4 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llui.cpp
  3. * @brief UI implementation
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. // Utilities functions the user interface needs
  27. #include "linden_common.h"
  28. #include <string>
  29. #include <map>
  30. // Linden library includes
  31. #include "v2math.h"
  32. #include "m3math.h"
  33. #include "v4color.h"
  34. #include "llrender.h"
  35. #include "llrect.h"
  36. #include "lldir.h"
  37. #include "llgl.h"
  38. // Project includes
  39. #include "llcommandmanager.h"
  40. #include "llcontrol.h"
  41. #include "llui.h"
  42. #include "lluicolortable.h"
  43. #include "llview.h"
  44. #include "lllineeditor.h"
  45. #include "llfloater.h"
  46. #include "llfloaterreg.h"
  47. #include "llmenugl.h"
  48. #include "llmenubutton.h"
  49. #include "llloadingindicator.h"
  50. #include "llwindow.h"
  51. // for registration
  52. #include "llfiltereditor.h"
  53. #include "llflyoutbutton.h"
  54. #include "llsearcheditor.h"
  55. #include "lltoolbar.h"
  56. // for XUIParse
  57. #include "llquaternion.h"
  58. #include <boost/tokenizer.hpp>
  59. #include <boost/algorithm/string/find_iterator.hpp>
  60. #include <boost/algorithm/string/finder.hpp>
  61. //
  62. // Globals
  63. //
  64. const LLColor4 UI_VERTEX_COLOR(1.f, 1.f, 1.f, 1.f);
  65. // Language for UI construction
  66. std::map<std::string, std::string> gTranslation;
  67. std::list<std::string> gUntranslated;
  68. /*static*/ LLUI::settings_map_t LLUI::sSettingGroups;
  69. /*static*/ LLImageProviderInterface* LLUI::sImageProvider = NULL;
  70. /*static*/ LLUIAudioCallback LLUI::sAudioCallback = NULL;
  71. /*static*/ LLVector2 LLUI::sGLScaleFactor(1.f, 1.f);
  72. /*static*/ LLWindow* LLUI::sWindow = NULL;
  73. /*static*/ LLView* LLUI::sRootView = NULL;
  74. /*static*/ BOOL LLUI::sDirty = FALSE;
  75. /*static*/ LLRect LLUI::sDirtyRect;
  76. /*static*/ LLHelp* LLUI::sHelpImpl = NULL;
  77. /*static*/ std::vector<std::string> LLUI::sXUIPaths;
  78. /*static*/ LLFrameTimer LLUI::sMouseIdleTimer;
  79. /*static*/ LLUI::add_popup_t LLUI::sAddPopupFunc;
  80. /*static*/ LLUI::remove_popup_t LLUI::sRemovePopupFunc;
  81. /*static*/ LLUI::clear_popups_t LLUI::sClearPopupsFunc;
  82. // register filter editor here
  83. static LLDefaultChildRegistry::Register<LLFilterEditor> register_filter_editor("filter_editor");
  84. static LLDefaultChildRegistry::Register<LLFlyoutButton> register_flyout_button("flyout_button");
  85. static LLDefaultChildRegistry::Register<LLSearchEditor> register_search_editor("search_editor");
  86. // register other widgets which otherwise may not be linked in
  87. static LLDefaultChildRegistry::Register<LLLoadingIndicator> register_loading_indicator("loading_indicator");
  88. static LLDefaultChildRegistry::Register<LLToolBar> register_toolbar("toolbar");
  89. //
  90. // Functions
  91. //
  92. void make_ui_sound(const char* namep)
  93. {
  94. std::string name = ll_safe_string(namep);
  95. if (!LLUI::sSettingGroups["config"]->controlExists(name))
  96. {
  97. llwarns << "tried to make UI sound for unknown sound name: " << name << llendl;
  98. }
  99. else
  100. {
  101. LLUUID uuid(LLUI::sSettingGroups["config"]->getString(name));
  102. if (uuid.isNull())
  103. {
  104. if (LLUI::sSettingGroups["config"]->getString(name) == LLUUID::null.asString())
  105. {
  106. if (LLUI::sSettingGroups["config"]->getBOOL("UISndDebugSpamToggle"))
  107. {
  108. llinfos << "UI sound name: " << name << " triggered but silent (null uuid)" << llendl;
  109. }
  110. }
  111. else
  112. {
  113. llwarns << "UI sound named: " << name << " does not translate to a valid uuid" << llendl;
  114. }
  115. }
  116. else if (LLUI::sAudioCallback != NULL)
  117. {
  118. if (LLUI::sSettingGroups["config"]->getBOOL("UISndDebugSpamToggle"))
  119. {
  120. llinfos << "UI sound name: " << name << llendl;
  121. }
  122. LLUI::sAudioCallback(uuid);
  123. }
  124. }
  125. }
  126. BOOL ui_point_in_rect(S32 x, S32 y, S32 left, S32 top, S32 right, S32 bottom)
  127. {
  128. if (x < left || right < x) return FALSE;
  129. if (y < bottom || top < y) return FALSE;
  130. return TRUE;
  131. }
  132. // Puts GL into 2D drawing mode by turning off lighting, setting to an
  133. // orthographic projection, etc.
  134. void gl_state_for_2d(S32 width, S32 height)
  135. {
  136. stop_glerror();
  137. F32 window_width = (F32) width;//gViewerWindow->getWindowWidth();
  138. F32 window_height = (F32) height;//gViewerWindow->getWindowHeight();
  139. gGL.matrixMode(LLRender::MM_PROJECTION);
  140. gGL.loadIdentity();
  141. gGL.ortho(0.0f, llmax(window_width, 1.f), 0.0f, llmax(window_height,1.f), -1.0f, 1.0f);
  142. gGL.matrixMode(LLRender::MM_MODELVIEW);
  143. gGL.loadIdentity();
  144. stop_glerror();
  145. }
  146. void gl_draw_x(const LLRect& rect, const LLColor4& color)
  147. {
  148. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  149. gGL.color4fv( color.mV );
  150. gGL.begin( LLRender::LINES );
  151. gGL.vertex2i( rect.mLeft, rect.mTop );
  152. gGL.vertex2i( rect.mRight, rect.mBottom );
  153. gGL.vertex2i( rect.mLeft, rect.mBottom );
  154. gGL.vertex2i( rect.mRight, rect.mTop );
  155. gGL.end();
  156. }
  157. void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, S32 pixel_offset, BOOL filled)
  158. {
  159. gGL.color4fv(color.mV);
  160. gl_rect_2d_offset_local(left, top, right, bottom, pixel_offset, filled);
  161. }
  162. void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, S32 pixel_offset, BOOL filled)
  163. {
  164. gGL.pushUIMatrix();
  165. left += LLFontGL::sCurOrigin.mX;
  166. right += LLFontGL::sCurOrigin.mX;
  167. bottom += LLFontGL::sCurOrigin.mY;
  168. top += LLFontGL::sCurOrigin.mY;
  169. gGL.loadUIIdentity();
  170. gl_rect_2d(llfloor((F32)left * LLUI::sGLScaleFactor.mV[VX]) - pixel_offset,
  171. llfloor((F32)top * LLUI::sGLScaleFactor.mV[VY]) + pixel_offset,
  172. llfloor((F32)right * LLUI::sGLScaleFactor.mV[VX]) + pixel_offset,
  173. llfloor((F32)bottom * LLUI::sGLScaleFactor.mV[VY]) - pixel_offset,
  174. filled);
  175. gGL.popUIMatrix();
  176. }
  177. void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled )
  178. {
  179. stop_glerror();
  180. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  181. // Counterclockwise quad will face the viewer
  182. if( filled )
  183. {
  184. gGL.begin( LLRender::QUADS );
  185. gGL.vertex2i(left, top);
  186. gGL.vertex2i(left, bottom);
  187. gGL.vertex2i(right, bottom);
  188. gGL.vertex2i(right, top);
  189. gGL.end();
  190. }
  191. else
  192. {
  193. if( gGLManager.mATIOffsetVerticalLines )
  194. {
  195. // Work around bug in ATI driver: vertical lines are offset by (-1,-1)
  196. gGL.begin( LLRender::LINES );
  197. // Verticals
  198. gGL.vertex2i(left + 1, top);
  199. gGL.vertex2i(left + 1, bottom);
  200. gGL.vertex2i(right, bottom);
  201. gGL.vertex2i(right, top);
  202. // Horizontals
  203. top--;
  204. right--;
  205. gGL.vertex2i(left, bottom);
  206. gGL.vertex2i(right, bottom);
  207. gGL.vertex2i(left, top);
  208. gGL.vertex2i(right, top);
  209. gGL.end();
  210. }
  211. else
  212. {
  213. top--;
  214. right--;
  215. gGL.begin( LLRender::LINE_STRIP );
  216. gGL.vertex2i(left, top);
  217. gGL.vertex2i(left, bottom);
  218. gGL.vertex2i(right, bottom);
  219. gGL.vertex2i(right, top);
  220. gGL.vertex2i(left, top);
  221. gGL.end();
  222. }
  223. }
  224. stop_glerror();
  225. }
  226. void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, BOOL filled )
  227. {
  228. gGL.color4fv( color.mV );
  229. gl_rect_2d( left, top, right, bottom, filled );
  230. }
  231. void gl_rect_2d( const LLRect& rect, const LLColor4& color, BOOL filled )
  232. {
  233. gGL.color4fv( color.mV );
  234. gl_rect_2d( rect.mLeft, rect.mTop, rect.mRight, rect.mBottom, filled );
  235. }
  236. // Given a rectangle on the screen, draws a drop shadow _outside_
  237. // the right and bottom edges of it. Along the right it has width "lines"
  238. // and along the bottom it has height "lines".
  239. void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &start_color, S32 lines)
  240. {
  241. stop_glerror();
  242. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  243. // HACK: Overlap with the rectangle by a single pixel.
  244. right--;
  245. bottom++;
  246. lines++;
  247. LLColor4 end_color = start_color;
  248. end_color.mV[VALPHA] = 0.f;
  249. gGL.begin(LLRender::QUADS);
  250. // Right edge, CCW faces screen
  251. gGL.color4fv(start_color.mV);
  252. gGL.vertex2i(right, top-lines);
  253. gGL.vertex2i(right, bottom);
  254. gGL.color4fv(end_color.mV);
  255. gGL.vertex2i(right+lines, bottom);
  256. gGL.vertex2i(right+lines, top-lines);
  257. // Bottom edge, CCW faces screen
  258. gGL.color4fv(start_color.mV);
  259. gGL.vertex2i(right, bottom);
  260. gGL.vertex2i(left+lines, bottom);
  261. gGL.color4fv(end_color.mV);
  262. gGL.vertex2i(left+lines, bottom-lines);
  263. gGL.vertex2i(right, bottom-lines);
  264. // bottom left Corner
  265. gGL.color4fv(start_color.mV);
  266. gGL.vertex2i(left+lines, bottom);
  267. gGL.color4fv(end_color.mV);
  268. gGL.vertex2i(left, bottom);
  269. // make the bottom left corner not sharp
  270. gGL.vertex2i(left+1, bottom-lines+1);
  271. gGL.vertex2i(left+lines, bottom-lines);
  272. // bottom right corner
  273. gGL.color4fv(start_color.mV);
  274. gGL.vertex2i(right, bottom);
  275. gGL.color4fv(end_color.mV);
  276. gGL.vertex2i(right, bottom-lines);
  277. // make the rightmost corner not sharp
  278. gGL.vertex2i(right+lines-1, bottom-lines+1);
  279. gGL.vertex2i(right+lines, bottom);
  280. // top right corner
  281. gGL.color4fv(start_color.mV);
  282. gGL.vertex2i( right, top-lines );
  283. gGL.color4fv(end_color.mV);
  284. gGL.vertex2i( right+lines, top-lines );
  285. // make the corner not sharp
  286. gGL.vertex2i( right+lines-1, top-1 );
  287. gGL.vertex2i( right, top );
  288. gGL.end();
  289. stop_glerror();
  290. }
  291. void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2 )
  292. {
  293. // Work around bug in ATI driver: vertical lines are offset by (-1,-1)
  294. if( (x1 == x2) && gGLManager.mATIOffsetVerticalLines )
  295. {
  296. x1++;
  297. x2++;
  298. y1++;
  299. y2++;
  300. }
  301. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  302. gGL.begin(LLRender::LINES);
  303. gGL.vertex2i(x1, y1);
  304. gGL.vertex2i(x2, y2);
  305. gGL.end();
  306. }
  307. void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2, const LLColor4 &color )
  308. {
  309. // Work around bug in ATI driver: vertical lines are offset by (-1,-1)
  310. if( (x1 == x2) && gGLManager.mATIOffsetVerticalLines )
  311. {
  312. x1++;
  313. x2++;
  314. y1++;
  315. y2++;
  316. }
  317. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  318. gGL.color4fv( color.mV );
  319. gGL.begin(LLRender::LINES);
  320. gGL.vertex2i(x1, y1);
  321. gGL.vertex2i(x2, y2);
  322. gGL.end();
  323. }
  324. void gl_triangle_2d(S32 x1, S32 y1, S32 x2, S32 y2, S32 x3, S32 y3, const LLColor4& color, BOOL filled)
  325. {
  326. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  327. gGL.color4fv(color.mV);
  328. if (filled)
  329. {
  330. gGL.begin(LLRender::TRIANGLES);
  331. }
  332. else
  333. {
  334. gGL.begin(LLRender::LINE_LOOP);
  335. }
  336. gGL.vertex2i(x1, y1);
  337. gGL.vertex2i(x2, y2);
  338. gGL.vertex2i(x3, y3);
  339. gGL.end();
  340. }
  341. void gl_corners_2d(S32 left, S32 top, S32 right, S32 bottom, S32 length, F32 max_frac)
  342. {
  343. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  344. length = llmin((S32)(max_frac*(right - left)), length);
  345. length = llmin((S32)(max_frac*(top - bottom)), length);
  346. gGL.begin(LLRender::LINES);
  347. gGL.vertex2i(left, top);
  348. gGL.vertex2i(left + length, top);
  349. gGL.vertex2i(left, top);
  350. gGL.vertex2i(left, top - length);
  351. gGL.vertex2i(left, bottom);
  352. gGL.vertex2i(left + length, bottom);
  353. gGL.vertex2i(left, bottom);
  354. gGL.vertex2i(left, bottom + length);
  355. gGL.vertex2i(right, top);
  356. gGL.vertex2i(right - length, top);
  357. gGL.vertex2i(right, top);
  358. gGL.vertex2i(right, top - length);
  359. gGL.vertex2i(right, bottom);
  360. gGL.vertex2i(right - length, bottom);
  361. gGL.vertex2i(right, bottom);
  362. gGL.vertex2i(right, bottom + length);
  363. gGL.end();
  364. }
  365. void gl_draw_image( S32 x, S32 y, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect )
  366. {
  367. if (NULL == image)
  368. {
  369. llwarns << "image == NULL; aborting function" << llendl;
  370. return;
  371. }
  372. gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), 0.f, image, color, uv_rect );
  373. }
  374. void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect)
  375. {
  376. if (NULL == image)
  377. {
  378. llwarns << "image == NULL; aborting function" << llendl;
  379. return;
  380. }
  381. gl_draw_scaled_rotated_image( x, y, width, height, 0.f, image, color, uv_rect );
  382. }
  383. void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_rect)
  384. {
  385. if (NULL == image)
  386. {
  387. llwarns << "image == NULL; aborting function" << llendl;
  388. return;
  389. }
  390. // scale screen size of borders down
  391. F32 border_width_fraction = (F32)border_width / (F32)image->getWidth(0);
  392. F32 border_height_fraction = (F32)border_height / (F32)image->getHeight(0);
  393. LLRectf scale_rect(border_width_fraction, 1.f - border_height_fraction, 1.f - border_width_fraction, border_height_fraction);
  394. gl_draw_scaled_image_with_border(x, y, width, height, image, color, solid_color, uv_rect, scale_rect);
  395. }
  396. void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_outer_rect, const LLRectf& center_rect)
  397. {
  398. stop_glerror();
  399. if (NULL == image)
  400. {
  401. llwarns << "image == NULL; aborting function" << llendl;
  402. return;
  403. }
  404. // add in offset of current image to current UI translation
  405. const LLVector3 ui_scale = gGL.getUIScale();
  406. const LLVector3 ui_translation = (gGL.getUITranslation() + LLVector3(x, y, 0.f)).scaledVec(ui_scale);
  407. F32 uv_width = uv_outer_rect.getWidth();
  408. F32 uv_height = uv_outer_rect.getHeight();
  409. // shrink scaling region to be proportional to clipped image region
  410. LLRectf uv_center_rect(
  411. uv_outer_rect.mLeft + (center_rect.mLeft * uv_width),
  412. uv_outer_rect.mBottom + (center_rect.mTop * uv_height),
  413. uv_outer_rect.mLeft + (center_rect.mRight * uv_width),
  414. uv_outer_rect.mBottom + (center_rect.mBottom * uv_height));
  415. F32 image_width = image->getWidth(0);
  416. F32 image_height = image->getHeight(0);
  417. S32 image_natural_width = llround(image_width * uv_width);
  418. S32 image_natural_height = llround(image_height * uv_height);
  419. LLRectf draw_center_rect( uv_center_rect.mLeft * image_width,
  420. uv_center_rect.mTop * image_height,
  421. uv_center_rect.mRight * image_width,
  422. uv_center_rect.mBottom * image_height);
  423. { // scale fixed region of image to drawn region
  424. draw_center_rect.mRight += width - image_natural_width;
  425. draw_center_rect.mTop += height - image_natural_height;
  426. F32 border_shrink_width = llmax(0.f, draw_center_rect.mLeft - draw_center_rect.mRight);
  427. F32 border_shrink_height = llmax(0.f, draw_center_rect.mBottom - draw_center_rect.mTop);
  428. F32 shrink_width_ratio = center_rect.getWidth() == 1.f ? 0.f : border_shrink_width / ((F32)image_natural_width * (1.f - center_rect.getWidth()));
  429. F32 shrink_height_ratio = center_rect.getHeight() == 1.f ? 0.f : border_shrink_height / ((F32)image_natural_height * (1.f - center_rect.getHeight()));
  430. F32 shrink_scale = 1.f - llmax(shrink_width_ratio, shrink_height_ratio);
  431. draw_center_rect.mLeft = llround(ui_translation.mV[VX] + (F32)draw_center_rect.mLeft * shrink_scale * ui_scale.mV[VX]);
  432. draw_center_rect.mTop = llround(ui_translation.mV[VY] + lerp((F32)height, (F32)draw_center_rect.mTop, shrink_scale) * ui_scale.mV[VY]);
  433. draw_center_rect.mRight = llround(ui_translation.mV[VX] + lerp((F32)width, (F32)draw_center_rect.mRight, shrink_scale) * ui_scale.mV[VX]);
  434. draw_center_rect.mBottom = llround(ui_translation.mV[VY] + (F32)draw_center_rect.mBottom * shrink_scale * ui_scale.mV[VY]);
  435. }
  436. LLRectf draw_outer_rect(ui_translation.mV[VX],
  437. ui_translation.mV[VY] + height * ui_scale.mV[VY],
  438. ui_translation.mV[VX] + width * ui_scale.mV[VX],
  439. ui_translation.mV[VY]);
  440. LLGLSUIDefault gls_ui;
  441. if (solid_color)
  442. {
  443. if (LLGLSLShader::sNoFixedFunction)
  444. {
  445. gSolidColorProgram.bind();
  446. }
  447. else
  448. {
  449. gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
  450. gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA);
  451. }
  452. }
  453. gGL.getTexUnit(0)->bind(image, true);
  454. gGL.color4fv(color.mV);
  455. const S32 NUM_VERTICES = 9 * 4; // 9 quads
  456. LLVector2 uv[NUM_VERTICES];
  457. LLVector3 pos[NUM_VERTICES];
  458. S32 index = 0;
  459. gGL.begin(LLRender::QUADS);
  460. {
  461. // draw bottom left
  462. uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mBottom);
  463. pos[index] = LLVector3(draw_outer_rect.mLeft, draw_outer_rect.mBottom, 0.f);
  464. index++;
  465. uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom);
  466. pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
  467. index++;
  468. uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
  469. pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
  470. index++;
  471. uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom);
  472. pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
  473. index++;
  474. // draw bottom middle
  475. uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom);
  476. pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
  477. index++;
  478. uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom);
  479. pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
  480. index++;
  481. uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
  482. pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
  483. index++;
  484. uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
  485. pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
  486. index++;
  487. // draw bottom right
  488. uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom);
  489. pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
  490. index++;
  491. uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mBottom);
  492. pos[index] = LLVector3(draw_outer_rect.mRight, draw_outer_rect.mBottom, 0.f);
  493. index++;
  494. uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom);
  495. pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
  496. index++;
  497. uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
  498. pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
  499. index++;
  500. // draw left
  501. uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom);
  502. pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
  503. index++;
  504. uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
  505. pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
  506. index++;
  507. uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
  508. pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
  509. index++;
  510. uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop);
  511. pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
  512. index++;
  513. // draw middle
  514. uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
  515. pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
  516. index++;
  517. uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
  518. pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
  519. index++;
  520. uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
  521. pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
  522. index++;
  523. uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
  524. pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
  525. index++;
  526. // draw right
  527. uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
  528. pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
  529. index++;
  530. uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom);
  531. pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
  532. index++;
  533. uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop);
  534. pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
  535. index++;
  536. uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
  537. pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
  538. index++;
  539. // draw top left
  540. uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop);
  541. pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
  542. index++;
  543. uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
  544. pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
  545. index++;
  546. uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop);
  547. pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
  548. index++;
  549. uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mTop);
  550. pos[index] = LLVector3(draw_outer_rect.mLeft, draw_outer_rect.mTop, 0.f);
  551. index++;
  552. // draw top middle
  553. uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
  554. pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
  555. index++;
  556. uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
  557. pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
  558. index++;
  559. uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop);
  560. pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
  561. index++;
  562. uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop);
  563. pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
  564. index++;
  565. // draw top right
  566. uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
  567. pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
  568. index++;
  569. uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop);
  570. pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
  571. index++;
  572. uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mTop);
  573. pos[index] = LLVector3(draw_outer_rect.mRight, draw_outer_rect.mTop, 0.f);
  574. index++;
  575. uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop);
  576. pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
  577. index++;
  578. gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES);
  579. }
  580. gGL.end();
  581. if (solid_color)
  582. {
  583. if (LLGLSLShader::sNoFixedFunction)
  584. {
  585. gUIProgram.bind();
  586. }
  587. else
  588. {
  589. gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
  590. }
  591. }
  592. }
  593. void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect)
  594. {
  595. gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), degrees, image, color, uv_rect );
  596. }
  597. void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect)
  598. {
  599. if (NULL == image)
  600. {
  601. llwarns << "image == NULL; aborting function" << llendl;
  602. return;
  603. }
  604. LLGLSUIDefault gls_ui;
  605. gGL.getTexUnit(0)->bind(image, true);
  606. gGL.color4fv(color.mV);
  607. if (degrees == 0.f)
  608. {
  609. const S32 NUM_VERTICES = 4; // 9 quads
  610. LLVector2 uv[NUM_VERTICES];
  611. LLVector3 pos[NUM_VERTICES];
  612. gGL.begin(LLRender::QUADS);
  613. {
  614. LLVector3 ui_scale = gGL.getUIScale();
  615. LLVector3 ui_translation = gGL.getUITranslation();
  616. ui_translation.mV[VX] += x;
  617. ui_translation.mV[VY] += y;
  618. ui_translation.scaleVec(ui_scale);
  619. S32 index = 0;
  620. S32 scaled_width = llround(width * ui_scale.mV[VX]);
  621. S32 scaled_height = llround(height * ui_scale.mV[VY]);
  622. uv[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
  623. pos[index] = LLVector3(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY] + scaled_height, 0.f);
  624. index++;
  625. uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop);
  626. pos[index] = LLVector3(ui_translation.mV[VX], ui_translation.mV[VY] + scaled_height, 0.f);
  627. index++;
  628. uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
  629. pos[index] = LLVector3(ui_translation.mV[VX], ui_translation.mV[VY], 0.f);
  630. index++;
  631. uv[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom);
  632. pos[index] = LLVector3(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY], 0.f);
  633. index++;
  634. gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES);
  635. }
  636. gGL.end();
  637. }
  638. else
  639. {
  640. gGL.pushUIMatrix();
  641. gGL.translateUI((F32)x, (F32)y, 0.f);
  642. F32 offset_x = F32(width/2);
  643. F32 offset_y = F32(height/2);
  644. gGL.translateUI(offset_x, offset_y, 0.f);
  645. LLMatrix3 quat(0.f, 0.f, degrees*DEG_TO_RAD);
  646. gGL.getTexUnit(0)->bind(image, true);
  647. gGL.color4fv(color.mV);
  648. gGL.begin(LLRender::QUADS);
  649. {
  650. LLVector3 v;
  651. v = LLVector3(offset_x, offset_y, 0.f) * quat;
  652. gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
  653. gGL.vertex2f(v.mV[0], v.mV[1] );
  654. v = LLVector3(-offset_x, offset_y, 0.f) * quat;
  655. gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
  656. gGL.vertex2f(v.mV[0], v.mV[1] );
  657. v = LLVector3(-offset_x, -offset_y, 0.f) * quat;
  658. gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
  659. gGL.vertex2f(v.mV[0], v.mV[1] );
  660. v = LLVector3(offset_x, -offset_y, 0.f) * quat;
  661. gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
  662. gGL.vertex2f(v.mV[0], v.mV[1] );
  663. }
  664. gGL.end();
  665. gGL.popUIMatrix();
  666. }
  667. }
  668. void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase )
  669. {
  670. phase = fmod(phase, 1.f);
  671. S32 shift = S32(phase * 4.f) % 4;
  672. // Stippled line
  673. LLGLEnable stipple(GL_LINE_STIPPLE);
  674. gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], color.mV[VALPHA]);
  675. gGL.flush();
  676. glLineWidth(2.5f);
  677. glLineStipple(2, 0x3333 << shift);
  678. gGL.begin(LLRender::LINES);
  679. {
  680. gGL.vertex3fv( start.mV );
  681. gGL.vertex3fv( end.mV );
  682. }
  683. gGL.end();
  684. LLUI::setLineWidth(1.f);
  685. }
  686. void gl_arc_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled, F32 start_angle, F32 end_angle)
  687. {
  688. if (end_angle < start_angle)
  689. {
  690. end_angle += F_TWO_PI;
  691. }
  692. gGL.pushUIMatrix();
  693. {
  694. gGL.translateUI(center_x, center_y, 0.f);
  695. // Inexact, but reasonably fast.
  696. F32 delta = (end_angle - start_angle) / steps;
  697. F32 sin_delta = sin( delta );
  698. F32 cos_delta = cos( delta );
  699. F32 x = cosf(start_angle) * radius;
  700. F32 y = sinf(start_angle) * radius;
  701. if (filled)
  702. {
  703. gGL.begin(LLRender::TRIANGLE_FAN);
  704. gGL.vertex2f(0.f, 0.f);
  705. // make sure circle is complete
  706. steps += 1;
  707. }
  708. else
  709. {
  710. gGL.begin(LLRender::LINE_STRIP);
  711. }
  712. while( steps-- )
  713. {
  714. // Successive rotations
  715. gGL.vertex2f( x, y );
  716. F32 x_new = x * cos_delta - y * sin_delta;
  717. y = x * sin_delta + y * cos_delta;
  718. x = x_new;
  719. }
  720. gGL.end();
  721. }
  722. gGL.popUIMatrix();
  723. }
  724. void gl_circle_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled)
  725. {
  726. gGL.pushUIMatrix();
  727. {
  728. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  729. gGL.translateUI(center_x, center_y, 0.f);
  730. // Inexact, but reasonably fast.
  731. F32 delta = F_TWO_PI / steps;
  732. F32 sin_delta = sin( delta );
  733. F32 cos_delta = cos( delta );
  734. F32 x = radius;
  735. F32 y = 0.f;
  736. if (filled)
  737. {
  738. gGL.begin(LLRender::TRIANGLE_FAN);
  739. gGL.vertex2f(0.f, 0.f);
  740. // make sure circle is complete
  741. steps += 1;
  742. }
  743. else
  744. {
  745. gGL.begin(LLRender::LINE_LOOP);
  746. }
  747. while( steps-- )
  748. {
  749. // Successive rotations
  750. gGL.vertex2f( x, y );
  751. F32 x_new = x * cos_delta - y * sin_delta;
  752. y = x * sin_delta + y * cos_delta;
  753. x = x_new;
  754. }
  755. gGL.end();
  756. }
  757. gGL.popUIMatrix();
  758. }
  759. // Renders a ring with sides (tube shape)
  760. void gl_deep_circle( F32 radius, F32 depth, S32 steps )
  761. {
  762. F32 x = radius;
  763. F32 y = 0.f;
  764. F32 angle_delta = F_TWO_PI / (F32)steps;
  765. gGL.begin( LLRender::TRIANGLE_STRIP );
  766. {
  767. S32 step = steps + 1; // An extra step to close the circle.
  768. while( step-- )
  769. {
  770. gGL.vertex3f( x, y, depth );
  771. gGL.vertex3f( x, y, 0.f );
  772. F32 x_new = x * cosf(angle_delta) - y * sinf(angle_delta);
  773. y = x * sinf(angle_delta) + y * cosf(angle_delta);
  774. x = x_new;
  775. }
  776. }
  777. gGL.end();
  778. }
  779. void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor4& side_color, S32 steps, BOOL render_center )
  780. {
  781. gGL.pushUIMatrix();
  782. {
  783. gGL.translateUI(0.f, 0.f, -width / 2);
  784. if( render_center )
  785. {
  786. gGL.color4fv(center_color.mV);
  787. gGL.diffuseColor4fv(center_color.mV);
  788. gl_deep_circle( radius, width, steps );
  789. }
  790. else
  791. {
  792. gGL.diffuseColor4fv(side_color.mV);
  793. gl_washer_2d(radius, radius - width, steps, side_color, side_color);
  794. gGL.translateUI(0.f, 0.f, width);
  795. gl_washer_2d(radius - width, radius, steps, side_color, side_color);
  796. }
  797. }
  798. gGL.popUIMatrix();
  799. }
  800. // Draw gray and white checkerboard with black border
  801. void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha)
  802. {
  803. // Initialize the first time this is called.
  804. const S32 PIXELS = 32;
  805. static GLubyte checkerboard[PIXELS * PIXELS];
  806. static BOOL first = TRUE;
  807. if( first )
  808. {
  809. for( S32 i = 0; i < PIXELS; i++ )
  810. {
  811. for( S32 j = 0; j < PIXELS; j++ )
  812. {
  813. checkerboard[i * PIXELS + j] = ((i & 1) ^ (j & 1)) * 0xFF;
  814. }
  815. }
  816. first = FALSE;
  817. }
  818. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  819. // ...white squares
  820. gGL.color4f( 1.f, 1.f, 1.f, alpha );
  821. gl_rect_2d(rect);
  822. // ...gray squares
  823. gGL.color4f( .7f, .7f, .7f, alpha );
  824. gGL.flush();
  825. if (!LLGLSLShader::sNoFixedFunction)
  826. { //polygon stipple is deprecated
  827. glPolygonStipple( checkerboard );
  828. LLGLEnable polygon_stipple(GL_POLYGON_STIPPLE);
  829. gl_rect_2d(rect);
  830. }
  831. else
  832. {
  833. gl_rect_2d(rect);
  834. }
  835. gGL.flush();
  836. }
  837. // Draws the area between two concentric circles, like
  838. // a doughnut or washer.
  839. void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color)
  840. {
  841. const F32 DELTA = F_TWO_PI / steps;
  842. const F32 SIN_DELTA = sin( DELTA );
  843. const F32 COS_DELTA = cos( DELTA );
  844. F32 x1 = outer_radius;
  845. F32 y1 = 0.f;
  846. F32 x2 = inner_radius;
  847. F32 y2 = 0.f;
  848. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  849. gGL.begin( LLRender::TRIANGLE_STRIP );
  850. {
  851. steps += 1; // An extra step to close the circle.
  852. while( steps-- )
  853. {
  854. gGL.color4fv(outer_color.mV);
  855. gGL.vertex2f( x1, y1 );
  856. gGL.color4fv(inner_color.mV);
  857. gGL.vertex2f( x2, y2 );
  858. F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA;
  859. y1 = x1 * SIN_DELTA + y1 * COS_DELTA;
  860. x1 = x1_new;
  861. F32 x2_new = x2 * COS_DELTA - y2 * SIN_DELTA;
  862. y2 = x2 * SIN_DELTA + y2 * COS_DELTA;
  863. x2 = x2_new;
  864. }
  865. }
  866. gGL.end();
  867. }
  868. // Draws the area between two concentric circles, like
  869. // a doughnut or washer.
  870. void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians, F32 end_radians, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color)
  871. {
  872. const F32 DELTA = (end_radians - start_radians) / steps;
  873. const F32 SIN_DELTA = sin( DELTA );
  874. const F32 COS_DELTA = cos( DELTA );
  875. F32 x1 = outer_radius * cos( start_radians );
  876. F32 y1 = outer_radius * sin( start_radians );
  877. F32 x2 = inner_radius * cos( start_radians );
  878. F32 y2 = inner_radius * sin( start_radians );
  879. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  880. gGL.begin( LLRender::TRIANGLE_STRIP );
  881. {
  882. steps += 1; // An extra step to close the circle.
  883. while( steps-- )
  884. {
  885. gGL.color4fv(outer_color.mV);
  886. gGL.vertex2f( x1, y1 );
  887. gGL.color4fv(inner_color.mV);
  888. gGL.vertex2f( x2, y2 );
  889. F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA;
  890. y1 = x1 * SIN_DELTA + y1 * COS_DELTA;
  891. x1 = x1_new;
  892. F32 x2_new = x2 * COS_DELTA - y2 * SIN_DELTA;
  893. y2 = x2 * SIN_DELTA + y2 * COS_DELTA;
  894. x2 = x2_new;
  895. }
  896. }
  897. gGL.end();
  898. }
  899. void gl_rect_2d_simple_tex( S32 width, S32 height )
  900. {
  901. gGL.begin( LLRender::QUADS );
  902. gGL.texCoord2f(1.f, 1.f);
  903. gGL.vertex2i(width, height);
  904. gGL.texCoord2f(0.f, 1.f);
  905. gGL.vertex2i(0, height);
  906. gGL.texCoord2f(0.f, 0.f);
  907. gGL.vertex2i(0, 0);
  908. gGL.texCoord2f(1.f, 0.f);
  909. gGL.vertex2i(width, 0);
  910. gGL.end();
  911. }
  912. void gl_rect_2d_simple( S32 width, S32 height )
  913. {
  914. gGL.begin( LLRender::QUADS );
  915. gGL.vertex2i(width, height);
  916. gGL.vertex2i(0, height);
  917. gGL.vertex2i(0, 0);
  918. gGL.vertex2i(width, 0);
  919. gGL.end();
  920. }
  921. void gl_segmented_rect_2d_tex(const S32 left,
  922. const S32 top,
  923. const S32 right,
  924. const S32 bottom,
  925. const S32 texture_width,
  926. const S32 texture_height,
  927. const S32 border_size,
  928. const U32 edges)
  929. {
  930. S32 width = llabs(right - left);
  931. S32 height = llabs(top - bottom);
  932. gGL.pushUIMatrix();
  933. gGL.translateUI((F32)left, (F32)bottom, 0.f);
  934. LLVector2 border_uv_scale((F32)border_size / (F32)texture_width, (F32)border_size / (F32)texture_height);
  935. if (border_uv_scale.mV[VX] > 0.5f)
  936. {
  937. border_uv_scale *= 0.5f / border_uv_scale.mV[VX];
  938. }
  939. if (border_uv_scale.mV[VY] > 0.5f)
  940. {
  941. border_uv_scale *= 0.5f / border_uv_scale.mV[VY];
  942. }
  943. F32 border_scale = llmin((F32)border_size, (F32)width * 0.5f, (F32)height * 0.5f);
  944. LLVector2 border_width_left = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero;
  945. LLVector2 border_width_right = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero;
  946. LLVector2 border_height_bottom = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero;
  947. LLVector2 border_height_top = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero;
  948. LLVector2 width_vec((F32)width, 0.f);
  949. LLVector2 height_vec(0.f, (F32)height);
  950. gGL.begin(LLRender::QUADS);
  951. {
  952. // draw bottom left
  953. gGL.texCoord2f(0.f, 0.f);
  954. gGL.vertex2f(0.f, 0.f);
  955. gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
  956. gGL.vertex2fv(border_width_left.mV);
  957. gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
  958. gGL.vertex2fv((border_width_left + border_height_bottom).mV);
  959. gGL.texCoord2f(0.f, border_uv_scale.mV[VY]);
  960. gGL.vertex2fv(border_height_bottom.mV);
  961. // draw bottom middle
  962. gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
  963. gGL.vertex2fv(border_width_left.mV);
  964. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
  965. gGL.vertex2fv((width_vec - border_width_right).mV);
  966. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
  967. gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
  968. gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
  969. gGL.vertex2fv((border_width_left + border_height_bottom).mV);
  970. // draw bottom right
  971. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
  972. gGL.vertex2fv((width_vec - border_width_right).mV);
  973. gGL.texCoord2f(1.f, 0.f);
  974. gGL.vertex2fv(width_vec.mV);
  975. gGL.texCoord2f(1.f, border_uv_scale.mV[VY]);
  976. gGL.vertex2fv((width_vec + border_height_bottom).mV);
  977. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
  978. gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
  979. // draw left
  980. gGL.texCoord2f(0.f, border_uv_scale.mV[VY]);
  981. gGL.vertex2fv(border_height_bottom.mV);
  982. gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
  983. gGL.vertex2fv((border_width_left + border_height_bottom).mV);
  984. gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
  985. gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
  986. gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]);
  987. gGL.vertex2fv((height_vec - border_height_top).mV);
  988. // draw middle
  989. gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
  990. gGL.vertex2fv((border_width_left + border_height_bottom).mV);
  991. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
  992. gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
  993. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
  994. gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
  995. gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
  996. gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
  997. // draw right
  998. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
  999. gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
  1000. gGL.texCoord2f(1.f, border_uv_scale.mV[VY]);
  1001. gGL.vertex2fv((width_vec + border_height_bottom).mV);
  1002. gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]);
  1003. gGL.vertex2fv((width_vec + height_vec - border_height_top).mV);
  1004. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
  1005. gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
  1006. // draw top left
  1007. gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]);
  1008. gGL.vertex2fv((height_vec - border_height_top).mV);
  1009. gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
  1010. gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
  1011. gGL.texCoord2f(border_uv_scale.mV[VX], 1.f);
  1012. gGL.vertex2fv((border_width_left + height_vec).mV);
  1013. gGL.texCoord2f(0.f, 1.f);
  1014. gGL.vertex2fv((height_vec).mV);
  1015. // draw top middle
  1016. gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
  1017. gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
  1018. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
  1019. gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
  1020. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
  1021. gGL.vertex2fv((width_vec - border_width_right + height_vec).mV);
  1022. gGL.texCoord2f(border_uv_scale.mV[VX], 1.f);
  1023. gGL.vertex2fv((border_width_left + height_vec).mV);
  1024. // draw top right
  1025. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
  1026. gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
  1027. gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]);
  1028. gGL.vertex2fv((width_vec + height_vec - border_height_top).mV);
  1029. gGL.texCoord2f(1.f, 1.f);
  1030. gGL.vertex2fv((width_vec + height_vec).mV);
  1031. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
  1032. gGL.vertex2fv((width_vec - border_width_right + height_vec).mV);
  1033. }
  1034. gGL.end();
  1035. gGL.popUIMatrix();
  1036. }
  1037. //FIXME: rewrite to use scissor?
  1038. void gl_segmented_rect_2d_fragment_tex(const S32 left,
  1039. const S32 top,
  1040. const S32 right,
  1041. const S32 bottom,
  1042. const S32 texture_width,
  1043. const S32 texture_height,
  1044. const S32 border_size,
  1045. const F32 start_fragment,
  1046. const F32 end_fragment,
  1047. const U32 edges)
  1048. {
  1049. S32 width = llabs(right - left);
  1050. S32 height = llabs(top - bottom);
  1051. gGL.pushUIMatrix();
  1052. gGL.translateUI((F32)left, (F32)bottom, 0.f);
  1053. LLVector2 border_uv_scale((F32)border_size / (F32)texture_width, (F32)border_size / (F32)texture_height);
  1054. if (border_uv_scale.mV[VX] > 0.5f)
  1055. {
  1056. border_uv_scale *= 0.5f / border_uv_scale.mV[VX];
  1057. }
  1058. if (border_uv_scale.mV[VY] > 0.5f)
  1059. {
  1060. border_uv_scale *= 0.5f / border_uv_scale.mV[VY];
  1061. }
  1062. F32 border_scale = llmin((F32)border_size, (F32)width * 0.5f, (F32)height * 0.5f);
  1063. LLVector2 border_width_left = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero;
  1064. LLVector2 border_width_right = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero;
  1065. LLVector2 border_height_bottom = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero;
  1066. LLVector2 border_height_top = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero;
  1067. LLVector2 width_vec((F32)width, 0.f);
  1068. LLVector2 height_vec(0.f, (F32)height);
  1069. F32 middle_start = border_scale / (F32)width;
  1070. F32 middle_end = 1.f - middle_start;
  1071. F32 u_min;
  1072. F32 u_max;
  1073. LLVector2 x_min;
  1074. LLVector2 x_max;
  1075. gGL.begin(LLRender::QUADS);
  1076. {
  1077. if (start_fragment < middle_start)
  1078. {
  1079. u_min = (start_fragment / middle_start) * border_uv_scale.mV[VX];
  1080. u_max = llmin(end_fragment / middle_start, 1.f) * border_uv_scale.mV[VX];
  1081. x_min = (start_fragment / middle_start) * border_width_left;
  1082. x_max = llmin(end_fragment / middle_start, 1.f) * border_width_left;
  1083. // draw bottom left
  1084. gGL.texCoord2f(u_min, 0.f);
  1085. gGL.vertex2fv(x_min.mV);
  1086. gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
  1087. gGL.vertex2fv(x_max.mV);
  1088. gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
  1089. gGL.vertex2fv((x_max + border_height_bottom).mV);
  1090. gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
  1091. gGL.vertex2fv((x_min + border_height_bottom).mV);
  1092. // draw left
  1093. gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
  1094. gGL.vertex2fv((x_min + border_height_bottom).mV);
  1095. gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
  1096. gGL.vertex2fv((x_max + border_height_bottom).mV);
  1097. gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
  1098. gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
  1099. gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
  1100. gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
  1101. // draw top left
  1102. gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
  1103. gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
  1104. gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
  1105. gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
  1106. gGL.texCoord2f(u_max, 1.f);
  1107. gGL.vertex2fv((x_max + height_vec).mV);
  1108. gGL.texCoord2f(u_min, 1.f);
  1109. gGL.vertex2fv((x_min + height_vec).mV);
  1110. }
  1111. if (end_fragment > middle_start || start_fragment < middle_end)
  1112. {
  1113. x_min = border_width_left + ((llclamp(start_fragment, middle_start, middle_end) - middle_start)) * width_vec;
  1114. x_max = border_width_left + ((llclamp(end_fragment, middle_start, middle_end) - middle_start)) * width_vec;
  1115. // draw bottom middle
  1116. gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
  1117. gGL.vertex2fv(x_min.mV);
  1118. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
  1119. gGL.vertex2fv((x_max).mV);
  1120. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
  1121. gGL.vertex2fv((x_max + border_height_bottom).mV);
  1122. gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
  1123. gGL.vertex2fv((x_min + border_height_bottom).mV);
  1124. // draw middle
  1125. gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
  1126. gGL.vertex2fv((x_min + border_height_bottom).mV);
  1127. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
  1128. gGL.vertex2fv((x_max + border_height_bottom).mV);
  1129. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
  1130. gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
  1131. gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
  1132. gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
  1133. // draw top middle
  1134. gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
  1135. gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
  1136. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
  1137. gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
  1138. gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
  1139. gGL.vertex2fv((x_max + height_vec).mV);
  1140. gGL.texCoord2f(border_uv_scale.mV[VX], 1.f);
  1141. gGL.vertex2fv((x_min + height_vec).mV);
  1142. }
  1143. if (end_fragment > middle_end)
  1144. {
  1145. u_min = (1.f - llmax(0.f, ((start_fragment - middle_end) / middle_start))) * border_uv_scale.mV[VX];
  1146. u_max = (1.f - ((end_fragment - middle_end) / middle_start)) * border_uv_scale.mV[VX];
  1147. x_min = width_vec - ((1.f - llmax(0.f, ((start_fragment - middle_end) / middle_start))) * border_width_right);
  1148. x_max = width_vec - ((1.f - ((end_fragment - middle_end) / middle_start)) * border_width_right);
  1149. // draw bottom right
  1150. gGL.texCoord2f(u_min, 0.f);
  1151. gGL.vertex2fv((x_min).mV);
  1152. gGL.texCoord2f(u_max, 0.f);
  1153. gGL.vertex2fv(x_max.mV);
  1154. gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
  1155. gGL.vertex2fv((x_max + border_height_bottom).mV);
  1156. gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
  1157. gGL.vertex2fv((x_min + border_height_bottom).mV);
  1158. // draw right
  1159. gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
  1160. gGL.vertex2fv((x_min + border_height_bottom).mV);
  1161. gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
  1162. gGL.vertex2fv((x_max + border_height_bottom).mV);
  1163. gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
  1164. gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
  1165. gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
  1166. gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
  1167. // draw top right
  1168. gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
  1169. gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
  1170. gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
  1171. gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
  1172. gGL.texCoord2f(u_max, 1.f);
  1173. gGL.vertex2fv((x_max + height_vec).mV);
  1174. gGL.texCoord2f(u_min, 1.f);
  1175. gGL.vertex2fv((x_min + height_vec).mV);
  1176. }
  1177. }
  1178. gGL.end();
  1179. gGL.popUIMatrix();
  1180. }
  1181. void gl_segmented_rect_3d_tex(const LLVector2& border_scale, const LLVector3& border_width,
  1182. const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec,
  1183. const U32 edges)
  1184. {
  1185. LLVector3 left_border_width = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? border_width : LLVector3::zero;
  1186. LLVector3 right_border_width = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? border_width : LLVector3::zero;
  1187. LLVector3 top_border_height = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? border_height : LLVector3::zero;
  1188. LLVector3 bottom_border_height = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? border_height : LLVector3::zero;
  1189. gGL.begin(LLRender::QUADS);
  1190. {
  1191. // draw bottom left
  1192. gGL.texCoord2f(0.f, 0.f);
  1193. gGL.vertex3f(0.f, 0.f, 0.f);
  1194. gGL.texCoord2f(border_scale.mV[VX], 0.f);
  1195. gGL.vertex3fv(left_border_width.mV);
  1196. gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
  1197. gGL.vertex3fv((left_border_width + bottom_border_height).mV);
  1198. gGL.texCoord2f(0.f, border_scale.mV[VY]);
  1199. gGL.vertex3fv(bottom_border_height.mV);
  1200. // draw bottom middle
  1201. gGL.texCoord2f(border_scale.mV[VX], 0.f);
  1202. gGL.vertex3fv(left_border_width.mV);
  1203. gGL.texCoord2f(1.f - border_scale.mV[VX], 0.f);
  1204. gGL.vertex3fv((width_vec - right_border_width).mV);
  1205. gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
  1206. gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV);
  1207. gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
  1208. gGL.vertex3fv((left_border_width + bottom_border_height).mV);
  1209. // draw bottom right
  1210. gGL.texCoord2f(1.f - border_scale.mV[VX], 0.f);
  1211. gGL.vertex3fv((width_vec - right_border_width).mV);
  1212. gGL.texCoord2f(1.f, 0.f);
  1213. gGL.vertex3fv(width_vec.mV);
  1214. gGL.texCoord2f(1.f, border_scale.mV[VY]);
  1215. gGL.vertex3fv((width_vec + bottom_border_height).mV);
  1216. gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
  1217. gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV);
  1218. // draw left
  1219. gGL.texCoord2f(0.f, border_scale.mV[VY]);
  1220. gGL.vertex3fv(bottom_border_height.mV);
  1221. gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
  1222. gGL.vertex3fv((left_border_width + bottom_border_height).mV);
  1223. gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
  1224. gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV);
  1225. gGL.texCoord2f(0.f, 1.f - border_scale.mV[VY]);
  1226. gGL.vertex3fv((height_vec - top_border_height).mV);
  1227. // draw middle
  1228. gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
  1229. gGL.vertex3fv((left_border_width + bottom_border_height).mV);
  1230. gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
  1231. gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV);
  1232. gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
  1233. gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
  1234. gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
  1235. gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV);
  1236. // draw right
  1237. gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
  1238. gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV);
  1239. gGL.texCoord2f(1.f, border_scale.mV[VY]);
  1240. gGL.vertex3fv((width_vec + bottom_border_height).mV);
  1241. gGL.texCoord2f(1.f, 1.f - border_scale.mV[VY]);
  1242. gGL.vertex3fv((width_vec + height_vec - top_border_height).mV);
  1243. gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
  1244. gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
  1245. // draw top left
  1246. gGL.texCoord2f(0.f, 1.f - border_scale.mV[VY]);
  1247. gGL.vertex3fv((height_vec - top_border_height).mV);
  1248. gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
  1249. gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV);
  1250. gGL.texCoord2f(border_scale.mV[VX], 1.f);
  1251. gGL.vertex3fv((left_border_width + height_vec).mV);
  1252. gGL.texCoord2f(0.f, 1.f);
  1253. gGL.vertex3fv((height_vec).mV);
  1254. // draw top middle
  1255. gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
  1256. gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV);
  1257. gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
  1258. gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
  1259. gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f);
  1260. gGL.vertex3fv((width_vec - right_border_width + height_vec).mV);
  1261. gGL.texCoord2f(border_scale.mV[VX], 1.f);
  1262. gGL.vertex3fv((left_border_width + height_vec).mV);
  1263. // draw top right
  1264. gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
  1265. gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
  1266. gGL.texCoord2f(1.f, 1.f - border_scale.mV[VY]);
  1267. gGL.vertex3fv((width_vec + height_vec - top_border_height).mV);
  1268. gGL.texCoord2f(1.f, 1.f);
  1269. gGL.vertex3fv((width_vec + height_vec).mV);
  1270. gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f);
  1271. gGL.vertex3fv((width_vec - right_border_width + height_vec).mV);
  1272. }
  1273. gGL.end();
  1274. }
  1275. void gl_segmented_rect_3d_tex_top(const LLVector2& border_scale, const LLVector3& border_width, const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec)
  1276. {
  1277. gl_segmented_rect_3d_tex(border_scale, border_width, border_height, width_vec, height_vec, ROUNDED_RECT_TOP);
  1278. }
  1279. void LLUI::initClass(const settings_map_t& settings,
  1280. LLImageProviderInterface* image_provider,
  1281. LLUIAudioCallback audio_callback,
  1282. const LLVector2* scale_factor,
  1283. const std::string& language)
  1284. {
  1285. sSettingGroups = settings;
  1286. if ((get_ptr_in_map(sSettingGroups, std::string("config")) == NULL) ||
  1287. (get_ptr_in_map(sSettingGroups, std::string("floater")) == NULL) ||
  1288. (get_ptr_in_map(sSettingGroups, std::string("ignores")) == NULL))
  1289. {
  1290. llerrs << "Failure to initialize configuration groups" << llendl;
  1291. }
  1292. sImageProvider = image_provider;
  1293. sAudioCallback = audio_callback;
  1294. sGLScaleFactor = (scale_factor == NULL) ? LLVector2(1.f, 1.f) : *scale_factor;
  1295. sWindow = NULL; // set later in startup
  1296. LLFontGL::sShadowColor = LLUIColorTable::instance().getColor("ColorDropShadow");
  1297. LLUICtrl::CommitCallbackRegistry::Registrar& reg = LLUICtrl::CommitCallbackRegistry::defaultRegistrar();
  1298. // Callbacks for associating controls with floater visibility:
  1299. reg.add("Floater.Toggle", boost::bind(&LLFloaterReg::toggleInstance, _2, LLSD()));
  1300. reg.add("Floater.ToggleOrBringToFront", boost::bind(&LLFloaterReg::toggleInstanceOrBringToFront, _2, LLSD()));
  1301. reg.add("Floater.Show", boost::bind(&LLFloaterReg::showInstance, _2, LLSD(), FALSE));
  1302. reg.add("Floater.Hide", boost::bind(&LLFloaterReg::hideInstance, _2, LLSD()));
  1303. // Button initialization callback for toggle buttons
  1304. reg.add("Button.SetFloaterToggle", boost::bind(&LLButton::setFloaterToggle, _1, _2));
  1305. // Button initialization callback for toggle buttons on dockable floaters
  1306. reg.add("Button.SetDockableFloaterToggle", boost::bind(&LLButton::setDockableFloaterToggle, _1, _2));
  1307. // Display the help topic for the current context
  1308. reg.add("Button.ShowHelp", boost::bind(&LLButton::showHelp, _1, _2));
  1309. // Currently unused, but kept for reference:
  1310. reg.add("Button.ToggleFloater", boost::bind(&LLButton::toggleFloaterAndSetToggleState, _1, _2));
  1311. // Used by menus along with Floater.Toggle to display visibility as a check-mark
  1312. LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.Visible", boost::bind(&LLFloaterReg::instanceVisible, _2, LLSD()));
  1313. LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.IsOpen", boost::bind(&LLFloaterReg::instanceVisible, _2, LLSD()));
  1314. // Parse the master list of commands
  1315. LLCommandManager::load();
  1316. }
  1317. void LLUI::cleanupClass()
  1318. {
  1319. if(sImageProvider)
  1320. {
  1321. sImageProvider->cleanUp();
  1322. }
  1323. }
  1324. void LLUI::setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t& remove_popup, const clear_popups_t& clear_popups)
  1325. {
  1326. sAddPopupFunc = add_popup;
  1327. sRemovePopupFunc = remove_popup;
  1328. sClearPopupsFunc = clear_popups;
  1329. }
  1330. //static
  1331. void LLUI::dirtyRect(LLRect rect)
  1332. {
  1333. if (!sDirty)
  1334. {
  1335. sDirtyRect = rect;
  1336. sDirty = TRUE;
  1337. }
  1338. else
  1339. {
  1340. sDirtyRect.unionWith(rect);
  1341. }
  1342. }
  1343. //static
  1344. void LLUI::translate(F32 x, F32 y, F32 z)
  1345. {
  1346. gGL.translateUI(x,y,z);
  1347. LLFontGL::sCurOrigin.mX += (S32) x;
  1348. LLFontGL::sCurOrigin.mY += (S32) y;
  1349. LLFontGL::sCurOrigin.mZ += z;
  1350. }
  1351. //static
  1352. void LLUI::pushMatrix()
  1353. {
  1354. gGL.pushUIMatrix();
  1355. LLFontGL::sOriginStack.push_back(LLFontGL::sCurOrigin);
  1356. }
  1357. //static
  1358. void LLUI::popMatrix()
  1359. {
  1360. gGL.popUIMatrix();
  1361. LLFontGL::sCurOrigin = *LLFontGL::sOriginStack.rbegin();
  1362. LLFontGL::sOriginStack.pop_back();
  1363. }
  1364. //static
  1365. void LLUI::loadIdentity()
  1366. {
  1367. gGL.loadUIIdentity();
  1368. LLFontGL::sCurOrigin.mX = 0;
  1369. LLFontGL::sCurOrigin.mY = 0;
  1370. LLFontGL::sCurOrigin.mZ = 0;
  1371. }
  1372. //static
  1373. void LLUI::setScaleFactor(const LLVector2 &scale_factor)
  1374. {
  1375. sGLScaleFactor = scale_factor;
  1376. }
  1377. //static
  1378. void LLUI::setLineWidth(F32 width)
  1379. {
  1380. gGL.flush();
  1381. glLineWidth(width * lerp(sGLScaleFactor.mV[VX], sGLScaleFactor.mV[VY], 0.5f));
  1382. }
  1383. //static
  1384. void LLUI::setMousePositionScreen(S32 x, S32 y)
  1385. {
  1386. S32 screen_x, screen_y;
  1387. screen_x = llround((F32)x * sGLScaleFactor.mV[VX]);
  1388. screen_y = llround((F32)y * sGLScaleFactor.mV[VY]);
  1389. LLCoordWindow window_point;
  1390. LLView::getWindow()->convertCoords(LLCoordGL(screen_x, screen_y), &window_point);
  1391. LLView::getWindow()->setCursorPosition(window_point);
  1392. }
  1393. //static
  1394. void LLUI::getMousePositionScreen(S32 *x, S32 *y)
  1395. {
  1396. LLCoordWindow cursor_pos_window;
  1397. getWindow()->getCursorPosition(&cursor_pos_window);
  1398. LLCoordGL cursor_pos_gl;
  1399. getWindow()->convertCoords(cursor_pos_window, &cursor_pos_gl);
  1400. *x = llround((F32)cursor_pos_gl.mX / sGLScaleFactor.mV[VX]);
  1401. *y = llround((F32)cursor_pos_gl.mY / sGLScaleFactor.mV[VX]);
  1402. }
  1403. //static
  1404. void LLUI::setMousePositionLocal(const LLView* viewp, S32 x, S32 y)
  1405. {
  1406. S32 screen_x, screen_y;
  1407. viewp->localPointToScreen(x, y, &screen_x, &screen_y);
  1408. setMousePositionScreen(screen_x, screen_y);
  1409. }
  1410. //static
  1411. void LLUI::getMousePositionLocal(const LLView* viewp, S32 *x, S32 *y)
  1412. {
  1413. S32 screen_x, screen_y;
  1414. getMousePositionScreen(&screen_x, &screen_y);
  1415. viewp->screenPointToLocal(screen_x, screen_y, x, y);
  1416. }
  1417. // On Windows, the user typically sets the language when they install the
  1418. // app (by running it with a shortcut that sets InstallLanguage). On Mac,
  1419. // or on Windows if the SecondLife.exe executable is run directly, the
  1420. // language follows the OS language. In all cases the user can override
  1421. // the language manually in preferences. JC
  1422. // static
  1423. std::string LLUI::getLanguage()
  1424. {
  1425. std::string language = "en";
  1426. if (sSettingGroups["config"])
  1427. {
  1428. language = sSettingGroups["config"]->getString("Language");
  1429. if (language.empty() || language == "default")
  1430. {
  1431. language = sSettingGroups["config"]->getString("InstallLanguage");
  1432. }
  1433. if (language.empty() || language == "default")
  1434. {
  1435. language = sSettingGroups["config"]->getString("SystemLanguage");
  1436. }
  1437. if (language.empty() || language == "default")
  1438. {
  1439. language = "en";
  1440. }
  1441. }
  1442. return language;
  1443. }
  1444. struct SubDir : public LLInitParam::Block<SubDir>
  1445. {
  1446. Mandatory<std::string> value;
  1447. SubDir()
  1448. : value("value")
  1449. {}
  1450. };
  1451. struct Directory : public LLInitParam::Block<Directory>
  1452. {
  1453. Multiple<SubDir, AtLeast<1> > subdirs;
  1454. Directory()
  1455. : subdirs("subdir")
  1456. {}
  1457. };
  1458. struct Paths : public LLInitParam::Block<Paths>
  1459. {
  1460. Multiple<Directory, AtLeast<1> > directories;
  1461. Paths()
  1462. : directories("directory")
  1463. {}
  1464. };
  1465. //static
  1466. void LLUI::setupPaths()
  1467. {
  1468. std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "paths.xml");
  1469. LLXMLNodePtr root;
  1470. BOOL success = LLXMLNode::parseFile(filename, root, NULL);
  1471. Paths paths;
  1472. if(success)
  1473. {
  1474. LLXUIParser parser;
  1475. parser.readXUI(root, paths, filename);
  1476. }
  1477. sXUIPaths.clear();
  1478. if (success && paths.validateBlock())
  1479. {
  1480. LLStringUtil::format_map_t path_args;
  1481. path_args["[LANGUAGE]"] = LLUI::getLanguage();
  1482. for (LLInitParam::ParamIterator<Directory>::const_iterator it = paths.directories.begin(),
  1483. end_it = paths.directories.end();
  1484. it != end_it;
  1485. ++it)
  1486. {
  1487. std::string path_val_ui;
  1488. for (LLInitParam::ParamIterator<SubDir>::const_iterator subdir_it = it->subdirs.begin(),
  1489. subdir_end_it = it->subdirs.end();
  1490. subdir_it != subdir_end_it;)
  1491. {
  1492. path_val_ui += subdir_it->value();
  1493. if (++subdir_it != subdir_end_it)
  1494. path_val_ui += gDirUtilp->getDirDelimiter();
  1495. }
  1496. LLStringUtil::format(path_val_ui, path_args);
  1497. if (std::find(sXUIPaths.begin(), sXUIPaths.end(), path_val_ui) == sXUIPaths.end())
  1498. {
  1499. sXUIPaths.push_back(path_val_ui);
  1500. }
  1501. }
  1502. }
  1503. else // parsing failed
  1504. {
  1505. std::string slash = gDirUtilp->getDirDelimiter();
  1506. std::string dir = "xui" + slash + "en";
  1507. llwarns << "XUI::config file unable to open: " << filename << llendl;
  1508. sXUIPaths.push_back(dir);
  1509. }
  1510. }
  1511. //static
  1512. std::string LLUI::locateSkin(const std::string& filename)
  1513. {
  1514. std::string slash = gDirUtilp->getDirDelimiter();
  1515. std::string found_file = filename;
  1516. if (!gDirUtilp->fileExists(found_file))
  1517. {
  1518. found_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); // Should be CUSTOM_SKINS?
  1519. }
  1520. if (sSettingGroups["config"] && sSettingGroups["config"]->controlExists("Language"))
  1521. {
  1522. if (!gDirUtilp->fileExists(found_file))
  1523. {
  1524. std::string localization = getLanguage();
  1525. std::string local_skin = "xui" + slash + localization + slash + filename;
  1526. found_file = gDirUtilp->findSkinnedFilename(local_skin);
  1527. }
  1528. }
  1529. if (!gDirUtilp->fileExists(found_file))
  1530. {
  1531. std::string local_skin = "xui" + slash + "en" + slash + filename;
  1532. found_file = gDirUtilp->findSkinnedFilename(local_skin);
  1533. }
  1534. if (!gDirUtilp->fileExists(found_file))
  1535. {
  1536. found_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, filename);
  1537. }
  1538. return found_file;
  1539. }
  1540. //static
  1541. LLVector2 LLUI::getWindowSize()
  1542. {
  1543. LLCoordWindow window_rect;
  1544. sWindow->getSize(&window_rect);
  1545. return LLVector2(window_rect.mX / sGLScaleFactor.mV[VX], window_rect.mY / sGLScaleFactor.mV[VY]);
  1546. }
  1547. //static
  1548. void LLUI::screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y)
  1549. {
  1550. *gl_x = llround((F32)screen_x * sGLScaleFactor.mV[VX]);
  1551. *gl_y = llround((F32)screen_y * sGLScaleFactor.mV[VY]);
  1552. }
  1553. //static
  1554. void LLUI::glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y)
  1555. {
  1556. *screen_x = llround((F32)gl_x / sGLScaleFactor.mV[VX]);
  1557. *screen_y = llround((F32)gl_y / sGLScaleFactor.mV[VY]);
  1558. }
  1559. //static
  1560. void LLUI::screenRectToGL(const LLRect& screen, LLRect *gl)
  1561. {
  1562. screenPointToGL(screen.mLeft, screen.mTop, &gl->mLeft, &gl->mTop);
  1563. screenPointToGL(screen.mRight, screen.mBottom, &gl->mRight, &gl->mBottom);
  1564. }
  1565. //static
  1566. void LLUI::glRectToScreen(const LLRect& gl, LLRect *screen)
  1567. {
  1568. glPointToScreen(gl.mLeft, gl.mTop, &screen->mLeft, &screen->mTop);
  1569. glPointToScreen(gl.mRight, gl.mBottom, &screen->mRight, &screen->mBottom);
  1570. }
  1571. //static
  1572. LLPointer<LLUIImage> LLUI::getUIImageByID(const LLUUID& image_id, S32 priority)
  1573. {
  1574. if (sImageProvider)
  1575. {
  1576. return sImageProvider->getUIImageByID(image_id, priority);
  1577. }
  1578. else
  1579. {
  1580. return NULL;
  1581. }
  1582. }
  1583. //static
  1584. LLPointer<LLUIImage> LLUI::getUIImage(const std::string& name, S32 priority)
  1585. {
  1586. if (!name.empty() && sImageProvider)
  1587. return sImageProvider->getUIImage(name, priority);
  1588. else
  1589. return NULL;
  1590. }
  1591. LLControlGroup& LLUI::getControlControlGroup (const std::string& controlname)
  1592. {
  1593. for (settings_map_t::iterator itor = sSettingGroups.begin();
  1594. itor != sSettingGroups.end(); ++itor)
  1595. {
  1596. LLControlGroup* control_group = itor->second;
  1597. if(control_group != NULL)
  1598. {
  1599. if (control_group->controlExists(controlname))
  1600. return *control_group;
  1601. }
  1602. }
  1603. return *sSettingGroups["config"]; // default group
  1604. }
  1605. //static
  1606. void LLUI::addPopup(LLView* viewp)
  1607. {
  1608. if (sAddPopupFunc)
  1609. {
  1610. sAddPopupFunc(viewp);
  1611. }
  1612. }
  1613. //static
  1614. void LLUI::removePopup(LLView* viewp)
  1615. {
  1616. if (sRemovePopupFunc)
  1617. {
  1618. sRemovePopupFunc(viewp);
  1619. }
  1620. }
  1621. //static
  1622. void LLUI::clearPopups()
  1623. {
  1624. if (sClearPopupsFunc)
  1625. {
  1626. sClearPopupsFunc();
  1627. }
  1628. }
  1629. //static
  1630. void LLUI::reportBadKeystroke()
  1631. {
  1632. make_ui_sound("UISndBadKeystroke");
  1633. }
  1634. //static
  1635. // spawn_x and spawn_y are top left corner of view in screen GL coordinates
  1636. void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y)
  1637. {
  1638. const S32 CURSOR_HEIGHT = 16; // Approximate "normal" cursor size
  1639. const S32 CURSOR_WIDTH = 8;
  1640. LLView* parent = view->getParent();
  1641. S32 mouse_x;
  1642. S32 mouse_y;
  1643. LLUI::getMousePositionScreen(&mouse_x, &mouse_y);
  1644. // If no spawn location provided, use mouse position
  1645. if (spawn_x == S32_MAX || spawn_y == S32_MAX)
  1646. {
  1647. spawn_x = mouse_x + CURSOR_WIDTH;
  1648. spawn_y = mouse_y - CURSOR_HEIGHT;
  1649. }
  1650. LLRect virtual_window_rect = parent->getLocalRect();
  1651. LLRect mouse_rect;
  1652. const S32 MOUSE_CURSOR_PADDING = 1;
  1653. mouse_rect.setLeftTopAndSize(mouse_x - MOUSE_CURSOR_PADDING,
  1654. mouse_y + MOUSE_CURSOR_PADDING,
  1655. CURSOR_WIDTH + MOUSE_CURSOR_PADDING * 2,
  1656. CURSOR_HEIGHT + MOUSE_CURSOR_PADDING * 2);
  1657. S32 local_x, local_y;
  1658. // convert screen coordinates to tooltip view-local coordinates
  1659. parent->screenPointToLocal(spawn_x, spawn_y, &local_x, &local_y);
  1660. // Start at spawn position (using left/top)
  1661. view->setOrigin( local_x, local_y - view->getRect().getHeight());
  1662. // Make sure we're on-screen and not overlapping the mouse
  1663. view->translateIntoRectWithExclusion( virtual_window_rect, mouse_rect, FALSE );
  1664. }
  1665. LLView* LLUI::resolvePath(LLView* context, const std::string& path)
  1666. {
  1667. // Nothing about resolvePath() should require non-const LLView*. If caller
  1668. // wants non-const, call the const flavor and then cast away const-ness.
  1669. return const_cast<LLView*>(resolvePath(const_cast<const LLView*>(context), path));
  1670. }
  1671. const LLView* LLUI::resolvePath(const LLView* context, const std::string& path)
  1672. {
  1673. // Create an iterator over slash-separated parts of 'path'. Dereferencing
  1674. // this iterator returns an iterator_range over the substring. Unlike
  1675. // LLStringUtil::getTokens(), this split_iterator doesn't combine adjacent
  1676. // delimiters: leading/trailing slash produces an empty substring, double
  1677. // slash produces an empty substring. That's what we need.
  1678. boost::split_iterator<std::string::const_iterator> ti(path, boost::first_finder("/")), tend;
  1679. if (ti == tend)
  1680. {
  1681. // 'path' is completely empty, no navigation
  1682. return context;
  1683. }
  1684. // leading / means "start at root"
  1685. if (ti->empty())
  1686. {
  1687. context = getRootView();
  1688. ++ti;
  1689. }
  1690. bool recurse = false;
  1691. for (; ti != tend && context; ++ti)
  1692. {
  1693. if (ti->empty())
  1694. {
  1695. recurse = true;
  1696. }
  1697. else
  1698. {
  1699. std::string part(ti->begin(), ti->end());
  1700. context = context->findChildView(part, recurse);
  1701. recurse = false;
  1702. }
  1703. }
  1704. return context;
  1705. }
  1706. // LLLocalClipRect and LLScreenClipRect moved to lllocalcliprect.h/cpp
  1707. namespace LLInitParam
  1708. {
  1709. ParamValue<LLUIColor, TypeValues<LLUIColor> >::ParamValue(const LLUIColor& color)
  1710. : super_t(color),
  1711. red("red"),
  1712. green("green"),
  1713. blue("blue"),
  1714. alpha("alpha"),
  1715. control("")
  1716. {
  1717. updateBlockFromValue(false);
  1718. }
  1719. void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateValueFromBlock()
  1720. {
  1721. if (control.isProvided() && !control().empty())
  1722. {
  1723. updateValue(LLUIColorTable::instance().getColor(control));
  1724. }
  1725. else
  1726. {
  1727. updateValue(LLColor4(red, green, blue, alpha));
  1728. }
  1729. }
  1730. void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateBlockFromValue(bool make_block_authoritative)
  1731. {
  1732. LLColor4 color = getValue();
  1733. red.set(color.mV[VRED], make_block_authoritative);
  1734. green.set(color.mV[VGREEN], make_block_authoritative);
  1735. blue.set(color.mV[VBLUE], make_block_authoritative);
  1736. alpha.set(color.mV[VALPHA], make_block_authoritative);
  1737. control.set("", make_block_authoritative);
  1738. }
  1739. bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b)
  1740. {
  1741. return !(a->getFontDesc() < b->getFontDesc())
  1742. && !(b->getFontDesc() < a->getFontDesc());
  1743. }
  1744. ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::ParamValue(const LLFontGL* fontp)
  1745. : super_t(fontp),
  1746. name("name"),
  1747. size("size"),
  1748. style("style")
  1749. {
  1750. if (!fontp)
  1751. {
  1752. updateValue(LLFontGL::getFontDefault());
  1753. }
  1754. addSynonym(name, "");
  1755. updateBlockFromValue(false);
  1756. }
  1757. void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateValueFromBlock()
  1758. {
  1759. const LLFontGL* res_fontp = LLFontGL::getFontByName(name);
  1760. if (res_fontp)
  1761. {
  1762. updateValue(res_fontp);
  1763. return;
  1764. }
  1765. U8 fontstyle = 0;
  1766. fontstyle = LLFontGL::getStyleFromString(style());
  1767. LLFontDescriptor desc(name(), size(), fontstyle);
  1768. const LLFontGL* fontp = LLFontGL::getFont(desc);
  1769. if (fontp)
  1770. {
  1771. updateValue(fontp);
  1772. }
  1773. else
  1774. {
  1775. updateValue(LLFontGL::getFontDefault());
  1776. }
  1777. }
  1778. void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateBlockFromValue(bool make_block_authoritative)
  1779. {
  1780. if (getValue())
  1781. {
  1782. name.set(LLFontGL::nameFromFont(getValue()), make_block_authoritative);
  1783. size.set(LLFontGL::sizeFromFont(getValue()), make_block_author