summaryrefslogtreecommitdiff
path: root/indra/llui/llui.cpp
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
committerJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
commit420b91db29485df39fd6e724e782c449158811cb (patch)
treeb471a94563af914d3ed3edd3e856d21cb1b69945 /indra/llui/llui.cpp
Print done when done.
Diffstat (limited to 'indra/llui/llui.cpp')
-rw-r--r--indra/llui/llui.cpp1764
1 files changed, 1764 insertions, 0 deletions
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
new file mode 100644
index 0000000000..d951cb70f6
--- /dev/null
+++ b/indra/llui/llui.cpp
@@ -0,0 +1,1764 @@
+/**
+ * @file llui.cpp
+ * @brief UI implementation
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+// Utilities functions the user interface needs
+
+//#include "llviewerprecompiledheaders.h"
+#include "linden_common.h"
+
+#include <string>
+#include <map>
+
+// Linden library includes
+#include "audioengine.h"
+#include "v2math.h"
+#include "v4color.h"
+#include "llgl.h"
+#include "llrect.h"
+#include "llimagegl.h"
+//#include "llviewerimage.h"
+#include "lldir.h"
+#include "llfontgl.h"
+
+// Project includes
+//#include "audioengine.h"
+#include "llcontrol.h"
+//#include "llstartup.h"
+#include "llui.h"
+#include "llview.h"
+#include "llwindow.h"
+
+#include "llglheaders.h"
+
+//
+// Globals
+//
+const LLColor4 UI_VERTEX_COLOR(1.f, 1.f, 1.f, 1.f);
+
+// Used to hide the flashing text cursor when window doesn't have focus.
+BOOL gShowTextEditCursor = TRUE;
+
+// Language for UI construction
+LLString gLanguage = "english-usa";
+std::map<LLString, LLString> gTranslation;
+std::list<LLString> gUntranslated;
+
+LLControlGroup* LLUI::sConfigGroup = NULL;
+LLControlGroup* LLUI::sColorsGroup = NULL;
+LLControlGroup* LLUI::sAssetsGroup = NULL;
+LLImageProviderInterface* LLUI::sImageProvider = NULL;
+LLUIAudioCallback LLUI::sAudioCallback = NULL;
+LLVector2 LLUI::sGLScaleFactor(1.f, 1.f);
+LLWindow* LLUI::sWindow = NULL;
+BOOL LLUI::sShowXUINames = FALSE;
+//
+// Functions
+//
+void make_ui_sound(const LLString& name)
+{
+ if (!LLUI::sConfigGroup->controlExists(name))
+ {
+ llwarns << "tried to make ui sound for unknown sound name: " << name << llendl;
+ }
+ else
+ {
+ LLUUID uuid(LLUI::sConfigGroup->getString(name));
+ if (uuid.isNull())
+ {
+ if ("00000000-0000-0000-0000-000000000000" == LLUI::sConfigGroup->getString(name))
+ {
+ if (LLUI::sConfigGroup->getBOOL("UISndDebugSpamToggle"))
+ {
+ llinfos << "ui sound name: " << name << " triggered but silent (null uuid)" << llendl;
+ }
+ }
+ else
+ {
+ llwarns << "ui sound named: " << name << " does not translate to a valid uuid" << llendl;
+ }
+
+ }
+ else if (LLUI::sAudioCallback != NULL)
+ {
+ if (LLUI::sConfigGroup->getBOOL("UISndDebugSpamToggle"))
+ {
+ llinfos << "ui sound name: " << name << llendl;
+ }
+ LLUI::sAudioCallback(uuid, LLUI::sConfigGroup->getF32("AudioLevelUI"));
+ }
+ }
+}
+
+BOOL ui_point_in_rect(S32 x, S32 y, S32 left, S32 top, S32 right, S32 bottom)
+{
+ if (x < left || right < x) return FALSE;
+ if (y < bottom || top < y) return FALSE;
+ return TRUE;
+}
+
+
+// Puts GL into 2D drawing mode by turning off lighting, setting to an
+// orthographic projection, etc.
+void gl_state_for_2d(S32 width, S32 height)
+{
+ stop_glerror();
+ F32 window_width = (F32) width;//gViewerWindow->getWindowWidth();
+ F32 window_height = (F32) height;//gViewerWindow->getWindowHeight();
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0.0f, window_width, 0.0f, window_height, -1.0f, 1.0f);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ stop_glerror();
+}
+
+
+void gl_draw_x(const LLRect& rect, const LLColor4& color)
+{
+ LLGLSNoTexture no_texture;
+
+ glColor4fv( color.mV );
+
+ glBegin( GL_LINES );
+ glVertex2i( rect.mLeft, rect.mTop );
+ glVertex2i( rect.mRight, rect.mBottom );
+ glVertex2i( rect.mLeft, rect.mBottom );
+ glVertex2i( rect.mRight, rect.mTop );
+ glEnd();
+}
+
+
+void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, S32 pixel_offset, BOOL filled)
+{
+ glColor4fv(color.mV);
+ gl_rect_2d_offset_local(left, top, right, bottom, pixel_offset, filled);
+}
+
+void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, S32 pixel_offset, BOOL filled)
+{
+ glPushMatrix();
+ left += LLFontGL::sCurOrigin.mX;
+ right += LLFontGL::sCurOrigin.mX;
+ bottom += LLFontGL::sCurOrigin.mY;
+ top += LLFontGL::sCurOrigin.mY;
+
+ glLoadIdentity();
+ gl_rect_2d(llfloor((F32)left * LLUI::sGLScaleFactor.mV[VX]) - pixel_offset,
+ llfloor((F32)top * LLUI::sGLScaleFactor.mV[VY]) + pixel_offset,
+ llfloor((F32)right * LLUI::sGLScaleFactor.mV[VX]) + pixel_offset,
+ llfloor((F32)bottom * LLUI::sGLScaleFactor.mV[VY]) - pixel_offset,
+ filled);
+ glPopMatrix();
+}
+
+
+void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled )
+{
+ stop_glerror();
+ LLGLSNoTexture no_texture;
+
+ // Counterclockwise quad will face the viewer
+ if( filled )
+ {
+ glBegin( GL_QUADS );
+ glVertex2i(left, top);
+ glVertex2i(left, bottom);
+ glVertex2i(right, bottom);
+ glVertex2i(right, top);
+ glEnd();
+ }
+ else
+ {
+ if( gGLManager.mATIOffsetVerticalLines )
+ {
+ // Work around bug in ATI driver: vertical lines are offset by (-1,-1)
+ glBegin( GL_LINES );
+
+ // Verticals
+ glVertex2i(left + 1, top);
+ glVertex2i(left + 1, bottom);
+
+ glVertex2i(right, bottom);
+ glVertex2i(right, top);
+
+ // Horizontals
+ top--;
+ right--;
+ glVertex2i(left, bottom);
+ glVertex2i(right, bottom);
+
+ glVertex2i(left, top);
+ glVertex2i(right, top);
+ glEnd();
+ }
+ else
+ {
+ top--;
+ right--;
+ glBegin( GL_LINE_STRIP );
+ glVertex2i(left, top);
+ glVertex2i(left, bottom);
+ glVertex2i(right, bottom);
+ glVertex2i(right, top);
+ glVertex2i(left, top);
+ glEnd();
+ }
+ }
+ stop_glerror();
+}
+
+void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, BOOL filled )
+{
+ glColor4fv( color.mV );
+ gl_rect_2d( left, top, right, bottom, filled );
+}
+
+
+void gl_rect_2d( const LLRect& rect, const LLColor4& color, BOOL filled )
+{
+ glColor4fv( color.mV );
+ gl_rect_2d( rect.mLeft, rect.mTop, rect.mRight, rect.mBottom, filled );
+}
+
+// Given a rectangle on the screen, draws a drop shadow _outside_
+// the right and bottom edges of it. Along the right it has width "lines"
+// and along the bottom it has height "lines".
+void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &start_color, S32 lines)
+{
+ stop_glerror();
+ LLGLSNoTexture no_texture;
+
+ // HACK: Overlap with the rectangle by a single pixel.
+ right--;
+ bottom++;
+ lines++;
+
+ LLColor4 end_color = start_color;
+ end_color.mV[VALPHA] = 0.f;
+
+ glBegin(GL_QUADS);
+
+ // Right edge, CCW faces screen
+ glColor4fv(start_color.mV);
+ glVertex2i(right, top-lines);
+ glVertex2i(right, bottom);
+ glColor4fv(end_color.mV);
+ glVertex2i(right+lines, bottom);
+ glVertex2i(right+lines, top-lines);
+
+ // Bottom edge, CCW faces screen
+ glColor4fv(start_color.mV);
+ glVertex2i(right, bottom);
+ glVertex2i(left+lines, bottom);
+ glColor4fv(end_color.mV);
+ glVertex2i(left+lines, bottom-lines);
+ glVertex2i(right, bottom-lines);
+
+ // bottom left Corner
+ glColor4fv(start_color.mV);
+ glVertex2i(left+lines, bottom);
+ glColor4fv(end_color.mV);
+ glVertex2i(left, bottom);
+ // make the bottom left corner not sharp
+ glVertex2i(left+1, bottom-lines+1);
+ glVertex2i(left+lines, bottom-lines);
+
+ // bottom right corner
+ glColor4fv(start_color.mV);
+ glVertex2i(right, bottom);
+ glColor4fv(end_color.mV);
+ glVertex2i(right, bottom-lines);
+ // make the rightmost corner not sharp
+ glVertex2i(right+lines-1, bottom-lines+1);
+ glVertex2i(right+lines, bottom);
+
+ // top right corner
+ glColor4fv(start_color.mV);
+ glVertex2i( right, top-lines );
+ glColor4fv(end_color.mV);
+ glVertex2i( right+lines, top-lines );
+ // make the corner not sharp
+ glVertex2i( right+lines-1, top-1 );
+ glVertex2i( right, top );
+
+ glEnd();
+ stop_glerror();
+}
+
+void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2 )
+{
+ // Work around bug in ATI driver: vertical lines are offset by (-1,-1)
+ if( gGLManager.mATIOffsetVerticalLines && (x1 == x2) )
+ {
+ x1++;
+ x2++;
+ y1++;
+ y2++;
+ }
+
+ LLGLSNoTexture no_texture;
+
+ glBegin(GL_LINES);
+ glVertex2i(x1, y1);
+ glVertex2i(x2, y2);
+ glEnd();
+}
+
+void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2, const LLColor4 &color )
+{
+ // Work around bug in ATI driver: vertical lines are offset by (-1,-1)
+ if( gGLManager.mATIOffsetVerticalLines && (x1 == x2) )
+ {
+ x1++;
+ x2++;
+ y1++;
+ y2++;
+ }
+
+ LLGLSNoTexture no_texture;
+
+ glColor4fv( color.mV );
+
+ glBegin(GL_LINES);
+ glVertex2i(x1, y1);
+ glVertex2i(x2, y2);
+ glEnd();
+}
+
+void gl_triangle_2d(S32 x1, S32 y1, S32 x2, S32 y2, S32 x3, S32 y3, const LLColor4& color, BOOL filled)
+{
+ LLGLSNoTexture no_texture;
+
+ glColor4fv(color.mV);
+
+ if (filled)
+ {
+ glBegin(GL_TRIANGLES);
+ }
+ else
+ {
+ glBegin(GL_LINE_LOOP);
+ }
+ glVertex2i(x1, y1);
+ glVertex2i(x2, y2);
+ glVertex2i(x3, y3);
+ glEnd();
+}
+
+void gl_corners_2d(S32 left, S32 top, S32 right, S32 bottom, S32 length, F32 max_frac)
+{
+ LLGLSNoTexture no_texture;
+
+ length = llmin((S32)(max_frac*(right - left)), length);
+ length = llmin((S32)(max_frac*(top - bottom)), length);
+ glBegin(GL_LINES);
+ glVertex2i(left, top);
+ glVertex2i(left + length, top);
+
+ glVertex2i(left, top);
+ glVertex2i(left, top - length);
+
+ glVertex2i(left, bottom);
+ glVertex2i(left + length, bottom);
+
+ glVertex2i(left, bottom);
+ glVertex2i(left, bottom + length);
+
+ glVertex2i(right, top);
+ glVertex2i(right - length, top);
+
+ glVertex2i(right, top);
+ glVertex2i(right, top - length);
+
+ glVertex2i(right, bottom);
+ glVertex2i(right - length, bottom);
+
+ glVertex2i(right, bottom);
+ glVertex2i(right, bottom + length);
+ glEnd();
+}
+
+
+void gl_draw_image( S32 x, S32 y, LLImageGL* image, const LLColor4& color )
+{
+ gl_draw_scaled_rotated_image( x, y, image->getWidth(), image->getHeight(), 0.f, image, color );
+}
+
+void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color)
+{
+ gl_draw_scaled_rotated_image( x, y, width, height, 0.f, image, color );
+}
+
+void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLImageGL* image, const LLColor4& color, BOOL solid_color)
+{
+ stop_glerror();
+ F32 border_scale = 1.f;
+
+ if (border_height * 2 > height)
+ {
+ border_scale = (F32)height / ((F32)border_height * 2.f);
+ }
+ if (border_width * 2 > width)
+ {
+ border_scale = llmin(border_scale, (F32)width / ((F32)border_width * 2.f));
+ }
+
+ // scale screen size of borders down
+ S32 scaled_border_width = llfloor(border_scale * (F32)border_width);
+ S32 scaled_border_height = llfloor(border_scale * (F32)border_height);
+
+ LLGLSUIDefault gls_ui;
+
+ if (solid_color)
+ {
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PRIMARY_COLOR_ARB);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
+ }
+
+ glPushMatrix();
+ {
+ glTranslatef((F32)x, (F32)y, 0.f);
+
+ image->bind();
+
+ glColor4fv(color.mV);
+
+ F32 border_width_fraction = (F32)border_width / (F32)image->getWidth();
+ F32 border_height_fraction = (F32)border_height / (F32)image->getHeight();
+
+ glBegin(GL_QUADS);
+ {
+ // draw bottom left
+ glTexCoord2f(0.f, 0.f);
+ glVertex2i(0, 0);
+
+ glTexCoord2f(border_width_fraction, 0.f);
+ glVertex2i(scaled_border_width, 0);
+
+ glTexCoord2f(border_width_fraction, border_height_fraction);
+ glVertex2i(scaled_border_width, scaled_border_height);
+
+ glTexCoord2f(0.f, border_height_fraction);
+ glVertex2i(0, scaled_border_height);
+
+ // draw bottom middle
+ glTexCoord2f(border_width_fraction, 0.f);
+ glVertex2i(scaled_border_width, 0);
+
+ glTexCoord2f(1.f - border_width_fraction, 0.f);
+ glVertex2i(width - scaled_border_width, 0);
+
+ glTexCoord2f(1.f - border_width_fraction, border_height_fraction);
+ glVertex2i(width - scaled_border_width, scaled_border_height);
+
+ glTexCoord2f(border_width_fraction, border_height_fraction);
+ glVertex2i(scaled_border_width, scaled_border_height);
+
+ // draw bottom right
+ glTexCoord2f(1.f - border_width_fraction, 0.f);
+ glVertex2i(width - scaled_border_width, 0);
+
+ glTexCoord2f(1.f, 0.f);
+ glVertex2i(width, 0);
+
+ glTexCoord2f(1.f, border_height_fraction);
+ glVertex2i(width, scaled_border_height);
+
+ glTexCoord2f(1.f - border_width_fraction, border_height_fraction);
+ glVertex2i(width - scaled_border_width, scaled_border_height);
+
+ // draw left
+ glTexCoord2f(0.f, border_height_fraction);
+ glVertex2i(0, scaled_border_height);
+
+ glTexCoord2f(border_width_fraction, border_height_fraction);
+ glVertex2i(scaled_border_width, scaled_border_height);
+
+ glTexCoord2f(border_width_fraction, 1.f - border_height_fraction);
+ glVertex2i(scaled_border_width, height - scaled_border_height);
+
+ glTexCoord2f(0.f, 1.f - border_height_fraction);
+ glVertex2i(0, height - scaled_border_height);
+
+ // draw middle
+ glTexCoord2f(border_width_fraction, border_height_fraction);
+ glVertex2i(scaled_border_width, scaled_border_height);
+
+ glTexCoord2f(1.f - border_width_fraction, border_height_fraction);
+ glVertex2i(width - scaled_border_width, scaled_border_height);
+
+ glTexCoord2f(1.f - border_width_fraction, 1.f - border_height_fraction);
+ glVertex2i(width - scaled_border_width, height - scaled_border_height);
+
+ glTexCoord2f(border_width_fraction, 1.f - border_height_fraction);
+ glVertex2i(scaled_border_width, height - scaled_border_height);
+
+ // draw right
+ glTexCoord2f(1.f - border_width_fraction, border_height_fraction);
+ glVertex2i(width - scaled_border_width, scaled_border_height);
+
+ glTexCoord2f(1.f, border_height_fraction);
+ glVertex2i(width, scaled_border_height);
+
+ glTexCoord2f(1.f, 1.f - border_height_fraction);
+ glVertex2i(width, height - scaled_border_height);
+
+ glTexCoord2f(1.f - border_width_fraction, 1.f - border_height_fraction);
+ glVertex2i(width - scaled_border_width, height - scaled_border_height);
+
+ // draw top left
+ glTexCoord2f(0.f, 1.f - border_height_fraction);
+ glVertex2i(0, height - scaled_border_height);
+
+ glTexCoord2f(border_width_fraction, 1.f - border_height_fraction);
+ glVertex2i(scaled_border_width, height - scaled_border_height);
+
+ glTexCoord2f(border_width_fraction, 1.f);
+ glVertex2i(scaled_border_width, height);
+
+ glTexCoord2f(0.f, 1.f);
+ glVertex2i(0, height);
+
+ // draw top middle
+ glTexCoord2f(border_width_fraction, 1.f - border_height_fraction);
+ glVertex2i(scaled_border_width, height - scaled_border_height);
+
+ glTexCoord2f(1.f - border_width_fraction, 1.f - border_height_fraction);
+ glVertex2i(width - scaled_border_width, height - scaled_border_height);
+
+ glTexCoord2f(1.f - border_width_fraction, 1.f);
+ glVertex2i(width - scaled_border_width, height);
+
+ glTexCoord2f(border_width_fraction, 1.f);
+ glVertex2i(scaled_border_width, height);
+
+ // draw top right
+ glTexCoord2f(1.f - border_width_fraction, 1.f - border_height_fraction);
+ glVertex2i(width - scaled_border_width, height - scaled_border_height);
+
+ glTexCoord2f(1.f, 1.f - border_height_fraction);
+ glVertex2i(width, height - scaled_border_height);
+
+ glTexCoord2f(1.f, 1.f);
+ glVertex2i(width, height);
+
+ glTexCoord2f(1.f - border_width_fraction, 1.f);
+ glVertex2i(width - scaled_border_width, height);
+ }
+ glEnd();
+ }
+ glPopMatrix();
+
+ if (solid_color)
+ {
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ }
+}
+
+void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLImageGL* image, const LLColor4& color)
+{
+ gl_draw_scaled_rotated_image( x, y, image->getWidth(), image->getHeight(), degrees, image, color );
+}
+
+void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees, LLImageGL* image, const LLColor4& color)
+{
+ LLGLSUIDefault gls_ui;
+
+ glPushMatrix();
+ {
+ glTranslatef((F32)x, (F32)y, 0.f);
+ if( degrees )
+ {
+ F32 offset_x = F32(width/2);
+ F32 offset_y = F32(height/2);
+ glTranslatef( offset_x, offset_y, 0.f);
+ glRotatef( degrees, 0.f, 0.f, 1.f );
+ glTranslatef( -offset_x, -offset_y, 0.f );
+ }
+
+ image->bind();
+
+ glColor4fv(color.mV);
+
+ glBegin(GL_QUADS);
+ {
+ glTexCoord2f(1.f, 1.f);
+ glVertex2i(width, height );
+
+ glTexCoord2f(0.f, 1.f);
+ glVertex2i(0, height );
+
+ glTexCoord2f(0.f, 0.f);
+ glVertex2i(0, 0);
+
+ glTexCoord2f(1.f, 0.f);
+ glVertex2i(width, 0);
+ }
+ glEnd();
+ }
+ glPopMatrix();
+}
+
+
+void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color)
+{
+ LLGLSUIDefault gls_ui;
+
+ glPushMatrix();
+ {
+ glTranslatef((F32)x, (F32)y, 0.f);
+
+ image->bind();
+
+ glColor4fv(color.mV);
+
+ glBegin(GL_QUADS);
+ {
+ glTexCoord2f(1.f, 0.f);
+ glVertex2i(width, height );
+
+ glTexCoord2f(0.f, 0.f);
+ glVertex2i(0, height );
+
+ glTexCoord2f(0.f, 1.f);
+ glVertex2i(0, 0);
+
+ glTexCoord2f(1.f, 1.f);
+ glVertex2i(width, 0);
+ }
+ glEnd();
+ }
+ glPopMatrix();
+}
+
+
+void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase )
+{
+ phase = fmod(phase, 1.f);
+
+ S32 shift = S32(phase * 4.f) % 4;
+
+ // Stippled line
+ LLGLEnable stipple(GL_LINE_STIPPLE);
+
+ glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], color.mV[VALPHA]);
+ glLineWidth(2.5f);
+ glLineStipple(2, 0x3333 << shift);
+
+ glBegin(GL_LINES);
+ {
+ glVertex3fv( start.mV );
+ glVertex3fv( end.mV );
+ }
+ glEnd();
+
+ LLUI::setLineWidth(1.f);
+}
+
+
+void gl_rect_2d_xor(S32 left, S32 top, S32 right, S32 bottom)
+{
+ glColor4fv( LLColor4::white.mV );
+ glLogicOp( GL_XOR );
+ stop_glerror();
+
+ glBegin(GL_QUADS);
+ glVertex2i(left, top);
+ glVertex2i(left, bottom);
+ glVertex2i(right, bottom);
+ glVertex2i(right, top);
+ glEnd();
+
+ glLogicOp( GL_COPY );
+ stop_glerror();
+}
+
+
+void gl_arc_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled, F32 start_angle, F32 end_angle)
+{
+ if (end_angle < start_angle)
+ {
+ end_angle += F_TWO_PI;
+ }
+
+ glPushMatrix();
+ {
+ glTranslatef(center_x, center_y, 0.f);
+
+ // Inexact, but reasonably fast.
+ F32 delta = (end_angle - start_angle) / steps;
+ F32 sin_delta = sin( delta );
+ F32 cos_delta = cos( delta );
+ F32 x = cosf(start_angle) * radius;
+ F32 y = sinf(start_angle) * radius;
+
+ if (filled)
+ {
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex2f(0.f, 0.f);
+ // make sure circle is complete
+ steps += 1;
+ }
+ else
+ {
+ glBegin(GL_LINE_STRIP);
+ }
+
+ while( steps-- )
+ {
+ // Successive rotations
+ glVertex2f( x, y );
+ F32 x_new = x * cos_delta - y * sin_delta;
+ y = x * sin_delta + y * cos_delta;
+ x = x_new;
+ }
+ glEnd();
+ }
+ glPopMatrix();
+}
+
+void gl_circle_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled)
+{
+ glPushMatrix();
+ {
+ LLGLSNoTexture gls_no_texture;
+ glTranslatef(center_x, center_y, 0.f);
+
+ // Inexact, but reasonably fast.
+ F32 delta = F_TWO_PI / steps;
+ F32 sin_delta = sin( delta );
+ F32 cos_delta = cos( delta );
+ F32 x = radius;
+ F32 y = 0.f;
+
+ if (filled)
+ {
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex2f(0.f, 0.f);
+ // make sure circle is complete
+ steps += 1;
+ }
+ else
+ {
+ glBegin(GL_LINE_LOOP);
+ }
+
+ while( steps-- )
+ {
+ // Successive rotations
+ glVertex2f( x, y );
+ F32 x_new = x * cos_delta - y * sin_delta;
+ y = x * sin_delta + y * cos_delta;
+ x = x_new;
+ }
+ glEnd();
+ }
+ glPopMatrix();
+}
+
+// Renders a ring with sides (tube shape)
+void gl_deep_circle( F32 radius, F32 depth, S32 steps )
+{
+ F32 x = radius;
+ F32 y = 0.f;
+ F32 angle_delta = F_TWO_PI / (F32)steps;
+ glBegin( GL_TRIANGLE_STRIP );
+ {
+ S32 step = steps + 1; // An extra step to close the circle.
+ while( step-- )
+ {
+ glVertex3f( x, y, depth );
+ glVertex3f( x, y, 0.f );
+
+ F32 x_new = x * cosf(angle_delta) - y * sinf(angle_delta);
+ y = x * sinf(angle_delta) + y * cosf(angle_delta);
+ x = x_new;
+ }
+ }
+ glEnd();
+}
+
+void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor4& side_color, S32 steps, BOOL render_center )
+{
+ glPushMatrix();
+ {
+ glTranslatef(0.f, 0.f, -width / 2);
+ if( render_center )
+ {
+ glColor4fv(center_color.mV);
+ gl_deep_circle( radius, width, steps );
+ }
+ else
+ {
+ gl_washer_2d(radius, radius - width, steps, side_color, side_color);
+ glTranslatef(0.f, 0.f, width);
+ gl_washer_2d(radius - width, radius, steps, side_color, side_color);
+ }
+ }
+ glPopMatrix();
+}
+
+// Draw gray and white checkerboard with black border
+void gl_rect_2d_checkerboard(const LLRect& rect)
+{
+ // Initialize the first time this is called.
+ const S32 PIXELS = 32;
+ static GLubyte checkerboard[PIXELS * PIXELS];
+ static BOOL first = TRUE;
+ if( first )
+ {
+ for( S32 i = 0; i < PIXELS; i++ )
+ {
+ for( S32 j = 0; j < PIXELS; j++ )
+ {
+ checkerboard[i * PIXELS + j] = ((i & 1) ^ (j & 1)) * 0xFF;
+ }
+ }
+ first = FALSE;
+ }
+
+ LLGLSNoTexture gls_no_texture;
+
+ // ...white squares
+ glColor3f( 1.f, 1.f, 1.f );
+ gl_rect_2d(rect);
+
+ // ...gray squares
+ glColor3f( .7f, .7f, .7f );
+ glPolygonStipple( checkerboard );
+
+ LLGLEnable polygon_stipple(GL_POLYGON_STIPPLE);
+ gl_rect_2d(rect);
+}
+
+
+// Draws the area between two concentric circles, like
+// a doughnut or washer.
+void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color)
+{
+ const F32 DELTA = F_TWO_PI / steps;
+ const F32 SIN_DELTA = sin( DELTA );
+ const F32 COS_DELTA = cos( DELTA );
+
+ F32 x1 = outer_radius;
+ F32 y1 = 0.f;
+ F32 x2 = inner_radius;
+ F32 y2 = 0.f;
+
+ LLGLSNoTexture gls_no_texture;
+
+ glBegin( GL_TRIANGLE_STRIP );
+ {
+ steps += 1; // An extra step to close the circle.
+ while( steps-- )
+ {
+ glColor4fv(outer_color.mV);
+ glVertex2f( x1, y1 );
+ glColor4fv(inner_color.mV);
+ glVertex2f( x2, y2 );
+
+ F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA;
+ y1 = x1 * SIN_DELTA + y1 * COS_DELTA;
+ x1 = x1_new;
+
+ F32 x2_new = x2 * COS_DELTA - y2 * SIN_DELTA;
+ y2 = x2 * SIN_DELTA + y2 * COS_DELTA;
+ x2 = x2_new;
+ }
+ }
+ glEnd();
+}
+
+// Draws the area between two concentric circles, like
+// a doughnut or washer.
+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)
+{
+ const F32 DELTA = (end_radians - start_radians) / steps;
+ const F32 SIN_DELTA = sin( DELTA );
+ const F32 COS_DELTA = cos( DELTA );
+
+ F32 x1 = outer_radius * cos( start_radians );
+ F32 y1 = outer_radius * sin( start_radians );
+ F32 x2 = inner_radius * cos( start_radians );
+ F32 y2 = inner_radius * sin( start_radians );
+
+ LLGLSNoTexture gls_no_texture;
+ glBegin( GL_TRIANGLE_STRIP );
+ {
+ steps += 1; // An extra step to close the circle.
+ while( steps-- )
+ {
+ glColor4fv(outer_color.mV);
+ glVertex2f( x1, y1 );
+ glColor4fv(inner_color.mV);
+ glVertex2f( x2, y2 );
+
+ F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA;
+ y1 = x1 * SIN_DELTA + y1 * COS_DELTA;
+ x1 = x1_new;
+
+ F32 x2_new = x2 * COS_DELTA - y2 * SIN_DELTA;
+ y2 = x2 * SIN_DELTA + y2 * COS_DELTA;
+ x2 = x2_new;
+ }
+ }
+ glEnd();
+}
+
+// Draws spokes around a circle.
+void gl_washer_spokes_2d(F32 outer_radius, F32 inner_radius, S32 count, const LLColor4& inner_color, const LLColor4& outer_color)
+{
+ const F32 DELTA = F_TWO_PI / count;
+ const F32 HALF_DELTA = DELTA * 0.5f;
+ const F32 SIN_DELTA = sin( DELTA );
+ const F32 COS_DELTA = cos( DELTA );
+
+ F32 x1 = outer_radius * cos( HALF_DELTA );
+ F32 y1 = outer_radius * sin( HALF_DELTA );
+ F32 x2 = inner_radius * cos( HALF_DELTA );
+ F32 y2 = inner_radius * sin( HALF_DELTA );
+
+ LLGLSNoTexture gls_no_texture;
+
+ glBegin( GL_LINES );
+ {
+ while( count-- )
+ {
+ glColor4fv(outer_color.mV);
+ glVertex2f( x1, y1 );
+ glColor4fv(inner_color.mV);
+ glVertex2f( x2, y2 );
+
+ F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA;
+ y1 = x1 * SIN_DELTA + y1 * COS_DELTA;
+ x1 = x1_new;
+
+ F32 x2_new = x2 * COS_DELTA - y2 * SIN_DELTA;
+ y2 = x2 * SIN_DELTA + y2 * COS_DELTA;
+ x2 = x2_new;
+ }
+ }
+ glEnd();
+}
+
+void gl_rect_2d_simple_tex( S32 width, S32 height )
+{
+ glBegin( GL_QUADS );
+
+ glTexCoord2f(1.f, 1.f);
+ glVertex2i(width, height);
+
+ glTexCoord2f(0.f, 1.f);
+ glVertex2i(0, height);
+
+ glTexCoord2f(0.f, 0.f);
+ glVertex2i(0, 0);
+
+ glTexCoord2f(1.f, 0.f);
+ glVertex2i(width, 0);
+
+ glEnd();
+}
+
+void gl_rect_2d_simple( S32 width, S32 height )
+{
+ glBegin( GL_QUADS );
+ glVertex2i(width, height);
+ glVertex2i(0, height);
+ glVertex2i(0, 0);
+ glVertex2i(width, 0);
+ glEnd();
+}
+
+void gl_segmented_rect_2d_tex(const S32 left,
+ const S32 top,
+ const S32 right,
+ const S32 bottom,
+ const S32 texture_width,
+ const S32 texture_height,
+ const S32 border_size,
+ const U32 edges)
+{
+ S32 width = llabs(right - left);
+ S32 height = llabs(top - bottom);
+
+ glPushMatrix();
+
+ glTranslatef((F32)left, (F32)bottom, 0.f);
+ LLVector2 border_uv_scale((F32)border_size / (F32)texture_width, (F32)border_size / (F32)texture_height);
+
+ if (border_uv_scale.mV[VX] > 0.5f)
+ {
+ border_uv_scale *= 0.5f / border_uv_scale.mV[VX];
+ }
+ if (border_uv_scale.mV[VY] > 0.5f)
+ {
+ border_uv_scale *= 0.5f / border_uv_scale.mV[VY];
+ }
+
+ F32 border_scale = llmin((F32)border_size, (F32)width * 0.5f, (F32)height * 0.5f);
+ LLVector2 border_width_left = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero;
+ LLVector2 border_width_right = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero;
+ LLVector2 border_height_bottom = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero;
+ LLVector2 border_height_top = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero;
+ LLVector2 width_vec((F32)width, 0.f);
+ LLVector2 height_vec(0.f, (F32)height);
+
+ glBegin(GL_QUADS);
+ {
+ // draw bottom left
+ glTexCoord2f(0.f, 0.f);
+ glVertex2f(0.f, 0.f);
+
+ glTexCoord2f(border_uv_scale.mV[VX], 0.f);
+ glVertex2fv(border_width_left.mV);
+
+ glTexCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ glVertex2fv((border_width_left + border_height_bottom).mV);
+
+ glTexCoord2f(0.f, border_uv_scale.mV[VY]);
+ glVertex2fv(border_height_bottom.mV);
+
+ // draw bottom middle
+ glTexCoord2f(border_uv_scale.mV[VX], 0.f);
+ glVertex2fv(border_width_left.mV);
+
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
+ glVertex2fv((width_vec - border_width_right).mV);
+
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ glVertex2fv((width_vec - border_width_right + border_height_bottom).mV);
+
+ glTexCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ glVertex2fv((border_width_left + border_height_bottom).mV);
+
+ // draw bottom right
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
+ glVertex2fv((width_vec - border_width_right).mV);
+
+ glTexCoord2f(1.f, 0.f);
+ glVertex2fv(width_vec.mV);
+
+ glTexCoord2f(1.f, border_uv_scale.mV[VY]);
+ glVertex2fv((width_vec + border_height_bottom).mV);
+
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ glVertex2fv((width_vec - border_width_right + border_height_bottom).mV);
+
+ // draw left
+ glTexCoord2f(0.f, border_uv_scale.mV[VY]);
+ glVertex2fv(border_height_bottom.mV);
+
+ glTexCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ glVertex2fv((border_width_left + border_height_bottom).mV);
+
+ glTexCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((border_width_left + height_vec - border_height_top).mV);
+
+ glTexCoord2f(0.f, 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((height_vec - border_height_top).mV);
+
+ // draw middle
+ glTexCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ glVertex2fv((border_width_left + border_height_bottom).mV);
+
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ glVertex2fv((width_vec - border_width_right + border_height_bottom).mV);
+
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
+
+ glTexCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((border_width_left + height_vec - border_height_top).mV);
+
+ // draw right
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ glVertex2fv((width_vec - border_width_right + border_height_bottom).mV);
+
+ glTexCoord2f(1.f, border_uv_scale.mV[VY]);
+ glVertex2fv((width_vec + border_height_bottom).mV);
+
+ glTexCoord2f(1.f, 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((width_vec + height_vec - border_height_top).mV);
+
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
+
+ // draw top left
+ glTexCoord2f(0.f, 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((height_vec - border_height_top).mV);
+
+ glTexCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((border_width_left + height_vec - border_height_top).mV);
+
+ glTexCoord2f(border_uv_scale.mV[VX], 1.f);
+ glVertex2fv((border_width_left + height_vec).mV);
+
+ glTexCoord2f(0.f, 1.f);
+ glVertex2fv((height_vec).mV);
+
+ // draw top middle
+ glTexCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((border_width_left + height_vec - border_height_top).mV);
+
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
+
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
+ glVertex2fv((width_vec - border_width_right + height_vec).mV);
+
+ glTexCoord2f(border_uv_scale.mV[VX], 1.f);
+ glVertex2fv((border_width_left + height_vec).mV);
+
+ // draw top right
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
+
+ glTexCoord2f(1.f, 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((width_vec + height_vec - border_height_top).mV);
+
+ glTexCoord2f(1.f, 1.f);
+ glVertex2fv((width_vec + height_vec).mV);
+
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
+ glVertex2fv((width_vec - border_width_right + height_vec).mV);
+ }
+ glEnd();
+
+ glPopMatrix();
+}
+
+void gl_segmented_rect_2d_fragment_tex(const S32 left,
+ const S32 top,
+ const S32 right,
+ const S32 bottom,
+ const S32 texture_width,
+ const S32 texture_height,
+ const S32 border_size,
+ const F32 start_fragment,
+ const F32 end_fragment,
+ const U32 edges)
+{
+ S32 width = llabs(right - left);
+ S32 height = llabs(top - bottom);
+
+ glPushMatrix();
+
+ glTranslatef((F32)left, (F32)bottom, 0.f);
+ LLVector2 border_uv_scale((F32)border_size / (F32)texture_width, (F32)border_size / (F32)texture_height);
+
+ if (border_uv_scale.mV[VX] > 0.5f)
+ {
+ border_uv_scale *= 0.5f / border_uv_scale.mV[VX];
+ }
+ if (border_uv_scale.mV[VY] > 0.5f)
+ {
+ border_uv_scale *= 0.5f / border_uv_scale.mV[VY];
+ }
+
+ F32 border_scale = llmin((F32)border_size, (F32)width * 0.5f, (F32)height * 0.5f);
+ LLVector2 border_width_left = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero;
+ LLVector2 border_width_right = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero;
+ LLVector2 border_height_bottom = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero;
+ LLVector2 border_height_top = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero;
+ LLVector2 width_vec((F32)width, 0.f);
+ LLVector2 height_vec(0.f, (F32)height);
+
+ F32 middle_start = border_scale / (F32)width;
+ F32 middle_end = 1.f - middle_start;
+
+ F32 u_min;
+ F32 u_max;
+ LLVector2 x_min;
+ LLVector2 x_max;
+
+ glBegin(GL_QUADS);
+ {
+ if (start_fragment < middle_start)
+ {
+ u_min = (start_fragment / middle_start) * border_uv_scale.mV[VX];
+ u_max = llmin(end_fragment / middle_start, 1.f) * border_uv_scale.mV[VX];
+ x_min = (start_fragment / middle_start) * border_width_left;
+ x_max = llmin(end_fragment / middle_start, 1.f) * border_width_left;
+
+ // draw bottom left
+ glTexCoord2f(u_min, 0.f);
+ glVertex2fv(x_min.mV);
+
+ glTexCoord2f(border_uv_scale.mV[VX], 0.f);
+ glVertex2fv(x_max.mV);
+
+ glTexCoord2f(u_max, border_uv_scale.mV[VY]);
+ glVertex2fv((x_max + border_height_bottom).mV);
+
+ glTexCoord2f(u_min, border_uv_scale.mV[VY]);
+ glVertex2fv((x_min + border_height_bottom).mV);
+
+ // draw left
+ glTexCoord2f(u_min, border_uv_scale.mV[VY]);
+ glVertex2fv((x_min + border_height_bottom).mV);
+
+ glTexCoord2f(u_max, border_uv_scale.mV[VY]);
+ glVertex2fv((x_max + border_height_bottom).mV);
+
+ glTexCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((x_max + height_vec - border_height_top).mV);
+
+ glTexCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((x_min + height_vec - border_height_top).mV);
+
+ // draw top left
+ glTexCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((x_min + height_vec - border_height_top).mV);
+
+ glTexCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((x_max + height_vec - border_height_top).mV);
+
+ glTexCoord2f(u_max, 1.f);
+ glVertex2fv((x_max + height_vec).mV);
+
+ glTexCoord2f(u_min, 1.f);
+ glVertex2fv((x_min + height_vec).mV);
+ }
+
+ if (end_fragment > middle_start || start_fragment < middle_end)
+ {
+ x_min = border_width_left + ((llclamp(start_fragment, middle_start, middle_end) - middle_start)) * width_vec;
+ x_max = border_width_left + ((llclamp(end_fragment, middle_start, middle_end) - middle_start)) * width_vec;
+
+ // draw bottom middle
+ glTexCoord2f(border_uv_scale.mV[VX], 0.f);
+ glVertex2fv(x_min.mV);
+
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
+ glVertex2fv((x_max).mV);
+
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ glVertex2fv((x_max + border_height_bottom).mV);
+
+ glTexCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ glVertex2fv((x_min + border_height_bottom).mV);
+
+ // draw middle
+ glTexCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ glVertex2fv((x_min + border_height_bottom).mV);
+
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+ glVertex2fv((x_max + border_height_bottom).mV);
+
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((x_max + height_vec - border_height_top).mV);
+
+ glTexCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((x_min + height_vec - border_height_top).mV);
+
+ // draw top middle
+ glTexCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((x_min + height_vec - border_height_top).mV);
+
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((x_max + height_vec - border_height_top).mV);
+
+ glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
+ glVertex2fv((x_max + height_vec).mV);
+
+ glTexCoord2f(border_uv_scale.mV[VX], 1.f);
+ glVertex2fv((x_min + height_vec).mV);
+ }
+
+ if (end_fragment > middle_end)
+ {
+ u_min = (1.f - llmax(0.f, ((start_fragment - middle_end) / middle_start))) * border_uv_scale.mV[VX];
+ u_max = (1.f - ((end_fragment - middle_end) / middle_start)) * border_uv_scale.mV[VX];
+ x_min = width_vec - ((1.f - llmax(0.f, ((start_fragment - middle_end) / middle_start))) * border_width_right);
+ x_max = width_vec - ((1.f - ((end_fragment - middle_end) / middle_start)) * border_width_right);
+
+ // draw bottom right
+ glTexCoord2f(u_min, 0.f);
+ glVertex2fv((x_min).mV);
+
+ glTexCoord2f(u_max, 0.f);
+ glVertex2fv(x_max.mV);
+
+ glTexCoord2f(u_max, border_uv_scale.mV[VY]);
+ glVertex2fv((x_max + border_height_bottom).mV);
+
+ glTexCoord2f(u_min, border_uv_scale.mV[VY]);
+ glVertex2fv((x_min + border_height_bottom).mV);
+
+ // draw right
+ glTexCoord2f(u_min, border_uv_scale.mV[VY]);
+ glVertex2fv((x_min + border_height_bottom).mV);
+
+ glTexCoord2f(u_max, border_uv_scale.mV[VY]);
+ glVertex2fv((x_max + border_height_bottom).mV);
+
+ glTexCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((x_max + height_vec - border_height_top).mV);
+
+ glTexCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((x_min + height_vec - border_height_top).mV);
+
+ // draw top right
+ glTexCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((x_min + height_vec - border_height_top).mV);
+
+ glTexCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
+ glVertex2fv((x_max + height_vec - border_height_top).mV);
+
+ glTexCoord2f(u_max, 1.f);
+ glVertex2fv((x_max + height_vec).mV);
+
+ glTexCoord2f(u_min, 1.f);
+ glVertex2fv((x_min + height_vec).mV);
+ }
+ }
+ glEnd();
+
+ glPopMatrix();
+}
+
+void gl_segmented_rect_3d_tex(const LLVector2& border_scale, const LLVector3& border_width,
+ const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec,
+ const U32 edges)
+{
+ LLVector3 left_border_width = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? border_width : LLVector3::zero;
+ LLVector3 right_border_width = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? border_width : LLVector3::zero;
+
+ LLVector3 top_border_height = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? border_height : LLVector3::zero;
+ LLVector3 bottom_border_height = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? border_height : LLVector3::zero;
+
+ glBegin(GL_QUADS);
+ {
+ // draw bottom left
+ glTexCoord2f(0.f, 0.f);
+ glVertex3f(0.f, 0.f, 0.f);
+
+ glTexCoord2f(border_scale.mV[VX], 0.f);
+ glVertex3fv(left_border_width.mV);
+
+ glTexCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
+ glVertex3fv((left_border_width + bottom_border_height).mV);
+
+ glTexCoord2f(0.f, border_scale.mV[VY]);
+ glVertex3fv(bottom_border_height.mV);
+
+ // draw bottom middle
+ glTexCoord2f(border_scale.mV[VX], 0.f);
+ glVertex3fv(left_border_width.mV);
+
+ glTexCoord2f(1.f - border_scale.mV[VX], 0.f);
+ glVertex3fv((width_vec - right_border_width).mV);
+
+ glTexCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
+ glVertex3fv((width_vec - right_border_width + bottom_border_height).mV);
+
+ glTexCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
+ glVertex3fv((left_border_width + bottom_border_height).mV);
+
+ // draw bottom right
+ glTexCoord2f(1.f - border_scale.mV[VX], 0.f);
+ glVertex3fv((width_vec - right_border_width).mV);
+
+ glTexCoord2f(1.f, 0.f);
+ glVertex3fv(width_vec.mV);
+
+ glTexCoord2f(1.f, border_scale.mV[VY]);
+ glVertex3fv((width_vec + bottom_border_height).mV);
+
+ glTexCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
+ glVertex3fv((width_vec - right_border_width + bottom_border_height).mV);
+
+ // draw left
+ glTexCoord2f(0.f, border_scale.mV[VY]);
+ glVertex3fv(bottom_border_height.mV);
+
+ glTexCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
+ glVertex3fv((left_border_width + bottom_border_height).mV);
+
+ glTexCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
+ glVertex3fv((left_border_width + height_vec - top_border_height).mV);
+
+ glTexCoord2f(0.f, 1.f - border_scale.mV[VY]);
+ glVertex3fv((height_vec - top_border_height).mV);
+
+ // draw middle
+ glTexCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
+ glVertex3fv((left_border_width + bottom_border_height).mV);
+
+ glTexCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
+ glVertex3fv((width_vec - right_border_width + bottom_border_height).mV);
+
+ glTexCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
+ glVertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
+
+ glTexCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
+ glVertex3fv((left_border_width + height_vec - top_border_height).mV);
+
+ // draw right
+ glTexCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
+ glVertex3fv((width_vec - right_border_width + bottom_border_height).mV);
+
+ glTexCoord2f(1.f, border_scale.mV[VY]);
+ glVertex3fv((width_vec + bottom_border_height).mV);
+
+ glTexCoord2f(1.f, 1.f - border_scale.mV[VY]);
+ glVertex3fv((width_vec + height_vec - top_border_height).mV);
+
+ glTexCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
+ glVertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
+
+ // draw top left
+ glTexCoord2f(0.f, 1.f - border_scale.mV[VY]);
+ glVertex3fv((height_vec - top_border_height).mV);
+
+ glTexCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
+ glVertex3fv((left_border_width + height_vec - top_border_height).mV);
+
+ glTexCoord2f(border_scale.mV[VX], 1.f);
+ glVertex3fv((left_border_width + height_vec).mV);
+
+ glTexCoord2f(0.f, 1.f);
+ glVertex3fv((height_vec).mV);
+
+ // draw top middle
+ glTexCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
+ glVertex3fv((left_border_width + height_vec - top_border_height).mV);
+
+ glTexCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
+ glVertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
+
+ glTexCoord2f(1.f - border_scale.mV[VX], 1.f);
+ glVertex3fv((width_vec - right_border_width + height_vec).mV);
+
+ glTexCoord2f(border_scale.mV[VX], 1.f);
+ glVertex3fv((left_border_width + height_vec).mV);
+
+ // draw top right
+ glTexCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
+ glVertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
+
+ glTexCoord2f(1.f, 1.f - border_scale.mV[VY]);
+ glVertex3fv((width_vec + height_vec - top_border_height).mV);
+
+ glTexCoord2f(1.f, 1.f);
+ glVertex3fv((width_vec + height_vec).mV);
+
+ glTexCoord2f(1.f - border_scale.mV[VX], 1.f);
+ glVertex3fv((width_vec - right_border_width + height_vec).mV);
+ }
+ glEnd();
+}
+
+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)
+{
+ gl_segmented_rect_3d_tex(border_scale, border_width, border_height, width_vec, height_vec, ROUNDED_RECT_TOP);
+}
+
+#if 0 // No longer used
+void load_tr(const LLString& lang)
+{
+ LLString inname = "words." + lang + ".txt";
+ LLString filename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, inname.c_str());
+
+ llifstream file;
+ file.open(filename.c_str(), std::ios_base::binary);
+ if (!file)
+ {
+ llinfos << "No translation dictionary for: " << filename << llendl;
+ return;
+ }
+
+ llinfos << "Reading language translation dictionary: " << filename << llendl;
+
+ gTranslation.clear();
+ gUntranslated.clear();
+
+ const S32 MAX_LINE_LEN = 1024;
+ char buffer[MAX_LINE_LEN];
+ while (!file.eof())
+ {
+ file.getline(buffer, MAX_LINE_LEN);
+ LLString line(buffer);
+ S32 commentpos = line.find("//");
+ if (commentpos != LLString::npos)
+ {
+ line = line.substr(0, commentpos);
+ }
+ S32 offset = line.find('\t');
+ if (offset != LLString::npos)
+ {
+ LLString english = line.substr(0,offset);
+ LLString translation = line.substr(offset+1);
+ //llinfos << "TR: " << english << " = " << translation << llendl;
+ gTranslation[english] = translation;
+ }
+ }
+
+ file.close();
+}
+
+void init_tr(const LLString& language)
+{
+ if (!language.empty())
+ {
+ gLanguage = language;
+ }
+ load_tr(gLanguage);
+}
+
+void cleanup_tr()
+{
+ // Dump untranslated phrases to help with translation
+ if (gUntranslated.size() > 0)
+ {
+ LLString outname = "untranslated_" + gLanguage + ".txt";
+ LLString outfilename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, outname.c_str());
+ llofstream outfile;
+ outfile.open(outfilename.c_str());
+ if (!outfile)
+ {
+ return;
+ }
+ llinfos << "Writing untranslated words to: " << outfilename << llendl;
+ LLString outtext;
+ for (std::list<LLString>::iterator iter = gUntranslated.begin();
+ iter != gUntranslated.end(); ++iter)
+ {
+ // output: english_phrase english_phrase
+ outtext += *iter;
+ outtext += "\t";
+ outtext += *iter;
+ outtext += "\n";
+ }
+ outfile << outtext.c_str();
+ outfile.close();
+ }
+}
+
+LLString tr(const LLString& english_string)
+{
+ std::map<LLString, LLString>::iterator it = gTranslation.find(english_string);
+ if (it != gTranslation.end())
+ {
+ return it->second;
+ }
+ else
+ {
+ gUntranslated.push_back(english_string);
+ return english_string;
+ }
+}
+
+#endif
+
+
+class LLShowXUINamesListener: public LLSimpleListener
+{
+ bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
+ {
+ LLUI::sShowXUINames = (BOOL) event->getValue().asBoolean();
+ return true;
+ }
+};
+static LLShowXUINamesListener show_xui_names_listener;
+
+
+void LLUI::initClass(LLControlGroup* config,
+ LLControlGroup* colors,
+ LLControlGroup* assets,
+ LLImageProviderInterface* image_provider,
+ LLUIAudioCallback audio_callback,
+ const LLVector2* scale_factor,
+ const LLString& language)
+{
+ sConfigGroup = config;
+ sColorsGroup = colors;
+ sAssetsGroup = assets;
+ sImageProvider = image_provider;
+ sAudioCallback = audio_callback;
+ sGLScaleFactor = (scale_factor == NULL) ? LLVector2(1.f, 1.f) : *scale_factor;
+ sWindow = NULL; // set later in startup
+ LLFontGL::sShadowColor = colors->getColor("ColorDropShadow");
+
+ LLUI::sShowXUINames = LLUI::sConfigGroup->getBOOL("ShowXUINames");
+ LLUI::sConfigGroup->getControl("ShowXUINames")->addListener(&show_xui_names_listener);
+// init_tr(language);
+}
+
+void LLUI::cleanupClass()
+{
+// cleanup_tr();
+}
+
+
+//static
+void LLUI::translate(F32 x, F32 y, F32 z)
+{
+ glTranslatef(x,y,z);
+ LLFontGL::sCurOrigin.mX += (S32) x;
+ LLFontGL::sCurOrigin.mY += (S32) y;
+ LLFontGL::sCurOrigin.mZ += z;
+}
+
+//static
+void LLUI::pushMatrix()
+{
+ glPushMatrix();
+ LLFontGL::sOriginStack.push_back(LLFontGL::sCurOrigin);
+}
+
+//static
+void LLUI::popMatrix()
+{
+ glPopMatrix();
+ LLFontGL::sCurOrigin = *LLFontGL::sOriginStack.rbegin();
+ LLFontGL::sOriginStack.pop_back();
+}
+
+//static
+void LLUI::loadIdentity()
+{
+ glLoadIdentity();
+ LLFontGL::sCurOrigin.mX = 0;
+ LLFontGL::sCurOrigin.mY = 0;
+ LLFontGL::sCurOrigin.mZ = 0;
+}
+
+//static
+void LLUI::setScissorRegionScreen(const LLRect& rect)
+{
+ stop_glerror();
+ S32 x,y,w,h;
+ x = llround(rect.mLeft * LLUI::sGLScaleFactor.mV[VX]);
+ y = llround(rect.mBottom * LLUI::sGLScaleFactor.mV[VY]);
+ w = llround(rect.getWidth() * LLUI::sGLScaleFactor.mV[VX]);
+ h = llround(rect.getHeight() * LLUI::sGLScaleFactor.mV[VY]);
+ glScissor( x,y,w,h );
+ stop_glerror();
+}
+
+//static
+void LLUI::setScissorRegionLocal(const LLRect& rect)
+{
+ stop_glerror();
+ S32 screen_left = LLFontGL::sCurOrigin.mX + rect.mLeft;
+ S32 screen_bottom = LLFontGL::sCurOrigin.mY + rect.mBottom;
+
+ S32 x,y,w,h;
+
+ x = llround((F32)screen_left * LLUI::sGLScaleFactor.mV[VX]);
+ y = llround((F32)screen_bottom * LLUI::sGLScaleFactor.mV[VY]);
+ w = llround((F32)rect.getWidth() * LLUI::sGLScaleFactor.mV[VX]);
+ h = llround((F32)rect.getHeight() * LLUI::sGLScaleFactor.mV[VY]);
+
+ w = llmax(0,w);
+ h = llmax(0,h);
+
+ glScissor(x,y,w,h);
+ stop_glerror();
+}
+
+//static
+void LLUI::setScaleFactor(const LLVector2 &scale_factor)
+{
+ sGLScaleFactor = scale_factor;
+}
+
+//static
+void LLUI::setLineWidth(F32 width)
+{
+ glLineWidth(width * lerp(sGLScaleFactor.mV[VX], sGLScaleFactor.mV[VY], 0.5f));
+}
+
+//static
+void LLUI::setCursorPositionScreen(S32 x, S32 y)
+{
+ S32 screen_x, screen_y;
+ screen_x = llround((F32)x * sGLScaleFactor.mV[VX]);
+ screen_y = llround((F32)y * sGLScaleFactor.mV[VY]);
+
+ LLCoordWindow window_point;
+ LLView::getWindow()->convertCoords(LLCoordGL(screen_x, screen_y), &window_point);
+
+ LLView::getWindow()->setCursorPosition(window_point);
+}
+
+//static
+void LLUI::setCursorPositionLocal(LLView* viewp, S32 x, S32 y)
+{
+ S32 screen_x, screen_y;
+ viewp->localPointToScreen(x, y, &screen_x, &screen_y);
+
+ setCursorPositionScreen(screen_x, screen_y);
+}
+
+//static
+LLString LLUI::locateSkin(const LLString& filename)
+{
+ LLString slash = gDirUtilp->getDirDelimiter();
+ LLString found_file = filename;
+ if (!gDirUtilp->fileExists(found_file))
+ {
+ found_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); // Should be CUSTOM_SKINS?
+ }
+ if (sConfigGroup && sConfigGroup->controlExists("Language"))
+ {
+ if (!gDirUtilp->fileExists(found_file))
+ {
+ LLString localization(sConfigGroup->getString("Language"));
+ LLString local_skin = "xui" + slash + localization + slash + filename;
+ found_file = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, local_skin);
+ }
+ }
+ if (!gDirUtilp->fileExists(found_file))
+ {
+ LLString local_skin = "xui" + slash + "en-us" + slash + filename;
+ found_file = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, local_skin);
+ }
+ if (!gDirUtilp->fileExists(found_file))
+ {
+ found_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, filename);
+ }
+ return found_file;
+}
+
+//static
+LLVector2 LLUI::getWindowSize()
+{
+ LLCoordWindow window_rect;
+ sWindow->getSize(&window_rect);
+
+ return LLVector2(window_rect.mX / sGLScaleFactor.mV[VX], window_rect.mY / sGLScaleFactor.mV[VY]);
+}
+
+//static
+LLUUID LLUI::findAssetUUIDByName(const LLString &asset_name)
+{
+ if(asset_name == LLString::null) return LLUUID::null;
+ LLString foundValue = LLUI::sConfigGroup->findString(asset_name);
+ if(foundValue==LLString::null)
+ {
+ foundValue = LLUI::sAssetsGroup->findString(asset_name);
+ }
+ if(foundValue == LLString::null){
+ return LLUUID::null;
+ }
+ return LLUUID( foundValue );
+}