PageRenderTime 48ms CodeModel.GetById 26ms 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

Large files files are truncated, but you can click here to view the full file

  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,

Large files files are truncated, but you can click here to view the full file