PageRenderTime 160ms CodeModel.GetById 19ms app.highlight 129ms RepoModel.GetById 1ms app.codeStats 1ms

/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

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
  27// Utilities functions the user interface needs
  28
  29#include "linden_common.h"
  30
  31#include <string>
  32#include <map>
  33
  34// Linden library includes
  35#include "v2math.h"
  36#include "m3math.h"
  37#include "v4color.h"
  38#include "llrender.h"
  39#include "llrect.h"
  40#include "lldir.h"
  41#include "llgl.h"
  42
  43// Project includes
  44#include "llcommandmanager.h"
  45#include "llcontrol.h"
  46#include "llui.h"
  47#include "lluicolortable.h"
  48#include "llview.h"
  49#include "lllineeditor.h"
  50#include "llfloater.h"
  51#include "llfloaterreg.h"
  52#include "llmenugl.h"
  53#include "llmenubutton.h"
  54#include "llloadingindicator.h"
  55#include "llwindow.h"
  56
  57// for registration
  58#include "llfiltereditor.h"
  59#include "llflyoutbutton.h"
  60#include "llsearcheditor.h"
  61#include "lltoolbar.h"
  62
  63// for XUIParse
  64#include "llquaternion.h"
  65#include <boost/tokenizer.hpp>
  66#include <boost/algorithm/string/find_iterator.hpp>
  67#include <boost/algorithm/string/finder.hpp>
  68
  69//
  70// Globals
  71//
  72const LLColor4 UI_VERTEX_COLOR(1.f, 1.f, 1.f, 1.f);
  73
  74// Language for UI construction
  75std::map<std::string, std::string> gTranslation;
  76std::list<std::string> gUntranslated;
  77/*static*/ LLUI::settings_map_t LLUI::sSettingGroups;
  78/*static*/ LLImageProviderInterface* LLUI::sImageProvider = NULL;
  79/*static*/ LLUIAudioCallback LLUI::sAudioCallback = NULL;
  80/*static*/ LLVector2		LLUI::sGLScaleFactor(1.f, 1.f);
  81/*static*/ LLWindow*		LLUI::sWindow = NULL;
  82/*static*/ LLView*			LLUI::sRootView = NULL;
  83/*static*/ BOOL                         LLUI::sDirty = FALSE;
  84/*static*/ LLRect                       LLUI::sDirtyRect;
  85/*static*/ LLHelp*			LLUI::sHelpImpl = NULL;
  86/*static*/ std::vector<std::string> LLUI::sXUIPaths;
  87/*static*/ LLFrameTimer		LLUI::sMouseIdleTimer;
  88/*static*/ LLUI::add_popup_t	LLUI::sAddPopupFunc;
  89/*static*/ LLUI::remove_popup_t	LLUI::sRemovePopupFunc;
  90/*static*/ LLUI::clear_popups_t	LLUI::sClearPopupsFunc;
  91
  92// register filter editor here
  93static LLDefaultChildRegistry::Register<LLFilterEditor> register_filter_editor("filter_editor");
  94static LLDefaultChildRegistry::Register<LLFlyoutButton> register_flyout_button("flyout_button");
  95static LLDefaultChildRegistry::Register<LLSearchEditor> register_search_editor("search_editor");
  96
  97// register other widgets which otherwise may not be linked in
  98static LLDefaultChildRegistry::Register<LLLoadingIndicator> register_loading_indicator("loading_indicator");
  99static LLDefaultChildRegistry::Register<LLToolBar> register_toolbar("toolbar");
 100
 101//
 102// Functions
 103//
 104void make_ui_sound(const char* namep)
 105{
 106	std::string name = ll_safe_string(namep);
 107	if (!LLUI::sSettingGroups["config"]->controlExists(name))
 108	{
 109		llwarns << "tried to make UI sound for unknown sound name: " << name << llendl;	
 110	}
 111	else
 112	{
 113		LLUUID uuid(LLUI::sSettingGroups["config"]->getString(name));
 114		if (uuid.isNull())
 115		{
 116			if (LLUI::sSettingGroups["config"]->getString(name) == LLUUID::null.asString())
 117			{
 118				if (LLUI::sSettingGroups["config"]->getBOOL("UISndDebugSpamToggle"))
 119				{
 120					llinfos << "UI sound name: " << name << " triggered but silent (null uuid)" << llendl;	
 121				}				
 122			}
 123			else
 124			{
 125				llwarns << "UI sound named: " << name << " does not translate to a valid uuid" << llendl;	
 126			}
 127
 128		}
 129		else if (LLUI::sAudioCallback != NULL)
 130		{
 131			if (LLUI::sSettingGroups["config"]->getBOOL("UISndDebugSpamToggle"))
 132			{
 133				llinfos << "UI sound name: " << name << llendl;	
 134			}
 135			LLUI::sAudioCallback(uuid);
 136		}
 137	}
 138}
 139
 140BOOL ui_point_in_rect(S32 x, S32 y, S32 left, S32 top, S32 right, S32 bottom)
 141{
 142	if (x < left || right < x) return FALSE;
 143	if (y < bottom || top < y) return FALSE;
 144	return TRUE;
 145}
 146
 147
 148// Puts GL into 2D drawing mode by turning off lighting, setting to an
 149// orthographic projection, etc.
 150void gl_state_for_2d(S32 width, S32 height)
 151{
 152	stop_glerror();
 153	F32 window_width = (F32) width;//gViewerWindow->getWindowWidth();
 154	F32 window_height = (F32) height;//gViewerWindow->getWindowHeight();
 155
 156	gGL.matrixMode(LLRender::MM_PROJECTION);
 157	gGL.loadIdentity();
 158	gGL.ortho(0.0f, llmax(window_width, 1.f), 0.0f, llmax(window_height,1.f), -1.0f, 1.0f);
 159	gGL.matrixMode(LLRender::MM_MODELVIEW);
 160	gGL.loadIdentity();
 161	stop_glerror();
 162}
 163
 164
 165void gl_draw_x(const LLRect& rect, const LLColor4& color)
 166{
 167	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 168
 169	gGL.color4fv( color.mV );
 170
 171	gGL.begin( LLRender::LINES );
 172		gGL.vertex2i( rect.mLeft,		rect.mTop );
 173		gGL.vertex2i( rect.mRight,	rect.mBottom );
 174		gGL.vertex2i( rect.mLeft,		rect.mBottom );
 175		gGL.vertex2i( rect.mRight,	rect.mTop );
 176	gGL.end();
 177}
 178
 179
 180void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, S32 pixel_offset, BOOL filled)
 181{
 182	gGL.color4fv(color.mV);
 183	gl_rect_2d_offset_local(left, top, right, bottom, pixel_offset, filled);
 184}
 185
 186void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, S32 pixel_offset, BOOL filled)
 187{
 188	gGL.pushUIMatrix();
 189	left += LLFontGL::sCurOrigin.mX;
 190	right += LLFontGL::sCurOrigin.mX;
 191	bottom += LLFontGL::sCurOrigin.mY;
 192	top += LLFontGL::sCurOrigin.mY;
 193
 194	gGL.loadUIIdentity();
 195	gl_rect_2d(llfloor((F32)left * LLUI::sGLScaleFactor.mV[VX]) - pixel_offset,
 196				llfloor((F32)top * LLUI::sGLScaleFactor.mV[VY]) + pixel_offset,
 197				llfloor((F32)right * LLUI::sGLScaleFactor.mV[VX]) + pixel_offset,
 198				llfloor((F32)bottom * LLUI::sGLScaleFactor.mV[VY]) - pixel_offset,
 199				filled);
 200	gGL.popUIMatrix();
 201}
 202
 203
 204void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled )
 205{
 206	stop_glerror();
 207	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 208
 209	// Counterclockwise quad will face the viewer
 210	if( filled )
 211	{ 
 212		gGL.begin( LLRender::QUADS );
 213			gGL.vertex2i(left, top);
 214			gGL.vertex2i(left, bottom);
 215			gGL.vertex2i(right, bottom);
 216			gGL.vertex2i(right, top);
 217		gGL.end();
 218	}
 219	else
 220	{
 221		if( gGLManager.mATIOffsetVerticalLines )
 222		{
 223			// Work around bug in ATI driver: vertical lines are offset by (-1,-1)
 224			gGL.begin( LLRender::LINES );
 225
 226				// Verticals 
 227				gGL.vertex2i(left + 1, top);
 228				gGL.vertex2i(left + 1, bottom);
 229
 230				gGL.vertex2i(right, bottom);
 231				gGL.vertex2i(right, top);
 232
 233				// Horizontals
 234				top--;
 235				right--;
 236				gGL.vertex2i(left, bottom);
 237				gGL.vertex2i(right, bottom);
 238
 239				gGL.vertex2i(left, top);
 240				gGL.vertex2i(right, top);
 241			gGL.end();
 242		}
 243		else
 244		{
 245			top--;
 246			right--;
 247			gGL.begin( LLRender::LINE_STRIP );
 248				gGL.vertex2i(left, top);
 249				gGL.vertex2i(left, bottom);
 250				gGL.vertex2i(right, bottom);
 251				gGL.vertex2i(right, top);
 252				gGL.vertex2i(left, top);
 253			gGL.end();
 254		}
 255	}
 256	stop_glerror();
 257}
 258
 259void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, BOOL filled )
 260{
 261	gGL.color4fv( color.mV );
 262	gl_rect_2d( left, top, right, bottom, filled );
 263}
 264
 265
 266void gl_rect_2d( const LLRect& rect, const LLColor4& color, BOOL filled )
 267{
 268	gGL.color4fv( color.mV );
 269	gl_rect_2d( rect.mLeft, rect.mTop, rect.mRight, rect.mBottom, filled );
 270}
 271
 272// Given a rectangle on the screen, draws a drop shadow _outside_
 273// the right and bottom edges of it.  Along the right it has width "lines"
 274// and along the bottom it has height "lines".
 275void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &start_color, S32 lines)
 276{
 277	stop_glerror();
 278	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 279	
 280	// HACK: Overlap with the rectangle by a single pixel.
 281	right--;
 282	bottom++;
 283	lines++;
 284
 285	LLColor4 end_color = start_color;
 286	end_color.mV[VALPHA] = 0.f;
 287
 288	gGL.begin(LLRender::QUADS);
 289
 290	// Right edge, CCW faces screen
 291	gGL.color4fv(start_color.mV);
 292	gGL.vertex2i(right,		top-lines);
 293	gGL.vertex2i(right,		bottom);
 294	gGL.color4fv(end_color.mV);
 295	gGL.vertex2i(right+lines, bottom);
 296	gGL.vertex2i(right+lines, top-lines);
 297
 298	// Bottom edge, CCW faces screen
 299	gGL.color4fv(start_color.mV);
 300	gGL.vertex2i(right,		bottom);
 301	gGL.vertex2i(left+lines,	bottom);
 302	gGL.color4fv(end_color.mV);
 303	gGL.vertex2i(left+lines,	bottom-lines);
 304	gGL.vertex2i(right,		bottom-lines);
 305
 306	// bottom left Corner
 307	gGL.color4fv(start_color.mV);
 308	gGL.vertex2i(left+lines,	bottom);
 309	gGL.color4fv(end_color.mV);
 310	gGL.vertex2i(left,		bottom);
 311	// make the bottom left corner not sharp
 312	gGL.vertex2i(left+1,		bottom-lines+1);
 313	gGL.vertex2i(left+lines,	bottom-lines);
 314
 315	// bottom right corner
 316	gGL.color4fv(start_color.mV);
 317	gGL.vertex2i(right,		bottom);
 318	gGL.color4fv(end_color.mV);
 319	gGL.vertex2i(right,		bottom-lines);
 320	// make the rightmost corner not sharp
 321	gGL.vertex2i(right+lines-1,	bottom-lines+1);
 322	gGL.vertex2i(right+lines,	bottom);
 323
 324	// top right corner
 325	gGL.color4fv(start_color.mV);
 326	gGL.vertex2i( right,			top-lines );
 327	gGL.color4fv(end_color.mV);
 328	gGL.vertex2i( right+lines,	top-lines );
 329	// make the corner not sharp
 330	gGL.vertex2i( right+lines-1,	top-1 );
 331	gGL.vertex2i( right,			top );
 332
 333	gGL.end();
 334	stop_glerror();
 335}
 336
 337void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2 )
 338{
 339	// Work around bug in ATI driver: vertical lines are offset by (-1,-1)
 340	if( (x1 == x2) && gGLManager.mATIOffsetVerticalLines )
 341	{
 342		x1++;
 343		x2++;
 344		y1++;
 345		y2++;
 346	}
 347
 348	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 349	
 350	gGL.begin(LLRender::LINES);
 351		gGL.vertex2i(x1, y1);
 352		gGL.vertex2i(x2, y2);
 353	gGL.end();
 354}
 355
 356void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2, const LLColor4 &color )
 357{
 358	// Work around bug in ATI driver: vertical lines are offset by (-1,-1)
 359	if( (x1 == x2) && gGLManager.mATIOffsetVerticalLines )
 360	{
 361		x1++;
 362		x2++;
 363		y1++;
 364		y2++;
 365	}
 366
 367	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 368
 369	gGL.color4fv( color.mV );
 370
 371	gGL.begin(LLRender::LINES);
 372		gGL.vertex2i(x1, y1);
 373		gGL.vertex2i(x2, y2);
 374	gGL.end();
 375}
 376
 377void gl_triangle_2d(S32 x1, S32 y1, S32 x2, S32 y2, S32 x3, S32 y3, const LLColor4& color, BOOL filled)
 378{
 379	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 380
 381	gGL.color4fv(color.mV);
 382
 383	if (filled)
 384	{
 385		gGL.begin(LLRender::TRIANGLES);
 386	}
 387	else
 388	{
 389		gGL.begin(LLRender::LINE_LOOP);
 390	}
 391	gGL.vertex2i(x1, y1);
 392	gGL.vertex2i(x2, y2);
 393	gGL.vertex2i(x3, y3);
 394	gGL.end();
 395}
 396
 397void gl_corners_2d(S32 left, S32 top, S32 right, S32 bottom, S32 length, F32 max_frac)
 398{
 399	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 400
 401	length = llmin((S32)(max_frac*(right - left)), length);
 402	length = llmin((S32)(max_frac*(top - bottom)), length);
 403	gGL.begin(LLRender::LINES);
 404	gGL.vertex2i(left, top);
 405	gGL.vertex2i(left + length, top);
 406	
 407	gGL.vertex2i(left, top);
 408	gGL.vertex2i(left, top - length);
 409
 410	gGL.vertex2i(left, bottom);
 411	gGL.vertex2i(left + length, bottom);
 412	
 413	gGL.vertex2i(left, bottom);
 414	gGL.vertex2i(left, bottom + length);
 415
 416	gGL.vertex2i(right, top);
 417	gGL.vertex2i(right - length, top);
 418
 419	gGL.vertex2i(right, top);
 420	gGL.vertex2i(right, top - length);
 421
 422	gGL.vertex2i(right, bottom);
 423	gGL.vertex2i(right - length, bottom);
 424
 425	gGL.vertex2i(right, bottom);
 426	gGL.vertex2i(right, bottom + length);
 427	gGL.end();
 428}
 429
 430
 431void gl_draw_image( S32 x, S32 y, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect )
 432{
 433	if (NULL == image)
 434	{
 435		llwarns << "image == NULL; aborting function" << llendl;
 436		return;
 437	}
 438	gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), 0.f, image, color, uv_rect );
 439}
 440
 441void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect)
 442{
 443	if (NULL == image)
 444	{
 445		llwarns << "image == NULL; aborting function" << llendl;
 446		return;
 447	}
 448	gl_draw_scaled_rotated_image( x, y, width, height, 0.f, image, color, uv_rect );
 449}
 450
 451void 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)
 452{
 453	if (NULL == image)
 454	{
 455		llwarns << "image == NULL; aborting function" << llendl;
 456		return;
 457	}
 458
 459	// scale screen size of borders down
 460	F32 border_width_fraction = (F32)border_width / (F32)image->getWidth(0);
 461	F32 border_height_fraction = (F32)border_height / (F32)image->getHeight(0);
 462
 463	LLRectf scale_rect(border_width_fraction, 1.f - border_height_fraction, 1.f - border_width_fraction, border_height_fraction);
 464	gl_draw_scaled_image_with_border(x, y, width, height, image, color, solid_color, uv_rect, scale_rect);
 465}
 466
 467void 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)
 468{
 469	stop_glerror();
 470
 471	if (NULL == image)
 472	{
 473		llwarns << "image == NULL; aborting function" << llendl;
 474		return;
 475	}
 476
 477	// add in offset of current image to current UI translation
 478	const LLVector3 ui_scale = gGL.getUIScale();
 479	const LLVector3 ui_translation = (gGL.getUITranslation() + LLVector3(x, y, 0.f)).scaledVec(ui_scale);
 480
 481	F32 uv_width = uv_outer_rect.getWidth();
 482	F32 uv_height = uv_outer_rect.getHeight();
 483
 484	// shrink scaling region to be proportional to clipped image region
 485	LLRectf uv_center_rect(
 486		uv_outer_rect.mLeft + (center_rect.mLeft * uv_width),
 487		uv_outer_rect.mBottom + (center_rect.mTop * uv_height),
 488		uv_outer_rect.mLeft + (center_rect.mRight * uv_width),
 489		uv_outer_rect.mBottom + (center_rect.mBottom * uv_height));
 490
 491	F32 image_width = image->getWidth(0);
 492	F32 image_height = image->getHeight(0);
 493
 494	S32 image_natural_width = llround(image_width * uv_width);
 495	S32 image_natural_height = llround(image_height * uv_height);
 496
 497	LLRectf draw_center_rect(	uv_center_rect.mLeft * image_width,
 498								uv_center_rect.mTop * image_height,
 499								uv_center_rect.mRight * image_width,
 500								uv_center_rect.mBottom * image_height);
 501
 502	{	// scale fixed region of image to drawn region
 503		draw_center_rect.mRight += width - image_natural_width;
 504		draw_center_rect.mTop += height - image_natural_height;
 505
 506		F32 border_shrink_width = llmax(0.f, draw_center_rect.mLeft - draw_center_rect.mRight);
 507		F32 border_shrink_height = llmax(0.f, draw_center_rect.mBottom - draw_center_rect.mTop);
 508
 509		F32 shrink_width_ratio = center_rect.getWidth() == 1.f ? 0.f : border_shrink_width / ((F32)image_natural_width * (1.f - center_rect.getWidth()));
 510		F32 shrink_height_ratio = center_rect.getHeight() == 1.f ? 0.f : border_shrink_height / ((F32)image_natural_height * (1.f - center_rect.getHeight()));
 511
 512		F32 shrink_scale = 1.f - llmax(shrink_width_ratio, shrink_height_ratio);
 513
 514		draw_center_rect.mLeft = llround(ui_translation.mV[VX] + (F32)draw_center_rect.mLeft * shrink_scale * ui_scale.mV[VX]);
 515		draw_center_rect.mTop = llround(ui_translation.mV[VY] + lerp((F32)height, (F32)draw_center_rect.mTop, shrink_scale) * ui_scale.mV[VY]);
 516		draw_center_rect.mRight = llround(ui_translation.mV[VX] + lerp((F32)width, (F32)draw_center_rect.mRight, shrink_scale) * ui_scale.mV[VX]);
 517		draw_center_rect.mBottom = llround(ui_translation.mV[VY] + (F32)draw_center_rect.mBottom * shrink_scale * ui_scale.mV[VY]);
 518	}
 519
 520	LLRectf draw_outer_rect(ui_translation.mV[VX], 
 521							ui_translation.mV[VY] + height * ui_scale.mV[VY], 
 522							ui_translation.mV[VX] + width * ui_scale.mV[VX], 
 523							ui_translation.mV[VY]);
 524
 525	LLGLSUIDefault gls_ui;
 526	
 527	if (solid_color)
 528	{
 529		if (LLGLSLShader::sNoFixedFunction)
 530		{
 531			gSolidColorProgram.bind();
 532		}
 533		else
 534		{
 535			gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
 536			gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA);
 537		}
 538	}
 539
 540	gGL.getTexUnit(0)->bind(image, true);
 541
 542	gGL.color4fv(color.mV);
 543	
 544	const S32 NUM_VERTICES = 9 * 4; // 9 quads
 545	LLVector2 uv[NUM_VERTICES];
 546	LLVector3 pos[NUM_VERTICES];
 547
 548	S32 index = 0;
 549
 550	gGL.begin(LLRender::QUADS);
 551	{
 552		// draw bottom left
 553		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mBottom);
 554		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_outer_rect.mBottom, 0.f);
 555		index++;
 556
 557		uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom);
 558		pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
 559		index++;
 560
 561		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
 562		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
 563		index++;
 564
 565		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom);
 566		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
 567		index++;
 568
 569		// draw bottom middle
 570		uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom);
 571		pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
 572		index++;
 573
 574		uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom);
 575		pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
 576		index++;
 577
 578		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
 579		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
 580		index++;
 581
 582		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
 583		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
 584		index++;
 585
 586		// draw bottom right
 587		uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom);
 588		pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
 589		index++;
 590
 591		uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mBottom);
 592		pos[index] = LLVector3(draw_outer_rect.mRight, draw_outer_rect.mBottom, 0.f);
 593		index++;
 594
 595		uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom);
 596		pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
 597		index++;
 598
 599		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
 600		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
 601		index++;
 602
 603		// draw left 
 604		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom);
 605		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
 606		index++;
 607
 608		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
 609		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
 610		index++;
 611
 612		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
 613		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
 614		index++;
 615
 616		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop);
 617		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
 618		index++;
 619
 620		// draw middle
 621		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
 622		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
 623		index++;
 624
 625		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
 626		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
 627		index++;
 628
 629		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
 630		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
 631		index++;
 632
 633		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
 634		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
 635		index++;
 636
 637		// draw right 
 638		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
 639		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
 640		index++;
 641
 642		uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom);
 643		pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
 644		index++;
 645
 646		uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop);
 647		pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
 648		index++;
 649
 650		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
 651		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
 652		index++;
 653
 654		// draw top left
 655		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop);
 656		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
 657		index++;
 658
 659		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
 660		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
 661		index++;
 662
 663		uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop);
 664		pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
 665		index++;
 666
 667		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mTop);
 668		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_outer_rect.mTop, 0.f);
 669		index++;
 670
 671		// draw top middle
 672		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
 673		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
 674		index++;
 675
 676		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
 677		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
 678		index++;
 679
 680		uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop);
 681		pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
 682		index++;
 683
 684		uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop);
 685		pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
 686		index++;
 687
 688		// draw top right
 689		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
 690		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
 691		index++;
 692
 693		uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop);
 694		pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
 695		index++;
 696
 697		uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mTop);
 698		pos[index] = LLVector3(draw_outer_rect.mRight, draw_outer_rect.mTop, 0.f);
 699		index++;
 700
 701		uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop);
 702		pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
 703		index++;
 704
 705		gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES);
 706	}
 707	gGL.end();
 708
 709	if (solid_color)
 710	{
 711		if (LLGLSLShader::sNoFixedFunction)
 712		{
 713			gUIProgram.bind();
 714		}
 715		else
 716		{
 717			gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 718		}
 719	}
 720}
 721
 722void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect)
 723{
 724	gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), degrees, image, color, uv_rect );
 725}
 726
 727void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect)
 728{
 729	if (NULL == image)
 730	{
 731		llwarns << "image == NULL; aborting function" << llendl;
 732		return;
 733	}
 734
 735	LLGLSUIDefault gls_ui;
 736
 737
 738	gGL.getTexUnit(0)->bind(image, true);
 739
 740	gGL.color4fv(color.mV);
 741
 742	if (degrees == 0.f)
 743	{
 744		const S32 NUM_VERTICES = 4; // 9 quads
 745		LLVector2 uv[NUM_VERTICES];
 746		LLVector3 pos[NUM_VERTICES];
 747
 748		gGL.begin(LLRender::QUADS);
 749		{
 750			LLVector3 ui_scale = gGL.getUIScale();
 751			LLVector3 ui_translation = gGL.getUITranslation();
 752			ui_translation.mV[VX] += x;
 753			ui_translation.mV[VY] += y;
 754			ui_translation.scaleVec(ui_scale);
 755			S32 index = 0;
 756			S32 scaled_width = llround(width * ui_scale.mV[VX]);
 757			S32 scaled_height = llround(height * ui_scale.mV[VY]);
 758
 759			uv[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
 760			pos[index] = LLVector3(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY] + scaled_height, 0.f);
 761			index++;
 762
 763			uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop);
 764			pos[index] = LLVector3(ui_translation.mV[VX], ui_translation.mV[VY] + scaled_height, 0.f);
 765			index++;
 766
 767			uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
 768			pos[index] = LLVector3(ui_translation.mV[VX], ui_translation.mV[VY], 0.f);
 769			index++;
 770
 771			uv[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom);
 772			pos[index] = LLVector3(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY], 0.f);
 773			index++;
 774
 775			gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES);
 776		}
 777		gGL.end();
 778	}
 779	else
 780	{
 781		gGL.pushUIMatrix();
 782		gGL.translateUI((F32)x, (F32)y, 0.f);
 783	
 784		F32 offset_x = F32(width/2);
 785		F32 offset_y = F32(height/2);
 786
 787		gGL.translateUI(offset_x, offset_y, 0.f);
 788
 789		LLMatrix3 quat(0.f, 0.f, degrees*DEG_TO_RAD);
 790		
 791		gGL.getTexUnit(0)->bind(image, true);
 792
 793		gGL.color4fv(color.mV);
 794		
 795		gGL.begin(LLRender::QUADS);
 796		{
 797			LLVector3 v;
 798
 799			v = LLVector3(offset_x, offset_y, 0.f) * quat;
 800			gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
 801			gGL.vertex2f(v.mV[0], v.mV[1] );
 802
 803			v = LLVector3(-offset_x, offset_y, 0.f) * quat;
 804			gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
 805			gGL.vertex2f(v.mV[0], v.mV[1] );
 806
 807			v = LLVector3(-offset_x, -offset_y, 0.f) * quat;
 808			gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
 809			gGL.vertex2f(v.mV[0], v.mV[1] );
 810
 811			v = LLVector3(offset_x, -offset_y, 0.f) * quat;
 812			gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
 813			gGL.vertex2f(v.mV[0], v.mV[1] );
 814		}
 815		gGL.end();
 816		gGL.popUIMatrix();
 817	}
 818}
 819
 820
 821void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase )
 822{
 823	phase = fmod(phase, 1.f);
 824
 825	S32 shift = S32(phase * 4.f) % 4;
 826
 827	// Stippled line
 828	LLGLEnable stipple(GL_LINE_STIPPLE);
 829	
 830	gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], color.mV[VALPHA]);
 831
 832	gGL.flush();
 833	glLineWidth(2.5f);
 834	glLineStipple(2, 0x3333 << shift);
 835
 836	gGL.begin(LLRender::LINES);
 837	{
 838		gGL.vertex3fv( start.mV );
 839		gGL.vertex3fv( end.mV );
 840	}
 841	gGL.end();
 842
 843	LLUI::setLineWidth(1.f);
 844}
 845
 846void gl_arc_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled, F32 start_angle, F32 end_angle)
 847{
 848	if (end_angle < start_angle)
 849	{
 850		end_angle += F_TWO_PI;
 851	}
 852
 853	gGL.pushUIMatrix();
 854	{
 855		gGL.translateUI(center_x, center_y, 0.f);
 856
 857		// Inexact, but reasonably fast.
 858		F32 delta = (end_angle - start_angle) / steps;
 859		F32 sin_delta = sin( delta );
 860		F32 cos_delta = cos( delta );
 861		F32 x = cosf(start_angle) * radius;
 862		F32 y = sinf(start_angle) * radius;
 863
 864		if (filled)
 865		{
 866			gGL.begin(LLRender::TRIANGLE_FAN);
 867			gGL.vertex2f(0.f, 0.f);
 868			// make sure circle is complete
 869			steps += 1;
 870		}
 871		else
 872		{
 873			gGL.begin(LLRender::LINE_STRIP);
 874		}
 875
 876		while( steps-- )
 877		{
 878			// Successive rotations
 879			gGL.vertex2f( x, y );
 880			F32 x_new = x * cos_delta - y * sin_delta;
 881			y = x * sin_delta +  y * cos_delta;
 882			x = x_new;
 883		}
 884		gGL.end();
 885	}
 886	gGL.popUIMatrix();
 887}
 888
 889void gl_circle_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled)
 890{
 891	gGL.pushUIMatrix();
 892	{
 893		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 894		gGL.translateUI(center_x, center_y, 0.f);
 895
 896		// Inexact, but reasonably fast.
 897		F32 delta = F_TWO_PI / steps;
 898		F32 sin_delta = sin( delta );
 899		F32 cos_delta = cos( delta );
 900		F32 x = radius;
 901		F32 y = 0.f;
 902
 903		if (filled)
 904		{
 905			gGL.begin(LLRender::TRIANGLE_FAN);
 906			gGL.vertex2f(0.f, 0.f);
 907			// make sure circle is complete
 908			steps += 1;
 909		}
 910		else
 911		{
 912			gGL.begin(LLRender::LINE_LOOP);
 913		}
 914
 915		while( steps-- )
 916		{
 917			// Successive rotations
 918			gGL.vertex2f( x, y );
 919			F32 x_new = x * cos_delta - y * sin_delta;
 920			y = x * sin_delta +  y * cos_delta;
 921			x = x_new;
 922		}
 923		gGL.end();
 924	}
 925	gGL.popUIMatrix();
 926}
 927
 928// Renders a ring with sides (tube shape)
 929void gl_deep_circle( F32 radius, F32 depth, S32 steps )
 930{
 931	F32 x = radius;
 932	F32 y = 0.f;
 933	F32 angle_delta = F_TWO_PI / (F32)steps;
 934	gGL.begin( LLRender::TRIANGLE_STRIP  );
 935	{
 936		S32 step = steps + 1; // An extra step to close the circle.
 937		while( step-- )
 938		{
 939			gGL.vertex3f( x, y, depth );
 940			gGL.vertex3f( x, y, 0.f );
 941
 942			F32 x_new = x * cosf(angle_delta) - y * sinf(angle_delta);
 943			y = x * sinf(angle_delta) +  y * cosf(angle_delta);
 944			x = x_new;
 945		}
 946	}
 947	gGL.end();
 948}
 949
 950void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor4& side_color, S32 steps, BOOL render_center )
 951{
 952	gGL.pushUIMatrix();
 953	{
 954		gGL.translateUI(0.f, 0.f, -width / 2);
 955		if( render_center )
 956		{
 957			gGL.color4fv(center_color.mV);
 958			gGL.diffuseColor4fv(center_color.mV);
 959			gl_deep_circle( radius, width, steps );
 960		}
 961		else
 962		{
 963			gGL.diffuseColor4fv(side_color.mV);
 964			gl_washer_2d(radius, radius - width, steps, side_color, side_color);
 965			gGL.translateUI(0.f, 0.f, width);
 966			gl_washer_2d(radius - width, radius, steps, side_color, side_color);
 967		}
 968	}
 969	gGL.popUIMatrix();
 970}
 971
 972// Draw gray and white checkerboard with black border
 973void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha)
 974{
 975	// Initialize the first time this is called.
 976	const S32 PIXELS = 32;
 977	static GLubyte checkerboard[PIXELS * PIXELS];
 978	static BOOL first = TRUE;
 979	if( first )
 980	{
 981		for( S32 i = 0; i < PIXELS; i++ )
 982		{
 983			for( S32 j = 0; j < PIXELS; j++ )
 984			{
 985				checkerboard[i * PIXELS + j] = ((i & 1) ^ (j & 1)) * 0xFF;
 986			}
 987		}
 988		first = FALSE;
 989	}
 990	
 991	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 992
 993	// ...white squares
 994	gGL.color4f( 1.f, 1.f, 1.f, alpha );
 995	gl_rect_2d(rect);
 996
 997	// ...gray squares
 998	gGL.color4f( .7f, .7f, .7f, alpha );
 999	gGL.flush();
1000
1001	if (!LLGLSLShader::sNoFixedFunction)
1002	{ //polygon stipple is deprecated
1003		glPolygonStipple( checkerboard );
1004
1005		LLGLEnable polygon_stipple(GL_POLYGON_STIPPLE);
1006		gl_rect_2d(rect);
1007	}
1008	else
1009	{
1010		gl_rect_2d(rect);
1011	}
1012	gGL.flush();
1013}
1014
1015
1016// Draws the area between two concentric circles, like
1017// a doughnut or washer.
1018void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color)
1019{
1020	const F32 DELTA = F_TWO_PI / steps;
1021	const F32 SIN_DELTA = sin( DELTA );
1022	const F32 COS_DELTA = cos( DELTA );
1023
1024	F32 x1 = outer_radius;
1025	F32 y1 = 0.f;
1026	F32 x2 = inner_radius;
1027	F32 y2 = 0.f;
1028
1029	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
1030
1031	gGL.begin( LLRender::TRIANGLE_STRIP  );
1032	{
1033		steps += 1; // An extra step to close the circle.
1034		while( steps-- )
1035		{
1036			gGL.color4fv(outer_color.mV);
1037			gGL.vertex2f( x1, y1 );
1038			gGL.color4fv(inner_color.mV);
1039			gGL.vertex2f( x2, y2 );
1040
1041			F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA;
1042			y1 = x1 * SIN_DELTA +  y1 * COS_DELTA;
1043			x1 = x1_new;
1044
1045			F32 x2_new = x2 * COS_DELTA - y2 * SIN_DELTA;
1046			y2 = x2 * SIN_DELTA +  y2 * COS_DELTA;
1047			x2 = x2_new;
1048		}
1049	}
1050	gGL.end();
1051}
1052
1053// Draws the area between two concentric circles, like
1054// a doughnut or washer.
1055void 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)
1056{
1057	const F32 DELTA = (end_radians - start_radians) / steps;
1058	const F32 SIN_DELTA = sin( DELTA );
1059	const F32 COS_DELTA = cos( DELTA );
1060
1061	F32 x1 = outer_radius * cos( start_radians );
1062	F32 y1 = outer_radius * sin( start_radians );
1063	F32 x2 = inner_radius * cos( start_radians );
1064	F32 y2 = inner_radius * sin( start_radians );
1065
1066	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
1067	gGL.begin( LLRender::TRIANGLE_STRIP  );
1068	{
1069		steps += 1; // An extra step to close the circle.
1070		while( steps-- )
1071		{
1072			gGL.color4fv(outer_color.mV);
1073			gGL.vertex2f( x1, y1 );
1074			gGL.color4fv(inner_color.mV);
1075			gGL.vertex2f( x2, y2 );
1076
1077			F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA;
1078			y1 = x1 * SIN_DELTA +  y1 * COS_DELTA;
1079			x1 = x1_new;
1080
1081			F32 x2_new = x2 * COS_DELTA - y2 * SIN_DELTA;
1082			y2 = x2 * SIN_DELTA +  y2 * COS_DELTA;
1083			x2 = x2_new;
1084		}
1085	}
1086	gGL.end();
1087}
1088
1089void gl_rect_2d_simple_tex( S32 width, S32 height )
1090{
1091	gGL.begin( LLRender::QUADS );
1092
1093		gGL.texCoord2f(1.f, 1.f);
1094		gGL.vertex2i(width, height);
1095
1096		gGL.texCoord2f(0.f, 1.f);
1097		gGL.vertex2i(0, height);
1098
1099		gGL.texCoord2f(0.f, 0.f);
1100		gGL.vertex2i(0, 0);
1101
1102		gGL.texCoord2f(1.f, 0.f);
1103		gGL.vertex2i(width, 0);
1104	
1105	gGL.end();
1106}
1107
1108void gl_rect_2d_simple( S32 width, S32 height )
1109{
1110	gGL.begin( LLRender::QUADS );
1111		gGL.vertex2i(width, height);
1112		gGL.vertex2i(0, height);
1113		gGL.vertex2i(0, 0);
1114		gGL.vertex2i(width, 0);
1115	gGL.end();
1116}
1117
1118void gl_segmented_rect_2d_tex(const S32 left, 
1119							  const S32 top, 
1120							  const S32 right, 
1121							  const S32 bottom, 
1122							  const S32 texture_width, 
1123							  const S32 texture_height, 
1124							  const S32 border_size, 
1125							  const U32 edges)
1126{
1127	S32 width = llabs(right - left);
1128	S32 height = llabs(top - bottom);
1129
1130	gGL.pushUIMatrix();
1131
1132	gGL.translateUI((F32)left, (F32)bottom, 0.f);
1133	LLVector2 border_uv_scale((F32)border_size / (F32)texture_width, (F32)border_size / (F32)texture_height);
1134
1135	if (border_uv_scale.mV[VX] > 0.5f)
1136	{
1137		border_uv_scale *= 0.5f / border_uv_scale.mV[VX];
1138	}
1139	if (border_uv_scale.mV[VY] > 0.5f)
1140	{
1141		border_uv_scale *= 0.5f / border_uv_scale.mV[VY];
1142	}
1143
1144	F32 border_scale = llmin((F32)border_size, (F32)width * 0.5f, (F32)height * 0.5f);
1145	LLVector2 border_width_left = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero;
1146	LLVector2 border_width_right = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero;
1147	LLVector2 border_height_bottom = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero;
1148	LLVector2 border_height_top = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero;
1149	LLVector2 width_vec((F32)width, 0.f);
1150	LLVector2 height_vec(0.f, (F32)height);
1151
1152	gGL.begin(LLRender::QUADS);
1153	{
1154		// draw bottom left
1155		gGL.texCoord2f(0.f, 0.f);
1156		gGL.vertex2f(0.f, 0.f);
1157
1158		gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
1159		gGL.vertex2fv(border_width_left.mV);
1160
1161		gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
1162		gGL.vertex2fv((border_width_left + border_height_bottom).mV);
1163
1164		gGL.texCoord2f(0.f, border_uv_scale.mV[VY]);
1165		gGL.vertex2fv(border_height_bottom.mV);
1166
1167		// draw bottom middle
1168		gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
1169		gGL.vertex2fv(border_width_left.mV);
1170
1171		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
1172		gGL.vertex2fv((width_vec - border_width_right).mV);
1173
1174		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
1175		gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
1176
1177		gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
1178		gGL.vertex2fv((border_width_left + border_height_bottom).mV);
1179
1180		// draw bottom right
1181		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
1182		gGL.vertex2fv((width_vec - border_width_right).mV);
1183
1184		gGL.texCoord2f(1.f, 0.f);
1185		gGL.vertex2fv(width_vec.mV);
1186
1187		gGL.texCoord2f(1.f, border_uv_scale.mV[VY]);
1188		gGL.vertex2fv((width_vec + border_height_bottom).mV);
1189
1190		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
1191		gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
1192
1193		// draw left 
1194		gGL.texCoord2f(0.f, border_uv_scale.mV[VY]);
1195		gGL.vertex2fv(border_height_bottom.mV);
1196
1197		gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
1198		gGL.vertex2fv((border_width_left + border_height_bottom).mV);
1199
1200		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
1201		gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
1202
1203		gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]);
1204		gGL.vertex2fv((height_vec - border_height_top).mV);
1205
1206		// draw middle
1207		gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
1208		gGL.vertex2fv((border_width_left + border_height_bottom).mV);
1209
1210		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
1211		gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
1212
1213		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
1214		gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
1215
1216		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
1217		gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
1218
1219		// draw right 
1220		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
1221		gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
1222
1223		gGL.texCoord2f(1.f, border_uv_scale.mV[VY]);
1224		gGL.vertex2fv((width_vec + border_height_bottom).mV);
1225
1226		gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]);
1227		gGL.vertex2fv((width_vec + height_vec - border_height_top).mV);
1228
1229		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
1230		gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
1231
1232		// draw top left
1233		gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]);
1234		gGL.vertex2fv((height_vec - border_height_top).mV);
1235
1236		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
1237		gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
1238
1239		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f);
1240		gGL.vertex2fv((border_width_left + height_vec).mV);
1241
1242		gGL.texCoord2f(0.f, 1.f);
1243		gGL.vertex2fv((height_vec).mV);
1244
1245		// draw top middle
1246		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
1247		gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
1248
1249		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
1250		gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
1251
1252		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
1253		gGL.vertex2fv((width_vec - border_width_right + height_vec).mV);
1254
1255		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f);
1256		gGL.vertex2fv((border_width_left + height_vec).mV);
1257
1258		// draw top right
1259		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
1260		gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
1261
1262		gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]);
1263		gGL.vertex2fv((width_vec + height_vec - border_height_top).mV);
1264
1265		gGL.texCoord2f(1.f, 1.f);
1266		gGL.vertex2fv((width_vec + height_vec).mV);
1267
1268		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
1269		gGL.vertex2fv((width_vec - border_width_right + height_vec).mV);
1270	}
1271	gGL.end();
1272
1273	gGL.popUIMatrix();
1274}
1275
1276//FIXME: rewrite to use scissor?
1277void gl_segmented_rect_2d_fragment_tex(const S32 left, 
1278									   const S32 top, 
1279									   const S32 right, 
1280									   const S32 bottom, 
1281									   const S32 texture_width, 
1282									   const S32 texture_height, 
1283									   const S32 border_size, 
1284									   const F32 start_fragment, 
1285									   const F32 end_fragment, 
1286									   const U32 edges)
1287{
1288	S32 width = llabs(right - left);
1289	S32 height = llabs(top - bottom);
1290
1291	gGL.pushUIMatrix();
1292
1293	gGL.translateUI((F32)left, (F32)bottom, 0.f);
1294	LLVector2 border_uv_scale((F32)border_size / (F32)texture_width, (F32)border_size / (F32)texture_height);
1295
1296	if (border_uv_scale.mV[VX] > 0.5f)
1297	{
1298		border_uv_scale *= 0.5f / border_uv_scale.mV[VX];
1299	}
1300	if (border_uv_scale.mV[VY] > 0.5f)
1301	{
1302		border_uv_scale *= 0.5f / border_uv_scale.mV[VY];
1303	}
1304
1305	F32 border_scale = llmin((F32)border_size, (F32)width * 0.5f, (F32)height * 0.5f);
1306	LLVector2 border_width_left = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero;
1307	LLVector2 border_width_right = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero;
1308	LLVector2 border_height_bottom = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero;
1309	LLVector2 border_height_top = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero;
1310	LLVector2 width_vec((F32)width, 0.f);
1311	LLVector2 height_vec(0.f, (F32)height);
1312
1313	F32 middle_start = border_scale / (F32)width;
1314	F32 middle_end = 1.f - middle_start;
1315
1316	F32 u_min;
1317	F32 u_max;
1318	LLVector2 x_min;
1319	LLVector2 x_max;
1320
1321	gGL.begin(LLRender::QUADS);
1322	{
1323		if (start_fragment < middle_start)
1324		{
1325			u_min = (start_fragment / middle_start) * border_uv_scale.mV[VX];
1326			u_max = llmin(end_fragment / middle_start, 1.f) * border_uv_scale.mV[VX];
1327			x_min = (start_fragment / middle_start) * border_width_left;
1328			x_max = llmin(end_fragment / middle_start, 1.f) * border_width_left;
1329
1330			// draw bottom left
1331			gGL.texCoord2f(u_min, 0.f);
1332			gGL.vertex2fv(x_min.mV);
1333
1334			gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
1335			gGL.vertex2fv(x_max.mV);
1336
1337			gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
1338			gGL.vertex2fv((x_max + border_height_bottom).mV);
1339
1340			gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
1341			gGL.vertex2fv((x_min + border_height_bottom).mV);
1342
1343			// draw left 
1344			gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
1345			gGL.vertex2fv((x_min + border_height_bottom).mV);
1346
1347			gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
1348			gGL.vertex2fv((x_max + border_height_bottom).mV);
1349
1350			gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
1351			gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
1352
1353			gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
1354			gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
1355			
1356			// draw top left
1357			gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
1358			gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
1359
1360			gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
1361			gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
1362
1363			gGL.texCoord2f(u_max, 1.f);
1364			gGL.vertex2fv((x_max + height_vec).mV);
1365
1366			gGL.texCoord2f(u_min, 1.f);
1367			gGL.vertex2fv((x_min + height_vec).mV);
1368		}
1369
1370		if (end_fragment > middle_start || start_fragment < middle_end)
1371		{
1372			x_min = border_width_left + ((llclamp(start_fragment, middle_start, middle_end) - middle_start)) * width_vec;
1373			x_max = border_width_left + ((llclamp(end_fragment, middle_start, middle_end) - middle_start)) * width_vec;
1374
1375			// draw bottom middle
1376			gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
1377			gGL.vertex2fv(x_min.mV);
1378
1379			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
1380			gGL.vertex2fv((x_max).mV);
1381
1382			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
1383			gGL.vertex2fv((x_max + border_height_bottom).mV);
1384
1385			gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
1386			gGL.vertex2fv((x_min + border_height_bottom).mV);
1387
1388			// draw middle
1389			gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
1390			gGL.vertex2fv((x_min + border_height_bottom).mV);
1391
1392			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
1393			gGL.vertex2fv((x_max + border_height_bottom).mV);
1394
1395			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
1396			gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
1397
1398			gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
1399			gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
1400
1401			// draw top middle
1402			gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
1403			gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
1404
1405			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
1406			gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
1407
1408			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
1409			gGL.vertex2fv((x_max + height_vec).mV);
1410
1411			gGL.texCoord2f(border_uv_scale.mV[VX], 1.f);
1412			gGL.vertex2fv((x_min + height_vec).mV);
1413		}
1414
1415		if (end_fragment > middle_end)
1416		{
1417			u_min = (1.f - llmax(0.f, ((start_fragment - middle_end) / middle_start))) * border_uv_scale.mV[VX];
1418			u_max = (1.f - ((end_fragment - middle_end) / middle_start)) * border_uv_scale.mV[VX];
1419			x_min = width_vec - ((1.f - llmax(0.f, ((start_fragment - middle_end) / middle_start))) * border_width_right);
1420			x_max = width_vec - ((1.f - ((end_fragment - middle_end) / middle_start)) * border_width_right);
1421
1422			// draw bottom right
1423			gGL.texCoord2f(u_min, 0.f);
1424			gGL.vertex2fv((x_min).mV);
1425
1426			gGL.texCoord2f(u_max, 0.f);
1427			gGL.vertex2fv(x_max.mV);
1428
1429			gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
1430			gGL.vertex2fv((x_max + border_height_bottom).mV);
1431
1432			gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
1433			gGL.vertex2fv((x_min + border_height_bottom).mV);
1434
1435			// draw right 
1436			gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
1437			gGL.vertex2fv((x_min + border_height_bottom).mV);
1438
1439			gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
1440			gGL.vertex2fv((x_max + border_height_bottom).mV);
1441
1442			gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
1443			gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
1444
1445			gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
1446			gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
1447
1448			// draw top right
1449			gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
1450			gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
1451
1452			gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
1453			gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
1454
1455			gGL.texCoord2f(u_max, 1.f);
1456			gGL.vertex2fv((x_max + height_vec).mV);
1457
1458			gGL.texCoord2f(u_min, 1.f);
1459			gGL.vertex2fv((x_min + height_vec).mV);
1460		}
1461	}
1462	gGL.end();
1463
1464	gGL.popUIMatrix();
1465}
1466
1467void gl_segmented_rect_3d_tex(const LLVector2& border_scale, const LLVector3& border_width, 
1468							  const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec,
1469							  const U32 edges)
1470{
1471	LLVector3 left_border_width = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? border_width : LLVector3::zero;
1472	LLVector3 right_border_width = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? border_width : LLVector3::zero;
1473
1474	LLVector3 top_border_height = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? border_height : LLVector3::zero;
1475	LLVector3 bottom_border_height = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? border_height : LLVector3::zero;
1476
1477
1478	gGL.begin(LLRender::QUADS);
1479	{
1480		// draw bottom left
1481		gGL.texCoord2f(0.f, 0.f);
1482		gGL.vertex3f(0.f, 0.f, 0.f);
1483
1484		gGL.texCoord2f(border_scale.mV[VX], 0.f);
1485		gGL.vertex3fv(left_border_width.mV);
1486
1487		gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
1488		gGL.vertex3fv((left_border_width + bottom_border_height).mV);
1489
1490		gGL.texCoord2f(0.f, border_scale.mV[VY]);
1491		gGL.vertex3fv(bottom_border_height.mV);
1492
1493		// draw bottom middle
1494		gGL.texCoord2f(border_scale.mV[VX], 0.f);
1495		gGL.vertex3fv(left_border_width.mV);
1496
1497		gGL.texCoord2f(1.f - border_scale.mV[VX], 0.f);
1498		gGL.vertex3fv((width_vec - right_border_width).mV);
1499
1500		gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
1501		gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV);
1502
1503		gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
1504		gGL.vertex3fv((left_border_width + bottom_border_height).mV);
1505
1506		// draw bottom right
1507		gGL.texCoord2f(1.f - border_scale.mV[VX], 0.f);
1508		gGL.vertex3fv((width_vec - right_border_width).mV);
1509
1510		gGL.texCoord2f(1.f, 0.f);
1511		gGL.vertex3fv(width_vec.mV);
1512
1513		gGL.texCoord2f(1.f, border_scale.mV[VY]);
1514		gGL.vertex3fv((width_vec + bottom_border_height).mV);
1515
1516		gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
1517		gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV);
1518
1519		// draw left 
1520		gGL.texCoord2f(0.f, border_scale.mV[VY]);
1521		gGL.vertex3fv(bottom_border_height.mV);
1522
1523		gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
1524		gGL.vertex3fv((left_border_width + bottom_border_height).mV);
1525
1526		gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
1527		gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV);
1528
1529		gGL.texCoord2f(0.f, 1.f - border_scale.mV[VY]);
1530		gGL.vertex3fv((height_vec - top_border_height).mV);
1531
1532		// draw middle
1533		gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
1534		gGL.vertex3fv((left_border_width + bottom_border_height).mV);
1535
1536		gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
1537		gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV);
1538
1539		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
1540		gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
1541
1542		gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
1543		gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV);
1544
1545		// draw right 
1546		gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
1547		gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV);
1548
1549		gGL.texCoord2f(1.f, border_scale.mV[VY]);
1550		gGL.vertex3fv((width_vec + bottom_border_height).mV);
1551
1552		gGL.texCoord2f(1.f, 1.f - border_scale.mV[VY]);
1553		gGL.vertex3fv((width_vec + height_vec - top_border_height).mV);
1554
1555		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
1556		gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
1557
1558		// draw top left
1559		gGL.texCoord2f(0.f, 1.f - border_scale.mV[VY]);
1560		gGL.vertex3fv((height_vec - top_border_height).mV);
1561
1562		gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
1563		gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV);
1564
1565		gGL.texCoord2f(border_scale.mV[VX], 1.f);
1566		gGL.vertex3fv((left_border_width + height_vec).mV);
1567
1568		gGL.texCoord2f(0.f, 1.f);
1569		gGL.vertex3fv((height_vec).mV);
1570
1571		// draw top middle
1572		gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
1573		gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV);
1574
1575		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
1576		gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
1577
1578		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f);
1579		gGL.vertex3fv((width_vec - right_border_width + height_vec).mV);
1580
1581		gGL.texCoord2f(border_scale.mV[VX], 1.f);
1582		gGL.vertex3fv((left_border_width + height_vec).mV);
1583
1584		// draw top right
1585		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
1586		gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
1587
1588		gGL.texCoord2f(1.f, 1.f - border_scale.mV[VY]);
1589		gGL.vertex3fv((width_vec + height_vec - top_border_height).mV);
1590
1591		gGL.texCoord2f(1.f, 1.f);
1592		gGL.vertex3fv((width_vec + height_vec).mV);
1593
1594		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f);
1595		gGL.vertex3fv((width_vec - right_border_width + height_vec).mV);
1596	}
1597	gGL.end();
1598
1599}
1600
1601void 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)
1602{
1603	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