summaryrefslogtreecommitdiff
path: root/indra/newview/llviewerwindow.cpp
diff options
context:
space:
mode:
authorAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 19:04:52 +0200
committerAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 19:04:52 +0200
commit1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch)
treeab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/llviewerwindow.cpp
parent6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff)
parente1623bb276f83a43ce7a197e388720c05bdefe61 (diff)
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts: # autobuild.xml # indra/cmake/CMakeLists.txt # indra/cmake/GoogleMock.cmake # indra/llaudio/llaudioengine_fmodstudio.cpp # indra/llaudio/llaudioengine_fmodstudio.h # indra/llaudio/lllistener_fmodstudio.cpp # indra/llaudio/lllistener_fmodstudio.h # indra/llaudio/llstreamingaudio_fmodstudio.cpp # indra/llaudio/llstreamingaudio_fmodstudio.h # indra/llcharacter/llmultigesture.cpp # indra/llcharacter/llmultigesture.h # indra/llimage/llimage.cpp # indra/llimage/llimagepng.cpp # indra/llimage/llimageworker.cpp # indra/llimage/tests/llimageworker_test.cpp # indra/llmessage/tests/llmockhttpclient.h # indra/llprimitive/llgltfmaterial.h # indra/llrender/llfontfreetype.cpp # indra/llui/llcombobox.cpp # indra/llui/llfolderview.cpp # indra/llui/llfolderviewmodel.h # indra/llui/lllineeditor.cpp # indra/llui/lllineeditor.h # indra/llui/lltextbase.cpp # indra/llui/lltextbase.h # indra/llui/lltexteditor.cpp # indra/llui/lltextvalidate.cpp # indra/llui/lltextvalidate.h # indra/llui/lluictrl.h # indra/llui/llview.cpp # indra/llwindow/llwindowmacosx.cpp # indra/newview/app_settings/settings.xml # indra/newview/llappearancemgr.cpp # indra/newview/llappearancemgr.h # indra/newview/llavatarpropertiesprocessor.cpp # indra/newview/llavatarpropertiesprocessor.h # indra/newview/llbreadcrumbview.cpp # indra/newview/llbreadcrumbview.h # indra/newview/llbreastmotion.cpp # indra/newview/llbreastmotion.h # indra/newview/llconversationmodel.h # indra/newview/lldensityctrl.cpp # indra/newview/lldensityctrl.h # indra/newview/llface.inl # indra/newview/llfloatereditsky.cpp # indra/newview/llfloatereditwater.cpp # indra/newview/llfloateremojipicker.h # indra/newview/llfloaterimsessiontab.cpp # indra/newview/llfloaterprofiletexture.cpp # indra/newview/llfloaterprofiletexture.h # indra/newview/llgesturemgr.cpp # indra/newview/llgesturemgr.h # indra/newview/llimpanel.cpp # indra/newview/llimpanel.h # indra/newview/llinventorybridge.cpp # indra/newview/llinventorybridge.h # indra/newview/llinventoryclipboard.cpp # indra/newview/llinventoryclipboard.h # indra/newview/llinventoryfunctions.cpp # indra/newview/llinventoryfunctions.h # indra/newview/llinventorygallery.cpp # indra/newview/lllistbrowser.cpp # indra/newview/lllistbrowser.h # indra/newview/llpanelobjectinventory.cpp # indra/newview/llpanelprofile.cpp # indra/newview/llpanelprofile.h # indra/newview/llpreviewgesture.cpp # indra/newview/llsavedsettingsglue.cpp # indra/newview/llsavedsettingsglue.h # indra/newview/lltooldraganddrop.cpp # indra/newview/llurllineeditorctrl.cpp # indra/newview/llvectorperfoptions.cpp # indra/newview/llvectorperfoptions.h # indra/newview/llviewerparceloverlay.cpp # indra/newview/llviewertexlayer.cpp # indra/newview/llviewertexturelist.cpp # indra/newview/macmain.h # indra/test/test.cpp
Diffstat (limited to 'indra/newview/llviewerwindow.cpp')
-rw-r--r--indra/newview/llviewerwindow.cpp12801
1 files changed, 6407 insertions, 6394 deletions
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 44297526e3..f607ffdbb5 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1,6394 +1,6407 @@
-/**
- * @file llviewerwindow.cpp
- * @brief Implementation of the LLViewerWindow class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-#include "llviewerwindow.h"
-
-
-// system library includes
-#include <stdio.h>
-#include <iostream>
-#include <fstream>
-#include <algorithm>
-#include <boost/filesystem.hpp>
-#include <boost/lambda/core.hpp>
-#include <boost/regex.hpp>
-
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llcommandhandler.h"
-#include "llcommunicationchannel.h"
-#include "llfloaterreg.h"
-#include "llhudicon.h"
-#include "llmeshrepository.h"
-#include "llnotificationhandler.h"
-#include "llpanellogin.h"
-#include "llsetkeybinddialog.h"
-#include "llviewerinput.h"
-#include "llviewermenu.h"
-
-#include "llviewquery.h"
-#include "llxmltree.h"
-#include "llslurl.h"
-#include "llrender.h"
-
-#include "stringize.h"
-
-//
-// TODO: Many of these includes are unnecessary. Remove them.
-//
-
-// linden library includes
-#include "llaudioengine.h" // mute on minimize
-#include "llchatentry.h"
-#include "indra_constants.h"
-#include "llassetstorage.h"
-#include "llerrorcontrol.h"
-#include "llfontgl.h"
-#include "llmousehandler.h"
-#include "llrect.h"
-#include "llsky.h"
-#include "llstring.h"
-#include "llui.h"
-#include "lluuid.h"
-#include "llview.h"
-#include "llxfermanager.h"
-#include "message.h"
-#include "object_flags.h"
-#include "lltimer.h"
-#include "llviewermenu.h"
-#include "lltooltip.h"
-#include "llmediaentry.h"
-#include "llurldispatcher.h"
-#include "raytrace.h"
-
-// newview includes
-#include "llagent.h"
-#include "llbox.h"
-#include "llchicletbar.h"
-#include "llconsole.h"
-#include "llviewercontrol.h"
-#include "llcylinder.h"
-#include "lldebugview.h"
-#include "lldir.h"
-#include "lldrawable.h"
-#include "lldrawpoolalpha.h"
-#include "lldrawpoolbump.h"
-#include "lldrawpoolwater.h"
-#include "llmaniptranslate.h"
-#include "llface.h"
-#include "llfeaturemanager.h"
-#include "llfilepicker.h"
-#include "llfirstuse.h"
-#include "llfloater.h"
-#include "llfloaterbuyland.h"
-#include "llfloatercamera.h"
-#include "llfloaterland.h"
-#include "llfloaterinspect.h"
-#include "llfloatermap.h"
-#include "llfloaternamedesc.h"
-#include "llfloaterpreference.h"
-#include "llfloatersnapshot.h"
-#include "llfloatertools.h"
-#include "llfloaterworldmap.h"
-#include "llfocusmgr.h"
-#include "llfontfreetype.h"
-#include "llgesturemgr.h"
-#include "llglheaders.h"
-#include "lltooltip.h"
-#include "llhudmanager.h"
-#include "llhudobject.h"
-#include "llhudview.h"
-#include "llimage.h"
-#include "llimagej2c.h"
-#include "llimageworker.h"
-#include "llkeyboard.h"
-#include "lllineeditor.h"
-#include "llmenugl.h"
-#include "llmenuoptionpathfindingrebakenavmesh.h"
-#include "llmodaldialog.h"
-#include "llmorphview.h"
-#include "llmoveview.h"
-#include "llnavigationbar.h"
-#include "llnotificationhandler.h"
-#include "llpaneltopinfobar.h"
-#include "llpopupview.h"
-#include "llpreviewtexture.h"
-#include "llprogressview.h"
-#include "llresmgr.h"
-#include "llselectmgr.h"
-#include "llrootview.h"
-#include "llrendersphere.h"
-#include "llstartup.h"
-#include "llstatusbar.h"
-#include "llstatview.h"
-#include "llsurface.h"
-#include "llsurfacepatch.h"
-#include "lltexlayer.h"
-#include "lltextbox.h"
-#include "lltexturecache.h"
-#include "lltexturefetch.h"
-#include "lltextureview.h"
-#include "lltoast.h"
-#include "lltool.h"
-#include "lltoolbarview.h"
-#include "lltoolcomp.h"
-#include "lltooldraganddrop.h"
-#include "lltoolface.h"
-#include "lltoolfocus.h"
-#include "lltoolgrab.h"
-#include "lltoolmgr.h"
-#include "lltoolmorph.h"
-#include "lltoolpie.h"
-#include "lltoolselectland.h"
-#include "lltrans.h"
-#include "lluictrlfactory.h"
-#include "llurldispatcher.h" // SLURL from other app instance
-#include "llversioninfo.h"
-#include "llvieweraudio.h"
-#include "llviewercamera.h"
-#include "llviewergesture.h"
-#include "llviewertexturelist.h"
-#include "llviewerinventory.h"
-#include "llviewerinput.h"
-#include "llviewermedia.h"
-#include "llviewermediafocus.h"
-#include "llviewermenu.h"
-#include "llviewermessage.h"
-#include "llviewerobjectlist.h"
-#include "llviewerparcelmgr.h"
-#include "llviewerregion.h"
-#include "llviewershadermgr.h"
-#include "llviewerstats.h"
-#include "llvoavatarself.h"
-#include "llvopartgroup.h"
-#include "llvovolume.h"
-#include "llworld.h"
-#include "llworldmapview.h"
-#include "pipeline.h"
-#include "llappviewer.h"
-#include "llviewerdisplay.h"
-#include "llspatialpartition.h"
-#include "llviewerjoystick.h"
-#include "llviewermenufile.h" // LLFilePickerReplyThread
-#include "llviewernetwork.h"
-#include "llpostprocess.h"
-#include "llfloaterimnearbychat.h"
-#include "llagentui.h"
-#include "llwearablelist.h"
-
-#include "llviewereventrecorder.h"
-
-#include "llnotifications.h"
-#include "llnotificationsutil.h"
-#include "llnotificationmanager.h"
-
-#include "llfloaternotificationsconsole.h"
-
-#include "llwindowlistener.h"
-#include "llviewerwindowlistener.h"
-#include "llpaneltopinfobar.h"
-#include "llcleanup.h"
-
-#if LL_WINDOWS
-#include <tchar.h> // For Unicode conversion methods
-#include "llwindowwin32.h" // For AltGr handling
-#endif
-
-//
-// Globals
-//
-void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
-void swap();
-
-extern bool gDebugClicks;
-extern bool gDisplaySwapBuffers;
-extern bool gDepthDirty;
-extern bool gResizeScreenTexture;
-extern bool gCubeSnapshot;
-extern bool gSnapshotNoPost;
-
-LLViewerWindow *gViewerWindow = NULL;
-
-LLFrameTimer gAwayTimer;
-LLFrameTimer gAwayTriggerTimer;
-
-bool gShowOverlayTitle = false;
-
-LLViewerObject* gDebugRaycastObject = NULL;
-LLVOPartGroup* gDebugRaycastParticle = NULL;
-LLVector4a gDebugRaycastIntersection;
-LLVector4a gDebugRaycastParticleIntersection;
-LLVector2 gDebugRaycastTexCoord;
-LLVector4a gDebugRaycastNormal;
-LLVector4a gDebugRaycastTangent;
-S32 gDebugRaycastFaceHit;
-LLVector4a gDebugRaycastStart;
-LLVector4a gDebugRaycastEnd;
-
-// HUD display lines in lower right
-bool gDisplayWindInfo = false;
-bool gDisplayCameraPos = false;
-bool gDisplayFOV = false;
-bool gDisplayBadge = false;
-
-static const U8 NO_FACE = 255;
-bool gQuietSnapshot = false;
-
-// Minimum value for UIScaleFactor, also defined in preferences, ui_scale_slider
-static const F32 MIN_UI_SCALE = 0.75f;
-// 4.0 in preferences, but win10 supports larger scaling and value is used more as
-// sanity check, so leaving space for larger values from DPI updates.
-static const F32 MAX_UI_SCALE = 7.0f;
-static const F32 MIN_DISPLAY_SCALE = 0.75f;
-
-static const char KEY_MOUSELOOK = 'M';
-
-static LLCachedControl<std::string> sSnapshotBaseName(LLCachedControl<std::string>(gSavedPerAccountSettings, "SnapshotBaseName", "Snapshot"));
-static LLCachedControl<std::string> sSnapshotDir(LLCachedControl<std::string>(gSavedPerAccountSettings, "SnapshotBaseDir", ""));
-
-LLTrace::SampleStatHandle<> LLViewerWindow::sMouseVelocityStat("Mouse Velocity");
-
-
-class RecordToChatConsoleRecorder : public LLError::Recorder
-{
-public:
- virtual void recordMessage(LLError::ELevel level,
- const std::string& message)
- {
- //FIXME: this is NOT thread safe, and will do bad things when a warning is issued from a non-UI thread
-
- // only log warnings to chat console
- //if (level == LLError::LEVEL_WARN)
- //{
- //LLFloaterChat* chat_floater = LLFloaterReg::findTypedInstance<LLFloaterChat>("chat");
- //if (chat_floater && gSavedSettings.getBOOL("WarningsAsChat"))
- //{
- // LLChat chat;
- // chat.mText = message;
- // chat.mSourceType = CHAT_SOURCE_SYSTEM;
-
- // chat_floater->addChat(chat, false, false);
- //}
- //}
- }
-};
-
-class RecordToChatConsole : public LLSingleton<RecordToChatConsole>
-{
- LLSINGLETON(RecordToChatConsole);
-public:
- void startRecorder() { LLError::addRecorder(mRecorder); }
- void stopRecorder() { LLError::removeRecorder(mRecorder); }
-
-private:
- LLError::RecorderPtr mRecorder;
-};
-
-RecordToChatConsole::RecordToChatConsole():
- mRecorder(new RecordToChatConsoleRecorder())
-{
- mRecorder->showTags(false);
- mRecorder->showLocation(false);
- mRecorder->showMultiline(true);
-}
-
-////////////////////////////////////////////////////////////////////////////
-//
-// Print Utility
-//
-
-// Convert a normalized float (-1.0 <= x <= +1.0) to a fixed 1.4 format string:
-//
-// s#.####
-//
-// Where:
-// s sign character; space if x is positiv, minus if negative
-// # decimal digits
-//
-// This is similar to printf("%+.4f") except positive numbers are NOT cluttered with a leading '+' sign.
-// NOTE: This does NOT null terminate the output
-void normalized_float_to_string(const float x, char *out_str)
-{
- static const unsigned char DECIMAL_BCD2[] =
- {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
- 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
- 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99
- };
-
- int neg = (x < 0);
- int rem = neg
- ? (int)(x * -10000.)
- : (int)(x * 10000.);
-
- int d10 = rem % 100; rem /= 100;
- int d32 = rem % 100; rem /= 100;
-
- out_str[6] = '0' + ((DECIMAL_BCD2[ d10 ] >> 0) & 0xF);
- out_str[5] = '0' + ((DECIMAL_BCD2[ d10 ] >> 4) & 0xF);
- out_str[4] = '0' + ((DECIMAL_BCD2[ d32 ] >> 0) & 0xF);
- out_str[3] = '0' + ((DECIMAL_BCD2[ d32 ] >> 4) & 0xF);
- out_str[2] = '.';
- out_str[1] = '0' + (rem & 1);
- out_str[0] = " -"[neg]; // Could always show '+' for positive but this clutters up the common case
-}
-
-// normalized float
-// printf("%-.4f %-.4f %-.4f")
-// Params:
-// float &matrix_row[4]
-// int matrix_cell_index
-// string out_buffer (size 32)
-// Note: The buffer is assumed to be pre-filled with spaces
-#define MATRIX_ROW_N32_TO_STR(matrix_row, i, out_buffer) \
- normalized_float_to_string(matrix_row[i+0], out_buffer + 0); \
- normalized_float_to_string(matrix_row[i+1], out_buffer + 11); \
- normalized_float_to_string(matrix_row[i+2], out_buffer + 22); \
- out_buffer[31] = 0;
-
-
-// regular float
-// sprintf(buffer, "%-8.2f %-8.2f %-8.2f", matrix_row[i+0], matrix_row[i+1], matrix_row[i+2]);
-// Params:
-// float &matrix_row[4]
-// int matrix_cell_index
-// char out_buffer[32]
-// Note: The buffer is assumed to be pre-filled with spaces
-#define MATRIX_ROW_F32_TO_STR(matrix_row, i, out_buffer) { \
- static const char *format[3] = { \
- "%-8.2f" , /* 0 */ \
- "> 99K ", /* 1 */ \
- "< -99K " /* 2 */ \
- }; \
- \
- F32 temp_0 = matrix_row[i+0]; \
- F32 temp_1 = matrix_row[i+1]; \
- F32 temp_2 = matrix_row[i+2]; \
- \
- U8 flag_0 = (((U8)(temp_0 < -99999.99)) << 1) | ((U8)(temp_0 > 99999.99)); \
- U8 flag_1 = (((U8)(temp_1 < -99999.99)) << 1) | ((U8)(temp_1 > 99999.99)); \
- U8 flag_2 = (((U8)(temp_2 < -99999.99)) << 1) | ((U8)(temp_2 > 99999.99)); \
- \
- if (temp_0 < 0.f) out_buffer[ 0] = '-'; \
- if (temp_1 < 0.f) out_buffer[11] = '-'; \
- if (temp_2 < 0.f) out_buffer[22] = '-'; \
- \
- sprintf(out_buffer+ 1,format[flag_0],fabsf(temp_0)); out_buffer[ 1+8] = ' '; \
- sprintf(out_buffer+12,format[flag_1],fabsf(temp_1)); out_buffer[12+8] = ' '; \
- sprintf(out_buffer+23,format[flag_2],fabsf(temp_2)); out_buffer[23+8] = 0 ; \
-}
-
-////////////////////////////////////////////////////////////////////////////
-//
-// LLDebugText
-//
-
-static LLTrace::BlockTimerStatHandle FTM_DISPLAY_DEBUG_TEXT("Display Debug Text");
-
-class LLDebugText
-{
-private:
- struct Line
- {
- Line(const std::string& in_text, S32 in_x, S32 in_y) : text(in_text), x(in_x), y(in_y) {}
- std::string text;
- S32 x,y;
- };
-
- LLViewerWindow *mWindow;
-
- typedef std::vector<Line> line_list_t;
- line_list_t mLineList;
- LLColor4 mTextColor;
-
- LLColor4 mBackColor;
- LLRect mBackRectCamera1;
- LLRect mBackRectCamera2;
-
- void addText(S32 x, S32 y, const std::string &text)
- {
- mLineList.push_back(Line(text, x, y));
- }
-
- void clearText() { mLineList.clear(); }
-
-public:
- LLDebugText(LLViewerWindow* window) : mWindow(window) {}
-
- void update()
- {
- if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- clearText();
- return;
- }
-
- static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic", false) ;
-
- std::string wind_vel_text;
- std::string wind_vector_text;
- std::string rwind_vel_text;
- std::string rwind_vector_text;
- std::string audio_text;
-
- static const std::string beacon_particle = LLTrans::getString("BeaconParticle");
- static const std::string beacon_physical = LLTrans::getString("BeaconPhysical");
- static const std::string beacon_scripted = LLTrans::getString("BeaconScripted");
- static const std::string beacon_scripted_touch = LLTrans::getString("BeaconScriptedTouch");
- static const std::string beacon_sound = LLTrans::getString("BeaconSound");
- static const std::string beacon_media = LLTrans::getString("BeaconMedia");
- static const std::string beacon_sun = LLTrans::getString("BeaconSun");
- static const std::string beacon_moon = LLTrans::getString("BeaconMoon");
- static const std::string particle_hiding = LLTrans::getString("ParticleHiding");
-
- // Draw the statistics in a light gray
- // and in a thin font
- mTextColor = LLColor4( 0.86f, 0.86f, 0.86f, 1.f );
-
- // Draw stuff growing up from right lower corner of screen
- S32 x_right = mWindow->getWorldViewWidthScaled();
- S32 xpos = x_right - 400;
- xpos = llmax(xpos, 0);
- S32 ypos = 64;
- const S32 y_inc = 20;
-
- // Camera matrix text is hard to see again a white background
- // Add a dark background underneath the matrices for readability (contrast)
- mBackRectCamera1.mLeft = xpos;
- mBackRectCamera1.mRight = x_right;
- mBackRectCamera1.mTop = -1;
- mBackRectCamera1.mBottom = -1;
- mBackRectCamera2 = mBackRectCamera1;
-
- mBackColor = LLUIColorTable::instance().getColor( "MenuDefaultBgColor" );
-
- clearText();
-
- if (gSavedSettings.getBOOL("DebugShowTime"))
- {
- F32 time = gFrameTimeSeconds;
- S32 hours = (S32)(time / (60*60));
- S32 mins = (S32)((time - hours*(60*60)) / 60);
- S32 secs = (S32)((time - hours*(60*60) - mins*60));
- addText(xpos, ypos, llformat("Time: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc;
- }
-
- if (gSavedSettings.getBOOL("DebugShowMemory"))
- {
- addText(xpos, ypos,
- STRINGIZE("Memory: " << (LLMemory::getCurrentRSS() / 1024) << " (KB)"));
- ypos += y_inc;
- }
-
- if (gDisplayCameraPos)
- {
- std::string camera_view_text;
- std::string camera_center_text;
- std::string agent_view_text;
- std::string agent_left_text;
- std::string agent_center_text;
- std::string agent_root_center_text;
-
- LLVector3d tvector; // Temporary vector to hold data for printing.
-
- // Update camera center, camera view, wind info every other frame
- tvector = gAgent.getPositionGlobal();
- agent_center_text = llformat("AgentCenter %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
-
- if (isAgentAvatarValid())
- {
- tvector = gAgent.getPosGlobalFromAgent(gAgentAvatarp->mRoot->getWorldPosition());
- agent_root_center_text = llformat("AgentRootCenter %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
- }
- else
- {
- agent_root_center_text = "---";
- }
-
-
- tvector = LLVector4(gAgent.getFrameAgent().getAtAxis());
- agent_view_text = llformat("AgentAtAxis %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
-
- tvector = LLVector4(gAgent.getFrameAgent().getLeftAxis());
- agent_left_text = llformat("AgentLeftAxis %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
-
- tvector = gAgentCamera.getCameraPositionGlobal();
- camera_center_text = llformat("CameraCenter %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
-
- tvector = LLVector4(LLViewerCamera::getInstance()->getAtAxis());
- camera_view_text = llformat("CameraAtAxis %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
-
- addText(xpos, ypos, agent_center_text); ypos += y_inc;
- addText(xpos, ypos, agent_root_center_text); ypos += y_inc;
- addText(xpos, ypos, agent_view_text); ypos += y_inc;
- addText(xpos, ypos, agent_left_text); ypos += y_inc;
- addText(xpos, ypos, camera_center_text); ypos += y_inc;
- addText(xpos, ypos, camera_view_text); ypos += y_inc;
- }
-
- if (gDisplayWindInfo)
- {
- wind_vel_text = llformat("Wind velocity %.2f m/s", gWindVec.magVec());
- wind_vector_text = llformat("Wind vector %.2f %.2f %.2f", gWindVec.mV[0], gWindVec.mV[1], gWindVec.mV[2]);
- rwind_vel_text = llformat("RWind vel %.2f m/s", gRelativeWindVec.magVec());
- rwind_vector_text = llformat("RWind vec %.2f %.2f %.2f", gRelativeWindVec.mV[0], gRelativeWindVec.mV[1], gRelativeWindVec.mV[2]);
-
- addText(xpos, ypos, wind_vel_text); ypos += y_inc;
- addText(xpos, ypos, wind_vector_text); ypos += y_inc;
- addText(xpos, ypos, rwind_vel_text); ypos += y_inc;
- addText(xpos, ypos, rwind_vector_text); ypos += y_inc;
- }
- if (gDisplayWindInfo)
- {
- audio_text = llformat("Audio for wind: %d", gAudiop ? gAudiop->isWindEnabled() : -1);
- addText(xpos, ypos, audio_text); ypos += y_inc;
- }
- if (gDisplayFOV)
- {
- addText(xpos, ypos, llformat("FOV: %2.1f deg", RAD_TO_DEG * LLViewerCamera::getInstance()->getView()));
- ypos += y_inc;
- }
- if (gDisplayBadge)
- {
- addText(xpos, ypos+(y_inc/2), llformat("Hippos!", RAD_TO_DEG * LLViewerCamera::getInstance()->getView()));
- ypos += y_inc * 2;
- }
-
- /*if (LLViewerJoystick::getInstance()->getOverrideCamera())
- {
- addText(xpos + 200, ypos, llformat("Flycam"));
- ypos += y_inc;
- }*/
-
- if (gSavedSettings.getBOOL("DebugShowRenderInfo"))
- {
- LLTrace::Recording& last_frame_recording = LLTrace::get_frame_recording().getLastRecording();
-
- //show streaming cost/triangle count of known prims in current region OR selection
- {
- F32 cost = 0.f;
- S32 count = 0;
- S32 vcount = 0;
- S32 object_count = 0;
- S32 total_bytes = 0;
- S32 visible_bytes = 0;
-
- const char* label = "Region";
- if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 0)
- { //region
- LLViewerRegion* region = gAgent.getRegion();
- if (region)
- {
- for (U32 i = 0; i < gObjectList.getNumObjects(); ++i)
- {
- LLViewerObject* object = gObjectList.getObject(i);
- if (object &&
- object->getRegion() == region &&
- object->getVolume())
- {
- object_count++;
- S32 bytes = 0;
- S32 visible = 0;
- cost += object->getStreamingCost();
- LLMeshCostData costs;
- if (object->getCostData(costs))
- {
- bytes = costs.getSizeTotal();
- visible = costs.getSizeByLOD(object->getLOD());
- }
-
- S32 vt = 0;
- count += object->getTriangleCount(&vt);
- vcount += vt;
- total_bytes += bytes;
- visible_bytes += visible;
- }
- }
- }
- }
- else
- {
- label = "Selection";
- cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectStreamingCost(&total_bytes, &visible_bytes);
- count = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectTriangleCount(&vcount);
- object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
- }
-
- addText(xpos,ypos, llformat("%s streaming cost: %.1f", label, cost));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat(" %.3f KTris, %.3f KVerts, %.1f/%.1f KB, %d objects",
- count/1000.f, vcount/1000.f, visible_bytes/1024.f, total_bytes/1024.f, object_count));
- ypos += y_inc;
-
- }
-
- addText(xpos, ypos, llformat("%d Texture Binds", LLImageGL::sBindCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Unique Textures", LLImageGL::sUniqueCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Render Calls", (U32)last_frame_recording.getSampleCount(LLPipeline::sStatBatchSize)));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d/%d Objects Active", gObjectList.getNumActiveObjects(), gObjectList.getNumObjects()));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Matrix Ops", gPipeline.mMatrixOpCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Texture Matrix Ops", gPipeline.mTextureMatrixOps));
- ypos += y_inc;
-
- gPipeline.mTextureMatrixOps = 0;
- gPipeline.mMatrixOpCount = 0;
-
- if (last_frame_recording.getSampleCount(LLPipeline::sStatBatchSize) > 0)
- {
- addText(xpos, ypos, llformat("Batch min/max/mean: %d/%d/%d", (U32)last_frame_recording.getMin(LLPipeline::sStatBatchSize), (U32)last_frame_recording.getMax(LLPipeline::sStatBatchSize), (U32)last_frame_recording.getMean(LLPipeline::sStatBatchSize)));
- }
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("UI Verts/Calls: %d/%d", LLRender::sUIVerts, LLRender::sUICalls));
- LLRender::sUICalls = LLRender::sUIVerts = 0;
- ypos += y_inc;
-
- addText(xpos,ypos, llformat("%d/%d Nodes visible", gPipeline.mNumVisibleNodes, LLSpatialGroup::sNodeCount));
-
- ypos += y_inc;
-
- if (!LLOcclusionCullingGroup::sPendingQueries.empty())
- {
- addText(xpos,ypos, llformat("%d Queries pending", LLOcclusionCullingGroup::sPendingQueries.size()));
- ypos += y_inc;
- }
-
-
- addText(xpos,ypos, llformat("%d Avatars visible", LLVOAvatar::sNumVisibleAvatars));
-
- ypos += y_inc;
-
- addText(xpos,ypos, llformat("%d Lights visible", LLPipeline::sVisibleLightCount));
-
- ypos += y_inc;
-
- if (gMeshRepo.meshRezEnabled())
- {
- addText(xpos, ypos, llformat("%.3f MB Mesh Data Received", LLMeshRepository::sBytesReceived/(1024.f*1024.f)));
-
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d/%d Mesh HTTP Requests/Retries", LLMeshRepository::sHTTPRequestCount,
- LLMeshRepository::sHTTPRetryCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d/%d Mesh LOD Pending/Processing", LLMeshRepository::sLODPending, LLMeshRepository::sLODProcessing));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%.3f/%.3f MB Mesh Cache Read/Write ", LLMeshRepository::sCacheBytesRead/(1024.f*1024.f), LLMeshRepository::sCacheBytesWritten/(1024.f*1024.f)));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%.3f/%.3f MB Mesh Skins/Decompositions Memory", LLMeshRepository::sCacheBytesSkins / (1024.f*1024.f), LLMeshRepository::sCacheBytesDecomps / (1024.f*1024.f)));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%.3f MB Mesh Headers Memory", LLMeshRepository::sCacheBytesHeaders / (1024.f*1024.f)));
-
- ypos += y_inc;
- }
-
- gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0;
- }
- if (gSavedSettings.getBOOL("DebugShowAvatarRenderInfo"))
- {
- std::map<std::string, LLVOAvatar*> sorted_avs;
-
- std::vector<LLCharacter*>::iterator sort_iter = LLCharacter::sInstances.begin();
- while (sort_iter != LLCharacter::sInstances.end())
- {
- LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*sort_iter);
- if (avatar &&
- !avatar->isDead()) // Not dead yet
- {
- // Stuff into a sorted map so the display is ordered
- sorted_avs[avatar->getFullname()] = avatar;
- }
- sort_iter++;
- }
-
- std::string trunc_name;
- std::map<std::string, LLVOAvatar*>::reverse_iterator av_iter = sorted_avs.rbegin(); // Put "A" at the top
- while (av_iter != sorted_avs.rend())
- {
- LLVOAvatar* avatar = av_iter->second;
-
- avatar->calculateUpdateRenderComplexity(); // Make sure the numbers are up-to-date
-
- trunc_name = utf8str_truncate(avatar->getFullname(), 16);
- addText(xpos, ypos, llformat("%s : %s, complexity %d, area %.2f",
- trunc_name.c_str(),
- LLVOAvatar::rezStatusToString(avatar->getRezzedStatus()).c_str(),
- avatar->getVisualComplexity(),
- avatar->getAttachmentSurfaceArea()));
- ypos += y_inc;
- av_iter++;
- }
- }
- if (gSavedSettings.getBOOL("DebugShowRenderMatrices"))
- {
- char camera_lines[8][32];
- memset(camera_lines, ' ', sizeof(camera_lines));
-
- // Projection last column is always <0,0,-1.0001,0>
- // Projection last row is always <0,0,-0.2>
- mBackRectCamera1.mBottom = ypos - y_inc + 2;
- MATRIX_ROW_N32_TO_STR(gGLProjection, 12,camera_lines[7]); addText(xpos, ypos, std::string(camera_lines[7])); ypos += y_inc;
- MATRIX_ROW_N32_TO_STR(gGLProjection, 8,camera_lines[6]); addText(xpos, ypos, std::string(camera_lines[6])); ypos += y_inc;
- MATRIX_ROW_N32_TO_STR(gGLProjection, 4,camera_lines[5]); addText(xpos, ypos, std::string(camera_lines[5])); ypos += y_inc; mBackRectCamera1.mTop = ypos + 2;
- MATRIX_ROW_N32_TO_STR(gGLProjection, 0,camera_lines[4]); addText(xpos, ypos, std::string(camera_lines[4])); ypos += y_inc; mBackRectCamera2.mBottom = ypos + 2;
-
- addText(xpos, ypos, "Projection Matrix");
- ypos += y_inc;
-
- // View last column is always <0,0,0,1>
- MATRIX_ROW_F32_TO_STR(gGLModelView, 12,camera_lines[3]); addText(xpos, ypos, std::string(camera_lines[3])); ypos += y_inc;
- MATRIX_ROW_N32_TO_STR(gGLModelView, 8,camera_lines[2]); addText(xpos, ypos, std::string(camera_lines[2])); ypos += y_inc;
- MATRIX_ROW_N32_TO_STR(gGLModelView, 4,camera_lines[1]); addText(xpos, ypos, std::string(camera_lines[1])); ypos += y_inc; mBackRectCamera2.mTop = ypos + 2;
- MATRIX_ROW_N32_TO_STR(gGLModelView, 0,camera_lines[0]); addText(xpos, ypos, std::string(camera_lines[0])); ypos += y_inc;
-
- addText(xpos, ypos, "View Matrix");
- ypos += y_inc;
- }
- // disable use of glReadPixels which messes up nVidia nSight graphics debugging
- if (gSavedSettings.getBOOL("DebugShowColor") && !LLRender::sNsightDebugSupport)
- {
- U8 color[4];
- LLCoordGL coord = gViewerWindow->getCurrentMouse();
-
- // Convert x,y to raw pixel coords
- S32 x_raw = llround(coord.mX * gViewerWindow->getWindowWidthRaw() / (F32) gViewerWindow->getWindowWidthScaled());
- S32 y_raw = llround(coord.mY * gViewerWindow->getWindowHeightRaw() / (F32) gViewerWindow->getWindowHeightScaled());
-
- glReadPixels(x_raw, y_raw, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
- addText(xpos, ypos, llformat("Pixel <%1d, %1d> R:%1d G:%1d B:%1d A:%1d", x_raw, y_raw, color[0], color[1], color[2], color[3]));
- ypos += y_inc;
- }
-
- // only display these messages if we are actually rendering beacons at this moment
- if (LLPipeline::getRenderBeacons() && LLFloaterReg::instanceVisible("beacons"))
- {
- if (LLPipeline::getRenderMOAPBeacons())
- {
- addText(xpos, ypos, "Viewing media beacons (white)");
- ypos += y_inc;
- }
-
- if (LLPipeline::toggleRenderTypeControlNegated(LLPipeline::RENDER_TYPE_PARTICLES))
- {
- addText(xpos, ypos, particle_hiding);
- ypos += y_inc;
- }
-
- if (LLPipeline::getRenderParticleBeacons())
- {
- addText(xpos, ypos, "Viewing particle beacons (blue)");
- ypos += y_inc;
- }
-
- if (LLPipeline::getRenderSoundBeacons())
- {
- addText(xpos, ypos, "Viewing sound beacons (yellow)");
- ypos += y_inc;
- }
-
- if (LLPipeline::getRenderScriptedBeacons())
- {
- addText(xpos, ypos, beacon_scripted);
- ypos += y_inc;
- }
- else
- if (LLPipeline::getRenderScriptedTouchBeacons())
- {
- addText(xpos, ypos, beacon_scripted_touch);
- ypos += y_inc;
- }
-
- if (LLPipeline::getRenderPhysicalBeacons())
- {
- addText(xpos, ypos, "Viewing physical object beacons (green)");
- ypos += y_inc;
- }
- }
-
- static LLUICachedControl<bool> show_sun_beacon("sunbeacon", false);
- static LLUICachedControl<bool> show_moon_beacon("moonbeacon", false);
-
- if (show_sun_beacon)
- {
- addText(xpos, ypos, beacon_sun);
- ypos += y_inc;
- }
- if (show_moon_beacon)
- {
- addText(xpos, ypos, beacon_moon);
- ypos += y_inc;
- }
-
- if(log_texture_traffic)
- {
- U32 old_y = ypos ;
- for(S32 i = LLViewerTexture::BOOST_NONE; i < LLViewerTexture::MAX_GL_IMAGE_CATEGORY; i++)
- {
- if(gTotalTextureBytesPerBoostLevel[i] > (S32Bytes)0)
- {
- addText(xpos, ypos, llformat("Boost_Level %d: %.3f MB", i, F32Megabytes(gTotalTextureBytesPerBoostLevel[i]).value()));
- ypos += y_inc;
- }
- }
- if(ypos != old_y)
- {
- addText(xpos, ypos, "Network traffic for textures:");
- ypos += y_inc;
- }
- }
-
- if (gSavedSettings.getBOOL("DebugShowTextureInfo"))
- {
- LLViewerObject* objectp = NULL ;
-
- LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode();
- if (nodep)
- {
- objectp = nodep->getObject();
- }
-
- if (objectp && !objectp->isDead())
- {
- S32 num_faces = objectp->mDrawable->getNumFaces() ;
- std::set<LLViewerFetchedTexture*> tex_list;
-
- for(S32 i = 0 ; i < num_faces; i++)
- {
- LLFace* facep = objectp->mDrawable->getFace(i) ;
- if(facep)
- {
- LLViewerFetchedTexture* tex = dynamic_cast<LLViewerFetchedTexture*>(facep->getTexture()) ;
- if(tex)
- {
- if(tex_list.find(tex) != tex_list.end())
- {
- continue ; //already displayed.
- }
- tex_list.insert(tex);
-
- std::string uuid_str;
- tex->getID().toString(uuid_str);
- uuid_str = uuid_str.substr(0,7);
-
- addText(xpos, ypos, llformat("ID: %s v_size: %.3f", uuid_str.c_str(), tex->getMaxVirtualSize()));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("discard level: %d desired level: %d Missing: %s", tex->getDiscardLevel(),
- tex->getDesiredDiscardLevel(), tex->isMissingAsset() ? "Y" : "N"));
- ypos += y_inc;
- }
- }
- }
- }
- }
- }
-
- void draw()
- {
- LL_RECORD_BLOCK_TIME(FTM_DISPLAY_DEBUG_TEXT);
-
- // Camera matrix text is hard to see again a white background
- // Add a dark background underneath the matrices for readability (contrast)
- if (mBackRectCamera1.mTop >= 0)
- {
- mBackColor.setAlpha( 0.75f );
- gl_rect_2d(mBackRectCamera1, mBackColor, true);
-
- mBackColor.setAlpha( 0.66f );
- gl_rect_2d(mBackRectCamera2, mBackColor, true);
- }
-
- for (line_list_t::iterator iter = mLineList.begin();
- iter != mLineList.end(); ++iter)
- {
- const Line& line = *iter;
- LLFontGL::getFontMonospace()->renderUTF8(line.text, 0, (F32)line.x, (F32)line.y, mTextColor,
- LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL, LLFontGL::NO_SHADOW);
- }
- }
-
-};
-
-void LLViewerWindow::updateDebugText()
-{
- mDebugText->update();
-}
-
-////////////////////////////////////////////////////////////////////////////
-//
-// LLViewerWindow
-//
-
-LLViewerWindow::Params::Params()
-: title("title"),
- name("name"),
- x("x"),
- y("y"),
- width("width"),
- height("height"),
- min_width("min_width"),
- min_height("min_height"),
- fullscreen("fullscreen", false),
- ignore_pixel_depth("ignore_pixel_depth", false)
-{}
-
-
-void LLViewerWindow::handlePieMenu(S32 x, S32 y, MASK mask)
-{
- if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() && gAgent.isInitialized())
- {
- // If the current tool didn't process the click, we should show
- // the pie menu. This can be done by passing the event to the pie
- // menu tool.
- LLToolPie::getInstance()->handleRightMouseDown(x, y, mask);
- }
-}
-
-bool LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, bool down, bool& is_toolmgr_action)
-{
- const char* buttonname = "";
- const char* buttonstatestr = "";
- S32 x = pos.mX;
- S32 y = pos.mY;
- x = ll_round((F32)x / mDisplayScale.mV[VX]);
- y = ll_round((F32)y / mDisplayScale.mV[VY]);
-
- // Handle non-consuming global keybindings, like voice
- gViewerInput.handleGlobalBindsMouse(clicktype, mask, down);
-
- // only send mouse clicks to UI if UI is visible
- if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
-
- if (down)
- {
- buttonstatestr = "down" ;
- }
- else
- {
- buttonstatestr = "up" ;
- }
-
- switch (clicktype)
- {
- case CLICK_LEFT:
- mLeftMouseDown = down;
- buttonname = "Left";
- break;
- case CLICK_RIGHT:
- mRightMouseDown = down;
- buttonname = "Right";
- break;
- case CLICK_MIDDLE:
- mMiddleMouseDown = down;
- buttonname = "Middle";
- break;
- case CLICK_DOUBLELEFT:
- mLeftMouseDown = down;
- buttonname = "Left Double Click";
- break;
- case CLICK_BUTTON4:
- buttonname = "Button 4";
- break;
- case CLICK_BUTTON5:
- buttonname = "Button 5";
- break;
- default:
- break; // COUNT and NONE
- }
-
- LLView::sMouseHandlerMessage.clear();
-
- if (gMenuBarView)
- {
- // stop ALT-key access to menu
- gMenuBarView->resetMenuTrigger();
- }
-
- if (gDebugClicks)
- {
- LL_INFOS() << "ViewerWindow " << buttonname << " mouse " << buttonstatestr << " at " << x << "," << y << LL_ENDL;
- }
-
- // Make sure we get a corresponding mouseup event, even if the mouse leaves the window
- if (down)
- mWindow->captureMouse();
- else
- mWindow->releaseMouse();
-
- // Indicate mouse was active
- LLUI::getInstance()->resetMouseIdleTimer();
-
- // Don't let the user move the mouse out of the window until mouse up.
- if( LLToolMgr::getInstance()->getCurrentTool()->clipMouseWhenDown() )
- {
- mWindow->setMouseClipping(down);
- }
-
- LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
- if( mouse_captor )
- {
- S32 local_x;
- S32 local_y;
- mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
- if (LLView::sDebugMouseHandling)
- {
- LL_INFOS() << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << LL_ENDL;
- }
-
- bool r = mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down);
- if (r) {
-
- LL_DEBUGS() << "LLViewerWindow::handleAnyMouseClick viewer with mousecaptor calling updatemouseeventinfo - local_x|global x "<< local_x << " " << x << "local/global y " << local_y << " " << y << LL_ENDL;
-
- LLViewerEventRecorder::instance().setMouseGlobalCoords(x,y);
- LLViewerEventRecorder::instance().logMouseEvent(std::string(buttonstatestr),std::string(buttonname));
-
- }
- else if (down && clicktype == CLICK_RIGHT)
- {
- handlePieMenu(x, y, mask);
- r = true;
- }
- return r;
- }
-
- // Mark the click as handled and return if we aren't within the root view to avoid spurious bugs
- if( !mRootView->pointInView(x, y) )
- {
- return true;
- }
- // Give the UI views a chance to process the click
-
- bool r= mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) ;
- if (r)
- {
-
- LL_DEBUGS() << "LLViewerWindow::handleAnyMouseClick calling updatemouseeventinfo - global x "<< " " << x << "global y " << y << "buttonstate: " << buttonstatestr << " buttonname " << buttonname << LL_ENDL;
-
- LLViewerEventRecorder::instance().setMouseGlobalCoords(x,y);
-
- // Clear local coords - this was a click on root window so these are not needed
- // By not including them, this allows the test skeleton generation tool to be smarter when generating code
- // the code generator can be smarter because when local coords are present it can try the xui path with local coords
- // and fallback to global coordinates only if needed.
- // The drawback to this approach is sometimes a valid xui path will appear to work fine, but NOT interact with the UI element
- // (VITA support not implemented yet or not visible to VITA due to widget further up xui path not being visible to VITA)
- // For this reason it's best to provide hints where possible here by leaving out local coordinates
- LLViewerEventRecorder::instance().setMouseLocalCoords(-1,-1);
- LLViewerEventRecorder::instance().logMouseEvent(buttonstatestr,buttonname);
-
- if (LLView::sDebugMouseHandling)
- {
- LL_INFOS() << buttonname << " Mouse " << buttonstatestr << " " << LLViewerEventRecorder::instance().get_xui() << LL_ENDL;
- }
- return true;
- } else if (LLView::sDebugMouseHandling)
- {
- LL_INFOS() << buttonname << " Mouse " << buttonstatestr << " not handled by view" << LL_ENDL;
- }
- }
-
- // Do not allow tool manager to handle mouseclicks if we have disconnected
- if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) )
- {
- LLViewerEventRecorder::instance().clear_xui();
- is_toolmgr_action = true;
- return true;
- }
-
- if (down && clicktype == CLICK_RIGHT)
- {
- handlePieMenu(x, y, mask);
- return true;
- }
-
- // If we got this far on a down-click, it wasn't handled.
- // Up-clicks, though, are always handled as far as the OS is concerned.
- bool default_rtn = !down;
- return default_rtn;
-}
-
-bool LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- mAllowMouseDragging = false;
- if (!mMouseDownTimer.getStarted())
- {
- mMouseDownTimer.start();
- }
- else
- {
- mMouseDownTimer.reset();
- }
- bool down = true;
- //handleMouse() loops back to LLViewerWindow::handleAnyMouseClick
- return gViewerInput.handleMouse(window, pos, mask, CLICK_LEFT, down);
-}
-
-bool LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- // try handling as a double-click first, then a single-click if that
- // wasn't handled.
- bool down = true;
- if (gViewerInput.handleMouse(window, pos, mask, CLICK_DOUBLELEFT, down))
- {
- return true;
- }
- return handleMouseDown(window, pos, mask);
-}
-
-bool LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- if (mMouseDownTimer.getStarted())
- {
- mMouseDownTimer.stop();
- }
- bool down = false;
- return gViewerInput.handleMouse(window, pos, mask, CLICK_LEFT, down);
-}
-bool LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- bool down = true;
- return gViewerInput.handleMouse(window, pos, mask, CLICK_RIGHT, down);
-}
-
-bool LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- bool down = false;
- return gViewerInput.handleMouse(window, pos, mask, CLICK_RIGHT, down);
-}
-
-bool LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- bool down = true;
- gViewerInput.handleMouse(window, pos, mask, CLICK_MIDDLE, down);
-
- // Always handled as far as the OS is concerned.
- return true;
-}
-
-LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, LLWindowCallbacks::DragNDropAction action, std::string data)
-{
- LLWindowCallbacks::DragNDropResult result = LLWindowCallbacks::DND_NONE;
-
- const bool prim_media_dnd_enabled = gSavedSettings.getBOOL("PrimMediaDragNDrop");
- const bool slurl_dnd_enabled = gSavedSettings.getBOOL("SLURLDragNDrop");
-
- if ( prim_media_dnd_enabled || slurl_dnd_enabled )
- {
- switch(action)
- {
- // Much of the handling for these two cases is the same.
- case LLWindowCallbacks::DNDA_TRACK:
- case LLWindowCallbacks::DNDA_DROPPED:
- case LLWindowCallbacks::DNDA_START_TRACKING:
- {
- bool drop = (LLWindowCallbacks::DNDA_DROPPED == action);
-
- if (slurl_dnd_enabled)
- {
- LLSLURL dropped_slurl(data);
- if(dropped_slurl.isSpatial())
- {
- if (drop)
- {
- LLURLDispatcher::dispatch( dropped_slurl.getSLURLString(), LLCommandHandler::NAV_TYPE_CLICKED, NULL, true );
- return LLWindowCallbacks::DND_MOVE;
- }
- return LLWindowCallbacks::DND_COPY;
- }
- }
-
- if (prim_media_dnd_enabled)
- {
- LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY,
- true /* pick_transparent */,
- false /* pick_rigged */);
-
- S32 object_face = pick_info.mObjectFace;
- std::string url = data;
-
- LL_DEBUGS() << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << LL_ENDL;
-
- LLVOVolume *obj = dynamic_cast<LLVOVolume*>(static_cast<LLViewerObject*>(pick_info.getObject()));
-
- if (obj && !obj->getRegion()->getCapability("ObjectMedia").empty())
- {
- LLTextureEntry *te = obj->getTE(object_face);
-
- // can modify URL if we can modify the object or we have navigate permissions
- bool allow_modify_url = obj->permModify() || obj->hasMediaPermission( te->getMediaData(), LLVOVolume::MEDIA_PERM_INTERACT );
-
- if (te && allow_modify_url )
- {
- if (drop)
- {
- // object does NOT have media already
- if ( ! te->hasMedia() )
- {
- // we are allowed to modify the object
- if ( obj->permModify() )
- {
- // Create new media entry
- LLSD media_data;
- // XXX Should we really do Home URL too?
- media_data[LLMediaEntry::HOME_URL_KEY] = url;
- media_data[LLMediaEntry::CURRENT_URL_KEY] = url;
- media_data[LLMediaEntry::AUTO_PLAY_KEY] = true;
- obj->syncMediaData(object_face, media_data, true, true);
- // XXX This shouldn't be necessary, should it ?!?
- if (obj->getMediaImpl(object_face))
- obj->getMediaImpl(object_face)->navigateReload();
- obj->sendMediaDataUpdate();
-
- result = LLWindowCallbacks::DND_COPY;
- }
- }
- else
- // object HAS media already
- {
- // URL passes the whitelist
- if (te->getMediaData()->checkCandidateUrl( url ) )
- {
- // just navigate to the URL
- if (obj->getMediaImpl(object_face))
- {
- obj->getMediaImpl(object_face)->navigateTo(url);
- }
- else
- {
- // This is very strange. Navigation should
- // happen via the Impl, but we don't have one.
- // This sends it to the server, which /should/
- // trigger us getting it. Hopefully.
- LLSD media_data;
- media_data[LLMediaEntry::CURRENT_URL_KEY] = url;
- obj->syncMediaData(object_face, media_data, true, true);
- obj->sendMediaDataUpdate();
- }
- result = LLWindowCallbacks::DND_LINK;
-
- }
- }
- LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
- mDragHoveredObject = NULL;
-
- }
- else
- {
- // Check the whitelist, if there's media (otherwise just show it)
- if (te->getMediaData() == NULL || te->getMediaData()->checkCandidateUrl(url))
- {
- if ( obj != mDragHoveredObject)
- {
- // Highlight the dragged object
- LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
- mDragHoveredObject = obj;
- LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject);
- }
- result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK;
-
- }
- }
- }
- }
- }
- }
- break;
-
- case LLWindowCallbacks::DNDA_STOP_TRACKING:
- // The cleanup case below will make sure things are unhilighted if necessary.
- break;
- }
-
- if (prim_media_dnd_enabled &&
- result == LLWindowCallbacks::DND_NONE && !mDragHoveredObject.isNull())
- {
- LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
- mDragHoveredObject = NULL;
- }
- }
-
- return result;
-}
-
-bool LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- bool down = false;
- gViewerInput.handleMouse(window, pos, mask, CLICK_MIDDLE, down);
-
- // Always handled as far as the OS is concerned.
- return true;
-}
-
-bool LLViewerWindow::handleOtherMouse(LLWindow *window, LLCoordGL pos, MASK mask, S32 button, bool down)
-{
- switch (button)
- {
- case 4:
- gViewerInput.handleMouse(window, pos, mask, CLICK_BUTTON4, down);
- break;
- case 5:
- gViewerInput.handleMouse(window, pos, mask, CLICK_BUTTON5, down);
- break;
- default:
- break;
- }
-
- // Always handled as far as the OS is concerned.
- return true;
-}
-
-bool LLViewerWindow::handleOtherMouseDown(LLWindow *window, LLCoordGL pos, MASK mask, S32 button)
-{
- return handleOtherMouse(window, pos, mask, button, true);
-}
-
-bool LLViewerWindow::handleOtherMouseUp(LLWindow *window, LLCoordGL pos, MASK mask, S32 button)
-{
- return handleOtherMouse(window, pos, mask, button, false);
-}
-
-// WARNING: this is potentially called multiple times per frame
-void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- S32 x = pos.mX;
- S32 y = pos.mY;
-
- x = ll_round((F32)x / mDisplayScale.mV[VX]);
- y = ll_round((F32)y / mDisplayScale.mV[VY]);
-
- mMouseInWindow = true;
-
- // Save mouse point for access during idle() and display()
-
- LLCoordGL mouse_point(x, y);
-
- if (mouse_point != mCurrentMousePoint)
- {
- LLUI::getInstance()->resetMouseIdleTimer();
- }
-
- saveLastMouse(mouse_point);
-
- mWindow->showCursorFromMouseMove();
-
- if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME
- && !gDisconnected)
- {
- gAgent.clearAFK();
- }
-}
-
-void LLViewerWindow::handleMouseDragged(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- if (mMouseDownTimer.getStarted())
- {
- if (mMouseDownTimer.getElapsedTimeF32() > 0.1)
- {
- mAllowMouseDragging = true;
- mMouseDownTimer.stop();
- }
- }
- if(mAllowMouseDragging || !LLToolCamera::getInstance()->hasMouseCapture())
- {
- handleMouseMove(window, pos, mask);
- }
-}
-
-void LLViewerWindow::handleMouseLeave(LLWindow *window)
-{
- // Note: we won't get this if we have captured the mouse.
- llassert( gFocusMgr.getMouseCapture() == NULL );
- mMouseInWindow = false;
- LLToolTipMgr::instance().blockToolTips();
-}
-
-bool LLViewerWindow::handleCloseRequest(LLWindow *window)
-{
- // User has indicated they want to close, but we may need to ask
- // about modified documents.
- LLAppViewer::instance()->userQuit();
- // Don't quit immediately
- return false;
-}
-
-void LLViewerWindow::handleQuit(LLWindow *window)
-{
- if (gNonInteractive)
- {
- LLAppViewer::instance()->requestQuit();
- }
- else
- {
- LL_INFOS() << "Window forced quit" << LL_ENDL;
- LLAppViewer::instance()->forceQuit();
- }
-}
-
-void LLViewerWindow::handleResize(LLWindow *window, S32 width, S32 height)
-{
- reshape(width, height);
- mResDirty = true;
-}
-
-// The top-level window has gained focus (e.g. via ALT-TAB)
-void LLViewerWindow::handleFocus(LLWindow *window)
-{
- gFocusMgr.setAppHasFocus(true);
- LLModalDialog::onAppFocusGained();
-
- gAgent.onAppFocusGained();
- LLToolMgr::getInstance()->onAppFocusGained();
-
- // See if we're coming in with modifier keys held down
- if (gKeyboard)
- {
- gKeyboard->resetMaskKeys();
- }
-
- // resume foreground running timer
- // since we artifically limit framerate when not frontmost
- gForegroundTime.unpause();
-}
-
-// The top-level window has lost focus (e.g. via ALT-TAB)
-void LLViewerWindow::handleFocusLost(LLWindow *window)
-{
- gFocusMgr.setAppHasFocus(false);
- //LLModalDialog::onAppFocusLost();
- LLToolMgr::getInstance()->onAppFocusLost();
- gFocusMgr.setMouseCapture( NULL );
-
- if (gMenuBarView)
- {
- // stop ALT-key access to menu
- gMenuBarView->resetMenuTrigger();
- }
-
- // restore mouse cursor
- showCursor();
- getWindow()->setMouseClipping(false);
-
- // If losing focus while keys are down, handle them as
- // an 'up' to correctly release states, then reset states
- if (gKeyboard)
- {
- gKeyboard->resetKeyDownAndHandle();
- gKeyboard->resetKeys();
- }
-
- // pause timer that tracks total foreground running time
- gForegroundTime.pause();
-}
-
-
-bool LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, bool repeated)
-{
- // Handle non-consuming global keybindings, like voice
- // Never affects event processing.
- gViewerInput.handleGlobalBindsKeyDown(key, mask);
-
- if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME)
- {
- gAgent.clearAFK();
- }
-
- // *NOTE: We want to interpret KEY_RETURN later when it arrives as
- // a Unicode char, not as a keydown. Otherwise when client frame
- // rate is really low, hitting return sends your chat text before
- // it's all entered/processed.
- if (key == KEY_RETURN && mask == MASK_NONE)
- {
- // RIDER: although, at times some of the controlls (in particular the CEF viewer
- // would like to know about the KEYDOWN for an enter key... so ask and pass it along.
- LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
- if (keyboard_focus && !keyboard_focus->wantsReturnKey())
- return false;
- }
-
- // remaps, handles ignored cases and returns back to viewer window.
- return gViewerInput.handleKey(key, mask, repeated);
-}
-
-bool LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask)
-{
- // Handle non-consuming global keybindings, like voice
- // Never affects event processing.
- gViewerInput.handleGlobalBindsKeyUp(key, mask);
-
- // Let the inspect tool code check for ALT key to set LLToolSelectRect active instead LLToolCamera
- LLToolCompInspect * tool_inspectp = LLToolCompInspect::getInstance();
- if (LLToolMgr::getInstance()->getCurrentTool() == tool_inspectp)
- {
- tool_inspectp->keyUp(key, mask);
- }
-
- return gViewerInput.handleKeyUp(key, mask);
-}
-
-void LLViewerWindow::handleScanKey(KEY key, bool key_down, bool key_up, bool key_level)
-{
- LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
- gViewerInput.scanKey(key, key_down, key_up, key_level);
- return; // Be clear this function returns nothing
-}
-
-
-
-
-bool LLViewerWindow::handleActivate(LLWindow *window, bool activated)
-{
- if (activated)
- {
- mActive = true;
- send_agent_resume();
- gAgent.clearAFK();
-
- // Unmute audio
- audio_update_volume();
- }
- else
- {
- mActive = false;
-
- // if the user has chosen to go Away automatically after some time, then go Away when minimizing
- if (gSavedSettings.getS32("AFKTimeout"))
- {
- gAgent.setAFK();
- }
-
- // SL-53351: Make sure we're not in mouselook when minimised, to prevent control issues
- if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
- {
- gAgentCamera.changeCameraToDefault();
- }
-
- send_agent_pause();
-
- // Mute audio
- audio_update_volume();
- }
- return true;
-}
-
-bool LLViewerWindow::handleActivateApp(LLWindow *window, bool activating)
-{
- //if (!activating) gAgentCamera.changeCameraToDefault();
-
- LLViewerJoystick::getInstance()->setNeedsReset(true);
- return false;
-}
-
-
-void LLViewerWindow::handleMenuSelect(LLWindow *window, S32 menu_item)
-{
-}
-
-
-bool LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height)
-{
- // *TODO: Enable similar information output for other platforms? DK 2011-02-18
-#if LL_WINDOWS
- if (gHeadlessClient)
- {
- HWND window_handle = (HWND)window->getPlatformWindow();
- PAINTSTRUCT ps;
- HDC hdc;
-
- RECT wnd_rect;
- wnd_rect.left = 0;
- wnd_rect.top = 0;
- wnd_rect.bottom = 200;
- wnd_rect.right = 500;
-
- hdc = BeginPaint(window_handle, &ps);
- //SetBKColor(hdc, RGB(255, 255, 255));
- FillRect(hdc, &wnd_rect, CreateSolidBrush(RGB(255, 255, 255)));
-
- std::string temp_str;
- LLTrace::Recording& recording = LLViewerStats::instance().getRecording();
- temp_str = llformat( "FPS %3.1f Phy FPS %2.1f Time Dil %1.3f", /* Flawfinder: ignore */
- recording.getPerSec(LLStatViewer::FPS), //mFPSStat.getMeanPerSec(),
- recording.getLastValue(LLStatViewer::SIM_PHYSICS_FPS),
- recording.getLastValue(LLStatViewer::SIM_TIME_DILATION));
- S32 len = temp_str.length();
- TextOutA(hdc, 0, 0, temp_str.c_str(), len);
-
-
- LLVector3d pos_global = gAgent.getPositionGlobal();
- temp_str = llformat( "Avatar pos %6.1lf %6.1lf %6.1lf", pos_global.mdV[0], pos_global.mdV[1], pos_global.mdV[2]);
- len = temp_str.length();
- TextOutA(hdc, 0, 25, temp_str.c_str(), len);
-
- TextOutA(hdc, 0, 50, "Set \"HeadlessClient FALSE\" in settings.ini file to reenable", 61);
- EndPaint(window_handle, &ps);
- return true;
- }
-#endif
- return false;
-}
-
-
-void LLViewerWindow::handleScrollWheel(LLWindow *window, S32 clicks)
-{
- handleScrollWheel( clicks );
-}
-
-void LLViewerWindow::handleScrollHWheel(LLWindow *window, S32 clicks)
-{
- handleScrollHWheel(clicks);
-}
-
-void LLViewerWindow::handleWindowBlock(LLWindow *window)
-{
- send_agent_pause();
-}
-
-void LLViewerWindow::handleWindowUnblock(LLWindow *window)
-{
- send_agent_resume();
-}
-
-void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data)
-{
- const S32 SLURL_MESSAGE_TYPE = 0;
- switch (data_type)
- {
- case SLURL_MESSAGE_TYPE:
- // received URL
- std::string url = (const char*)data;
- LLMediaCtrl* web = NULL;
- const bool trusted_browser = false;
- // don't treat slapps coming from external browsers as "clicks" as this would bypass throttling
- if (LLURLDispatcher::dispatch(url, LLCommandHandler::NAV_TYPE_EXTERNAL, web, trusted_browser))
- {
- // bring window to foreground, as it has just been "launched" from a URL
- mWindow->bringToFront();
- }
- break;
- }
-}
-
-bool LLViewerWindow::handleTimerEvent(LLWindow *window)
-{
- //TODO: just call this every frame from gatherInput instead of using a convoluted 30fps timer callback
- if (LLViewerJoystick::getInstance()->getOverrideCamera())
- {
- LLViewerJoystick::getInstance()->updateStatus();
- return true;
- }
- return false;
-}
-
-bool LLViewerWindow::handleDeviceChange(LLWindow *window)
-{
- // give a chance to use a joystick after startup (hot-plugging)
- if (!LLViewerJoystick::getInstance()->isJoystickInitialized() )
- {
- LLViewerJoystick::getInstance()->init(true);
- return true;
- }
- return false;
-}
-
-bool LLViewerWindow::handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height)
-{
- if (ui_scale_factor >= MIN_UI_SCALE && ui_scale_factor <= MAX_UI_SCALE)
- {
- LLViewerWindow::reshape(window_width, window_height);
- mResDirty = true;
- return true;
- }
- else
- {
- LL_WARNS() << "DPI change caused UI scale to go out of bounds: " << ui_scale_factor << LL_ENDL;
- return false;
- }
-}
-
-bool LLViewerWindow::handleWindowDidChangeScreen(LLWindow *window)
-{
- LLCoordScreen window_rect;
- mWindow->getSize(&window_rect);
- reshape(window_rect.mX, window_rect.mY);
- return true;
-}
-
-void LLViewerWindow::handlePingWatchdog(LLWindow *window, const char * msg)
-{
- LLAppViewer::instance()->pingMainloopTimeout(msg);
-}
-
-
-void LLViewerWindow::handleResumeWatchdog(LLWindow *window)
-{
- LLAppViewer::instance()->resumeMainloopTimeout();
-}
-
-void LLViewerWindow::handlePauseWatchdog(LLWindow *window)
-{
- LLAppViewer::instance()->pauseMainloopTimeout();
-}
-
-//virtual
-std::string LLViewerWindow::translateString(const char* tag)
-{
- return LLTrans::getString( std::string(tag) );
-}
-
-//virtual
-std::string LLViewerWindow::translateString(const char* tag,
- const std::map<std::string, std::string>& args)
-{
- // LLTrans uses a special subclass of std::string for format maps,
- // but we must use std::map<> in these callbacks, otherwise we create
- // a dependency between LLWindow and LLFormatMapString. So copy the data.
- LLStringUtil::format_map_t args_copy;
- std::map<std::string,std::string>::const_iterator it = args.begin();
- for ( ; it != args.end(); ++it)
- {
- args_copy[it->first] = it->second;
- }
- return LLTrans::getString( std::string(tag), args_copy);
-}
-
-//
-// Classes
-//
-LLViewerWindow::LLViewerWindow(const Params& p)
-: mWindow(NULL),
- mActive(true),
- mUIVisible(true),
- mWindowRectRaw(0, p.height, p.width, 0),
- mWindowRectScaled(0, p.height, p.width, 0),
- mWorldViewRectRaw(0, p.height, p.width, 0),
- mLeftMouseDown(false),
- mMiddleMouseDown(false),
- mRightMouseDown(false),
- mMouseInWindow( false ),
- mAllowMouseDragging(true),
- mMouseDownTimer(),
- mLastMask( MASK_NONE ),
- mToolStored( NULL ),
- mHideCursorPermanent( false ),
- mCursorHidden(false),
- mIgnoreActivate( false ),
- mResDirty(false),
- mStatesDirty(false),
- mCurrResolutionIndex(0),
- mProgressView(NULL)
-{
- // gKeyboard is still NULL, so it doesn't do LLWindowListener any good to
- // pass its value right now. Instead, pass it a nullary function that
- // will, when we later need it, return the value of gKeyboard.
- // boost::lambda::var() constructs such a functor on the fly.
- mWindowListener.reset(new LLWindowListener(this, boost::lambda::var(gKeyboard)));
- mViewerWindowListener.reset(new LLViewerWindowListener(this));
-
- mSystemChannel.reset(new LLNotificationChannel("System", "Visible", LLNotificationFilters::includeEverything));
- mCommunicationChannel.reset(new LLCommunicationChannel("Communication", "Visible"));
- mAlertsChannel.reset(new LLNotificationsUI::LLViewerAlertHandler("VW_alerts", "alert"));
- mModalAlertsChannel.reset(new LLNotificationsUI::LLViewerAlertHandler("VW_alertmodal", "alertmodal"));
-
- bool ignore = gSavedSettings.getBOOL("IgnoreAllNotifications");
- LLNotifications::instance().setIgnoreAllNotifications(ignore);
- if (ignore)
- {
- LL_INFOS() << "NOTE: ALL NOTIFICATIONS THAT OCCUR WILL GET ADDED TO IGNORE LIST FOR LATER RUNS." << LL_ENDL;
- }
-
-
- /*
- LLWindowCallbacks* callbacks,
- const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags,
- bool fullscreen,
- bool clearBg,
- bool disable_vsync,
- bool ignore_pixel_depth,
- U32 fsaa_samples)
- */
- // create window
-
- U32 max_core_count = gSavedSettings.getU32("EmulateCoreCount");
- F32 max_gl_version = gSavedSettings.getF32("RenderMaxOpenGLVersion");
-
- LLControlVariable* vram_control = gSavedSettings.getControl("RenderMaxVRAMBudget");
- U32 max_vram = vram_control->getValue().asInteger();
- mMaxVRAMControlConnection = vram_control->getSignal()->connect(
- [this](LLControlVariable* control, const LLSD& new_val, const LLSD& old_val)
- {
- if (mWindow) mWindow->setMaxVRAMMegabytes(new_val.asInteger());
- });
-
-
- mWindow = LLWindowManager::createWindow(this,
- p.title, p.name, p.x, p.y, p.width, p.height, 0,
- p.fullscreen,
- gHeadlessClient,
- gSavedSettings.getBOOL("RenderVSyncEnable"),
- !gHeadlessClient,
- p.ignore_pixel_depth,
- 0,
- max_core_count,
- max_vram,
- max_gl_version); //don't use window level anti-aliasing
-
- if (NULL == mWindow)
- {
- LLSplashScreen::update(LLTrans::getString("StartupRequireDriverUpdate"));
-
- LL_WARNS("Window") << "Failed to create window, to be shutting Down, be sure your graphics driver is updated." << LL_ENDL ;
-
- ms_sleep(5000) ; //wait for 5 seconds.
-
- LLSplashScreen::update(LLTrans::getString("ShuttingDown"));
-#if LL_LINUX
- LL_WARNS() << "Unable to create window, be sure screen is set at 32-bit color and your graphics driver is configured correctly. See README-linux.txt for further information."
- << LL_ENDL;
-#else
- LL_WARNS("Window") << "Unable to create window, be sure screen is set at 32-bit color in Control Panels->Display->Settings"
- << LL_ENDL;
-#endif
- LLAppViewer::instance()->fastQuit(1);
- }
- else if (!LLViewerShaderMgr::sInitialized)
- {
- //immediately initialize shaders
- LLViewerShaderMgr::sInitialized = true;
- LLViewerShaderMgr::instance()->setShaders();
- }
-
- if (!LLAppViewer::instance()->restoreErrorTrap())
- {
- // this always happens, so downgrading it to INFO
- LL_INFOS("Window") << " Someone took over my signal/exception handler (post createWindow; normal)" << LL_ENDL;
- }
-
- const bool do_not_enforce = false;
- mWindow->setMinSize(p.min_width, p.min_height, do_not_enforce); // root view not set
- LLCoordScreen scr;
- mWindow->getSize(&scr);
-
- // Reset UI scale factor on first run if OS's display scaling is not 100%
- if (gSavedSettings.getBOOL("ResetUIScaleOnFirstRun"))
- {
- if (mWindow->getSystemUISize() != 1.f)
- {
- gSavedSettings.setF32("UIScaleFactor", 1.f);
- }
- gSavedSettings.setBOOL("ResetUIScaleOnFirstRun", false);
- }
-
- // Get the real window rect the window was created with (since there are various OS-dependent reasons why
- // the size of a window or fullscreen context may have been adjusted slightly...)
- F32 ui_scale_factor = llclamp(gSavedSettings.getF32("UIScaleFactor") * mWindow->getSystemUISize(), MIN_UI_SCALE, MAX_UI_SCALE);
-
- mDisplayScale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
- mDisplayScale *= ui_scale_factor;
- LLUI::setScaleFactor(mDisplayScale);
-
- {
- LLCoordWindow size;
- mWindow->getSize(&size);
- mWindowRectRaw.set(0, size.mY, size.mX, 0);
- mWindowRectScaled.set(0, ll_round((F32)size.mY / mDisplayScale.mV[VY]), ll_round((F32)size.mX / mDisplayScale.mV[VX]), 0);
- }
-
- LLFontManager::initClass();
- // Init font system, load default fonts and generate basic glyphs
- // currently it takes aprox. 0.5 sec and we would load these fonts anyway
- // before login screen.
- LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"),
- mDisplayScale.mV[VX],
- mDisplayScale.mV[VY],
- gDirUtilp->getAppRODataDir());
-
- //
- // We want to set this stuff up BEFORE we initialize the pipeline, so we can turn off
- // stuff like AGP if we think that it'll crash the viewer.
- //
- LL_DEBUGS("Window") << "Loading feature tables." << LL_ENDL;
-
- // Initialize OpenGL Renderer
- LLVertexBuffer::initClass(mWindow);
- LL_INFOS("RenderInit") << "LLVertexBuffer initialization done." << LL_ENDL ;
- if (!gGL.init(true))
- {
- LLError::LLUserWarningMsg::show(LLTrans::getString("MBVideoDrvErr"));
- LL_ERRS() << "gGL not initialized" << LL_ENDL;
- }
-
- if (LLFeatureManager::getInstance()->isSafe()
- || (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion())
- || (gSavedSettings.getString("LastGPUString") != LLFeatureManager::getInstance()->getGPUString())
- || (gSavedSettings.getBOOL("ProbeHardwareOnStartup")))
- {
- LLFeatureManager::getInstance()->applyRecommendedSettings();
- gSavedSettings.setBOOL("ProbeHardwareOnStartup", false);
- }
-
- // If we crashed while initializng GL stuff last time, disable certain features
- if (gSavedSettings.getBOOL("RenderInitError"))
- {
- mInitAlert = "DisplaySettingsNoShaders";
- LLFeatureManager::getInstance()->setGraphicsLevel(0, false);
- gSavedSettings.setU32("RenderQualityPerformance", 0);
- }
-
- // Init the image list. Must happen after GL is initialized and before the images that
- // LLViewerWindow needs are requested, as well as before LLViewerMedia starts updating images.
- LLImageGL::initClass(mWindow, LLViewerTexture::MAX_GL_IMAGE_CATEGORY, false, gSavedSettings.getBOOL("RenderGLMultiThreadedTextures"), gSavedSettings.getBOOL("RenderGLMultiThreadedMedia"));
- gTextureList.init();
- LLViewerTextureManager::init() ;
- gBumpImageList.init();
-
- // Create container for all sub-views
- LLView::Params rvp;
- rvp.name("root");
- rvp.rect(mWindowRectScaled);
- rvp.mouse_opaque(false);
- rvp.follows.flags(FOLLOWS_NONE);
- mRootView = LLUICtrlFactory::create<LLRootView>(rvp);
- LLUI::getInstance()->setRootView(mRootView);
-
- // Make avatar head look forward at start
- mCurrentMousePoint.mX = getWindowWidthScaled() / 2;
- mCurrentMousePoint.mY = getWindowHeightScaled() / 2;
-
- gShowOverlayTitle = gSavedSettings.getBOOL("ShowOverlayTitle");
- mOverlayTitle = gSavedSettings.getString("OverlayTitle");
- // Can't have spaces in settings.ini strings, so use underscores instead and convert them.
- LLStringUtil::replaceChar(mOverlayTitle, '_', ' ');
-
- mDebugText = new LLDebugText(this);
-
- mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale);
-}
-
-std::string LLViewerWindow::getLastSnapshotDir()
-{
- return sSnapshotDir;
-}
-
-void LLViewerWindow::initGLDefaults()
-{
- // RN: Need this for translation and stretch manip.
- gBox.prerender();
-}
-
-struct MainPanel : public LLPanel
-{
-};
-
-void LLViewerWindow::initBase()
-{
- S32 height = getWindowHeightScaled();
- S32 width = getWindowWidthScaled();
-
- LLRect full_window(0, height, width, 0);
-
- ////////////////////
- //
- // Set the gamma
- //
-
- F32 gamma = gSavedSettings.getF32("RenderGamma");
- if (gamma != 0.0f)
- {
- getWindow()->setGamma(gamma);
- }
-
- // Create global views
-
- // Login screen and main_view.xml need edit menus for preferences and browser
- LL_DEBUGS("AppInit") << "initializing edit menu" << LL_ENDL;
- initialize_edit_menu();
-
- LLFontGL::loadCommonFonts();
-
- // Create the floater view at the start so that other views can add children to it.
- // (But wait to add it as a child of the root view so that it will be in front of the
- // other views.)
- MainPanel* main_view = new MainPanel();
- if (!main_view->buildFromFile("main_view.xml"))
- {
- LL_ERRS() << "Failed to initialize viewer: Viewer couldn't process file main_view.xml, "
- << "if this problem happens again, please validate your installation." << LL_ENDL;
- }
- main_view->setShape(full_window);
- getRootView()->addChild(main_view);
-
- // placeholder widget that controls where "world" is rendered
- mWorldViewPlaceholder = main_view->getChildView("world_view_rect")->getHandle();
- mPopupView = main_view->getChild<LLPopupView>("popup_holder");
- mHintHolder = main_view->getChild<LLView>("hint_holder")->getHandle();
- mLoginPanelHolder = main_view->getChild<LLView>("login_panel_holder")->getHandle();
-
- // Create the toolbar view
- // Get a pointer to the toolbar view holder
- LLPanel* panel_holder = main_view->getChild<LLPanel>("toolbar_view_holder");
- // Load the toolbar view from file
- gToolBarView = LLUICtrlFactory::getInstance()->createFromFile<LLToolBarView>("panel_toolbar_view.xml", panel_holder, LLDefaultChildRegistry::instance());
- if (!gToolBarView)
- {
- LL_ERRS() << "Failed to initialize viewer: Viewer couldn't process file panel_toolbar_view.xml, "
- << "if this problem happens again, please validate your installation." << LL_ENDL;
- }
- gToolBarView->setShape(panel_holder->getLocalRect());
- // Hide the toolbars for the moment: we'll make them visible after logging in world (see LLViewerWindow::initWorldUI())
- gToolBarView->setVisible(false);
-
- // Constrain floaters to inside the menu and status bar regions.
- gFloaterView = main_view->getChild<LLFloaterView>("Floater View");
- for (S32 i = 0; i < LLToolBarEnums::TOOLBAR_COUNT; ++i)
- {
- LLToolBar * toolbarp = gToolBarView->getToolbar((LLToolBarEnums::EToolBarLocation)i);
- if (toolbarp)
- {
- toolbarp->getCenterLayoutPanel()->setReshapeCallback(boost::bind(&LLFloaterView::setToolbarRect, gFloaterView, _1, _2));
- }
- }
- gFloaterView->setFloaterSnapView(main_view->getChild<LLView>("floater_snap_region")->getHandle());
- gSnapshotFloaterView = main_view->getChild<LLSnapshotFloaterView>("Snapshot Floater View");
-
- // Console
- llassert( !gConsole );
- LLConsole::Params cp;
- cp.name("console");
- cp.max_lines(gSavedSettings.getS32("ConsoleBufferSize"));
- cp.rect(getChatConsoleRect());
- cp.persist_time(gSavedSettings.getF32("ChatPersistTime"));
- cp.font_size_index(gSavedSettings.getS32("ChatFontSize"));
- cp.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
- gConsole = LLUICtrlFactory::create<LLConsole>(cp);
- getRootView()->addChild(gConsole);
-
- // optionally forward warnings to chat console/chat floater
- // for qa runs and dev builds
-#if !LL_RELEASE_FOR_DOWNLOAD
- RecordToChatConsole::getInstance()->startRecorder();
-#else
- if(gSavedSettings.getBOOL("QAMode"))
- {
- RecordToChatConsole::getInstance()->startRecorder();
- }
-#endif
-
- gDebugView = getRootView()->getChild<LLDebugView>("DebugView");
- gDebugView->init();
- gToolTipView = getRootView()->getChild<LLToolTipView>("tooltip view");
-
- // Initialize do not disturb response message when logged in
- LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLFloaterPreference::initDoNotDisturbResponse));
-
- // Add the progress bar view (startup view), which overrides everything
- mProgressView = getRootView()->findChild<LLProgressView>("progress_view");
- setShowProgress(false);
- setProgressCancelButtonVisible(false);
-
- gMenuHolder = getRootView()->getChild<LLViewerMenuHolderGL>("Menu Holder");
- LLMenuGL::sMenuContainer = gMenuHolder;
-}
-
-void LLViewerWindow::initWorldUI()
-{
- if (gNonInteractive)
- {
- gIMMgr = LLIMMgr::getInstance();
- LLNavigationBar::getInstance();
- gFloaterView->pushVisibleAll(false);
- return;
- }
-
- S32 height = mRootView->getRect().getHeight();
- S32 width = mRootView->getRect().getWidth();
- LLRect full_window(0, height, width, 0);
-
-
- gIMMgr = LLIMMgr::getInstance();
-
- //getRootView()->sendChildToFront(gFloaterView);
- //getRootView()->sendChildToFront(gSnapshotFloaterView);
-
- if (!gNonInteractive)
- {
- LLPanel* chiclet_container = getRootView()->getChild<LLPanel>("chiclet_container");
- LLChicletBar* chiclet_bar = LLChicletBar::getInstance();
- chiclet_bar->setShape(chiclet_container->getLocalRect());
- chiclet_bar->setFollowsAll();
- chiclet_container->addChild(chiclet_bar);
- chiclet_container->setVisible(true);
- }
-
- LLRect morph_view_rect = full_window;
- morph_view_rect.stretch( -STATUS_BAR_HEIGHT );
- morph_view_rect.mTop = full_window.mTop - 32;
- LLMorphView::Params mvp;
- mvp.name("MorphView");
- mvp.rect(morph_view_rect);
- mvp.visible(false);
- gMorphView = LLUICtrlFactory::create<LLMorphView>(mvp);
- getRootView()->addChild(gMorphView);
-
- LLWorldMapView::initClass();
-
- // Force gFloaterWorldMap to initialize
- LLFloaterReg::getInstance("world_map");
-
- // Force gFloaterTools to initialize
- LLFloaterReg::getInstance("build");
-
- LLNavigationBar* navbar = LLNavigationBar::getInstance();
- if (!gStatusBar)
- {
- // Status bar
- LLPanel* status_bar_container = getRootView()->getChild<LLPanel>("status_bar_container");
- gStatusBar = new LLStatusBar(status_bar_container->getLocalRect());
- gStatusBar->setFollows(FOLLOWS_LEFT | FOLLOWS_TOP | FOLLOWS_RIGHT);
- gStatusBar->setShape(status_bar_container->getLocalRect());
- // sync bg color with menu bar
- gStatusBar->setBackgroundColor(gMenuBarView->getBackgroundColor().get());
- // add InBack so that gStatusBar won't be drawn over menu
- status_bar_container->addChildInBack(gStatusBar, 2/*tab order, after menu*/);
- status_bar_container->setVisible(true);
-
- // Navigation bar
- LLView* nav_bar_container = getRootView()->getChild<LLView>("nav_bar_container");
-
- navbar->setShape(nav_bar_container->getLocalRect());
- navbar->setBackgroundColor(gMenuBarView->getBackgroundColor().get());
- nav_bar_container->addChild(navbar);
- nav_bar_container->setVisible(true);
- }
- else
- {
- LLPanel* status_bar_container = getRootView()->getChild<LLPanel>("status_bar_container");
- LLView* nav_bar_container = getRootView()->getChild<LLView>("nav_bar_container");
- status_bar_container->setVisible(true);
- nav_bar_container->setVisible(true);
- }
-
- if (!gSavedSettings.getBOOL("ShowNavbarNavigationPanel"))
- {
- navbar->setVisible(false);
- }
- else
- {
- reshapeStatusBarContainer();
- }
-
-
- // Top Info bar
- LLPanel* topinfo_bar_container = getRootView()->getChild<LLPanel>("topinfo_bar_container");
- LLPanelTopInfoBar* topinfo_bar = LLPanelTopInfoBar::getInstance();
-
- topinfo_bar->setShape(topinfo_bar_container->getLocalRect());
-
- topinfo_bar_container->addChild(topinfo_bar);
- topinfo_bar_container->setVisible(true);
-
- if (!gSavedSettings.getBOOL("ShowMiniLocationPanel"))
- {
- topinfo_bar->setVisible(false);
- }
-
- if ( gHUDView == NULL )
- {
- LLRect hud_rect = full_window;
- hud_rect.mBottom += 50;
- if (gMenuBarView && gMenuBarView->isInVisibleChain())
- {
- hud_rect.mTop -= gMenuBarView->getRect().getHeight();
- }
- gHUDView = new LLHUDView(hud_rect);
- getRootView()->addChild(gHUDView);
- getRootView()->sendChildToBack(gHUDView);
- }
-
- LLPanel* panel_ssf_container = getRootView()->getChild<LLPanel>("state_management_buttons_container");
-
- LLPanelStandStopFlying* panel_stand_stop_flying = LLPanelStandStopFlying::getInstance();
- panel_ssf_container->addChild(panel_stand_stop_flying);
-
- LLPanelHideBeacon* panel_hide_beacon = LLPanelHideBeacon::getInstance();
- panel_ssf_container->addChild(panel_hide_beacon);
-
- panel_ssf_container->setVisible(true);
-
- LLMenuOptionPathfindingRebakeNavmesh::getInstance()->initialize();
-
- // Load and make the toolbars visible
- // Note: we need to load the toolbars only *after* the user is logged in and IW
- if (gToolBarView)
- {
- gToolBarView->loadToolbars();
- gToolBarView->setVisible(true);
- }
-
- if (!gNonInteractive)
- {
- LLMediaCtrl* destinations = LLFloaterReg::getInstance("destinations")->getChild<LLMediaCtrl>("destination_guide_contents");
- if (destinations)
- {
- destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
- std::string url = gSavedSettings.getString("DestinationGuideURL");
- url = LLWeb::expandURLSubstitutions(url, LLSD());
- destinations->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
- }
- LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents");
- if (avatar_picker)
- {
- avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
- std::string url = gSavedSettings.getString("AvatarPickerURL");
- url = LLWeb::expandURLSubstitutions(url, LLSD());
- avatar_picker->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
- }
- }
-}
-
-// Destroy the UI
-void LLViewerWindow::shutdownViews()
-{
- // clean up warning logger
- RecordToChatConsole::getInstance()->stopRecorder();
- LL_INFOS() << "Warning logger is cleaned." << LL_ENDL ;
-
- gFocusMgr.unlockFocus();
- gFocusMgr.setMouseCapture(NULL);
- gFocusMgr.setKeyboardFocus(NULL);
- gFocusMgr.setTopCtrl(NULL);
- if (mWindow)
- {
- mWindow->allowLanguageTextInput(NULL, false);
- }
-
- delete mDebugText;
- mDebugText = NULL;
-
- LL_INFOS() << "DebugText deleted." << LL_ENDL ;
-
- // Cleanup global views
- if (gMorphView)
- {
- gMorphView->setVisible(false);
- }
- LL_INFOS() << "Global views cleaned." << LL_ENDL ;
-
- LLNotificationsUI::LLToast::cleanupToasts();
- LL_INFOS() << "Leftover toast cleaned up." << LL_ENDL;
-
- // DEV-40930: Clear sModalStack. Otherwise, any LLModalDialog left open
- // will crump with LL_ERRS.
- LLModalDialog::shutdownModals();
- LL_INFOS() << "LLModalDialog shut down." << LL_ENDL;
-
- // destroy the nav bar, not currently part of gViewerWindow
- // *TODO: Make LLNavigationBar part of gViewerWindow
- LLNavigationBar::deleteSingleton();
- LL_INFOS() << "LLNavigationBar destroyed." << LL_ENDL ;
-
- // destroy menus after instantiating navbar above, as it needs
- // access to gMenuHolder
- cleanup_menus();
- LL_INFOS() << "menus destroyed." << LL_ENDL ;
-
- view_listener_t::cleanup();
- LL_INFOS() << "view listeners destroyed." << LL_ENDL ;
-
- // Clean up pointers that are going to be invalid. (todo: check sMenuContainer)
- mProgressView = NULL;
- mPopupView = NULL;
-
- // Delete all child views.
- delete mRootView;
- mRootView = NULL;
- LL_INFOS() << "RootView deleted." << LL_ENDL ;
-
- LLMenuOptionPathfindingRebakeNavmesh::getInstance()->quit();
-
- // Automatically deleted as children of mRootView. Fix the globals.
- gStatusBar = NULL;
- gIMMgr = NULL;
- gToolTipView = NULL;
-
- gToolBarView = NULL;
- gFloaterView = NULL;
- gMorphView = NULL;
-
- gHUDView = NULL;
-}
-
-void LLViewerWindow::shutdownGL()
-{
- //--------------------------------------------------------
- // Shutdown GL cleanly. Order is very important here.
- //--------------------------------------------------------
- LLFontGL::destroyDefaultFonts();
- SUBSYSTEM_CLEANUP(LLFontManager);
- stop_glerror();
-
- gSky.cleanup();
- stop_glerror();
-
- LL_INFOS() << "Cleaning up pipeline" << LL_ENDL;
- gPipeline.cleanup();
- stop_glerror();
-
- //MUST clean up pipeline before cleaning up wearables
- LL_INFOS() << "Cleaning up wearables" << LL_ENDL;
- LLWearableList::instance().cleanup() ;
-
- gTextureList.shutdown();
- stop_glerror();
-
- gBumpImageList.shutdown();
- stop_glerror();
-
- LLWorldMapView::cleanupTextures();
-
- LLViewerTextureManager::cleanup() ;
- SUBSYSTEM_CLEANUP(LLImageGL) ;
-
- LL_INFOS() << "All textures and llimagegl images are destroyed!" << LL_ENDL ;
-
- LL_INFOS() << "Cleaning up select manager" << LL_ENDL;
- LLSelectMgr::getInstance()->cleanup();
-
- LL_INFOS() << "Stopping GL during shutdown" << LL_ENDL;
- stopGL(false);
- stop_glerror();
-
- gGL.shutdown();
-
- SUBSYSTEM_CLEANUP(LLVertexBuffer);
-
- LL_INFOS() << "LLVertexBuffer cleaned." << LL_ENDL ;
-}
-
-// shutdownViews() and shutdownGL() need to be called first
-LLViewerWindow::~LLViewerWindow()
-{
- LL_INFOS() << "Destroying Window" << LL_ENDL;
- destroyWindow();
-
- delete mDebugText;
- mDebugText = NULL;
-
- if (LLViewerShaderMgr::sInitialized)
- {
- LLViewerShaderMgr::releaseInstance();
- LLViewerShaderMgr::sInitialized = false;
- }
-
- mMaxVRAMControlConnection.disconnect();
-}
-
-
-void LLViewerWindow::setCursor( ECursorType c )
-{
- mWindow->setCursor( c );
-}
-
-void LLViewerWindow::showCursor()
-{
- mWindow->showCursor();
-
- mCursorHidden = false;
-}
-
-void LLViewerWindow::hideCursor()
-{
- // And hide the cursor
- mWindow->hideCursor();
-
- mCursorHidden = true;
-}
-
-void LLViewerWindow::sendShapeToSim()
-{
- LLMessageSystem* msg = gMessageSystem;
- if(!msg) return;
- msg->newMessageFast(_PREHASH_AgentHeightWidth);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addU32Fast(_PREHASH_CircuitCode, gMessageSystem->mOurCircuitCode);
- msg->nextBlockFast(_PREHASH_HeightWidthBlock);
- msg->addU32Fast(_PREHASH_GenCounter, 0);
- U16 height16 = (U16) mWorldViewRectRaw.getHeight();
- U16 width16 = (U16) mWorldViewRectRaw.getWidth();
- msg->addU16Fast(_PREHASH_Height, height16);
- msg->addU16Fast(_PREHASH_Width, width16);
- gAgent.sendReliableMessage();
-}
-
-// Must be called after window is created to set up agent
-// camera variables and UI variables.
-void LLViewerWindow::reshape(S32 width, S32 height)
-{
- // Destroying the window at quit time generates spurious
- // reshape messages. We don't care about these, and we
- // don't want to send messages because the message system
- // may have been destructed.
- if (!LLApp::isExiting())
- {
- gWindowResized = true;
-
- // update our window rectangle
- mWindowRectRaw.mRight = mWindowRectRaw.mLeft + width;
- mWindowRectRaw.mTop = mWindowRectRaw.mBottom + height;
-
- //glViewport(0, 0, width, height );
-
- LLViewerCamera * camera = LLViewerCamera::getInstance(); // simpleton, might not exist
- if (height > 0 && camera)
- {
- camera->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
- camera->setAspect( getWorldViewAspectRatio() );
- }
-
- calcDisplayScale();
-
- bool display_scale_changed = mDisplayScale != LLUI::getScaleFactor();
- LLUI::setScaleFactor(mDisplayScale);
-
- // update our window rectangle
- mWindowRectScaled.mRight = mWindowRectScaled.mLeft + ll_round((F32)width / mDisplayScale.mV[VX]);
- mWindowRectScaled.mTop = mWindowRectScaled.mBottom + ll_round((F32)height / mDisplayScale.mV[VY]);
-
- setup2DViewport();
-
- // Inform lower views of the change
- // round up when converting coordinates to make sure there are no gaps at edge of window
- LLView::sForceReshape = display_scale_changed;
- mRootView->reshape(llceil((F32)width / mDisplayScale.mV[VX]), llceil((F32)height / mDisplayScale.mV[VY]));
- if (display_scale_changed)
- {
- // Needs only a 'scale change' update, everything else gets handled by LLLayoutStack::updateClass()
- LLPanelLogin::reshapePanel();
- }
- LLView::sForceReshape = false;
-
- // clear font width caches
- if (display_scale_changed)
- {
- LLHUDObject::reshapeAll();
- }
-
- sendShapeToSim();
-
- // store new settings for the mode we are in, regardless
- bool maximized = mWindow->getMaximized();
- gSavedSettings.setBOOL("WindowMaximized", maximized);
-
- if (!maximized)
- {
- U32 min_window_width=gSavedSettings.getU32("MinWindowWidth");
- U32 min_window_height=gSavedSettings.getU32("MinWindowHeight");
- // tell the OS specific window code about min window size
- mWindow->setMinSize(min_window_width, min_window_height);
-
- LLCoordScreen window_rect;
- if (!gNonInteractive && mWindow->getSize(&window_rect))
- {
- // Only save size if not maximized
- gSavedSettings.setU32("WindowWidth", window_rect.mX);
- gSavedSettings.setU32("WindowHeight", window_rect.mY);
- }
- }
-
- sample(LLStatViewer::WINDOW_WIDTH, width);
- sample(LLStatViewer::WINDOW_HEIGHT, height);
-
- LLLayoutStack::updateClass();
- }
-}
-
-
-// Hide normal UI when a logon fails
-void LLViewerWindow::setNormalControlsVisible( bool visible )
-{
- if(LLChicletBar::instanceExists())
- {
- LLChicletBar::getInstance()->setVisible(visible);
- LLChicletBar::getInstance()->setEnabled(visible);
- }
-
- if ( gMenuBarView )
- {
- gMenuBarView->setVisible( visible );
- gMenuBarView->setEnabled( visible );
-
- // ...and set the menu color appropriately.
- setMenuBackgroundColor(gAgent.getGodLevel() > GOD_NOT,
- LLGridManager::getInstance()->isInProductionGrid());
- }
-
- if ( gStatusBar )
- {
- gStatusBar->setVisible( visible );
- gStatusBar->setEnabled( visible );
- }
-
- LLNavigationBar* navbarp = LLUI::getInstance()->getRootView()->findChild<LLNavigationBar>("navigation_bar");
- if (navbarp)
- {
- // when it's time to show navigation bar we need to ensure that the user wants to see it
- // i.e. ShowNavbarNavigationPanel option is true
- navbarp->setVisible( visible && gSavedSettings.getBOOL("ShowNavbarNavigationPanel") );
- }
-}
-
-void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid)
-{
- LLSD args;
- LLColor4 new_bg_color;
-
- // god more important than project, proj more important than grid
- if ( god_mode )
- {
- if ( LLGridManager::getInstance()->isInProductionGrid() )
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuBarGodBgColor" );
- }
- else
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionGodBgColor" );
- }
- }
- else
- {
- switch (LLVersionInfo::instance().getViewerMaturity())
- {
- case LLVersionInfo::TEST_VIEWER:
- new_bg_color = LLUIColorTable::instance().getColor( "MenuBarTestBgColor" );
- break;
-
- case LLVersionInfo::PROJECT_VIEWER:
- new_bg_color = LLUIColorTable::instance().getColor( "MenuBarProjectBgColor" );
- break;
-
- case LLVersionInfo::BETA_VIEWER:
- new_bg_color = LLUIColorTable::instance().getColor( "MenuBarBetaBgColor" );
- break;
-
- case LLVersionInfo::RELEASE_VIEWER:
- if(!LLGridManager::getInstance()->isInProductionGrid())
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" );
- }
- else
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuBarBgColor" );
- }
- break;
- }
- }
-
- if(gMenuBarView)
- {
- gMenuBarView->setBackgroundColor( new_bg_color );
- }
-
- if(gStatusBar)
- {
- gStatusBar->setBackgroundColor( new_bg_color );
- }
-}
-
-void LLViewerWindow::drawDebugText()
-{
- gUIProgram.bind();
- gGL.color4f(1,1,1,1);
- gGL.pushMatrix();
- gGL.pushUIMatrix();
- {
- // scale view by UI global scale factor and aspect ratio correction factor
- gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
- mDebugText->draw();
- }
- gGL.popUIMatrix();
- gGL.popMatrix();
-
- gGL.flush();
- gUIProgram.unbind();
-}
-
-void LLViewerWindow::draw()
-{
-
-//#if LL_DEBUG
- LLView::sIsDrawing = true;
-//#endif
- stop_glerror();
-
- LLUI::setLineWidth(1.f);
-
- LLUI::setLineWidth(1.f);
- // Reset any left-over transforms
- gGL.matrixMode(LLRender::MM_MODELVIEW);
-
- gGL.loadIdentity();
-
- //S32 screen_x, screen_y;
-
- if (!gSavedSettings.getBOOL("RenderUIBuffer"))
- {
- LLView::sDirtyRect = getWindowRectScaled();
- }
-
- // HACK for timecode debugging
- if (gSavedSettings.getBOOL("DisplayTimecode"))
- {
- // draw timecode block
- std::string text;
-
- gGL.loadIdentity();
-
- microsecondsToTimecodeString(gFrameTime,text);
- const LLFontGL* font = LLFontGL::getFontSansSerif();
- font->renderUTF8(text, 0,
- ll_round((getWindowWidthScaled()/2)-100.f),
- ll_round((getWindowHeightScaled()-60.f)),
- LLColor4( 1.f, 1.f, 1.f, 1.f ),
- LLFontGL::LEFT, LLFontGL::TOP);
- }
-
- // Draw all nested UI views.
- // No translation needed, this view is glued to 0,0
-
- gUIProgram.bind();
- gGL.color4f(1, 1, 1, 1);
-
- gGL.pushMatrix();
- LLUI::pushMatrix();
- {
-
- // scale view by UI global scale factor and aspect ratio correction factor
- gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
-
- LLVector2 old_scale_factor = LLUI::getScaleFactor();
- // apply camera zoom transform (for high res screenshots)
- F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
- S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
- if (zoom_factor > 1.f)
- {
- //decompose subregion number to x and y values
- int pos_y = sub_region / llceil(zoom_factor);
- int pos_x = sub_region - (pos_y*llceil(zoom_factor));
- // offset for this tile
- gGL.translatef((F32)getWindowWidthScaled() * -(F32)pos_x,
- (F32)getWindowHeightScaled() * -(F32)pos_y,
- 0.f);
- gGL.scalef(zoom_factor, zoom_factor, 1.f);
- LLUI::getScaleFactor() *= zoom_factor;
- }
-
- // Draw tool specific overlay on world
- LLToolMgr::getInstance()->getCurrentTool()->draw();
-
- if( gAgentCamera.cameraMouselook() || LLFloaterCamera::inFreeCameraMode() )
- {
- drawMouselookInstructions();
- stop_glerror();
- }
-
- // Draw all nested UI views.
- // No translation needed, this view is glued to 0,0
- mRootView->draw();
-
- if (LLView::sDebugRects)
- {
- gToolTipView->drawStickyRect();
- }
-
- // Draw optional on-top-of-everyone view
- LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- if (top_ctrl && top_ctrl->getVisible())
- {
- S32 screen_x, screen_y;
- top_ctrl->localPointToScreen(0, 0, &screen_x, &screen_y);
-
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- LLUI::pushMatrix();
- LLUI::translate( (F32) screen_x, (F32) screen_y);
- top_ctrl->draw();
- LLUI::popMatrix();
- }
-
-
- if( gShowOverlayTitle && !mOverlayTitle.empty() )
- {
- // Used for special titles such as "Second Life - Special E3 2003 Beta"
- const S32 DIST_FROM_TOP = 20;
- LLFontGL::getFontSansSerifBig()->renderUTF8(
- mOverlayTitle, 0,
- ll_round( getWindowWidthScaled() * 0.5f),
- getWindowHeightScaled() - DIST_FROM_TOP,
- LLColor4(1, 1, 1, 0.4f),
- LLFontGL::HCENTER, LLFontGL::TOP);
- }
-
- LLUI::setScaleFactor(old_scale_factor);
- }
- LLUI::popMatrix();
- gGL.popMatrix();
-
- gUIProgram.unbind();
-
- LLView::sIsDrawing = false;
-}
-
-// Takes a single keyup event, usually when UI is visible
-bool LLViewerWindow::handleKeyUp(KEY key, MASK mask)
-{
- if (LLSetKeyBindDialog::recordKey(key, mask, false))
- {
- LL_DEBUGS() << "KeyUp handled by LLSetKeyBindDialog" << LL_ENDL;
- LLViewerEventRecorder::instance().logKeyEvent(key, mask);
- return true;
- }
-
- LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
-
- if (keyboard_focus
- && !(mask & (MASK_CONTROL | MASK_ALT))
- && !gFocusMgr.getKeystrokesOnly())
- {
- // We have keyboard focus, and it's not an accelerator
- if (keyboard_focus && keyboard_focus->wantsKeyUpKeyDown())
- {
- return keyboard_focus->handleKeyUp(key, mask, false);
- }
- else if (key < 0x80)
- {
- // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first.
- return (gFocusMgr.getKeyboardFocus() != NULL);
- }
- }
-
- if (keyboard_focus)
- {
- if (keyboard_focus->handleKeyUp(key, mask, false))
- {
- LL_DEBUGS() << "LLviewerWindow::handleKeyUp - in 'traverse up' - no loops seen... just called keyboard_focus->handleKeyUp an it returned true" << LL_ENDL;
- LLViewerEventRecorder::instance().logKeyEvent(key, mask);
- return true;
- }
- else {
- LL_DEBUGS() << "LLviewerWindow::handleKeyUp - in 'traverse up' - no loops seen... just called keyboard_focus->handleKeyUp an it returned false" << LL_ENDL;
- }
- }
-
- // don't pass keys on to world when something in ui has focus
- return gFocusMgr.childHasKeyboardFocus(mRootView)
- || LLMenuGL::getKeyboardMode()
- || (gMenuBarView && gMenuBarView->getHighlightedItem() && gMenuBarView->getHighlightedItem()->isActive());
-}
-
-// Takes a single keydown event, usually when UI is visible
-bool LLViewerWindow::handleKey(KEY key, MASK mask)
-{
- // hide tooltips on keypress
- LLToolTipMgr::instance().blockToolTips();
-
- // Menus get handled on key down instead of key up
- // so keybindings have to be recorded before that
- if (LLSetKeyBindDialog::recordKey(key, mask, true))
- {
- LL_DEBUGS() << "Key handled by LLSetKeyBindDialog" << LL_ENDL;
- LLViewerEventRecorder::instance().logKeyEvent(key,mask);
- return true;
- }
-
- LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
-
- if (keyboard_focus
- && !gFocusMgr.getKeystrokesOnly())
- {
- //Most things should fall through, but mouselook is an exception,
- //don't switch to mouselook if any floater has focus
- if ((key == KEY_MOUSELOOK) && !(mask & (MASK_CONTROL | MASK_ALT)))
- {
- return true;
- }
-
- LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(keyboard_focus);
- if (cur_focus && cur_focus->acceptsTextInput())
- {
-#ifdef LL_WINDOWS
- // On windows Alt Gr key generates additional Ctrl event, as result handling situations
- // like 'AltGr + D' will result in 'Alt+Ctrl+D'. If it results in WM_CHAR, don't let it
- // pass into menu or it will trigger 'develop' menu assigned to this combination on top
- // of character handling.
- // Alt Gr can be additionally modified by Shift
- const MASK alt_gr = MASK_CONTROL | MASK_ALT;
- LLWindowWin32 *window = static_cast<LLWindowWin32*>(mWindow);
- U32 raw_key = window->getRawWParam();
- if ((mask & alt_gr) != 0
- && ((raw_key >= 0x30 && raw_key <= 0x5A) //0-9, plus normal chartacters
- || (raw_key >= 0xBA && raw_key <= 0xE4)) // Misc/OEM characters that can be covered by AltGr, ex: -, =, ~
- && (GetKeyState(VK_RMENU) & 0x8000) != 0
- && (GetKeyState(VK_RCONTROL) & 0x8000) == 0) // ensure right control is not pressed, only left one
- {
- // Alt Gr key is represented as right alt and left control.
- // Any alt+ctrl combination is treated as Alt Gr by TranslateMessage() and
- // will generate a WM_CHAR message, but here we only treat virtual Alt Graph
- // key by checking if this specific combination has unicode char.
- //
- // I decided to handle only virtual RAlt+LCtrl==AltGr combination to minimize
- // impact on menu, but the right way might be to handle all Alt+Ctrl calls.
-
- BYTE keyboard_state[256];
- if (GetKeyboardState(keyboard_state))
- {
- const int char_count = 6;
- wchar_t chars[char_count];
- HKL layout = GetKeyboardLayout(0);
- // ToUnicodeEx changes buffer state on OS below Win10, which is undesirable,
- // but since we already did a TranslateMessage() in gatherInput(), this
- // should have no negative effect
- // ToUnicodeEx works with virtual key codes
- int res = ToUnicodeEx(raw_key, 0, keyboard_state, chars, char_count, 1 << 2 /*do not modify buffer flag*/, layout);
- if (res == 1 && chars[0] >= 0x20)
- {
- // Let it fall through to character handler and get a WM_CHAR.
- return true;
- }
- }
- }
-#endif
-
- if (!(mask & (MASK_CONTROL | MASK_ALT)))
- {
- // We have keyboard focus, and it's not an accelerator
- if (keyboard_focus && keyboard_focus->wantsKeyUpKeyDown())
- {
- return keyboard_focus->handleKey(key, mask, false);
- }
- else if (key < 0x80)
- {
- // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first.
- return true;
- }
- }
- }
- }
-
- // let menus handle navigation keys for navigation
- if ((gMenuBarView && gMenuBarView->handleKey(key, mask, true))
- ||(gLoginMenuBarView && gLoginMenuBarView->handleKey(key, mask, true))
- ||(gMenuHolder && gMenuHolder->handleKey(key, mask, true)))
- {
- LL_DEBUGS() << "LLviewerWindow::handleKey handle nav keys for nav" << LL_ENDL;
- LLViewerEventRecorder::instance().logKeyEvent(key,mask);
- return true;
- }
-
-
- // give menus a chance to handle modified (Ctrl, Alt) shortcut keys before current focus
- // as long as focus isn't locked
- if (mask & (MASK_CONTROL | MASK_ALT) && !gFocusMgr.focusLocked())
- {
- // Check the current floater's menu first, if it has one.
- if (gFocusMgr.keyboardFocusHasAccelerators()
- && keyboard_focus
- && keyboard_focus->handleKey(key,mask,false))
- {
- LLViewerEventRecorder::instance().logKeyEvent(key,mask);
- return true;
- }
-
- if (gAgent.isInitialized()
- && (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE || gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL)
- && gMenuBarView
- && gMenuBarView->handleAcceleratorKey(key, mask))
- {
- LLViewerEventRecorder::instance().logKeyEvent(key, mask);
- return true;
- }
-
- if (gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask))
- {
- LLViewerEventRecorder::instance().logKeyEvent(key,mask);
- return true;
- }
- }
-
- // give floaters first chance to handle TAB key
- // so frontmost floater gets focus
- // if nothing has focus, go to first or last UI element as appropriate
- if (key == KEY_TAB && (mask & MASK_CONTROL || keyboard_focus == NULL))
- {
- LL_WARNS() << "LLviewerWindow::handleKey give floaters first chance at tab key " << LL_ENDL;
- if (gMenuHolder) gMenuHolder->hideMenus();
-
- // if CTRL-tabbing (and not just TAB with no focus), go into window cycle mode
- gFloaterView->setCycleMode((mask & MASK_CONTROL) != 0);
-
- // do CTRL-TAB and CTRL-SHIFT-TAB logic
- if (mask & MASK_SHIFT)
- {
- mRootView->focusPrevRoot();
- }
- else
- {
- mRootView->focusNextRoot();
- }
- LLViewerEventRecorder::instance().logKeyEvent(key,mask);
- return true;
- }
- // hidden edit menu for cut/copy/paste
- if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask))
- {
- LLViewerEventRecorder::instance().logKeyEvent(key,mask);
- return true;
- }
-
- LLFloater* focused_floaterp = gFloaterView->getFocusedFloater();
- std::string focusedFloaterName = (focused_floaterp ? focused_floaterp->getInstanceName() : "");
-
- if( keyboard_focus )
- {
- if ((focusedFloaterName == "nearby_chat") || (focusedFloaterName == "im_container") || (focusedFloaterName == "impanel"))
- {
- if (gSavedSettings.getBOOL("ArrowKeysAlwaysMove"))
- {
- // let Control-Up and Control-Down through for chat line history,
- if (!(key == KEY_UP && mask == MASK_CONTROL)
- && !(key == KEY_DOWN && mask == MASK_CONTROL)
- && !(key == KEY_UP && mask == MASK_ALT)
- && !(key == KEY_DOWN && mask == MASK_ALT))
- {
- switch(key)
- {
- case KEY_LEFT:
- case KEY_RIGHT:
- case KEY_UP:
- case KEY_DOWN:
- case KEY_PAGE_UP:
- case KEY_PAGE_DOWN:
- case KEY_HOME:
- case KEY_END:
- // when chatbar is empty or ArrowKeysAlwaysMove set,
- // pass arrow keys on to avatar...
- return false;
- default:
- break;
- }
- }
- }
- }
-
- if (keyboard_focus->handleKey(key, mask, false))
- {
-
- LL_DEBUGS() << "LLviewerWindow::handleKey - in 'traverse up' - no loops seen... just called keyboard_focus->handleKey an it returned true" << LL_ENDL;
- LLViewerEventRecorder::instance().logKeyEvent(key,mask);
- return true;
- } else {
- LL_DEBUGS() << "LLviewerWindow::handleKey - in 'traverse up' - no loops seen... just called keyboard_focus->handleKey an it returned false" << LL_ENDL;
- }
- }
-
- if( LLToolMgr::getInstance()->getCurrentTool()->handleKey(key, mask) )
- {
- LL_DEBUGS() << "LLviewerWindow::handleKey toolbar handling?" << LL_ENDL;
- LLViewerEventRecorder::instance().logKeyEvent(key,mask);
- return true;
- }
-
- // Try for a new-format gesture
- if (LLGestureMgr::instance().triggerGesture(key, mask))
- {
- LL_DEBUGS() << "LLviewerWindow::handleKey new gesture feature" << LL_ENDL;
- LLViewerEventRecorder::instance().logKeyEvent(key,mask);
- return true;
- }
-
- // See if this is a gesture trigger. If so, eat the key and
- // don't pass it down to the menus.
- if (gGestureList.trigger(key, mask))
- {
- LL_DEBUGS() << "LLviewerWindow::handleKey check gesture trigger" << LL_ENDL;
- LLViewerEventRecorder::instance().logKeyEvent(key,mask);
- return true;
- }
-
- // If "Pressing letter keys starts local chat" option is selected, we are not in mouselook,
- // no view has keyboard focus, this is a printable character key (and no modifier key is
- // pressed except shift), then give focus to nearby chat (STORM-560)
- if ( LLStartUp::getStartupState() >= STATE_STARTED &&
- gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() &&
- !keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) )
- {
- // Initialize nearby chat if it's missing
- LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
- if (!nearby_chat)
- {
- LLSD name("im_container");
- LLFloaterReg::toggleInstanceOrBringToFront(name);
- }
-
- LLChatEntry* chat_editor = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat")->getChatBox();
- if (chat_editor)
- {
- // passing NULL here, character will be added later when it is handled by character handler.
- nearby_chat->startChat(NULL);
- return true;
- }
- }
-
- // give menus a chance to handle unmodified accelerator keys
- if (gAgent.isInitialized()
- && (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE || gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL)
- && gMenuBarView
- && gMenuBarView->handleAcceleratorKey(key, mask))
- {
- LLViewerEventRecorder::instance().logKeyEvent(key, mask);
- return true;
- }
-
- if (gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask))
- {
- return true;
- }
-
- // don't pass keys on to world when something in ui has focus
- return gFocusMgr.childHasKeyboardFocus(mRootView)
- || LLMenuGL::getKeyboardMode()
- || (gMenuBarView && gMenuBarView->getHighlightedItem() && gMenuBarView->getHighlightedItem()->isActive());
-}
-
-
-bool LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
-{
- // HACK: We delay processing of return keys until they arrive as a Unicode char,
- // so that if you're typing chat text at low frame rate, we don't send the chat
- // until all keystrokes have been entered. JC
- // HACK: Numeric keypad <enter> on Mac is Unicode 3
- // HACK: Control-M on Windows is Unicode 13
- if ((uni_char == 13 && mask != MASK_CONTROL)
- || (uni_char == 3 && mask == MASK_NONE) )
- {
- if (mask != MASK_ALT)
- {
- // remaps, handles ignored cases and returns back to viewer window.
- return gViewerInput.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
- }
- }
-
- // let menus handle navigation (jump) keys
- if (gMenuBarView && gMenuBarView->handleUnicodeChar(uni_char, true))
- {
- return true;
- }
-
- // Traverses up the hierarchy
- LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
- if( keyboard_focus )
- {
- if (keyboard_focus->handleUnicodeChar(uni_char, false))
- {
- return true;
- }
-
- return true;
- }
-
- return false;
-}
-
-
-void LLViewerWindow::handleScrollWheel(S32 clicks)
-{
- LLUI::getInstance()->resetMouseIdleTimer();
-
- LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
- if( mouse_captor )
- {
- S32 local_x;
- S32 local_y;
- mouse_captor->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
- mouse_captor->handleScrollWheel(local_x, local_y, clicks);
- if (LLView::sDebugMouseHandling)
- {
- LL_INFOS() << "Scroll Wheel handled by captor " << mouse_captor->getName() << LL_ENDL;
- }
- return;
- }
-
- LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- if (top_ctrl)
- {
- S32 local_x;
- S32 local_y;
- top_ctrl->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
- if (top_ctrl->handleScrollWheel(local_x, local_y, clicks)) return;
- }
-
- if (mRootView->handleScrollWheel(mCurrentMousePoint.mX, mCurrentMousePoint.mY, clicks) )
- {
- if (LLView::sDebugMouseHandling)
- {
- LL_INFOS() << "Scroll Wheel" << LLView::sMouseHandlerMessage << LL_ENDL;
- }
- return;
- }
- else if (LLView::sDebugMouseHandling)
- {
- LL_INFOS() << "Scroll Wheel not handled by view" << LL_ENDL;
- }
-
- // Zoom the camera in and out behavior
-
- if(top_ctrl == 0
- && getWorldViewRectScaled().pointInRect(mCurrentMousePoint.mX, mCurrentMousePoint.mY)
- && gAgentCamera.isInitialized())
- gAgentCamera.handleScrollWheel(clicks);
-
- return;
-}
-
-void LLViewerWindow::handleScrollHWheel(S32 clicks)
-{
- if (LLAppViewer::instance()->quitRequested())
- {
- return;
- }
-
- LLUI::getInstance()->resetMouseIdleTimer();
-
- LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
- if (mouse_captor)
- {
- S32 local_x;
- S32 local_y;
- mouse_captor->screenPointToLocal(mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y);
- mouse_captor->handleScrollHWheel(local_x, local_y, clicks);
- if (LLView::sDebugMouseHandling)
- {
- LL_INFOS() << "Scroll Horizontal Wheel handled by captor " << mouse_captor->getName() << LL_ENDL;
- }
- return;
- }
-
- LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- if (top_ctrl)
- {
- S32 local_x;
- S32 local_y;
- top_ctrl->screenPointToLocal(mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y);
- if (top_ctrl->handleScrollHWheel(local_x, local_y, clicks)) return;
- }
-
- if (mRootView->handleScrollHWheel(mCurrentMousePoint.mX, mCurrentMousePoint.mY, clicks))
- {
- if (LLView::sDebugMouseHandling)
- {
- LL_INFOS() << "Scroll Horizontal Wheel" << LLView::sMouseHandlerMessage << LL_ENDL;
- }
- return;
- }
- else if (LLView::sDebugMouseHandling)
- {
- LL_INFOS() << "Scroll Horizontal Wheel not handled by view" << LL_ENDL;
- }
-
- return;
-}
-
-void LLViewerWindow::addPopup(LLView* popup)
-{
- if (mPopupView)
- {
- mPopupView->addPopup(popup);
- }
-}
-
-void LLViewerWindow::removePopup(LLView* popup)
-{
- if (mPopupView)
- {
- mPopupView->removePopup(popup);
- }
-}
-
-void LLViewerWindow::clearPopups()
-{
- if (mPopupView)
- {
- mPopupView->clearPopups();
- }
-}
-
-void LLViewerWindow::moveCursorToCenter()
-{
- if (! gSavedSettings.getBOOL("DisableMouseWarp"))
- {
- S32 x = getWorldViewWidthScaled() / 2;
- S32 y = getWorldViewHeightScaled() / 2;
-
- LLUI::getInstance()->setMousePositionScreen(x, y);
-
- //on a forced move, all deltas get zeroed out to prevent jumping
- mCurrentMousePoint.set(x,y);
- mLastMousePoint.set(x,y);
- mCurrentMouseDelta.set(0,0);
- }
-}
-
-
-//////////////////////////////////////////////////////////////////////
-//
-// Hover handlers
-//
-
-void append_xui_tooltip(LLView* viewp, LLToolTip::Params& params)
-{
- if (viewp)
- {
- if (!params.styled_message.empty())
- {
- params.styled_message.add().text("\n---------\n");
- }
- LLView::root_to_view_iterator_t end_tooltip_it = viewp->endRootToView();
- // NOTE: we skip "root" since it is assumed
- for (LLView::root_to_view_iterator_t tooltip_it = ++viewp->beginRootToView();
- tooltip_it != end_tooltip_it;
- ++tooltip_it)
- {
- LLView* viewp = *tooltip_it;
-
- params.styled_message.add().text(viewp->getName());
-
- LLPanel* panelp = dynamic_cast<LLPanel*>(viewp);
- if (panelp && !panelp->getXMLFilename().empty())
- {
- params.styled_message.add()
- .text("(" + panelp->getXMLFilename() + ")")
- .style.color(LLColor4(0.7f, 0.7f, 1.f, 1.f));
- }
- params.styled_message.add().text("/");
- }
- }
-}
-
-static LLTrace::BlockTimerStatHandle ftm("Update UI");
-
-// Update UI based on stored mouse position from mouse-move
-// event processing.
-void LLViewerWindow::updateUI()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(ftm);
-
- static std::string last_handle_msg;
-
- if (gLoggedInTime.getStarted())
- {
- if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("DestinationGuideHintTimeout"))
- {
- LLFirstUse::notUsingDestinationGuide();
- }
- if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("SidePanelHintTimeout"))
- {
- LLFirstUse::notUsingSidePanel();
- }
- }
-
- LLConsole::updateClass();
-
- // animate layout stacks so we have up to date rect for world view
- LLLayoutStack::updateClass();
-
- // use full window for world view when not rendering UI
- bool world_view_uses_full_window = gAgentCamera.cameraMouselook() || !gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
- updateWorldViewRect(world_view_uses_full_window);
-
- LLView::sMouseHandlerMessage.clear();
-
- S32 x = mCurrentMousePoint.mX;
- S32 y = mCurrentMousePoint.mY;
-
- MASK mask = gKeyboard->currentMask(true);
-
- if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
- {
- gDebugRaycastFaceHit = -1;
- gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, false, false, true, false,
- &gDebugRaycastFaceHit,
- &gDebugRaycastIntersection,
- &gDebugRaycastTexCoord,
- &gDebugRaycastNormal,
- &gDebugRaycastTangent,
- &gDebugRaycastStart,
- &gDebugRaycastEnd);
-
- gDebugRaycastParticle = gPipeline.lineSegmentIntersectParticle(gDebugRaycastStart, gDebugRaycastEnd, &gDebugRaycastParticleIntersection, NULL);
- }
-
- updateMouseDelta();
- updateKeyboardFocus();
-
- bool handled = false;
-
- LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
- LLView* captor_view = dynamic_cast<LLView*>(mouse_captor);
-
- //FIXME: only include captor and captor's ancestors if mouse is truly over them --RN
-
- //build set of views containing mouse cursor by traversing UI hierarchy and testing
- //screen rect against mouse cursor
- view_handle_set_t mouse_hover_set;
-
- // constraint mouse enter events to children of mouse captor
- LLView* root_view = captor_view;
-
- // if mouse captor doesn't exist or isn't a LLView
- // then allow mouse enter events on entire UI hierarchy
- if (!root_view)
- {
- root_view = mRootView;
- }
-
- static LLCachedControl<bool> dump_menu_holder(gSavedSettings, "DumpMenuHolderSize", false);
- if (dump_menu_holder)
- {
- static bool init = false;
- static LLFrameTimer child_count_timer;
- static std::vector <std::string> child_vec;
- if (!init)
- {
- child_count_timer.resetWithExpiry(5.f);
- init = true;
- }
- if (child_count_timer.hasExpired())
- {
- LL_INFOS() << "gMenuHolder child count: " << gMenuHolder->getChildCount() << LL_ENDL;
- std::vector<std::string> local_child_vec;
- LLView::child_list_t child_list = *gMenuHolder->getChildList();
- for (auto child : child_list)
- {
- local_child_vec.emplace_back(child->getName());
- }
- if (!local_child_vec.empty() && local_child_vec != child_vec)
- {
- std::vector<std::string> out_vec;
- std::sort(local_child_vec.begin(), local_child_vec.end());
- std::sort(child_vec.begin(), child_vec.end());
- std::set_difference(child_vec.begin(), child_vec.end(), local_child_vec.begin(), local_child_vec.end(), std::inserter(out_vec, out_vec.begin()));
- if (!out_vec.empty())
- {
- LL_INFOS() << "gMenuHolder removal diff size: '"<<out_vec.size() <<"' begin_child_diff";
- for (auto str : out_vec)
- {
- LL_CONT << " : " << str;
- }
- LL_CONT << " : end_child_diff" << LL_ENDL;
- }
-
- out_vec.clear();
- std::set_difference(local_child_vec.begin(), local_child_vec.end(), child_vec.begin(), child_vec.end(), std::inserter(out_vec, out_vec.begin()));
- if (!out_vec.empty())
- {
- LL_INFOS() << "gMenuHolder addition diff size: '" << out_vec.size() << "' begin_child_diff";
- for (auto str : out_vec)
- {
- LL_CONT << " : " << str;
- }
- LL_CONT << " : end_child_diff" << LL_ENDL;
- }
- child_vec.swap(local_child_vec);
- }
- child_count_timer.resetWithExpiry(5.f);
- }
- }
-
- // only update mouse hover set when UI is visible (since we shouldn't send hover events to invisible UI
- if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- // include all ancestors of captor_view as automatically having mouse
- if (captor_view)
- {
- LLView* captor_parent_view = captor_view->getParent();
- while(captor_parent_view)
- {
- mouse_hover_set.insert(captor_parent_view->getHandle());
- captor_parent_view = captor_parent_view->getParent();
- }
- }
-
- // aggregate visible views that contain mouse cursor in display order
- LLPopupView::popup_list_t popups = mPopupView->getCurrentPopups();
-
- for(LLPopupView::popup_list_t::iterator popup_it = popups.begin(); popup_it != popups.end(); ++popup_it)
- {
- LLView* popup = popup_it->get();
- if (popup && popup->calcScreenBoundingRect().pointInRect(x, y))
- {
- // iterator over contents of top_ctrl, and throw into mouse_hover_set
- for (LLView::tree_iterator_t it = popup->beginTreeDFS();
- it != popup->endTreeDFS();
- ++it)
- {
- LLView* viewp = *it;
- if (viewp->getVisible()
- && viewp->calcScreenBoundingRect().pointInRect(x, y))
- {
- // we have a view that contains the mouse, add it to the set
- mouse_hover_set.insert(viewp->getHandle());
- }
- else
- {
- // skip this view and all of its children
- it.skipDescendants();
- }
- }
- }
- }
-
- // while the top_ctrl contains the mouse cursor, only it and its descendants will receive onMouseEnter events
- if (top_ctrl && top_ctrl->calcScreenBoundingRect().pointInRect(x, y))
- {
- // iterator over contents of top_ctrl, and throw into mouse_hover_set
- for (LLView::tree_iterator_t it = top_ctrl->beginTreeDFS();
- it != top_ctrl->endTreeDFS();
- ++it)
- {
- LLView* viewp = *it;
- if (viewp->getVisible()
- && viewp->calcScreenBoundingRect().pointInRect(x, y))
- {
- // we have a view that contains the mouse, add it to the set
- mouse_hover_set.insert(viewp->getHandle());
- }
- else
- {
- // skip this view and all of its children
- it.skipDescendants();
- }
- }
- }
- else
- {
- // walk UI tree in depth-first order
- for (LLView::tree_iterator_t it = root_view->beginTreeDFS();
- it != root_view->endTreeDFS();
- ++it)
- {
- LLView* viewp = *it;
- // calculating the screen rect involves traversing the parent, so this is less than optimal
- if (viewp->getVisible()
- && viewp->calcScreenBoundingRect().pointInRect(x, y))
- {
-
- // if this view is mouse opaque, nothing behind it should be in mouse_hover_set
- if (viewp->getMouseOpaque())
- {
- // constrain further iteration to children of this widget
- it = viewp->beginTreeDFS();
- }
-
- // we have a view that contains the mouse, add it to the set
- mouse_hover_set.insert(viewp->getHandle());
- }
- else
- {
- // skip this view and all of its children
- it.skipDescendants();
- }
- }
- }
- }
-
- typedef std::vector<LLHandle<LLView> > view_handle_list_t;
-
- // call onMouseEnter() on all views which contain the mouse cursor but did not before
- view_handle_list_t mouse_enter_views;
- std::set_difference(mouse_hover_set.begin(), mouse_hover_set.end(),
- mMouseHoverViews.begin(), mMouseHoverViews.end(),
- std::back_inserter(mouse_enter_views));
- for (view_handle_list_t::iterator it = mouse_enter_views.begin();
- it != mouse_enter_views.end();
- ++it)
- {
- LLView* viewp = it->get();
- if (viewp)
- {
- LLRect view_screen_rect = viewp->calcScreenRect();
- viewp->onMouseEnter(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask);
- }
- }
-
- // call onMouseLeave() on all views which no longer contain the mouse cursor
- view_handle_list_t mouse_leave_views;
- std::set_difference(mMouseHoverViews.begin(), mMouseHoverViews.end(),
- mouse_hover_set.begin(), mouse_hover_set.end(),
- std::back_inserter(mouse_leave_views));
- for (view_handle_list_t::iterator it = mouse_leave_views.begin();
- it != mouse_leave_views.end();
- ++it)
- {
- LLView* viewp = it->get();
- if (viewp)
- {
- LLRect view_screen_rect = viewp->calcScreenRect();
- viewp->onMouseLeave(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask);
- }
- }
-
- // store resulting hover set for next frame
- swap(mMouseHoverViews, mouse_hover_set);
-
- // only handle hover events when UI is enabled
- if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
-
- if( mouse_captor )
- {
- // Pass hover events to object capturing mouse events.
- S32 local_x;
- S32 local_y;
- mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
- handled = mouse_captor->handleHover(local_x, local_y, mask);
- if (LLView::sDebugMouseHandling)
- {
- LL_INFOS() << "Hover handled by captor " << mouse_captor->getName() << LL_ENDL;
- }
-
- if( !handled )
- {
- LL_DEBUGS("UserInput") << "hover not handled by mouse captor" << LL_ENDL;
- }
- }
- else
- {
- if (top_ctrl)
- {
- S32 local_x, local_y;
- top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
- handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleHover(local_x, local_y, mask);
- }
-
- if ( !handled )
- {
- // x and y are from last time mouse was in window
- // mMouseInWindow tracks *actual* mouse location
- if (mMouseInWindow && mRootView->handleHover(x, y, mask) )
- {
- if (LLView::sDebugMouseHandling && LLView::sMouseHandlerMessage != last_handle_msg)
- {
- last_handle_msg = LLView::sMouseHandlerMessage;
- LL_INFOS() << "Hover" << LLView::sMouseHandlerMessage << LL_ENDL;
- }
- handled = true;
- }
- else if (LLView::sDebugMouseHandling)
- {
- if (last_handle_msg != LLStringUtil::null)
- {
- last_handle_msg.clear();
- LL_INFOS() << "Hover not handled by view" << LL_ENDL;
- }
- }
- }
-
- if (!handled)
- {
- LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
-
- if(mMouseInWindow && tool)
- {
- handled = tool->handleHover(x, y, mask);
- }
- }
- }
-
- // Show a new tool tip (or update one that is already shown)
- bool tool_tip_handled = false;
- std::string tool_tip_msg;
- if( handled
- && !mWindow->isCursorHidden())
- {
- LLRect screen_sticky_rect = mRootView->getLocalRect();
- S32 local_x, local_y;
-
- static LLCachedControl<bool> debug_show_xui_names(gSavedSettings, "DebugShowXUINames", 0);
- if (debug_show_xui_names)
- {
- LLToolTip::Params params;
-
- LLView* tooltip_view = mRootView;
- LLView::tree_iterator_t end_it = mRootView->endTreeDFS();
- for (LLView::tree_iterator_t it = mRootView->beginTreeDFS(); it != end_it; ++it)
- {
- LLView* viewp = *it;
- LLRect screen_rect;
- viewp->localRectToScreen(viewp->getLocalRect(), &screen_rect);
- if (!(viewp->getVisible()
- && screen_rect.pointInRect(x, y)))
- {
- it.skipDescendants();
- }
- // only report xui names for LLUICtrls,
- // and blacklist the various containers we don't care about
- else if (dynamic_cast<LLUICtrl*>(viewp)
- && viewp != gMenuHolder
- && viewp != gFloaterView
- && viewp != gConsole)
- {
- if (dynamic_cast<LLFloater*>(viewp))
- {
- // constrain search to descendants of this (frontmost) floater
- // by resetting iterator
- it = viewp->beginTreeDFS();
- }
-
- // if we are in a new part of the tree (not a descendent of current tooltip_view)
- // then push the results for tooltip_view and start with a new potential view
- // NOTE: this emulates visiting only the leaf nodes that meet our criteria
- if (!viewp->hasAncestor(tooltip_view))
- {
- append_xui_tooltip(tooltip_view, params);
- screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
- }
- tooltip_view = viewp;
- }
- }
-
- append_xui_tooltip(tooltip_view, params);
- params.styled_message.add().text("\n");
-
- screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
-
- params.sticky_rect = screen_sticky_rect;
- params.max_width = 400;
-
- LLToolTipMgr::instance().show(params);
- }
- // if there is a mouse captor, nothing else gets a tooltip
- else if (mouse_captor)
- {
- mouse_captor->screenPointToLocal(x, y, &local_x, &local_y);
- tool_tip_handled = mouse_captor->handleToolTip(local_x, local_y, mask);
- }
- else
- {
- // next is top_ctrl
- if (!tool_tip_handled && top_ctrl)
- {
- top_ctrl->screenPointToLocal(x, y, &local_x, &local_y);
- tool_tip_handled = top_ctrl->handleToolTip(local_x, local_y, mask );
- }
-
- if (!tool_tip_handled)
- {
- local_x = x; local_y = y;
- tool_tip_handled = mRootView->handleToolTip(local_x, local_y, mask );
- }
-
- LLTool* current_tool = LLToolMgr::getInstance()->getCurrentTool();
- if (!tool_tip_handled && current_tool)
- {
- current_tool->screenPointToLocal(x, y, &local_x, &local_y);
- tool_tip_handled = current_tool->handleToolTip(local_x, local_y, mask );
- }
- }
- }
- }
- else
- { // just have tools handle hover when UI is turned off
- LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
-
- if(mMouseInWindow && tool)
- {
- handled = tool->handleHover(x, y, mask);
- }
- }
-
- updateLayout();
-
- mLastMousePoint = mCurrentMousePoint;
-
- // cleanup unused selections when no modal dialogs are open
- if (LLModalDialog::activeCount() == 0)
- {
- LLViewerParcelMgr::getInstance()->deselectUnused();
- }
-
- if (LLModalDialog::activeCount() == 0)
- {
- LLSelectMgr::getInstance()->deselectUnused();
- }
-}
-
-
-void LLViewerWindow::updateLayout()
-{
- LLTool* tool = LLToolMgr::getInstance()->getCurrentTool();
- if (gFloaterTools != NULL
- && tool != NULL
- && tool != gToolNull
- && tool != LLToolCompInspect::getInstance()
- && tool != LLToolDragAndDrop::getInstance()
- && !gSavedSettings.getBOOL("FreezeTime"))
- {
- // Suppress the toolbox view if our source tool was the pie tool,
- // and we've overridden to something else.
- bool suppress_toolbox =
- (LLToolMgr::getInstance()->getBaseTool() == LLToolPie::getInstance()) &&
- (LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance());
-
- LLMouseHandler *captor = gFocusMgr.getMouseCapture();
- // With the null, inspect, or drag and drop tool, don't muck
- // with visibility.
-
- if (gFloaterTools->isMinimized()
- || (tool != LLToolPie::getInstance() // not default tool
- && tool != LLToolCompGun::getInstance() // not coming out of mouselook
- && !suppress_toolbox // not override in third person
- && LLToolMgr::getInstance()->getCurrentToolset()->isShowFloaterTools()
- && (!captor || dynamic_cast<LLView*>(captor) != NULL))) // not dragging
- {
- // Force floater tools to be visible (unless minimized)
- if (!gFloaterTools->getVisible())
- {
- gFloaterTools->openFloater();
- }
- // Update the location of the blue box tool popup
- LLCoordGL select_center_screen;
- MASK mask = gKeyboard->currentMask(true);
- gFloaterTools->updatePopup( select_center_screen, mask );
- }
- else
- {
- gFloaterTools->setVisible(false);
- }
- //gMenuBarView->setItemVisible("BuildTools", gFloaterTools->getVisible());
- }
-
- // Always update console
- if(gConsole)
- {
- LLRect console_rect = getChatConsoleRect();
- gConsole->reshape(console_rect.getWidth(), console_rect.getHeight());
- gConsole->setRect(console_rect);
- }
-}
-
-void LLViewerWindow::updateMouseDelta()
-{
-#if LL_WINDOWS
- LLCoordCommon delta;
- mWindow->getCursorDelta(&delta);
- S32 dx = delta.mX;
- S32 dy = delta.mY;
-#else
- S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::getScaleFactor().mV[VX]);
- S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::getScaleFactor().mV[VY]);
-#endif
-
- //RN: fix for asynchronous notification of mouse leaving window not working
- LLCoordWindow mouse_pos;
- mWindow->getCursorPosition(&mouse_pos);
- if (mouse_pos.mX < 0 ||
- mouse_pos.mY < 0 ||
- mouse_pos.mX > mWindowRectRaw.getWidth() ||
- mouse_pos.mY > mWindowRectRaw.getHeight())
- {
- mMouseInWindow = false;
- }
- else
- {
- mMouseInWindow = true;
- }
-
- LLVector2 mouse_vel;
-
- if (gSavedSettings.getBOOL("MouseSmooth"))
- {
- static F32 fdx = 0.f;
- static F32 fdy = 0.f;
-
- F32 amount = 16.f;
- fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds.value()*amount,1.f);
- fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds.value()*amount,1.f);
-
- mCurrentMouseDelta.set(ll_round(fdx), ll_round(fdy));
- mouse_vel.setVec(fdx,fdy);
- }
- else
- {
- mCurrentMouseDelta.set(dx, dy);
- mouse_vel.setVec((F32) dx, (F32) dy);
- }
-
- sample(sMouseVelocityStat, mouse_vel.magVec());
-}
-
-void LLViewerWindow::updateKeyboardFocus()
-{
- if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- gFocusMgr.setKeyboardFocus(NULL);
- }
-
- // clean up current focus
- LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
- if (cur_focus)
- {
- if (!cur_focus->isInVisibleChain() || !cur_focus->isInEnabledChain())
- {
- // don't release focus, just reassign so that if being given
- // to a sibling won't call onFocusLost on all the ancestors
- // gFocusMgr.releaseFocusIfNeeded(cur_focus);
-
- LLUICtrl* parent = cur_focus->getParentUICtrl();
- const LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot();
- bool new_focus_found = false;
- while(parent)
- {
- if (parent->isCtrl()
- && (parent->hasTabStop() || parent == focus_root)
- && !parent->getIsChrome()
- && parent->isInVisibleChain()
- && parent->isInEnabledChain())
- {
- if (!parent->focusFirstItem())
- {
- parent->setFocus(true);
- }
- new_focus_found = true;
- break;
- }
- parent = parent->getParentUICtrl();
- }
-
- // if we didn't find a better place to put focus, just release it
- // hasFocus() will return true if and only if we didn't touch focus since we
- // are only moving focus higher in the hierarchy
- if (!new_focus_found)
- {
- cur_focus->setFocus(false);
- }
- }
- else if (cur_focus->isFocusRoot())
- {
- // focus roots keep trying to delegate focus to their first valid descendant
- // this assumes that focus roots are not valid focus holders on their own
- cur_focus->focusFirstItem();
- }
- }
-
- // last ditch force of edit menu to selection manager
- if (LLEditMenuHandler::gEditMenuHandler == NULL && LLSelectMgr::getInstance()->getSelection()->getObjectCount())
- {
- LLEditMenuHandler::gEditMenuHandler = LLSelectMgr::getInstance();
- }
-
- if (gFloaterView->getCycleMode())
- {
- // sync all floaters with their focus state
- gFloaterView->highlightFocusedFloater();
- gSnapshotFloaterView->highlightFocusedFloater();
- MASK mask = gKeyboard->currentMask(true);
- if ((mask & MASK_CONTROL) == 0)
- {
- // control key no longer held down, finish cycle mode
- gFloaterView->setCycleMode(false);
-
- gFloaterView->syncFloaterTabOrder();
- }
- else
- {
- // user holding down CTRL, don't update tab order of floaters
- }
- }
- else
- {
- // update focused floater
- gFloaterView->highlightFocusedFloater();
- gSnapshotFloaterView->highlightFocusedFloater();
- // make sure floater visible order is in sync with tab order
- gFloaterView->syncFloaterTabOrder();
- }
-}
-
-static LLTrace::BlockTimerStatHandle FTM_UPDATE_WORLD_VIEW("Update World View");
-void LLViewerWindow::updateWorldViewRect(bool use_full_window)
-{
- LL_RECORD_BLOCK_TIME(FTM_UPDATE_WORLD_VIEW);
-
- // start off using whole window to render world
- LLRect new_world_rect = mWindowRectRaw;
-
- if (!use_full_window && mWorldViewPlaceholder.get())
- {
- new_world_rect = mWorldViewPlaceholder.get()->calcScreenRect();
- // clamp to at least a 1x1 rect so we don't try to allocate zero width gl buffers
- new_world_rect.mTop = llmax(new_world_rect.mTop, new_world_rect.mBottom + 1);
- new_world_rect.mRight = llmax(new_world_rect.mRight, new_world_rect.mLeft + 1);
-
- new_world_rect.mLeft = ll_round((F32)new_world_rect.mLeft * mDisplayScale.mV[VX]);
- new_world_rect.mRight = ll_round((F32)new_world_rect.mRight * mDisplayScale.mV[VX]);
- new_world_rect.mBottom = ll_round((F32)new_world_rect.mBottom * mDisplayScale.mV[VY]);
- new_world_rect.mTop = ll_round((F32)new_world_rect.mTop * mDisplayScale.mV[VY]);
- }
-
- if (mWorldViewRectRaw != new_world_rect)
- {
- mWorldViewRectRaw = new_world_rect;
- gResizeScreenTexture = true;
- LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
- LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() );
-
- LLRect old_world_rect_scaled = mWorldViewRectScaled;
- mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale);
-
- // sending a signal with a new WorldView rect
- mOnWorldViewRectUpdated(old_world_rect_scaled, mWorldViewRectScaled);
- }
-}
-
-void LLViewerWindow::saveLastMouse(const LLCoordGL &point)
-{
- // Store last mouse location.
- // If mouse leaves window, pretend last point was on edge of window
-
- if (point.mX < 0)
- {
- mCurrentMousePoint.mX = 0;
- }
- else if (point.mX > getWindowWidthScaled())
- {
- mCurrentMousePoint.mX = getWindowWidthScaled();
- }
- else
- {
- mCurrentMousePoint.mX = point.mX;
- }
-
- if (point.mY < 0)
- {
- mCurrentMousePoint.mY = 0;
- }
- else if (point.mY > getWindowHeightScaled() )
- {
- mCurrentMousePoint.mY = getWindowHeightScaled();
- }
- else
- {
- mCurrentMousePoint.mY = point.mY;
- }
-}
-
-
-// Draws the selection outlines for the currently selected objects
-// Must be called after displayObjects is called, which sets the mGLName parameter
-// NOTE: This function gets called 3 times:
-// render_ui_3d: false, false, true
-// render_hud_elements: false, false, false
-void LLViewerWindow::renderSelections( bool for_gl_pick, bool pick_parcel_walls, bool for_hud )
-{
- LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
-
- if (!for_hud && !for_gl_pick)
- {
- // Call this once and only once
- LLSelectMgr::getInstance()->updateSilhouettes();
- }
-
- // Draw fence around land selections
- if (for_gl_pick)
- {
- if (pick_parcel_walls)
- {
- LLViewerParcelMgr::getInstance()->renderParcelCollision();
- }
- }
- else if (( for_hud && selection->getSelectType() == SELECT_TYPE_HUD) ||
- (!for_hud && selection->getSelectType() != SELECT_TYPE_HUD))
- {
- LLSelectMgr::getInstance()->renderSilhouettes(for_hud);
-
- stop_glerror();
-
- // setup HUD render
- if (selection->getSelectType() == SELECT_TYPE_HUD && LLSelectMgr::getInstance()->getSelection()->getObjectCount())
- {
- LLBBox hud_bbox = gAgentAvatarp->getHUDBBox();
-
- // set up transform to encompass bounding box of HUD
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.pushMatrix();
- gGL.loadIdentity();
- F32 depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
- gGL.ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, depth);
-
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.pushMatrix();
- gGL.loadIdentity();
- gGL.loadMatrix(OGL_TO_CFR_ROTATION); // Load Cory's favorite reference frame
- gGL.translatef(-hud_bbox.getCenterLocal().mV[VX] + (depth *0.5f), 0.f, 0.f);
- }
-
- // Render light for editing
- if (LLSelectMgr::sRenderLightRadius && LLToolMgr::getInstance()->inEdit())
- {
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLGLEnable gls_blend(GL_BLEND);
- LLGLEnable gls_cull(GL_CULL_FACE);
- LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.pushMatrix();
- if (selection->getSelectType() == SELECT_TYPE_HUD)
- {
- F32 zoom = gAgentCamera.mHUDCurZoom;
- gGL.scalef(zoom, zoom, zoom);
- }
-
- struct f : public LLSelectedObjectFunctor
- {
- virtual bool apply(LLViewerObject* object)
- {
- LLDrawable* drawable = object->mDrawable;
- if (drawable && drawable->isLight())
- {
- LLVOVolume* vovolume = drawable->getVOVolume();
- gGL.pushMatrix();
-
- LLVector3 center = drawable->getPositionAgent();
- gGL.translatef(center[0], center[1], center[2]);
- F32 scale = vovolume->getLightRadius();
- gGL.scalef(scale, scale, scale);
-
- LLColor4 color(vovolume->getLightSRGBColor(), .5f);
- gGL.color4fv(color.mV);
-
- //F32 pixel_area = 100000.f;
- // Render Outside
- gSphere.render();
-
- // Render Inside
- glCullFace(GL_FRONT);
- gSphere.render();
- glCullFace(GL_BACK);
-
- gGL.popMatrix();
- }
- return true;
- }
- } func;
- LLSelectMgr::getInstance()->getSelection()->applyToObjects(&func);
-
- gGL.popMatrix();
- }
-
- // NOTE: The average position for the axis arrows of the selected objects should
- // not be recalculated at this time. If they are, then group rotations will break.
-
- // Draw arrows at average center of all selected objects
- LLTool* tool = LLToolMgr::getInstance()->getCurrentTool();
- if (tool)
- {
- if(tool->isAlwaysRendered())
- {
- tool->render();
- }
- else
- {
- if( !LLSelectMgr::getInstance()->getSelection()->isEmpty() )
- {
- bool all_selected_objects_move;
- bool all_selected_objects_modify;
- // Note: This might be costly to do on each frame and when a lot of objects are selected
- // we might be better off with some kind of memory for selection and/or states, consider
- // optimizing, perhaps even some kind of selection generation at level of LLSelectMgr to
- // make whole viewer benefit.
- LLSelectMgr::getInstance()->selectGetEditMoveLinksetPermissions(all_selected_objects_move, all_selected_objects_modify);
-
- bool draw_handles = true;
-
- if (tool == LLToolCompTranslate::getInstance() && !all_selected_objects_move && !LLSelectMgr::getInstance()->isMovableAvatarSelected())
- {
- draw_handles = false;
- }
-
- if (tool == LLToolCompRotate::getInstance() && !all_selected_objects_move && !LLSelectMgr::getInstance()->isMovableAvatarSelected())
- {
- draw_handles = false;
- }
-
- if ( !all_selected_objects_modify && tool == LLToolCompScale::getInstance() )
- {
- draw_handles = false;
- }
-
- if( draw_handles )
- {
- tool->render();
- }
- }
- }
- if (selection->getSelectType() == SELECT_TYPE_HUD && selection->getObjectCount())
- {
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.popMatrix();
-
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.popMatrix();
- stop_glerror();
- }
- }
- }
-}
-
-// Return a point near the clicked object representative of the place the object was clicked.
-LLVector3d LLViewerWindow::clickPointInWorldGlobal(S32 x, S32 y_from_bot, LLViewerObject* clicked_object) const
-{
- // create a normalized vector pointing from the camera center into the
- // world at the location of the mouse click
- LLVector3 mouse_direction_global = mouseDirectionGlobal( x, y_from_bot );
-
- LLVector3d relative_object = clicked_object->getPositionGlobal() - gAgentCamera.getCameraPositionGlobal();
-
- // make mouse vector as long as object vector, so it touchs a point near
- // where the user clicked on the object
- mouse_direction_global *= (F32) relative_object.magVec();
-
- LLVector3d new_pos;
- new_pos.setVec(mouse_direction_global);
- // transform mouse vector back to world coords
- new_pos += gAgentCamera.getCameraPositionGlobal();
-
- return new_pos;
-}
-
-
-bool LLViewerWindow::clickPointOnSurfaceGlobal(const S32 x, const S32 y, LLViewerObject *objectp, LLVector3d &point_global) const
-{
- bool intersect = false;
-
-// U8 shape = objectp->mPrimitiveCode & LL_PCODE_BASE_MASK;
- if (!intersect)
- {
- point_global = clickPointInWorldGlobal(x, y, objectp);
- LL_INFOS() << "approx intersection at " << (objectp->getPositionGlobal() - point_global) << LL_ENDL;
- }
- else
- {
- LL_INFOS() << "good intersection at " << (objectp->getPositionGlobal() - point_global) << LL_ENDL;
- }
-
- return intersect;
-}
-
-void LLViewerWindow::pickAsync( S32 x,
- S32 y_from_bot,
- MASK mask,
- void (*callback)(const LLPickInfo& info),
- bool pick_transparent,
- bool pick_rigged,
- bool pick_unselectable,
- bool pick_reflection_probes)
-{
- // "Show Debug Alpha" means no object actually transparent
- bool in_build_mode = LLFloaterReg::instanceVisible("build");
- if (LLDrawPoolAlpha::sShowDebugAlpha
- || (in_build_mode && gSavedSettings.getBOOL("SelectInvisibleObjects")))
- {
- pick_transparent = true;
- }
-
- LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, pick_rigged, false, pick_reflection_probes, pick_unselectable, true, callback);
- schedulePick(pick_info);
-}
-
-void LLViewerWindow::schedulePick(LLPickInfo& pick_info)
-{
- if (mPicks.size() >= 1024 || mWindow->getMinimized())
- { //something went wrong, picks are being scheduled but not processed
-
- if (pick_info.mPickCallback)
- {
- pick_info.mPickCallback(pick_info);
- }
-
- return;
- }
- mPicks.push_back(pick_info);
-
- // delay further event processing until we receive results of pick
- // only do this for async picks so that handleMouseUp won't be called
- // until the pick triggered in handleMouseDown has been processed, for example
- mWindow->delayInputProcessing();
-}
-
-
-void LLViewerWindow::performPick()
-{
- if (!mPicks.empty())
- {
- std::vector<LLPickInfo>::iterator pick_it;
- for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it)
- {
- pick_it->fetchResults();
- }
-
- mLastPick = mPicks.back();
- mPicks.clear();
- }
-}
-
-void LLViewerWindow::returnEmptyPicks()
-{
- std::vector<LLPickInfo>::iterator pick_it;
- for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it)
- {
- mLastPick = *pick_it;
- // just trigger callback with empty results
- if (pick_it->mPickCallback)
- {
- pick_it->mPickCallback(*pick_it);
- }
- }
- mPicks.clear();
-}
-
-// Performs the GL object/land pick.
-LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, bool pick_transparent, bool pick_rigged, bool pick_particle, bool pick_unselectable, bool pick_reflection_probe)
-{
- bool in_build_mode = LLFloaterReg::instanceVisible("build");
- if ((in_build_mode && gSavedSettings.getBOOL("SelectInvisibleObjects")) || LLDrawPoolAlpha::sShowDebugAlpha)
- {
- // build mode allows interaction with all transparent objects
- // "Show Debug Alpha" means no object actually transparent
- pick_transparent = true;
- }
-
- // shortcut queueing in mPicks and just update mLastPick in place
- MASK key_mask = gKeyboard->currentMask(true);
- mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), key_mask, pick_transparent, pick_rigged, pick_particle, pick_reflection_probe, true, false, NULL);
- mLastPick.fetchResults();
-
- return mLastPick;
-}
-
-LLHUDIcon* LLViewerWindow::cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 depth,
- LLVector4a* intersection)
-{
- S32 x = mouse_x;
- S32 y = mouse_y;
-
- if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position
- {
- x = getCurrentMouseX();
- y = getCurrentMouseY();
- }
-
- // world coordinates of mouse
- // VECTORIZE THIS
- LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
- LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin();
- LLVector3 mouse_world_start = mouse_point_global;
- LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth;
-
- LLVector4a start, end;
- start.load3(mouse_world_start.mV);
- end.load3(mouse_world_end.mV);
-
- return LLHUDIcon::lineSegmentIntersectAll(start, end, intersection);
-}
-
-LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 depth,
- LLViewerObject *this_object,
- S32 this_face,
- bool pick_transparent,
- bool pick_rigged,
- bool pick_unselectable,
- bool pick_reflection_probe,
- S32* face_hit,
- LLVector4a *intersection,
- LLVector2 *uv,
- LLVector4a *normal,
- LLVector4a *tangent,
- LLVector4a* start,
- LLVector4a* end)
-{
- S32 x = mouse_x;
- S32 y = mouse_y;
-
- if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position
- {
- x = getCurrentMouseX();
- y = getCurrentMouseY();
- }
-
- // HUD coordinates of mouse
- LLVector3 mouse_point_hud = mousePointHUD(x, y);
- LLVector3 mouse_hud_start = mouse_point_hud - LLVector3(depth, 0, 0);
- LLVector3 mouse_hud_end = mouse_point_hud + LLVector3(depth, 0, 0);
-
- // world coordinates of mouse
- LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
- LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin();
-
- //get near clip plane
- LLVector3 n = LLViewerCamera::getInstance()->getAtAxis();
- LLVector3 p = mouse_point_global + n * LLViewerCamera::getInstance()->getNear();
-
- //project mouse point onto plane
- LLVector3 pos;
- line_plane(mouse_point_global, mouse_direction_global, p, n, pos);
- mouse_point_global = pos;
-
- LLVector3 mouse_world_start = mouse_point_global;
- LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth;
-
- if (!LLViewerJoystick::getInstance()->getOverrideCamera())
- { //always set raycast intersection to mouse_world_end unless
- //flycam is on (for DoF effect)
- gDebugRaycastIntersection.load3(mouse_world_end.mV);
- }
-
- LLVector4a mw_start;
- mw_start.load3(mouse_world_start.mV);
- LLVector4a mw_end;
- mw_end.load3(mouse_world_end.mV);
-
- LLVector4a mh_start;
- mh_start.load3(mouse_hud_start.mV);
- LLVector4a mh_end;
- mh_end.load3(mouse_hud_end.mV);
-
- if (start)
- {
- *start = mw_start;
- }
-
- if (end)
- {
- *end = mw_end;
- }
-
- LLViewerObject* found = NULL;
-
- if (this_object) // check only this object
- {
- if (this_object->isHUDAttachment()) // is a HUD object?
- {
- if (this_object->lineSegmentIntersect(mh_start, mh_end, this_face, pick_transparent, pick_rigged, pick_unselectable,
- face_hit, intersection, uv, normal, tangent))
- {
- found = this_object;
- }
- }
- else // is a world object
- {
- if ((pick_reflection_probe || !this_object->isReflectionProbe())
- && this_object->lineSegmentIntersect(mw_start, mw_end, this_face, pick_transparent, pick_rigged, pick_unselectable,
- face_hit, intersection, uv, normal, tangent))
- {
- found = this_object;
- }
- }
- }
- else // check ALL objects
- {
- found = gPipeline.lineSegmentIntersectInHUD(mh_start, mh_end, pick_transparent,
- face_hit, intersection, uv, normal, tangent);
-
- if (!found) // if not found in HUD, look in world:
- {
- found = gPipeline.lineSegmentIntersectInWorld(mw_start, mw_end, pick_transparent, pick_rigged, pick_unselectable, pick_reflection_probe,
- face_hit, intersection, uv, normal, tangent);
- if (found && !pick_transparent)
- {
- gDebugRaycastIntersection = *intersection;
- }
- }
- }
-
- return found;
-}
-
-// Returns unit vector relative to camera
-// indicating direction of point on screen x,y
-LLVector3 LLViewerWindow::mouseDirectionGlobal(const S32 x, const S32 y) const
-{
- // find vertical field of view
- F32 fov = LLViewerCamera::getInstance()->getView();
-
- // find world view center in scaled ui coordinates
- F32 center_x = getWorldViewRectScaled().getCenterX();
- F32 center_y = getWorldViewRectScaled().getCenterY();
-
- // calculate pixel distance to screen
- F32 distance = ((F32)getWorldViewHeightScaled() * 0.5f) / (tan(fov / 2.f));
-
- // calculate click point relative to middle of screen
- F32 click_x = x - center_x;
- F32 click_y = y - center_y;
-
- // compute mouse vector
- LLVector3 mouse_vector = distance * LLViewerCamera::getInstance()->getAtAxis()
- - click_x * LLViewerCamera::getInstance()->getLeftAxis()
- + click_y * LLViewerCamera::getInstance()->getUpAxis();
-
- mouse_vector.normVec();
-
- return mouse_vector;
-}
-
-LLVector3 LLViewerWindow::mousePointHUD(const S32 x, const S32 y) const
-{
- // find screen resolution
- S32 height = getWorldViewHeightScaled();
-
- // find world view center
- F32 center_x = getWorldViewRectScaled().getCenterX();
- F32 center_y = getWorldViewRectScaled().getCenterY();
-
- // remap with uniform scale (1/height) so that top is -0.5, bottom is +0.5
- F32 hud_x = -((F32)x - center_x) / height;
- F32 hud_y = ((F32)y - center_y) / height;
-
- return LLVector3(0.f, hud_x/gAgentCamera.mHUDCurZoom, hud_y/gAgentCamera.mHUDCurZoom);
-}
-
-// Returns unit vector relative to camera in camera space
-// indicating direction of point on screen x,y
-LLVector3 LLViewerWindow::mouseDirectionCamera(const S32 x, const S32 y) const
-{
- // find vertical field of view
- F32 fov_height = LLViewerCamera::getInstance()->getView();
- F32 fov_width = fov_height * LLViewerCamera::getInstance()->getAspect();
-
- // find screen resolution
- S32 height = getWorldViewHeightScaled();
- S32 width = getWorldViewWidthScaled();
-
- // find world view center
- F32 center_x = getWorldViewRectScaled().getCenterX();
- F32 center_y = getWorldViewRectScaled().getCenterY();
-
- // calculate click point relative to middle of screen
- F32 click_x = (((F32)x - center_x) / (F32)width) * fov_width * -1.f;
- F32 click_y = (((F32)y - center_y) / (F32)height) * fov_height;
-
- // compute mouse vector
- LLVector3 mouse_vector = LLVector3(0.f, 0.f, -1.f);
- LLQuaternion mouse_rotate;
- mouse_rotate.setQuat(click_y, click_x, 0.f);
-
- mouse_vector = mouse_vector * mouse_rotate;
- // project to z = -1 plane;
- mouse_vector = mouse_vector * (-1.f / mouse_vector.mV[VZ]);
-
- return mouse_vector;
-}
-
-
-
-bool LLViewerWindow::mousePointOnPlaneGlobal(LLVector3d& point, const S32 x, const S32 y,
- const LLVector3d &plane_point_global,
- const LLVector3 &plane_normal_global)
-{
- LLVector3d mouse_direction_global_d;
-
- mouse_direction_global_d.setVec(mouseDirectionGlobal(x,y));
- LLVector3d plane_normal_global_d;
- plane_normal_global_d.setVec(plane_normal_global);
- F64 plane_mouse_dot = (plane_normal_global_d * mouse_direction_global_d);
- LLVector3d plane_origin_camera_rel = plane_point_global - gAgentCamera.getCameraPositionGlobal();
- F64 mouse_look_at_scale = (plane_normal_global_d * plane_origin_camera_rel)
- / plane_mouse_dot;
- if (llabs(plane_mouse_dot) < 0.00001)
- {
- // if mouse is parallel to plane, return closest point on line through plane origin
- // that is parallel to camera plane by scaling mouse direction vector
- // by distance to plane origin, modulated by deviation of mouse direction from plane origin
- LLVector3d plane_origin_dir = plane_origin_camera_rel;
- plane_origin_dir.normVec();
-
- mouse_look_at_scale = plane_origin_camera_rel.magVec() / (plane_origin_dir * mouse_direction_global_d);
- }
-
- point = gAgentCamera.getCameraPositionGlobal() + mouse_look_at_scale * mouse_direction_global_d;
-
- return mouse_look_at_scale > 0.0;
-}
-
-
-// Returns global position
-bool LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d *land_position_global, bool ignore_distance)
-{
- LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
- F32 mouse_dir_scale;
- bool hit_land = false;
- LLViewerRegion *regionp;
- F32 land_z;
- const F32 FIRST_PASS_STEP = 1.0f; // meters
- const F32 SECOND_PASS_STEP = 0.1f; // meters
- const F32 draw_distance = ignore_distance ? MAX_FAR_CLIP : gAgentCamera.mDrawDistance;
- LLVector3d camera_pos_global;
-
- camera_pos_global = gAgentCamera.getCameraPositionGlobal();
- LLVector3d probe_point_global;
- LLVector3 probe_point_region;
-
- // walk forwards to find the point
- for (mouse_dir_scale = FIRST_PASS_STEP; mouse_dir_scale < draw_distance; mouse_dir_scale += FIRST_PASS_STEP)
- {
- LLVector3d mouse_direction_global_d;
- mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale);
- probe_point_global = camera_pos_global + mouse_direction_global_d;
-
- regionp = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global);
-
- if (!regionp)
- {
- // ...we're outside the world somehow
- continue;
- }
-
- S32 i = (S32) (probe_point_region.mV[VX]/regionp->getLand().getMetersPerGrid());
- S32 j = (S32) (probe_point_region.mV[VY]/regionp->getLand().getMetersPerGrid());
- S32 grids_per_edge = (S32) regionp->getLand().mGridsPerEdge;
- if ((i >= grids_per_edge) || (j >= grids_per_edge))
- {
- //LL_INFOS() << "LLViewerWindow::mousePointOnLand probe_point is out of region" << LL_ENDL;
- continue;
- }
-
- land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
-
- //LL_INFOS() << "mousePointOnLand initial z " << land_z << LL_ENDL;
-
- if (probe_point_region.mV[VZ] < land_z)
- {
- // ...just went under land
-
- // cout << "under land at " << probe_point << " scale " << mouse_vec_scale << endl;
-
- hit_land = true;
- break;
- }
- }
-
-
- if (hit_land)
- {
- // Don't go more than one step beyond where we stopped above.
- // This can't just be "mouse_vec_scale" because floating point error
- // will stop the loop before the last increment.... X - 1.0 + 0.1 + 0.1 + ... + 0.1 != X
- F32 stop_mouse_dir_scale = mouse_dir_scale + FIRST_PASS_STEP;
-
- // take a step backwards, then walk forwards again to refine position
- for ( mouse_dir_scale -= FIRST_PASS_STEP; mouse_dir_scale <= stop_mouse_dir_scale; mouse_dir_scale += SECOND_PASS_STEP)
- {
- LLVector3d mouse_direction_global_d;
- mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale);
- probe_point_global = camera_pos_global + mouse_direction_global_d;
-
- regionp = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global);
-
- if (!regionp)
- {
- // ...we're outside the world somehow
- continue;
- }
-
- /*
- i = (S32) (local_probe_point.mV[VX]/regionp->getLand().getMetersPerGrid());
- j = (S32) (local_probe_point.mV[VY]/regionp->getLand().getMetersPerGrid());
- if ((i >= regionp->getLand().mGridsPerEdge) || (j >= regionp->getLand().mGridsPerEdge))
- {
- // LL_INFOS() << "LLViewerWindow::mousePointOnLand probe_point is out of region" << LL_ENDL;
- continue;
- }
- land_z = regionp->getLand().mSurfaceZ[ i + j * (regionp->getLand().mGridsPerEdge) ];
- */
-
- land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
-
- //LL_INFOS() << "mousePointOnLand refine z " << land_z << LL_ENDL;
-
- if (probe_point_region.mV[VZ] < land_z)
- {
- // ...just went under land again
-
- *land_position_global = probe_point_global;
- return true;
- }
- }
- }
-
- return false;
-}
-
-// Saves an image to the harddrive as "SnapshotX" where X >= 1.
-void LLViewerWindow::saveImageNumbered(LLImageFormatted *image, bool force_picker, const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb)
-{
- if (!image)
- {
- LL_WARNS() << "No image to save" << LL_ENDL;
- return;
- }
- std::string extension("." + image->getExtension());
- LLImageFormatted* formatted_image = image;
- // Get a base file location if needed.
- if (force_picker || !isSnapshotLocSet())
- {
- std::string proposed_name(sSnapshotBaseName);
-
- // getSaveFile will append an appropriate extension to the proposed name, based on the ESaveFilter constant passed in.
- LLFilePicker::ESaveFilter pick_type;
-
- if (extension == ".j2c")
- pick_type = LLFilePicker::FFSAVE_J2C;
- else if (extension == ".bmp")
- pick_type = LLFilePicker::FFSAVE_BMP;
- else if (extension == ".jpg")
- pick_type = LLFilePicker::FFSAVE_JPEG;
- else if (extension == ".png")
- pick_type = LLFilePicker::FFSAVE_PNG;
- else if (extension == ".tga")
- pick_type = LLFilePicker::FFSAVE_TGA;
- else
- pick_type = LLFilePicker::FFSAVE_ALL;
-
- LLFilePickerReplyThread::startPicker(boost::bind(&LLViewerWindow::onDirectorySelected, this, _1, formatted_image, success_cb, failure_cb), pick_type, proposed_name,
- boost::bind(&LLViewerWindow::onSelectionFailure, this, failure_cb));
- }
- else
- {
- saveImageLocal(formatted_image, success_cb, failure_cb);
- }
-}
-
-void LLViewerWindow::onDirectorySelected(const std::vector<std::string>& filenames, LLImageFormatted *image, const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb)
-{
- // Copy the directory + file name
- std::string filepath = filenames[0];
-
- gSavedPerAccountSettings.setString("SnapshotBaseName", gDirUtilp->getBaseFileName(filepath, true));
- gSavedPerAccountSettings.setString("SnapshotBaseDir", gDirUtilp->getDirName(filepath));
- saveImageLocal(image, success_cb, failure_cb);
-}
-
-void LLViewerWindow::onSelectionFailure(const snapshot_saved_signal_t::slot_type& failure_cb)
-{
- failure_cb();
-}
-
-
-void LLViewerWindow::saveImageLocal(LLImageFormatted *image, const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb)
-{
- std::string lastSnapshotDir = LLViewerWindow::getLastSnapshotDir();
- if (lastSnapshotDir.empty())
- {
- failure_cb();
- return;
- }
-
-// Check if there is enough free space to save snapshot
-#ifdef LL_WINDOWS
- boost::filesystem::path b_path(utf8str_to_utf16str(lastSnapshotDir));
-#else
- boost::filesystem::path b_path(lastSnapshotDir);
-#endif
- if (!boost::filesystem::is_directory(b_path))
- {
- LLSD args;
- args["PATH"] = lastSnapshotDir;
- LLNotificationsUtil::add("SnapshotToLocalDirNotExist", args);
- resetSnapshotLoc();
- failure_cb();
- return;
- }
- boost::filesystem::space_info b_space = boost::filesystem::space(b_path);
- if (b_space.free < image->getDataSize())
- {
- LLSD args;
- args["PATH"] = lastSnapshotDir;
-
- std::string needM_bytes_string;
- LLResMgr::getInstance()->getIntegerString(needM_bytes_string, (image->getDataSize()) >> 10);
- args["NEED_MEMORY"] = needM_bytes_string;
-
- std::string freeM_bytes_string;
- LLResMgr::getInstance()->getIntegerString(freeM_bytes_string, (b_space.free) >> 10);
- args["FREE_MEMORY"] = freeM_bytes_string;
-
- LLNotificationsUtil::add("SnapshotToComputerFailed", args);
-
- failure_cb();
- }
-
- // Look for an unused file name
- bool is_snapshot_name_loc_set = isSnapshotLocSet();
- std::string filepath;
- S32 i = 1;
- S32 err = 0;
- std::string extension("." + image->getExtension());
- do
- {
- filepath = sSnapshotDir;
- filepath += gDirUtilp->getDirDelimiter();
- filepath += sSnapshotBaseName;
-
- if (is_snapshot_name_loc_set)
- {
- filepath += llformat("_%.3d",i);
- }
-
- filepath += extension;
-
- llstat stat_info;
- err = LLFile::stat( filepath, &stat_info );
- i++;
- }
- while( -1 != err // Search until the file is not found (i.e., stat() gives an error).
- && is_snapshot_name_loc_set); // Or stop if we are rewriting.
-
- LL_INFOS() << "Saving snapshot to " << filepath << LL_ENDL;
- if (image->save(filepath))
- {
- playSnapshotAnimAndSound();
- success_cb();
- }
- else
- {
- failure_cb();
- }
-}
-
-void LLViewerWindow::resetSnapshotLoc()
-{
- gSavedPerAccountSettings.setString("SnapshotBaseDir", std::string());
-}
-
-// static
-void LLViewerWindow::movieSize(S32 new_width, S32 new_height)
-{
- LLCoordWindow size;
- LLCoordWindow new_size(new_width, new_height);
- gViewerWindow->getWindow()->getSize(&size);
- if ( size != new_size )
- {
- gViewerWindow->getWindow()->setSize(new_size);
- }
-}
-
-bool LLViewerWindow::saveSnapshot(const std::string& filepath, S32 image_width, S32 image_height, bool show_ui, bool show_hud, bool do_rebuild, LLSnapshotModel::ESnapshotLayerType type, LLSnapshotModel::ESnapshotFormat format)
-{
- LL_INFOS() << "Saving snapshot to: " << filepath << LL_ENDL;
-
- LLPointer<LLImageRaw> raw = new LLImageRaw;
- bool success = rawSnapshot(raw, image_width, image_height, true, false, show_ui, show_hud, do_rebuild);
-
- if (success)
- {
- U8 image_codec = IMG_CODEC_BMP;
- switch (format)
- {
- case LLSnapshotModel::SNAPSHOT_FORMAT_PNG:
- image_codec = IMG_CODEC_PNG;
- break;
- case LLSnapshotModel::SNAPSHOT_FORMAT_JPEG:
- image_codec = IMG_CODEC_JPEG;
- break;
- default:
- image_codec = IMG_CODEC_BMP;
- break;
- }
-
- LLPointer<LLImageFormatted> formated_image = LLImageFormatted::createFromType(image_codec);
- success = formated_image->encode(raw, 0.0f);
- if (success)
- {
- success = formated_image->save(filepath);
- }
- else
- {
- LL_WARNS() << "Unable to encode snapshot of format " << format << LL_ENDL;
- }
- }
- else
- {
- LL_WARNS() << "Unable to capture raw snapshot" << LL_ENDL;
- }
-
- return success;
-}
-
-
-void LLViewerWindow::playSnapshotAnimAndSound()
-{
- if (gSavedSettings.getBOOL("QuietSnapshotsToDisk"))
- {
- return;
- }
- gAgent.sendAnimationRequest(ANIM_AGENT_SNAPSHOT, ANIM_REQUEST_START);
- send_sound_trigger(LLUUID(gSavedSettings.getString("UISndSnapshot")), 1.0f);
-}
-
-bool LLViewerWindow::isSnapshotLocSet() const
-{
- std::string snapshot_dir = sSnapshotDir;
- return !snapshot_dir.empty();
-}
-
-void LLViewerWindow::resetSnapshotLoc() const
-{
- gSavedPerAccountSettings.setString("SnapshotBaseDir", std::string());
-}
-
-bool LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, bool show_ui, bool show_hud, bool do_rebuild, bool no_post, LLSnapshotModel::ESnapshotLayerType type)
-{
- return rawSnapshot(raw, preview_width, preview_height, false, false, show_ui, show_hud, do_rebuild, no_post, type);
-}
-
-// Saves the image from the screen to a raw image
-// Since the required size might be bigger than the available screen, this method rerenders the scene in parts (called subimages) and copy
-// the results over to the final raw image.
-bool LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height,
- bool keep_window_aspect, bool is_texture, bool show_ui, bool show_hud, bool do_rebuild, bool no_post, LLSnapshotModel::ESnapshotLayerType type, S32 max_size)
-{
- if (!raw)
- {
- return false;
- }
-
- //check if there is enough memory for the snapshot image
- if(image_width * image_height > (1 << 22)) //if snapshot image is larger than 2K by 2K
- {
- if(!LLMemory::tryToAlloc(NULL, image_width * image_height * 3))
- {
- LL_WARNS() << "No enough memory to take the snapshot with size (w : h): " << image_width << " : " << image_height << LL_ENDL ;
- return false ; //there is no enough memory for taking this snapshot.
- }
- }
-
- // PRE SNAPSHOT
- gSnapshotNoPost = no_post;
- gDisplaySwapBuffers = false;
-
- glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // stencil buffer is deprecated | GL_STENCIL_BUFFER_BIT);
- setCursor(UI_CURSOR_WAIT);
-
- // Hide all the UI widgets first and draw a frame
- bool prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
-
- if ( prev_draw_ui != show_ui)
- {
- LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);
- }
-
- bool hide_hud = !show_hud && LLPipeline::sShowHUDAttachments;
- if (hide_hud)
- {
- LLPipeline::sShowHUDAttachments = false;
- }
-
- // if not showing ui, use full window to render world view
- updateWorldViewRect(!show_ui);
-
- // Copy screen to a buffer
- // crop sides or top and bottom, if taking a snapshot of different aspect ratio
- // from window
- LLRect window_rect = show_ui ? getWindowRectRaw() : getWorldViewRectRaw();
-
- S32 snapshot_width = window_rect.getWidth();
- S32 snapshot_height = window_rect.getHeight();
- // SNAPSHOT
- S32 window_width = snapshot_width;
- S32 window_height = snapshot_height;
-
- // Note: Scaling of the UI is currently *not* supported so we limit the output size if UI is requested
- if (show_ui)
- {
- // If the user wants the UI, limit the output size to the available screen size
- image_width = llmin(image_width, window_width);
- image_height = llmin(image_height, window_height);
- }
-
- S32 original_width = 0;
- S32 original_height = 0;
- bool reset_deferred = false;
-
- LLRenderTarget scratch_space;
-
- F32 scale_factor = 1.0f ;
- if (!keep_window_aspect || (image_width > window_width) || (image_height > window_height))
- {
- if ((image_width <= gGLManager.mGLMaxTextureSize && image_height <= gGLManager.mGLMaxTextureSize) &&
- (image_width > window_width || image_height > window_height) && LLPipeline::sRenderDeferred && !show_ui)
- {
- U32 color_fmt = type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGBA;
- if (scratch_space.allocate(image_width, image_height, color_fmt, true))
- {
- original_width = gPipeline.mRT->deferredScreen.getWidth();
- original_height = gPipeline.mRT->deferredScreen.getHeight();
-
- if (gPipeline.allocateScreenBuffer(image_width, image_height))
- {
- window_width = image_width;
- window_height = image_height;
- snapshot_width = image_width;
- snapshot_height = image_height;
- reset_deferred = true;
- mWorldViewRectRaw.set(0, image_height, image_width, 0);
- LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
- LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() );
- scratch_space.bindTarget();
- }
- else
- {
- scratch_space.release();
- gPipeline.allocateScreenBuffer(original_width, original_height);
- }
- }
- }
-
- if (!reset_deferred)
- {
- // if image cropping or need to enlarge the scene, compute a scale_factor
- F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ;
- snapshot_width = (S32)(ratio * image_width) ;
- snapshot_height = (S32)(ratio * image_height) ;
- scale_factor = llmax(1.0f, 1.0f / ratio) ;
- }
- }
-
- if (show_ui && scale_factor > 1.f)
- {
- // Note: we should never get there...
- LL_WARNS() << "over scaling UI not supported." << LL_ENDL;
- }
-
- S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f);
- S32 buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f);
-
- S32 image_buffer_x = llfloor(snapshot_width * scale_factor) ;
- S32 image_buffer_y = llfloor(snapshot_height * scale_factor) ;
-
- if ((image_buffer_x > max_size) || (image_buffer_y > max_size)) // boundary check to avoid memory overflow
- {
- scale_factor *= llmin((F32)max_size / image_buffer_x, (F32)max_size / image_buffer_y) ;
- image_buffer_x = llfloor(snapshot_width * scale_factor) ;
- image_buffer_y = llfloor(snapshot_height * scale_factor) ;
- }
-
- LLImageDataLock lock(raw);
-
- if ((image_buffer_x > 0) && (image_buffer_y > 0))
- {
- raw->resize(image_buffer_x, image_buffer_y, 3);
- }
- else
- {
- return false;
- }
-
- if (raw->isBufferInvalid())
- {
- return false;
- }
-
- bool high_res = scale_factor >= 2.f; // Font scaling is slow, only do so if rez is much higher
- if (high_res && show_ui)
- {
- // Note: we should never get there...
- LL_WARNS() << "High res UI snapshot not supported. " << LL_ENDL;
- /*send_agent_pause();
- //rescale fonts
- initFonts(scale_factor);
- LLHUDObject::reshapeAll();*/
- }
-
- S32 output_buffer_offset_y = 0;
-
- F32 depth_conversion_factor_1 = (LLViewerCamera::getInstance()->getFar() + LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear());
- F32 depth_conversion_factor_2 = (LLViewerCamera::getInstance()->getFar() - LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear());
-
- // Subimages are in fact partial rendering of the final view. This happens when the final view is bigger than the screen.
- // In most common cases, scale_factor is 1 and there's no more than 1 iteration on x and y
- for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y)
- {
- S32 subimage_y_offset = llclamp(buffer_y_offset - (subimage_y * window_height), 0, window_height);;
- // handle fractional columns
- U32 read_height = llmax(0, (window_height - subimage_y_offset) -
- llmax(0, (window_height * (subimage_y + 1)) - (buffer_y_offset + raw->getHeight())));
-
- S32 output_buffer_offset_x = 0;
- for (int subimage_x = 0; subimage_x < scale_factor; ++subimage_x)
- {
- gDisplaySwapBuffers = false;
- gDepthDirty = true;
-
- S32 subimage_x_offset = llclamp(buffer_x_offset - (subimage_x * window_width), 0, window_width);
- // handle fractional rows
- U32 read_width = llmax(0, (window_width - subimage_x_offset) -
- llmax(0, (window_width * (subimage_x + 1)) - (buffer_x_offset + raw->getWidth())));
-
- // Skip rendering and sampling altogether if either width or height is degenerated to 0 (common in cropping cases)
- if (read_width && read_height)
- {
- const U32 subfield = subimage_x+(subimage_y*llceil(scale_factor));
- display(do_rebuild, scale_factor, subfield, true);
-
- if (!LLPipeline::sRenderDeferred)
- {
- // Required for showing the GUI in snapshots and performing bloom composite overlay
- // Call even if show_ui is false
- render_ui(scale_factor, subfield);
- swap();
- }
-
- for (U32 out_y = 0; out_y < read_height ; out_y++)
- {
- S32 output_buffer_offset = (
- (out_y * (raw->getWidth())) // ...plus iterated y...
- + (window_width * subimage_x) // ...plus subimage start in x...
- + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y...
- - output_buffer_offset_x // ...minus buffer padding x...
- - (output_buffer_offset_y * (raw->getWidth())) // ...minus buffer padding y...
- ) * raw->getComponents();
-
- // Ping the watchdog thread every 100 lines to keep us alive (arbitrary number, feel free to change)
- if (out_y % 100 == 0)
- {
- LLAppViewer::instance()->pingMainloopTimeout("LLViewerWindow::rawSnapshot");
- }
- // disable use of glReadPixels when doing nVidia nSight graphics debugging
- if (!LLRender::sNsightDebugSupport)
- {
- if (type == LLSnapshotModel::SNAPSHOT_TYPE_COLOR)
- {
- glReadPixels(
- subimage_x_offset, out_y + subimage_y_offset,
- read_width, 1,
- GL_RGB, GL_UNSIGNED_BYTE,
- raw->getData() + output_buffer_offset
- );
- }
- else // LLSnapshotModel::SNAPSHOT_TYPE_DEPTH
- {
- LLPointer<LLImageRaw> depth_line_buffer = new LLImageRaw(read_width, 1, sizeof(GL_FLOAT)); // need to store floating point values
- glReadPixels(
- subimage_x_offset, out_y + subimage_y_offset,
- read_width, 1,
- GL_DEPTH_COMPONENT, GL_FLOAT,
- depth_line_buffer->getData()// current output pixel is beginning of buffer...
- );
-
- for (S32 i = 0; i < (S32)read_width; i++)
- {
- F32 depth_float = *(F32*)(depth_line_buffer->getData() + (i * sizeof(F32)));
-
- F32 linear_depth_float = 1.f / (depth_conversion_factor_1 - (depth_float * depth_conversion_factor_2));
- U8 depth_byte = F32_to_U8(linear_depth_float, LLViewerCamera::getInstance()->getNear(), LLViewerCamera::getInstance()->getFar());
- // write converted scanline out to result image
- for (S32 j = 0; j < raw->getComponents(); j++)
- {
- *(raw->getData() + output_buffer_offset + (i * raw->getComponents()) + j) = depth_byte;
- }
- }
- }
- }
- }
- }
- output_buffer_offset_x += subimage_x_offset;
- stop_glerror();
- }
- output_buffer_offset_y += subimage_y_offset;
- }
-
- gDisplaySwapBuffers = false;
- gSnapshotNoPost = false;
- gDepthDirty = true;
-
- // POST SNAPSHOT
- if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);
- }
-
- if (hide_hud)
- {
- LLPipeline::sShowHUDAttachments = true;
- }
-
- /*if (high_res)
- {
- initFonts(1.f);
- LLHUDObject::reshapeAll();
- }*/
-
- // Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding)
- // Note: this formula depends on the number of components being 3. Not obvious, but it's correct.
- image_width += (image_width * 3) % 4;
-
- bool ret = true ;
- // Resize image
- if(llabs(image_width - image_buffer_x) > 4 || llabs(image_height - image_buffer_y) > 4)
- {
- ret = raw->scale( image_width, image_height );
- }
- else if(image_width != image_buffer_x || image_height != image_buffer_y)
- {
- ret = raw->scale( image_width, image_height, false );
- }
-
- setCursor(UI_CURSOR_ARROW);
-
- if (do_rebuild)
- {
- // If we had to do a rebuild, that means that the lists of drawables to be rendered
- // was empty before we started.
- // Need to reset these, otherwise we call state sort on it again when render gets called the next time
- // and we stand a good chance of crashing on rebuild because the render drawable arrays have multiple copies of
- // objects on them.
- gPipeline.resetDrawOrders();
- }
-
- if (reset_deferred)
- {
- mWorldViewRectRaw = window_rect;
- LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
- LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() );
- scratch_space.flush();
- scratch_space.release();
- gPipeline.allocateScreenBuffer(original_width, original_height);
-
- }
-
- if (high_res)
- {
- send_agent_resume();
- }
-
- return ret;
-}
-
-bool LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_height, const int num_render_passes)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
- gDisplaySwapBuffers = false;
-
- glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // stencil buffer is deprecated | GL_STENCIL_BUFFER_BIT);
- setCursor(UI_CURSOR_WAIT);
-
- bool prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
- if (prev_draw_ui)
- {
- LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);
- }
-
- bool hide_hud = LLPipeline::sShowHUDAttachments;
- if (hide_hud)
- {
- LLPipeline::sShowHUDAttachments = false;
- }
-
- LLRect window_rect = getWorldViewRectRaw();
-
- S32 original_width = LLPipeline::sRenderDeferred ? gPipeline.mRT->deferredScreen.getWidth() : gViewerWindow->getWorldViewWidthRaw();
- S32 original_height = LLPipeline::sRenderDeferred ? gPipeline.mRT->deferredScreen.getHeight() : gViewerWindow->getWorldViewHeightRaw();
-
- LLRenderTarget scratch_space;
- U32 color_fmt = GL_RGBA;
- if (scratch_space.allocate(image_width, image_height, color_fmt, true))
- {
- if (gPipeline.allocateScreenBuffer(image_width, image_height))
- {
- mWorldViewRectRaw.set(0, image_height, image_width, 0);
-
- scratch_space.bindTarget();
- }
- else
- {
- scratch_space.release();
- gPipeline.allocateScreenBuffer(original_width, original_height);
- }
- }
-
- // we render the scene more than once since this helps
- // greatly with the objects not being drawn in the
- // snapshot when they are drawn in the scene. This is
- // evident when you set this value via the debug setting
- // called 360CaptureNumRenderPasses to 1. The theory is
- // that the missing objects are caused by the sUseOcclusion
- // property in pipeline but that the use in pipeline.cpp
- // lags by a frame or two so rendering more than once
- // appears to help a lot.
- for (int i = 0; i < num_render_passes; ++i)
- {
- // turning this flag off here prohibits the screen swap
- // to present the new page to the viewer - this stops
- // the black flash in between captures when the number
- // of render passes is more than 1. We need to also
- // set it here because code in LLViewerDisplay resets
- // it to true each time.
- gDisplaySwapBuffers = false;
-
- // actually render the scene
- const U32 subfield = 0;
- const bool do_rebuild = true;
- const F32 zoom = 1.0;
- const bool for_snapshot = true;
- display(do_rebuild, zoom, subfield, for_snapshot);
- }
-
- LLImageDataSharedLock lock(raw);
-
- glReadPixels(
- 0, 0,
- image_width,
- image_height,
- GL_RGB, GL_UNSIGNED_BYTE,
- raw->getData()
- );
- stop_glerror();
-
- gDisplaySwapBuffers = false;
- gDepthDirty = true;
-
- if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- if (prev_draw_ui)
- {
- LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);
- }
- }
-
- if (hide_hud)
- {
- LLPipeline::sShowHUDAttachments = true;
- }
-
- setCursor(UI_CURSOR_ARROW);
-
- gPipeline.resetDrawOrders();
- mWorldViewRectRaw = window_rect;
- scratch_space.flush();
- scratch_space.release();
- gPipeline.allocateScreenBuffer(original_width, original_height);
-
- return true;
-}
-
-void display_cube_face();
-
-bool LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 cubeIndex, S32 face, F32 near_clip, bool dynamic_render)
-{
- // NOTE: implementation derived from LLFloater360Capture::capture360Images() and simpleSnapshot
- LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
- LL_PROFILE_GPU_ZONE("cubeSnapshot");
- llassert(LLPipeline::sRenderDeferred);
- llassert(!gCubeSnapshot); //assert a snapshot isn't already in progress
-
- U32 res = gPipeline.mRT->deferredScreen.getWidth();
-
- //llassert(res <= gPipeline.mRT->deferredScreen.getWidth());
- //llassert(res <= gPipeline.mRT->deferredScreen.getHeight());
-
- // save current view/camera settings so we can restore them afterwards
- S32 old_occlusion = LLPipeline::sUseOcclusion;
-
- // set new parameters specific to the 360 requirements
- LLPipeline::sUseOcclusion = 0;
- LLViewerCamera* camera = LLViewerCamera::getInstance();
-
- LLViewerCamera saved_camera = LLViewerCamera::instance();
- glh::matrix4f saved_proj = get_current_projection();
- glh::matrix4f saved_mod = get_current_modelview();
-
- // camera constants for the square, cube map capture image
- camera->setAspect(1.0); // must set aspect ratio first to avoid undesirable clamping of vertical FoV
- camera->setViewNoBroadcast(F_PI_BY_TWO);
- camera->yaw(0.0);
- camera->setOrigin(origin);
- camera->setNear(near_clip);
-
- glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // stencil buffer is deprecated | GL_STENCIL_BUFFER_BIT);
-
- U32 dynamic_render_types[] = {
- LLPipeline::RENDER_TYPE_AVATAR,
- LLPipeline::RENDER_TYPE_CONTROL_AV,
- LLPipeline::RENDER_TYPE_PARTICLES
- };
- constexpr U32 dynamic_render_type_count = sizeof(dynamic_render_types) / sizeof(U32);
- bool prev_dynamic_render_type[dynamic_render_type_count];
-
-
- if (!dynamic_render)
- {
- for (int i = 0; i < dynamic_render_type_count; ++i)
- {
- prev_dynamic_render_type[i] = gPipeline.hasRenderType(dynamic_render_types[i]);
- if (prev_dynamic_render_type[i])
- {
- gPipeline.toggleRenderType(dynamic_render_types[i]);
- }
- }
- }
-
- bool prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
- if (prev_draw_ui)
- {
- LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);
- }
-
- bool hide_hud = LLPipeline::sShowHUDAttachments;
- if (hide_hud)
- {
- LLPipeline::sShowHUDAttachments = false;
- }
- LLRect window_rect = getWorldViewRectRaw();
-
- mWorldViewRectRaw.set(0, res, res, 0);
-
- // these are the 6 directions we will point the camera, see LLCubeMapArray::sTargets
- LLVector3 look_dirs[6] = {
- LLVector3(1, 0, 0),
- LLVector3(-1, 0, 0),
- LLVector3(0, 1, 0),
- LLVector3(0, -1, 0),
- LLVector3(0, 0, 1),
- LLVector3(0, 0, -1)
- };
-
- LLVector3 look_upvecs[6] = {
- LLVector3(0, -1, 0),
- LLVector3(0, -1, 0),
- LLVector3(0, 0, 1),
- LLVector3(0, 0, -1),
- LLVector3(0, -1, 0),
- LLVector3(0, -1, 0)
- };
-
- // for each of six sides of cubemap
- //for (int i = 0; i < 6; ++i)
- int i = face;
- {
- // set up camera to look in each direction
- camera->lookDir(look_dirs[i], look_upvecs[i]);
-
- // turning this flag off here prohibits the screen swap
- // to present the new page to the viewer - this stops
- // the black flash in between captures when the number
- // of render passes is more than 1. We need to also
- // set it here because code in LLViewerDisplay resets
- // it to true each time.
- gDisplaySwapBuffers = false;
-
- // actually render the scene
- gCubeSnapshot = true;
- display_cube_face();
- gCubeSnapshot = false;
- }
-
- gDisplaySwapBuffers = true;
-
- if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- if (prev_draw_ui)
- {
- LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);
- }
- }
-
- if (!dynamic_render)
- {
- for (int i = 0; i < dynamic_render_type_count; ++i)
- {
- if (prev_dynamic_render_type[i])
- {
- gPipeline.toggleRenderType(dynamic_render_types[i]);
- }
- }
- }
-
- if (hide_hud)
- {
- LLPipeline::sShowHUDAttachments = true;
- }
-
- gPipeline.resetDrawOrders();
- mWorldViewRectRaw = window_rect;
-
- // restore original view/camera/avatar settings settings
- *camera = saved_camera;
- set_current_modelview(saved_mod);
- set_current_projection(saved_proj);
- setup3DViewport();
- LLPipeline::sUseOcclusion = old_occlusion;
-
- // ====================================================
- return true;
-}
-
-void LLViewerWindow::destroyWindow()
-{
- if (mWindow)
- {
- LLWindowManager::destroyWindow(mWindow);
- }
- mWindow = NULL;
-}
-
-
-void LLViewerWindow::drawMouselookInstructions()
-{
- // Draw instructions for mouselook ("Press ESC to return to World View" partially transparent at the bottom of the screen.)
- const std::string instructions = LLTrans::getString("LeaveMouselook");
- const LLFontGL* font = LLFontGL::getFont(LLFontDescriptor("SansSerif", "Large", LLFontGL::BOLD));
-
- //to be on top of Bottom bar when it is opened
- const S32 INSTRUCTIONS_PAD = 50;
-
- font->renderUTF8(
- instructions, 0,
- getWorldViewRectScaled().getCenterX(),
- getWorldViewRectScaled().mBottom + INSTRUCTIONS_PAD,
- LLColor4( 1.0f, 1.0f, 1.0f, 0.5f ),
- LLFontGL::HCENTER, LLFontGL::TOP,
- LLFontGL::NORMAL,LLFontGL::DROP_SHADOW);
-}
-
-void* LLViewerWindow::getPlatformWindow() const
-{
- return mWindow->getPlatformWindow();
-}
-
-void* LLViewerWindow::getMediaWindow() const
-{
- return mWindow->getMediaWindow();
-}
-
-void LLViewerWindow::focusClient() const
-{
- return mWindow->focusClient();
-}
-
-LLRootView* LLViewerWindow::getRootView() const
-{
- return mRootView;
-}
-
-LLRect LLViewerWindow::getWorldViewRectScaled() const
-{
- return mWorldViewRectScaled;
-}
-
-S32 LLViewerWindow::getWorldViewHeightScaled() const
-{
- return mWorldViewRectScaled.getHeight();
-}
-
-S32 LLViewerWindow::getWorldViewWidthScaled() const
-{
- return mWorldViewRectScaled.getWidth();
-}
-
-
-S32 LLViewerWindow::getWorldViewHeightRaw() const
-{
- return mWorldViewRectRaw.getHeight();
-}
-
-S32 LLViewerWindow::getWorldViewWidthRaw() const
-{
- return mWorldViewRectRaw.getWidth();
-}
-
-S32 LLViewerWindow::getWindowHeightScaled() const
-{
- return mWindowRectScaled.getHeight();
-}
-
-S32 LLViewerWindow::getWindowWidthScaled() const
-{
- return mWindowRectScaled.getWidth();
-}
-
-S32 LLViewerWindow::getWindowHeightRaw() const
-{
- return mWindowRectRaw.getHeight();
-}
-
-S32 LLViewerWindow::getWindowWidthRaw() const
-{
- return mWindowRectRaw.getWidth();
-}
-
-void LLViewerWindow::setup2DRender()
-{
- // setup ortho camera
- gl_state_for_2d(mWindowRectRaw.getWidth(), mWindowRectRaw.getHeight());
- setup2DViewport();
-}
-
-void LLViewerWindow::setup2DViewport(S32 x_offset, S32 y_offset)
-{
- gGLViewport[0] = mWindowRectRaw.mLeft + x_offset;
- gGLViewport[1] = mWindowRectRaw.mBottom + y_offset;
- gGLViewport[2] = mWindowRectRaw.getWidth();
- gGLViewport[3] = mWindowRectRaw.getHeight();
- glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
-}
-
-
-void LLViewerWindow::setup3DRender()
-{
- // setup perspective camera
- LLViewerCamera::getInstance()->setPerspective(NOT_FOR_SELECTION, mWorldViewRectRaw.mLeft, mWorldViewRectRaw.mBottom, mWorldViewRectRaw.getWidth(), mWorldViewRectRaw.getHeight(), false, LLViewerCamera::getInstance()->getNear(), MAX_FAR_CLIP*2.f);
- setup3DViewport();
-}
-
-void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
- gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset;
- gGLViewport[1] = mWorldViewRectRaw.mBottom + y_offset;
- gGLViewport[2] = mWorldViewRectRaw.getWidth();
- gGLViewport[3] = mWorldViewRectRaw.getHeight();
- glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
-}
-
-void LLViewerWindow::revealIntroPanel()
-{
- if (mProgressView)
- {
- mProgressView->revealIntroPanel();
- }
-}
-
-void LLViewerWindow::initTextures(S32 location_id)
-{
- if (mProgressView)
- {
- mProgressView->initTextures(location_id, LLGridManager::getInstance()->isInProductionGrid());
- }
-}
-
-void LLViewerWindow::setShowProgress(const bool show)
-{
- if (mProgressView)
- {
- mProgressView->setVisible(show);
- }
-}
-
-void LLViewerWindow::setStartupComplete()
-{
- if (mProgressView)
- {
- mProgressView->setStartupComplete();
- }
-}
-
-bool LLViewerWindow::getShowProgress() const
-{
- return (mProgressView && mProgressView->getVisible());
-}
-
-void LLViewerWindow::setProgressString(const std::string& string)
-{
- if (mProgressView)
- {
- mProgressView->setText(string);
- }
-}
-
-void LLViewerWindow::setProgressMessage(const std::string& msg)
-{
- if(mProgressView)
- {
- mProgressView->setMessage(msg);
- }
-}
-
-void LLViewerWindow::setProgressPercent(const F32 percent)
-{
- if (mProgressView)
- {
- mProgressView->setPercent(percent);
- }
-}
-
-void LLViewerWindow::setProgressCancelButtonVisible( bool b, const std::string& label )
-{
- if (mProgressView)
- {
- mProgressView->setCancelButtonVisible( b, label );
- }
-}
-
-LLProgressView *LLViewerWindow::getProgressView() const
-{
- return mProgressView;
-}
-
-void LLViewerWindow::dumpState()
-{
- LL_INFOS() << "LLViewerWindow Active " << S32(mActive) << LL_ENDL;
- LL_INFOS() << "mWindow visible " << S32(mWindow->getVisible())
- << " minimized " << S32(mWindow->getMinimized())
- << LL_ENDL;
-}
-
-void LLViewerWindow::stopGL(bool save_state)
-{
- //Note: --bao
- //if not necessary, do not change the order of the function calls in this function.
- //if change something, make sure it will not break anything.
- //especially be careful to put anything behind gTextureList.destroyGL(save_state);
- if (!gGLManager.mIsDisabled)
- {
- LL_INFOS() << "Shutting down GL..." << LL_ENDL;
-
- // Pause texture decode threads (will get unpaused during main loop)
- LLAppViewer::getTextureCache()->pause();
- LLAppViewer::getTextureFetch()->pause();
-
- gSky.destroyGL();
- stop_glerror();
-
- LLManipTranslate::destroyGL() ;
- stop_glerror();
-
- gBumpImageList.destroyGL();
- stop_glerror();
-
- LLFontGL::destroyAllGL();
- stop_glerror();
-
- LLVOAvatar::destroyGL();
- stop_glerror();
-
- LLVOPartGroup::destroyGL();
-
- LLViewerDynamicTexture::destroyGL();
- stop_glerror();
-
- if (gPipeline.isInit())
- {
- gPipeline.destroyGL();
- }
-
- gBox.cleanupGL();
-
- if(gPostProcess)
- {
- gPostProcess->invalidate();
- }
-
- gTextureList.destroyGL(save_state);
- stop_glerror();
-
- gGLManager.mIsDisabled = true;
- stop_glerror();
-
- //unload shader's
- while (LLGLSLShader::sInstances.size())
- {
- LLGLSLShader* shader = *(LLGLSLShader::sInstances.begin());
- shader->unload();
- }
- }
-}
-
-void LLViewerWindow::restoreGL(const std::string& progress_message)
-{
- //Note: --bao
- //if not necessary, do not change the order of the function calls in this function.
- //if change something, make sure it will not break anything.
- //especially, be careful to put something before gTextureList.restoreGL();
- if (gGLManager.mIsDisabled)
- {
- LL_INFOS() << "Restoring GL..." << LL_ENDL;
- gGLManager.mIsDisabled = false;
-
- initGLDefaults();
- LLGLState::restoreGL();
-
- gTextureList.restoreGL();
-
- // for future support of non-square pixels, and fonts that are properly stretched
- //LLFontGL::destroyDefaultFonts();
- initFonts();
-
- gSky.restoreGL();
- gPipeline.restoreGL();
- LLManipTranslate::restoreGL();
-
- gBumpImageList.restoreGL();
- LLViewerDynamicTexture::restoreGL();
- LLVOAvatar::restoreGL();
- LLVOPartGroup::restoreGL();
-
- gResizeScreenTexture = true;
- gWindowResized = true;
-
- if (isAgentAvatarValid() && gAgentAvatarp->isEditingAppearance())
- {
- LLVisualParamHint::requestHintUpdates();
- }
-
- if (!progress_message.empty())
- {
- gRestoreGLTimer.reset();
- gRestoreGL = true;
- setShowProgress(true);
- setProgressString(progress_message);
- }
- LL_INFOS() << "...Restoring GL done" << LL_ENDL;
- if(!LLAppViewer::instance()->restoreErrorTrap())
- {
- LL_WARNS() << " Someone took over my signal/exception handler (post restoreGL)!" << LL_ENDL;
- }
-
- }
-}
-
-void LLViewerWindow::initFonts(F32 zoom_factor)
-{
- LLFontGL::destroyAllGL();
- // Initialize with possibly different zoom factor
-
- LLFontManager::initClass();
-
- LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"),
- mDisplayScale.mV[VX] * zoom_factor,
- mDisplayScale.mV[VY] * zoom_factor,
- gDirUtilp->getAppRODataDir());
-}
-
-void LLViewerWindow::requestResolutionUpdate()
-{
- mResDirty = true;
-}
-
-static LLTrace::BlockTimerStatHandle FTM_WINDOW_CHECK_SETTINGS("Window Settings");
-
-void LLViewerWindow::checkSettings()
-{
- LL_RECORD_BLOCK_TIME(FTM_WINDOW_CHECK_SETTINGS);
- if (mStatesDirty)
- {
- gGL.refreshState();
- LLViewerShaderMgr::instance()->setShaders();
- mStatesDirty = false;
- }
-
- // We want to update the resolution AFTER the states getting refreshed not before.
- if (mResDirty)
- {
- reshape(getWindowWidthRaw(), getWindowHeightRaw());
- mResDirty = false;
- }
-}
-
-void LLViewerWindow::restartDisplay(bool show_progress_bar)
-{
- LL_INFOS() << "Restaring GL" << LL_ENDL;
- stopGL();
- if (show_progress_bar)
- {
- restoreGL(LLTrans::getString("ProgressChangingResolution"));
- }
- else
- {
- restoreGL();
- }
-}
-
-bool LLViewerWindow::changeDisplaySettings(LLCoordScreen size, bool enable_vsync, bool show_progress_bar)
-{
- //bool was_maximized = gSavedSettings.getBOOL("WindowMaximized");
-
- //gResizeScreenTexture = true;
-
-
- //U32 fsaa = gSavedSettings.getU32("RenderFSAASamples");
- //U32 old_fsaa = mWindow->getFSAASamples();
-
- // if not maximized, use the request size
- if (!mWindow->getMaximized())
- {
- mWindow->setSize(size);
- }
-
- //if (fsaa == old_fsaa)
- {
- return true;
- }
-
-/*
-
- // Close floaters that don't handle settings change
- LLFloaterReg::hideInstance("snapshot");
-
- bool result_first_try = false;
- bool result_second_try = false;
-
- LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
- send_agent_pause();
- LL_INFOS() << "Stopping GL during changeDisplaySettings" << LL_ENDL;
- stopGL();
- mIgnoreActivate = true;
- LLCoordScreen old_size;
- LLCoordScreen old_pos;
- mWindow->getSize(&old_size);
-
- //mWindow->setFSAASamples(fsaa);
-
- result_first_try = mWindow->switchContext(false, size, disable_vsync);
- if (!result_first_try)
- {
- // try to switch back
- //mWindow->setFSAASamples(old_fsaa);
- result_second_try = mWindow->switchContext(false, old_size, disable_vsync);
-
- if (!result_second_try)
- {
- // we are stuck...try once again with a minimal resolution?
- send_agent_resume();
- mIgnoreActivate = false;
- return false;
- }
- }
- send_agent_resume();
-
- LL_INFOS() << "Restoring GL during resolution change" << LL_ENDL;
- if (show_progress_bar)
- {
- restoreGL(LLTrans::getString("ProgressChangingResolution"));
- }
- else
- {
- restoreGL();
- }
-
- if (!result_first_try)
- {
- LLSD args;
- args["RESX"] = llformat("%d",size.mX);
- args["RESY"] = llformat("%d",size.mY);
- LLNotificationsUtil::add("ResolutionSwitchFail", args);
- size = old_size; // for reshape below
- }
-
- bool success = result_first_try || result_second_try;
-
- if (success)
- {
- // maximize window if was maximized, else reposition
- if (was_maximized)
- {
- mWindow->maximize();
- }
- else
- {
- S32 windowX = gSavedSettings.getS32("WindowX");
- S32 windowY = gSavedSettings.getS32("WindowY");
-
- mWindow->setPosition(LLCoordScreen ( windowX, windowY ) );
- }
- }
-
- mIgnoreActivate = false;
- gFocusMgr.setKeyboardFocus(keyboard_focus);
-
- return success;
-
- */
-}
-
-F32 LLViewerWindow::getWorldViewAspectRatio() const
-{
- F32 world_aspect = (F32)mWorldViewRectRaw.getWidth() / (F32)mWorldViewRectRaw.getHeight();
- return world_aspect;
-}
-
-void LLViewerWindow::calcDisplayScale()
-{
- F32 ui_scale_factor = llclamp(gSavedSettings.getF32("UIScaleFactor") * mWindow->getSystemUISize(), MIN_UI_SCALE, MAX_UI_SCALE);
- LLVector2 display_scale;
- display_scale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
- display_scale *= ui_scale_factor;
-
- // limit minimum display scale
- if (display_scale.mV[VX] < MIN_DISPLAY_SCALE || display_scale.mV[VY] < MIN_DISPLAY_SCALE)
- {
- display_scale *= MIN_DISPLAY_SCALE / llmin(display_scale.mV[VX], display_scale.mV[VY]);
- }
-
- if (display_scale != mDisplayScale)
- {
- LL_INFOS() << "Setting display scale to " << display_scale << " for ui scale: " << ui_scale_factor << LL_ENDL;
-
- mDisplayScale = display_scale;
- // Init default fonts
- initFonts();
- }
-}
-
-//static
-LLRect LLViewerWindow::calcScaledRect(const LLRect & rect, const LLVector2& display_scale)
-{
- LLRect res = rect;
- res.mLeft = ll_round((F32)res.mLeft / display_scale.mV[VX]);
- res.mRight = ll_round((F32)res.mRight / display_scale.mV[VX]);
- res.mBottom = ll_round((F32)res.mBottom / display_scale.mV[VY]);
- res.mTop = ll_round((F32)res.mTop / display_scale.mV[VY]);
-
- return res;
-}
-
-S32 LLViewerWindow::getChatConsoleBottomPad()
-{
- S32 offset = 0;
-
- if(gToolBarView)
- offset += gToolBarView->getBottomToolbar()->getRect().getHeight();
-
- return offset;
-}
-
-LLRect LLViewerWindow::getChatConsoleRect()
-{
- LLRect full_window(0, getWindowHeightScaled(), getWindowWidthScaled(), 0);
- LLRect console_rect = full_window;
-
- const S32 CONSOLE_PADDING_TOP = 24;
- const S32 CONSOLE_PADDING_LEFT = 24;
- const S32 CONSOLE_PADDING_RIGHT = 10;
-
- console_rect.mTop -= CONSOLE_PADDING_TOP;
- console_rect.mBottom += getChatConsoleBottomPad();
-
- console_rect.mLeft += CONSOLE_PADDING_LEFT;
-
- static const bool CHAT_FULL_WIDTH = gSavedSettings.getBOOL("ChatFullWidth");
-
- if (CHAT_FULL_WIDTH)
- {
- console_rect.mRight -= CONSOLE_PADDING_RIGHT;
- }
- else
- {
- // Make console rect somewhat narrow so having inventory open is
- // less of a problem.
- console_rect.mRight = console_rect.mLeft + 2 * getWindowWidthScaled() / 3;
- }
-
- return console_rect;
-}
-
-void LLViewerWindow::reshapeStatusBarContainer()
-{
- LLPanel* status_bar_container = getRootView()->getChild<LLPanel>("status_bar_container");
- LLView* nav_bar_container = getRootView()->getChild<LLView>("nav_bar_container");
-
- S32 new_height = status_bar_container->getRect().getHeight();
- S32 new_width = status_bar_container->getRect().getWidth();
-
- if (gSavedSettings.getBOOL("ShowNavbarNavigationPanel"))
- {
- // Navigation bar is outside visible area, expand status_bar_container to show it
- new_height += nav_bar_container->getRect().getHeight();
- }
- else
- {
- // collapse status_bar_container
- new_height -= nav_bar_container->getRect().getHeight();
- }
- status_bar_container->reshape(new_width, new_height, true);
-}
-
-void LLViewerWindow::resetStatusBarContainer()
-{
- LLNavigationBar* navbar = LLNavigationBar::getInstance();
- if (gSavedSettings.getBOOL("ShowNavbarNavigationPanel") || navbar->getVisible())
- {
- // was previously showing navigation bar
- LLView* nav_bar_container = getRootView()->getChild<LLView>("nav_bar_container");
- LLPanel* status_bar_container = getRootView()->getChild<LLPanel>("status_bar_container");
- S32 new_height = status_bar_container->getRect().getHeight();
- S32 new_width = status_bar_container->getRect().getWidth();
- new_height -= nav_bar_container->getRect().getHeight();
- status_bar_container->reshape(new_width, new_height, true);
- }
-}
-//----------------------------------------------------------------------------
-
-
-void LLViewerWindow::setUIVisibility(bool visible)
-{
- mUIVisible = visible;
-
- if (!visible)
- {
- gAgentCamera.changeCameraToThirdPerson(false);
- gFloaterView->hideAllFloaters();
- }
- else
- {
- gFloaterView->showHiddenFloaters();
- }
-
- if (gToolBarView)
- {
- gToolBarView->setToolBarsVisible(visible);
- }
-
- LLNavigationBar::getInstance()->setVisible(visible ? gSavedSettings.getBOOL("ShowNavbarNavigationPanel") : false);
- LLPanelTopInfoBar::getInstance()->setVisible(visible? gSavedSettings.getBOOL("ShowMiniLocationPanel") : false);
- mRootView->getChildView("status_bar_container")->setVisible(visible);
-}
-
-bool LLViewerWindow::getUIVisibility()
-{
- return mUIVisible;
-}
-
-////////////////////////////////////////////////////////////////////////////
-//
-// LLPickInfo
-//
-LLPickInfo::LLPickInfo()
- : mKeyMask(MASK_NONE),
- mPickCallback(NULL),
- mPickType(PICK_INVALID),
- mWantSurfaceInfo(false),
- mObjectFace(-1),
- mUVCoords(-1.f, -1.f),
- mSTCoords(-1.f, -1.f),
- mXYCoords(-1, -1),
- mIntersection(),
- mNormal(),
- mTangent(),
- mBinormal(),
- mHUDIcon(NULL),
- mPickTransparent(false),
- mPickRigged(false),
- mPickParticle(false)
-{
-}
-
-LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos,
- MASK keyboard_mask,
- bool pick_transparent,
- bool pick_rigged,
- bool pick_particle,
- bool pick_reflection_probe,
- bool pick_uv_coords,
- bool pick_unselectable,
- void (*pick_callback)(const LLPickInfo& pick_info))
- : mMousePt(mouse_pos),
- mKeyMask(keyboard_mask),
- mPickCallback(pick_callback),
- mPickType(PICK_INVALID),
- mWantSurfaceInfo(pick_uv_coords),
- mObjectFace(-1),
- mUVCoords(-1.f, -1.f),
- mSTCoords(-1.f, -1.f),
- mXYCoords(-1, -1),
- mNormal(),
- mTangent(),
- mBinormal(),
- mHUDIcon(NULL),
- mPickTransparent(pick_transparent),
- mPickRigged(pick_rigged),
- mPickParticle(pick_particle),
- mPickReflectionProbe(pick_reflection_probe),
- mPickUnselectable(pick_unselectable)
-{
-}
-
-void LLPickInfo::fetchResults()
-{
-
- S32 face_hit = -1;
- LLVector4a intersection, normal;
- LLVector4a tangent;
-
- LLVector2 uv;
-
- LLHUDIcon* hit_icon = gViewerWindow->cursorIntersectIcon(mMousePt.mX, mMousePt.mY, 512.f, &intersection);
-
- LLVector4a origin;
- origin.load3(LLViewerCamera::getInstance()->getOrigin().mV);
- F32 icon_dist = 0.f;
- LLVector4a start;
- LLVector4a end;
- LLVector4a particle_end;
-
- if (hit_icon)
- {
- LLVector4a delta;
- delta.setSub(intersection, origin);
- icon_dist = delta.getLength3().getF32();
- }
-
- LLViewerObject* hit_object = gViewerWindow->cursorIntersect(mMousePt.mX, mMousePt.mY, 512.f,
- NULL, -1, mPickTransparent, mPickRigged, mPickUnselectable, mPickReflectionProbe, &face_hit,
- &intersection, &uv, &normal, &tangent, &start, &end);
-
- mPickPt = mMousePt;
-
- U32 te_offset = face_hit > -1 ? face_hit : 0;
-
- if (mPickParticle)
- { //get the end point of line segement to use for particle raycast
- if (hit_object)
- {
- particle_end = intersection;
- }
- else
- {
- particle_end = end;
- }
- }
-
- LLViewerObject* objectp = hit_object;
-
-
- LLVector4a delta;
- delta.setSub(origin, intersection);
-
- if (hit_icon &&
- (!objectp ||
- icon_dist < delta.getLength3().getF32()))
- {
- // was this name referring to a hud icon?
- mHUDIcon = hit_icon;
- mPickType = PICK_ICON;
- mPosGlobal = mHUDIcon->getPositionGlobal();
-
- }
- else if (objectp)
- {
- if( objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH )
- {
- // Hit land
- mPickType = PICK_LAND;
- mObjectID.setNull(); // land has no id
-
- // put global position into land_pos
- LLVector3d land_pos;
- if (!gViewerWindow->mousePointOnLandGlobal(mPickPt.mX, mPickPt.mY, &land_pos, mPickUnselectable))
- {
- // The selected point is beyond the draw distance or is otherwise
- // not selectable. Return before calling mPickCallback().
- return;
- }
-
- // Fudge the land focus a little bit above ground.
- mPosGlobal = land_pos + LLVector3d::z_axis * 0.1f;
- }
- else
- {
- if(isFlora(objectp))
- {
- mPickType = PICK_FLORA;
- }
- else
- {
- mPickType = PICK_OBJECT;
- }
-
- LLVector3 v_intersection(intersection.getF32ptr());
-
- mObjectOffset = gAgentCamera.calcFocusOffset(objectp, v_intersection, mPickPt.mX, mPickPt.mY);
- mObjectID = objectp->mID;
- mObjectFace = (te_offset == NO_FACE) ? -1 : (S32)te_offset;
-
-
-
- mPosGlobal = gAgent.getPosGlobalFromAgent(v_intersection);
-
- if (mWantSurfaceInfo)
- {
- getSurfaceInfo();
- }
- }
- }
-
- if (mPickParticle)
- { //search for closest particle to click origin out to intersection point
- S32 part_face = -1;
-
- LLVOPartGroup* group = gPipeline.lineSegmentIntersectParticle(start, particle_end, NULL, &part_face);
- if (group)
- {
- mParticleOwnerID = group->getPartOwner(part_face);
- mParticleSourceID = group->getPartSource(part_face);
- }
- }
-
- if (mPickCallback)
- {
- mPickCallback(*this);
- }
-}
-
-LLPointer<LLViewerObject> LLPickInfo::getObject() const
-{
- return gObjectList.findObject( mObjectID );
-}
-
-void LLPickInfo::updateXYCoords()
-{
- if (mObjectFace > -1)
- {
- const LLTextureEntry* tep = getObject()->getTE(mObjectFace);
- LLPointer<LLViewerTexture> imagep = LLViewerTextureManager::getFetchedTexture(tep->getID());
- if(mUVCoords.mV[VX] >= 0.f && mUVCoords.mV[VY] >= 0.f && imagep.notNull())
- {
- mXYCoords.mX = ll_round(mUVCoords.mV[VX] * (F32)imagep->getWidth());
- mXYCoords.mY = ll_round((1.f - mUVCoords.mV[VY]) * (F32)imagep->getHeight());
- }
- }
-}
-
-void LLPickInfo::getSurfaceInfo()
-{
- // set values to uninitialized - this is what we return if no intersection is found
- mObjectFace = -1;
- mUVCoords = LLVector2(-1, -1);
- mSTCoords = LLVector2(-1, -1);
- mXYCoords = LLCoordScreen(-1, -1);
- mIntersection = LLVector3(0,0,0);
- mNormal = LLVector3(0,0,0);
- mBinormal = LLVector3(0,0,0);
- mTangent = LLVector4(0,0,0,0);
-
- LLVector4a tangent;
- LLVector4a intersection;
- LLVector4a normal;
-
- tangent.clear();
- normal.clear();
- intersection.clear();
-
- LLViewerObject* objectp = getObject();
-
- if (objectp)
- {
- if (gViewerWindow->cursorIntersect(ll_round((F32)mMousePt.mX), ll_round((F32)mMousePt.mY), 1024.f,
- objectp, -1, mPickTransparent, mPickRigged, mPickUnselectable, mPickReflectionProbe,
- &mObjectFace,
- &intersection,
- &mSTCoords,
- &normal,
- &tangent))
- {
- // if we succeeded with the intersect above, compute the texture coordinates:
-
- if (objectp->mDrawable.notNull() && mObjectFace > -1)
- {
- LLFace* facep = objectp->mDrawable->getFace(mObjectFace);
- if (facep)
- {
- mUVCoords = facep->surfaceToTexture(mSTCoords, intersection, normal);
- }
- }
-
- mIntersection.set(intersection.getF32ptr());
- mNormal.set(normal.getF32ptr());
- mTangent.set(tangent.getF32ptr());
-
- //extrapoloate binormal from normal and tangent
-
- LLVector4a binormal;
- binormal.setCross3(normal, tangent);
- binormal.mul(tangent.getF32ptr()[3]);
-
- mBinormal.set(binormal.getF32ptr());
-
- mBinormal.normalize();
- mNormal.normalize();
- mTangent.normalize();
-
- // and XY coords:
- updateXYCoords();
-
- }
- }
-}
-
-//static
-bool LLPickInfo::isFlora(LLViewerObject* object)
-{
- if (!object) return false;
-
- LLPCode pcode = object->getPCode();
-
- if( (LL_PCODE_LEGACY_GRASS == pcode)
- || (LL_PCODE_LEGACY_TREE == pcode)
- || (LL_PCODE_TREE_NEW == pcode))
- {
- return true;
- }
- return false;
-}
+/**
+ * @file llviewerwindow.cpp
+ * @brief Implementation of the LLViewerWindow class.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llviewerwindow.h"
+
+
+// system library includes
+#include <stdio.h>
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+#include <boost/filesystem.hpp>
+#include <boost/lambda/core.hpp>
+#include <boost/regex.hpp>
+
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llcommandhandler.h"
+#include "llcommunicationchannel.h"
+#include "llfloaterreg.h"
+#include "llhudicon.h"
+#include "llmeshrepository.h"
+#include "llnotificationhandler.h"
+#include "llpanellogin.h"
+#include "llsetkeybinddialog.h"
+#include "llviewerinput.h"
+#include "llviewermenu.h"
+
+#include "llviewquery.h"
+#include "llxmltree.h"
+#include "llslurl.h"
+#include "llrender.h"
+
+#include "stringize.h"
+
+//
+// TODO: Many of these includes are unnecessary. Remove them.
+//
+
+// linden library includes
+#include "llaudioengine.h" // mute on minimize
+#include "llchatentry.h"
+#include "indra_constants.h"
+#include "llassetstorage.h"
+#include "llerrorcontrol.h"
+#include "llfontgl.h"
+#include "llmousehandler.h"
+#include "llrect.h"
+#include "llsky.h"
+#include "llstring.h"
+#include "llui.h"
+#include "lluuid.h"
+#include "llview.h"
+#include "llxfermanager.h"
+#include "message.h"
+#include "object_flags.h"
+#include "lltimer.h"
+#include "llviewermenu.h"
+#include "lltooltip.h"
+#include "llmediaentry.h"
+#include "llurldispatcher.h"
+#include "raytrace.h"
+
+// newview includes
+#include "llagent.h"
+#include "llbox.h"
+#include "llchicletbar.h"
+#include "llconsole.h"
+#include "llviewercontrol.h"
+#include "llcylinder.h"
+#include "lldebugview.h"
+#include "lldir.h"
+#include "lldrawable.h"
+#include "lldrawpoolalpha.h"
+#include "lldrawpoolbump.h"
+#include "lldrawpoolwater.h"
+#include "llmaniptranslate.h"
+#include "llface.h"
+#include "llfeaturemanager.h"
+#include "llfilepicker.h"
+#include "llfirstuse.h"
+#include "llfloater.h"
+#include "llfloaterbuyland.h"
+#include "llfloatercamera.h"
+#include "llfloaterland.h"
+#include "llfloaterinspect.h"
+#include "llfloatermap.h"
+#include "llfloaternamedesc.h"
+#include "llfloaterpreference.h"
+#include "llfloatersnapshot.h"
+#include "llfloatertools.h"
+#include "llfloaterworldmap.h"
+#include "llfocusmgr.h"
+#include "llfontfreetype.h"
+#include "llgesturemgr.h"
+#include "llglheaders.h"
+#include "lltooltip.h"
+#include "llhudmanager.h"
+#include "llhudobject.h"
+#include "llhudview.h"
+#include "llimage.h"
+#include "llimagej2c.h"
+#include "llimageworker.h"
+#include "llkeyboard.h"
+#include "lllineeditor.h"
+#include "llmenugl.h"
+#include "llmenuoptionpathfindingrebakenavmesh.h"
+#include "llmodaldialog.h"
+#include "llmorphview.h"
+#include "llmoveview.h"
+#include "llnavigationbar.h"
+#include "llnotificationhandler.h"
+#include "llpaneltopinfobar.h"
+#include "llpopupview.h"
+#include "llpreviewtexture.h"
+#include "llprogressview.h"
+#include "llresmgr.h"
+#include "llselectmgr.h"
+#include "llrootview.h"
+#include "llrendersphere.h"
+#include "llstartup.h"
+#include "llstatusbar.h"
+#include "llstatview.h"
+#include "llsurface.h"
+#include "llsurfacepatch.h"
+#include "lltexlayer.h"
+#include "lltextbox.h"
+#include "lltexturecache.h"
+#include "lltexturefetch.h"
+#include "lltextureview.h"
+#include "lltoast.h"
+#include "lltool.h"
+#include "lltoolbarview.h"
+#include "lltoolcomp.h"
+#include "lltooldraganddrop.h"
+#include "lltoolface.h"
+#include "lltoolfocus.h"
+#include "lltoolgrab.h"
+#include "lltoolmgr.h"
+#include "lltoolmorph.h"
+#include "lltoolpie.h"
+#include "lltoolselectland.h"
+#include "lltrans.h"
+#include "lluictrlfactory.h"
+#include "llurldispatcher.h" // SLURL from other app instance
+#include "llversioninfo.h"
+#include "llvieweraudio.h"
+#include "llviewercamera.h"
+#include "llviewergesture.h"
+#include "llviewertexturelist.h"
+#include "llviewerinventory.h"
+#include "llviewerinput.h"
+#include "llviewermedia.h"
+#include "llviewermediafocus.h"
+#include "llviewermenu.h"
+#include "llviewermessage.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h"
+#include "llviewershadermgr.h"
+#include "llviewerstats.h"
+#include "llvoavatarself.h"
+#include "llvopartgroup.h"
+#include "llvovolume.h"
+#include "llworld.h"
+#include "llworldmapview.h"
+#include "pipeline.h"
+#include "llappviewer.h"
+#include "llviewerdisplay.h"
+#include "llspatialpartition.h"
+#include "llviewerjoystick.h"
+#include "llviewermenufile.h" // LLFilePickerReplyThread
+#include "llviewernetwork.h"
+#include "llpostprocess.h"
+#include "llfloaterimnearbychat.h"
+#include "llagentui.h"
+#include "llwearablelist.h"
+
+#include "llviewereventrecorder.h"
+
+#include "llnotifications.h"
+#include "llnotificationsutil.h"
+#include "llnotificationmanager.h"
+
+#include "llfloaternotificationsconsole.h"
+
+#include "llwindowlistener.h"
+#include "llviewerwindowlistener.h"
+#include "llpaneltopinfobar.h"
+#include "llcleanup.h"
+
+#if LL_WINDOWS
+#include <tchar.h> // For Unicode conversion methods
+#include "llwindowwin32.h" // For AltGr handling
+#endif
+
+//
+// Globals
+//
+void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
+void swap();
+
+extern bool gDebugClicks;
+extern bool gDisplaySwapBuffers;
+extern bool gDepthDirty;
+extern bool gResizeScreenTexture;
+extern bool gCubeSnapshot;
+extern bool gSnapshotNoPost;
+
+LLViewerWindow *gViewerWindow = NULL;
+
+LLFrameTimer gAwayTimer;
+LLFrameTimer gAwayTriggerTimer;
+
+bool gShowOverlayTitle = false;
+
+LLViewerObject* gDebugRaycastObject = NULL;
+LLVOPartGroup* gDebugRaycastParticle = NULL;
+LLVector4a gDebugRaycastIntersection;
+LLVector4a gDebugRaycastParticleIntersection;
+LLVector2 gDebugRaycastTexCoord;
+LLVector4a gDebugRaycastNormal;
+LLVector4a gDebugRaycastTangent;
+S32 gDebugRaycastFaceHit;
+LLVector4a gDebugRaycastStart;
+LLVector4a gDebugRaycastEnd;
+
+// HUD display lines in lower right
+bool gDisplayWindInfo = false;
+bool gDisplayCameraPos = false;
+bool gDisplayFOV = false;
+bool gDisplayBadge = false;
+
+static const U8 NO_FACE = 255;
+bool gQuietSnapshot = false;
+
+// Minimum value for UIScaleFactor, also defined in preferences, ui_scale_slider
+static const F32 MIN_UI_SCALE = 0.75f;
+// 4.0 in preferences, but win10 supports larger scaling and value is used more as
+// sanity check, so leaving space for larger values from DPI updates.
+static const F32 MAX_UI_SCALE = 7.0f;
+static const F32 MIN_DISPLAY_SCALE = 0.75f;
+
+static const char KEY_MOUSELOOK = 'M';
+
+static LLCachedControl<std::string> sSnapshotBaseName(LLCachedControl<std::string>(gSavedPerAccountSettings, "SnapshotBaseName", "Snapshot"));
+static LLCachedControl<std::string> sSnapshotDir(LLCachedControl<std::string>(gSavedPerAccountSettings, "SnapshotBaseDir", ""));
+
+LLTrace::SampleStatHandle<> LLViewerWindow::sMouseVelocityStat("Mouse Velocity");
+
+
+class RecordToChatConsoleRecorder : public LLError::Recorder
+{
+public:
+ virtual void recordMessage(LLError::ELevel level,
+ const std::string& message)
+ {
+ //FIXME: this is NOT thread safe, and will do bad things when a warning is issued from a non-UI thread
+
+ // only log warnings to chat console
+ //if (level == LLError::LEVEL_WARN)
+ //{
+ //LLFloaterChat* chat_floater = LLFloaterReg::findTypedInstance<LLFloaterChat>("chat");
+ //if (chat_floater && gSavedSettings.getBOOL("WarningsAsChat"))
+ //{
+ // LLChat chat;
+ // chat.mText = message;
+ // chat.mSourceType = CHAT_SOURCE_SYSTEM;
+
+ // chat_floater->addChat(chat, false, false);
+ //}
+ //}
+ }
+};
+
+class RecordToChatConsole : public LLSingleton<RecordToChatConsole>
+{
+ LLSINGLETON(RecordToChatConsole);
+public:
+ void startRecorder() { LLError::addRecorder(mRecorder); }
+ void stopRecorder() { LLError::removeRecorder(mRecorder); }
+
+private:
+ LLError::RecorderPtr mRecorder;
+};
+
+RecordToChatConsole::RecordToChatConsole():
+ mRecorder(new RecordToChatConsoleRecorder())
+{
+ mRecorder->showTags(false);
+ mRecorder->showLocation(false);
+ mRecorder->showMultiline(true);
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Print Utility
+//
+
+// Convert a normalized float (-1.0 <= x <= +1.0) to a fixed 1.4 format string:
+//
+// s#.####
+//
+// Where:
+// s sign character; space if x is positiv, minus if negative
+// # decimal digits
+//
+// This is similar to printf("%+.4f") except positive numbers are NOT cluttered with a leading '+' sign.
+// NOTE: This does NOT null terminate the output
+void normalized_float_to_string(const float x, char *out_str)
+{
+ static const unsigned char DECIMAL_BCD2[] =
+ {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99
+ };
+
+ int neg = (x < 0);
+ int rem = neg
+ ? (int)(x * -10000.)
+ : (int)(x * 10000.);
+
+ int d10 = rem % 100; rem /= 100;
+ int d32 = rem % 100; rem /= 100;
+
+ out_str[6] = '0' + ((DECIMAL_BCD2[ d10 ] >> 0) & 0xF);
+ out_str[5] = '0' + ((DECIMAL_BCD2[ d10 ] >> 4) & 0xF);
+ out_str[4] = '0' + ((DECIMAL_BCD2[ d32 ] >> 0) & 0xF);
+ out_str[3] = '0' + ((DECIMAL_BCD2[ d32 ] >> 4) & 0xF);
+ out_str[2] = '.';
+ out_str[1] = '0' + (rem & 1);
+ out_str[0] = " -"[neg]; // Could always show '+' for positive but this clutters up the common case
+}
+
+// normalized float
+// printf("%-.4f %-.4f %-.4f")
+// Params:
+// float &matrix_row[4]
+// int matrix_cell_index
+// string out_buffer (size 32)
+// Note: The buffer is assumed to be pre-filled with spaces
+#define MATRIX_ROW_N32_TO_STR(matrix_row, i, out_buffer) \
+ normalized_float_to_string(matrix_row[i+0], out_buffer + 0); \
+ normalized_float_to_string(matrix_row[i+1], out_buffer + 11); \
+ normalized_float_to_string(matrix_row[i+2], out_buffer + 22); \
+ out_buffer[31] = 0;
+
+
+// regular float
+// sprintf(buffer, "%-8.2f %-8.2f %-8.2f", matrix_row[i+0], matrix_row[i+1], matrix_row[i+2]);
+// Params:
+// float &matrix_row[4]
+// int matrix_cell_index
+// char out_buffer[32]
+// Note: The buffer is assumed to be pre-filled with spaces
+#define MATRIX_ROW_F32_TO_STR(matrix_row, i, out_buffer) { \
+ static const char *format[3] = { \
+ "%-8.2f" , /* 0 */ \
+ "> 99K ", /* 1 */ \
+ "< -99K " /* 2 */ \
+ }; \
+ \
+ F32 temp_0 = matrix_row[i+0]; \
+ F32 temp_1 = matrix_row[i+1]; \
+ F32 temp_2 = matrix_row[i+2]; \
+ \
+ U8 flag_0 = (((U8)(temp_0 < -99999.99)) << 1) | ((U8)(temp_0 > 99999.99)); \
+ U8 flag_1 = (((U8)(temp_1 < -99999.99)) << 1) | ((U8)(temp_1 > 99999.99)); \
+ U8 flag_2 = (((U8)(temp_2 < -99999.99)) << 1) | ((U8)(temp_2 > 99999.99)); \
+ \
+ if (temp_0 < 0.f) out_buffer[ 0] = '-'; \
+ if (temp_1 < 0.f) out_buffer[11] = '-'; \
+ if (temp_2 < 0.f) out_buffer[22] = '-'; \
+ \
+ sprintf(out_buffer+ 1,format[flag_0],fabsf(temp_0)); out_buffer[ 1+8] = ' '; \
+ sprintf(out_buffer+12,format[flag_1],fabsf(temp_1)); out_buffer[12+8] = ' '; \
+ sprintf(out_buffer+23,format[flag_2],fabsf(temp_2)); out_buffer[23+8] = 0 ; \
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// LLDebugText
+//
+
+static LLTrace::BlockTimerStatHandle FTM_DISPLAY_DEBUG_TEXT("Display Debug Text");
+
+class LLDebugText
+{
+private:
+ struct Line
+ {
+ Line(const std::string& in_text, S32 in_x, S32 in_y) : text(in_text), x(in_x), y(in_y) {}
+ std::string text;
+ S32 x,y;
+ };
+
+ LLViewerWindow *mWindow;
+
+ typedef std::vector<Line> line_list_t;
+ line_list_t mLineList;
+ LLColor4 mTextColor;
+
+ LLColor4 mBackColor;
+ LLRect mBackRectCamera1;
+ LLRect mBackRectCamera2;
+
+ void addText(S32 x, S32 y, const std::string &text)
+ {
+ mLineList.push_back(Line(text, x, y));
+ }
+
+ void clearText() { mLineList.clear(); }
+
+public:
+ LLDebugText(LLViewerWindow* window) : mWindow(window) {}
+
+ void update()
+ {
+ if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ clearText();
+ return;
+ }
+
+ static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic", false) ;
+
+ std::string wind_vel_text;
+ std::string wind_vector_text;
+ std::string rwind_vel_text;
+ std::string rwind_vector_text;
+ std::string audio_text;
+
+ static const std::string beacon_particle = LLTrans::getString("BeaconParticle");
+ static const std::string beacon_physical = LLTrans::getString("BeaconPhysical");
+ static const std::string beacon_scripted = LLTrans::getString("BeaconScripted");
+ static const std::string beacon_scripted_touch = LLTrans::getString("BeaconScriptedTouch");
+ static const std::string beacon_sound = LLTrans::getString("BeaconSound");
+ static const std::string beacon_media = LLTrans::getString("BeaconMedia");
+ static const std::string beacon_sun = LLTrans::getString("BeaconSun");
+ static const std::string beacon_moon = LLTrans::getString("BeaconMoon");
+ static const std::string particle_hiding = LLTrans::getString("ParticleHiding");
+
+ // Draw the statistics in a light gray
+ // and in a thin font
+ mTextColor = LLColor4( 0.86f, 0.86f, 0.86f, 1.f );
+
+ // Draw stuff growing up from right lower corner of screen
+ S32 x_right = mWindow->getWorldViewWidthScaled();
+ S32 xpos = x_right - 400;
+ xpos = llmax(xpos, 0);
+ S32 ypos = 64;
+ const S32 y_inc = 20;
+
+ // Camera matrix text is hard to see again a white background
+ // Add a dark background underneath the matrices for readability (contrast)
+ mBackRectCamera1.mLeft = xpos;
+ mBackRectCamera1.mRight = x_right;
+ mBackRectCamera1.mTop = -1;
+ mBackRectCamera1.mBottom = -1;
+ mBackRectCamera2 = mBackRectCamera1;
+
+ mBackColor = LLUIColorTable::instance().getColor( "MenuDefaultBgColor" );
+
+ clearText();
+
+ if (gSavedSettings.getBOOL("DebugShowTime"))
+ {
+ F32 time = gFrameTimeSeconds;
+ S32 hours = (S32)(time / (60*60));
+ S32 mins = (S32)((time - hours*(60*60)) / 60);
+ S32 secs = (S32)((time - hours*(60*60) - mins*60));
+ addText(xpos, ypos, llformat("Time: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc;
+ }
+
+ if (gSavedSettings.getBOOL("DebugShowMemory"))
+ {
+ addText(xpos, ypos,
+ STRINGIZE("Memory: " << (LLMemory::getCurrentRSS() / 1024) << " (KB)"));
+ ypos += y_inc;
+ }
+
+ if (gDisplayCameraPos)
+ {
+ std::string camera_view_text;
+ std::string camera_center_text;
+ std::string agent_view_text;
+ std::string agent_left_text;
+ std::string agent_center_text;
+ std::string agent_root_center_text;
+
+ LLVector3d tvector; // Temporary vector to hold data for printing.
+
+ // Update camera center, camera view, wind info every other frame
+ tvector = gAgent.getPositionGlobal();
+ agent_center_text = llformat("AgentCenter %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+
+ if (isAgentAvatarValid())
+ {
+ tvector = gAgent.getPosGlobalFromAgent(gAgentAvatarp->mRoot->getWorldPosition());
+ agent_root_center_text = llformat("AgentRootCenter %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+ }
+ else
+ {
+ agent_root_center_text = "---";
+ }
+
+
+ tvector = LLVector4(gAgent.getFrameAgent().getAtAxis());
+ agent_view_text = llformat("AgentAtAxis %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+
+ tvector = LLVector4(gAgent.getFrameAgent().getLeftAxis());
+ agent_left_text = llformat("AgentLeftAxis %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+
+ tvector = gAgentCamera.getCameraPositionGlobal();
+ camera_center_text = llformat("CameraCenter %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+
+ tvector = LLVector4(LLViewerCamera::getInstance()->getAtAxis());
+ camera_view_text = llformat("CameraAtAxis %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+
+ addText(xpos, ypos, agent_center_text); ypos += y_inc;
+ addText(xpos, ypos, agent_root_center_text); ypos += y_inc;
+ addText(xpos, ypos, agent_view_text); ypos += y_inc;
+ addText(xpos, ypos, agent_left_text); ypos += y_inc;
+ addText(xpos, ypos, camera_center_text); ypos += y_inc;
+ addText(xpos, ypos, camera_view_text); ypos += y_inc;
+ }
+
+ if (gDisplayWindInfo)
+ {
+ wind_vel_text = llformat("Wind velocity %.2f m/s", gWindVec.magVec());
+ wind_vector_text = llformat("Wind vector %.2f %.2f %.2f", gWindVec.mV[0], gWindVec.mV[1], gWindVec.mV[2]);
+ rwind_vel_text = llformat("RWind vel %.2f m/s", gRelativeWindVec.magVec());
+ rwind_vector_text = llformat("RWind vec %.2f %.2f %.2f", gRelativeWindVec.mV[0], gRelativeWindVec.mV[1], gRelativeWindVec.mV[2]);
+
+ addText(xpos, ypos, wind_vel_text); ypos += y_inc;
+ addText(xpos, ypos, wind_vector_text); ypos += y_inc;
+ addText(xpos, ypos, rwind_vel_text); ypos += y_inc;
+ addText(xpos, ypos, rwind_vector_text); ypos += y_inc;
+ }
+ if (gDisplayWindInfo)
+ {
+ audio_text = llformat("Audio for wind: %d", gAudiop ? gAudiop->isWindEnabled() : -1);
+ addText(xpos, ypos, audio_text); ypos += y_inc;
+ }
+ if (gDisplayFOV)
+ {
+ addText(xpos, ypos, llformat("FOV: %2.1f deg", RAD_TO_DEG * LLViewerCamera::getInstance()->getView()));
+ ypos += y_inc;
+ }
+ if (gDisplayBadge)
+ {
+ addText(xpos, ypos+(y_inc/2), llformat("Hippos!", RAD_TO_DEG * LLViewerCamera::getInstance()->getView()));
+ ypos += y_inc * 2;
+ }
+
+ /*if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ {
+ addText(xpos + 200, ypos, llformat("Flycam"));
+ ypos += y_inc;
+ }*/
+
+ if (gSavedSettings.getBOOL("DebugShowRenderInfo"))
+ {
+ LLTrace::Recording& last_frame_recording = LLTrace::get_frame_recording().getLastRecording();
+
+ //show streaming cost/triangle count of known prims in current region OR selection
+ {
+ F32 cost = 0.f;
+ S32 count = 0;
+ S32 vcount = 0;
+ S32 object_count = 0;
+ S32 total_bytes = 0;
+ S32 visible_bytes = 0;
+
+ const char* label = "Region";
+ if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 0)
+ { //region
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region)
+ {
+ for (U32 i = 0; i < gObjectList.getNumObjects(); ++i)
+ {
+ LLViewerObject* object = gObjectList.getObject(i);
+ if (object &&
+ object->getRegion() == region &&
+ object->getVolume())
+ {
+ object_count++;
+ S32 bytes = 0;
+ S32 visible = 0;
+ cost += object->getStreamingCost();
+ LLMeshCostData costs;
+ if (object->getCostData(costs))
+ {
+ bytes = costs.getSizeTotal();
+ visible = costs.getSizeByLOD(object->getLOD());
+ }
+
+ S32 vt = 0;
+ count += object->getTriangleCount(&vt);
+ vcount += vt;
+ total_bytes += bytes;
+ visible_bytes += visible;
+ }
+ }
+ }
+ }
+ else
+ {
+ label = "Selection";
+ cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectStreamingCost(&total_bytes, &visible_bytes);
+ count = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectTriangleCount(&vcount);
+ object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+ }
+
+ addText(xpos,ypos, llformat("%s streaming cost: %.1f", label, cost));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat(" %.3f KTris, %.3f KVerts, %.1f/%.1f KB, %d objects",
+ count/1000.f, vcount/1000.f, visible_bytes/1024.f, total_bytes/1024.f, object_count));
+ ypos += y_inc;
+
+ }
+
+ addText(xpos, ypos, llformat("%d Texture Binds", LLImageGL::sBindCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Unique Textures", LLImageGL::sUniqueCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Render Calls", (U32)last_frame_recording.getSampleCount(LLPipeline::sStatBatchSize)));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d/%d Objects Active", gObjectList.getNumActiveObjects(), gObjectList.getNumObjects()));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Matrix Ops", gPipeline.mMatrixOpCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Texture Matrix Ops", gPipeline.mTextureMatrixOps));
+ ypos += y_inc;
+
+ gPipeline.mTextureMatrixOps = 0;
+ gPipeline.mMatrixOpCount = 0;
+
+ if (last_frame_recording.getSampleCount(LLPipeline::sStatBatchSize) > 0)
+ {
+ addText(xpos, ypos, llformat("Batch min/max/mean: %d/%d/%d", (U32)last_frame_recording.getMin(LLPipeline::sStatBatchSize), (U32)last_frame_recording.getMax(LLPipeline::sStatBatchSize), (U32)last_frame_recording.getMean(LLPipeline::sStatBatchSize)));
+ }
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("UI Verts/Calls: %d/%d", LLRender::sUIVerts, LLRender::sUICalls));
+ LLRender::sUICalls = LLRender::sUIVerts = 0;
+ ypos += y_inc;
+
+ addText(xpos,ypos, llformat("%d/%d Nodes visible", gPipeline.mNumVisibleNodes, LLSpatialGroup::sNodeCount));
+
+ ypos += y_inc;
+
+ if (!LLOcclusionCullingGroup::sPendingQueries.empty())
+ {
+ addText(xpos,ypos, llformat("%d Queries pending", LLOcclusionCullingGroup::sPendingQueries.size()));
+ ypos += y_inc;
+ }
+
+
+ addText(xpos,ypos, llformat("%d Avatars visible", LLVOAvatar::sNumVisibleAvatars));
+
+ ypos += y_inc;
+
+ addText(xpos,ypos, llformat("%d Lights visible", LLPipeline::sVisibleLightCount));
+
+ ypos += y_inc;
+
+ if (gMeshRepo.meshRezEnabled())
+ {
+ addText(xpos, ypos, llformat("%.3f MB Mesh Data Received", LLMeshRepository::sBytesReceived/(1024.f*1024.f)));
+
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d/%d Mesh HTTP Requests/Retries", LLMeshRepository::sHTTPRequestCount,
+ LLMeshRepository::sHTTPRetryCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d/%d Mesh LOD Pending/Processing", LLMeshRepository::sLODPending, LLMeshRepository::sLODProcessing));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%.3f/%.3f MB Mesh Cache Read/Write ", LLMeshRepository::sCacheBytesRead/(1024.f*1024.f), LLMeshRepository::sCacheBytesWritten/(1024.f*1024.f)));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%.3f/%.3f MB Mesh Skins/Decompositions Memory", LLMeshRepository::sCacheBytesSkins / (1024.f*1024.f), LLMeshRepository::sCacheBytesDecomps / (1024.f*1024.f)));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%.3f MB Mesh Headers Memory", LLMeshRepository::sCacheBytesHeaders / (1024.f*1024.f)));
+
+ ypos += y_inc;
+ }
+
+ gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0;
+ }
+ if (gSavedSettings.getBOOL("DebugShowAvatarRenderInfo"))
+ {
+ std::map<std::string, LLVOAvatar*> sorted_avs;
+
+ std::vector<LLCharacter*>::iterator sort_iter = LLCharacter::sInstances.begin();
+ while (sort_iter != LLCharacter::sInstances.end())
+ {
+ LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*sort_iter);
+ if (avatar &&
+ !avatar->isDead()) // Not dead yet
+ {
+ // Stuff into a sorted map so the display is ordered
+ sorted_avs[avatar->getFullname()] = avatar;
+ }
+ sort_iter++;
+ }
+
+ std::string trunc_name;
+ std::map<std::string, LLVOAvatar*>::reverse_iterator av_iter = sorted_avs.rbegin(); // Put "A" at the top
+ while (av_iter != sorted_avs.rend())
+ {
+ LLVOAvatar* avatar = av_iter->second;
+
+ avatar->calculateUpdateRenderComplexity(); // Make sure the numbers are up-to-date
+
+ trunc_name = utf8str_truncate(avatar->getFullname(), 16);
+ addText(xpos, ypos, llformat("%s : %s, complexity %d, area %.2f",
+ trunc_name.c_str(),
+ LLVOAvatar::rezStatusToString(avatar->getRezzedStatus()).c_str(),
+ avatar->getVisualComplexity(),
+ avatar->getAttachmentSurfaceArea()));
+ ypos += y_inc;
+ av_iter++;
+ }
+ }
+ if (gSavedSettings.getBOOL("DebugShowRenderMatrices"))
+ {
+ char camera_lines[8][32];
+ memset(camera_lines, ' ', sizeof(camera_lines));
+
+ // Projection last column is always <0,0,-1.0001,0>
+ // Projection last row is always <0,0,-0.2>
+ mBackRectCamera1.mBottom = ypos - y_inc + 2;
+ MATRIX_ROW_N32_TO_STR(gGLProjection, 12,camera_lines[7]); addText(xpos, ypos, std::string(camera_lines[7])); ypos += y_inc;
+ MATRIX_ROW_N32_TO_STR(gGLProjection, 8,camera_lines[6]); addText(xpos, ypos, std::string(camera_lines[6])); ypos += y_inc;
+ MATRIX_ROW_N32_TO_STR(gGLProjection, 4,camera_lines[5]); addText(xpos, ypos, std::string(camera_lines[5])); ypos += y_inc; mBackRectCamera1.mTop = ypos + 2;
+ MATRIX_ROW_N32_TO_STR(gGLProjection, 0,camera_lines[4]); addText(xpos, ypos, std::string(camera_lines[4])); ypos += y_inc; mBackRectCamera2.mBottom = ypos + 2;
+
+ addText(xpos, ypos, "Projection Matrix");
+ ypos += y_inc;
+
+ // View last column is always <0,0,0,1>
+ MATRIX_ROW_F32_TO_STR(gGLModelView, 12,camera_lines[3]); addText(xpos, ypos, std::string(camera_lines[3])); ypos += y_inc;
+ MATRIX_ROW_N32_TO_STR(gGLModelView, 8,camera_lines[2]); addText(xpos, ypos, std::string(camera_lines[2])); ypos += y_inc;
+ MATRIX_ROW_N32_TO_STR(gGLModelView, 4,camera_lines[1]); addText(xpos, ypos, std::string(camera_lines[1])); ypos += y_inc; mBackRectCamera2.mTop = ypos + 2;
+ MATRIX_ROW_N32_TO_STR(gGLModelView, 0,camera_lines[0]); addText(xpos, ypos, std::string(camera_lines[0])); ypos += y_inc;
+
+ addText(xpos, ypos, "View Matrix");
+ ypos += y_inc;
+ }
+ // disable use of glReadPixels which messes up nVidia nSight graphics debugging
+ if (gSavedSettings.getBOOL("DebugShowColor") && !LLRender::sNsightDebugSupport)
+ {
+ U8 color[4];
+ LLCoordGL coord = gViewerWindow->getCurrentMouse();
+
+ // Convert x,y to raw pixel coords
+ S32 x_raw = llround(coord.mX * gViewerWindow->getWindowWidthRaw() / (F32) gViewerWindow->getWindowWidthScaled());
+ S32 y_raw = llround(coord.mY * gViewerWindow->getWindowHeightRaw() / (F32) gViewerWindow->getWindowHeightScaled());
+
+ glReadPixels(x_raw, y_raw, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
+ addText(xpos, ypos, llformat("Pixel <%1d, %1d> R:%1d G:%1d B:%1d A:%1d", x_raw, y_raw, color[0], color[1], color[2], color[3]));
+ ypos += y_inc;
+ }
+
+ // only display these messages if we are actually rendering beacons at this moment
+ if (LLPipeline::getRenderBeacons() && LLFloaterReg::instanceVisible("beacons"))
+ {
+ if (LLPipeline::getRenderMOAPBeacons())
+ {
+ addText(xpos, ypos, "Viewing media beacons (white)");
+ ypos += y_inc;
+ }
+
+ if (LLPipeline::toggleRenderTypeControlNegated(LLPipeline::RENDER_TYPE_PARTICLES))
+ {
+ addText(xpos, ypos, particle_hiding);
+ ypos += y_inc;
+ }
+
+ if (LLPipeline::getRenderParticleBeacons())
+ {
+ addText(xpos, ypos, "Viewing particle beacons (blue)");
+ ypos += y_inc;
+ }
+
+ if (LLPipeline::getRenderSoundBeacons())
+ {
+ addText(xpos, ypos, "Viewing sound beacons (yellow)");
+ ypos += y_inc;
+ }
+
+ if (LLPipeline::getRenderScriptedBeacons())
+ {
+ addText(xpos, ypos, beacon_scripted);
+ ypos += y_inc;
+ }
+ else
+ if (LLPipeline::getRenderScriptedTouchBeacons())
+ {
+ addText(xpos, ypos, beacon_scripted_touch);
+ ypos += y_inc;
+ }
+
+ if (LLPipeline::getRenderPhysicalBeacons())
+ {
+ addText(xpos, ypos, "Viewing physical object beacons (green)");
+ ypos += y_inc;
+ }
+ }
+
+ static LLUICachedControl<bool> show_sun_beacon("sunbeacon", false);
+ static LLUICachedControl<bool> show_moon_beacon("moonbeacon", false);
+
+ if (show_sun_beacon)
+ {
+ addText(xpos, ypos, beacon_sun);
+ ypos += y_inc;
+ }
+ if (show_moon_beacon)
+ {
+ addText(xpos, ypos, beacon_moon);
+ ypos += y_inc;
+ }
+
+ if(log_texture_traffic)
+ {
+ U32 old_y = ypos ;
+ for(S32 i = LLViewerTexture::BOOST_NONE; i < LLViewerTexture::MAX_GL_IMAGE_CATEGORY; i++)
+ {
+ if(gTotalTextureBytesPerBoostLevel[i] > (S32Bytes)0)
+ {
+ addText(xpos, ypos, llformat("Boost_Level %d: %.3f MB", i, F32Megabytes(gTotalTextureBytesPerBoostLevel[i]).value()));
+ ypos += y_inc;
+ }
+ }
+ if(ypos != old_y)
+ {
+ addText(xpos, ypos, "Network traffic for textures:");
+ ypos += y_inc;
+ }
+ }
+
+ if (gSavedSettings.getBOOL("DebugShowTextureInfo"))
+ {
+ LLViewerObject* objectp = NULL ;
+
+ LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode();
+ if (nodep)
+ {
+ objectp = nodep->getObject();
+ }
+
+ if (objectp && !objectp->isDead())
+ {
+ S32 num_faces = objectp->mDrawable->getNumFaces() ;
+ std::set<LLViewerFetchedTexture*> tex_list;
+
+ for(S32 i = 0 ; i < num_faces; i++)
+ {
+ LLFace* facep = objectp->mDrawable->getFace(i) ;
+ if(facep)
+ {
+ LLViewerFetchedTexture* tex = dynamic_cast<LLViewerFetchedTexture*>(facep->getTexture()) ;
+ if(tex)
+ {
+ if(tex_list.find(tex) != tex_list.end())
+ {
+ continue ; //already displayed.
+ }
+ tex_list.insert(tex);
+
+ std::string uuid_str;
+ tex->getID().toString(uuid_str);
+ uuid_str = uuid_str.substr(0,7);
+
+ addText(xpos, ypos, llformat("ID: %s v_size: %.3f", uuid_str.c_str(), tex->getMaxVirtualSize()));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("discard level: %d desired level: %d Missing: %s", tex->getDiscardLevel(),
+ tex->getDesiredDiscardLevel(), tex->isMissingAsset() ? "Y" : "N"));
+ ypos += y_inc;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void draw()
+ {
+ LL_RECORD_BLOCK_TIME(FTM_DISPLAY_DEBUG_TEXT);
+
+ // Camera matrix text is hard to see again a white background
+ // Add a dark background underneath the matrices for readability (contrast)
+ if (mBackRectCamera1.mTop >= 0)
+ {
+ mBackColor.setAlpha( 0.75f );
+ gl_rect_2d(mBackRectCamera1, mBackColor, true);
+
+ mBackColor.setAlpha( 0.66f );
+ gl_rect_2d(mBackRectCamera2, mBackColor, true);
+ }
+
+ for (line_list_t::iterator iter = mLineList.begin();
+ iter != mLineList.end(); ++iter)
+ {
+ const Line& line = *iter;
+ LLFontGL::getFontMonospace()->renderUTF8(line.text, 0, (F32)line.x, (F32)line.y, mTextColor,
+ LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL, LLFontGL::NO_SHADOW);
+ }
+ }
+
+};
+
+void LLViewerWindow::updateDebugText()
+{
+ mDebugText->update();
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// LLViewerWindow
+//
+
+LLViewerWindow::Params::Params()
+: title("title"),
+ name("name"),
+ x("x"),
+ y("y"),
+ width("width"),
+ height("height"),
+ min_width("min_width"),
+ min_height("min_height"),
+ fullscreen("fullscreen", false),
+ ignore_pixel_depth("ignore_pixel_depth", false)
+{}
+
+
+void LLViewerWindow::handlePieMenu(S32 x, S32 y, MASK mask)
+{
+ if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() && gAgent.isInitialized())
+ {
+ // If the current tool didn't process the click, we should show
+ // the pie menu. This can be done by passing the event to the pie
+ // menu tool.
+ LLToolPie::getInstance()->handleRightMouseDown(x, y, mask);
+ }
+}
+
+bool LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, bool down, bool& is_toolmgr_action)
+{
+ const char* buttonname = "";
+ const char* buttonstatestr = "";
+ S32 x = pos.mX;
+ S32 y = pos.mY;
+ x = ll_round((F32)x / mDisplayScale.mV[VX]);
+ y = ll_round((F32)y / mDisplayScale.mV[VY]);
+
+ // Handle non-consuming global keybindings, like voice
+ gViewerInput.handleGlobalBindsMouse(clicktype, mask, down);
+
+ // only send mouse clicks to UI if UI is visible
+ if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+
+ if (down)
+ {
+ buttonstatestr = "down" ;
+ }
+ else
+ {
+ buttonstatestr = "up" ;
+ }
+
+ switch (clicktype)
+ {
+ case CLICK_LEFT:
+ mLeftMouseDown = down;
+ buttonname = "Left";
+ break;
+ case CLICK_RIGHT:
+ mRightMouseDown = down;
+ buttonname = "Right";
+ break;
+ case CLICK_MIDDLE:
+ mMiddleMouseDown = down;
+ buttonname = "Middle";
+ break;
+ case CLICK_DOUBLELEFT:
+ mLeftMouseDown = down;
+ buttonname = "Left Double Click";
+ break;
+ case CLICK_BUTTON4:
+ buttonname = "Button 4";
+ break;
+ case CLICK_BUTTON5:
+ buttonname = "Button 5";
+ break;
+ default:
+ break; // COUNT and NONE
+ }
+
+ LLView::sMouseHandlerMessage.clear();
+
+ if (gMenuBarView)
+ {
+ // stop ALT-key access to menu
+ gMenuBarView->resetMenuTrigger();
+ }
+
+ if (gDebugClicks)
+ {
+ LL_INFOS() << "ViewerWindow " << buttonname << " mouse " << buttonstatestr << " at " << x << "," << y << LL_ENDL;
+ }
+
+ // Make sure we get a corresponding mouseup event, even if the mouse leaves the window
+ if (down)
+ mWindow->captureMouse();
+ else
+ mWindow->releaseMouse();
+
+ // Indicate mouse was active
+ LLUI::getInstance()->resetMouseIdleTimer();
+
+ // Don't let the user move the mouse out of the window until mouse up.
+ if( LLToolMgr::getInstance()->getCurrentTool()->clipMouseWhenDown() )
+ {
+ mWindow->setMouseClipping(down);
+ }
+
+ LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
+ if( mouse_captor )
+ {
+ S32 local_x;
+ S32 local_y;
+ mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
+ if (LLView::sDebugMouseHandling)
+ {
+ LL_INFOS() << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << LL_ENDL;
+ }
+
+ bool r = mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down);
+ if (r) {
+
+ LL_DEBUGS() << "LLViewerWindow::handleAnyMouseClick viewer with mousecaptor calling updatemouseeventinfo - local_x|global x "<< local_x << " " << x << "local/global y " << local_y << " " << y << LL_ENDL;
+
+ LLViewerEventRecorder::instance().setMouseGlobalCoords(x,y);
+ LLViewerEventRecorder::instance().logMouseEvent(std::string(buttonstatestr),std::string(buttonname));
+
+ }
+ else if (down && clicktype == CLICK_RIGHT)
+ {
+ handlePieMenu(x, y, mask);
+ r = true;
+ }
+ return r;
+ }
+
+ // Mark the click as handled and return if we aren't within the root view to avoid spurious bugs
+ if( !mRootView->pointInView(x, y) )
+ {
+ return true;
+ }
+ // Give the UI views a chance to process the click
+
+ bool r= mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) ;
+ if (r)
+ {
+
+ LL_DEBUGS() << "LLViewerWindow::handleAnyMouseClick calling updatemouseeventinfo - global x "<< " " << x << "global y " << y << "buttonstate: " << buttonstatestr << " buttonname " << buttonname << LL_ENDL;
+
+ LLViewerEventRecorder::instance().setMouseGlobalCoords(x,y);
+
+ // Clear local coords - this was a click on root window so these are not needed
+ // By not including them, this allows the test skeleton generation tool to be smarter when generating code
+ // the code generator can be smarter because when local coords are present it can try the xui path with local coords
+ // and fallback to global coordinates only if needed.
+ // The drawback to this approach is sometimes a valid xui path will appear to work fine, but NOT interact with the UI element
+ // (VITA support not implemented yet or not visible to VITA due to widget further up xui path not being visible to VITA)
+ // For this reason it's best to provide hints where possible here by leaving out local coordinates
+ LLViewerEventRecorder::instance().setMouseLocalCoords(-1,-1);
+ LLViewerEventRecorder::instance().logMouseEvent(buttonstatestr,buttonname);
+
+ if (LLView::sDebugMouseHandling)
+ {
+ LL_INFOS() << buttonname << " Mouse " << buttonstatestr << " " << LLViewerEventRecorder::instance().get_xui() << LL_ENDL;
+ }
+ return true;
+ } else if (LLView::sDebugMouseHandling)
+ {
+ LL_INFOS() << buttonname << " Mouse " << buttonstatestr << " not handled by view" << LL_ENDL;
+ }
+ }
+
+ // Do not allow tool manager to handle mouseclicks if we have disconnected
+ if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) )
+ {
+ LLViewerEventRecorder::instance().clear_xui();
+ is_toolmgr_action = true;
+ return true;
+ }
+
+ if (down && clicktype == CLICK_RIGHT)
+ {
+ handlePieMenu(x, y, mask);
+ return true;
+ }
+
+ // If we got this far on a down-click, it wasn't handled.
+ // Up-clicks, though, are always handled as far as the OS is concerned.
+ bool default_rtn = !down;
+ return default_rtn;
+}
+
+bool LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ mAllowMouseDragging = false;
+ if (!mMouseDownTimer.getStarted())
+ {
+ mMouseDownTimer.start();
+ }
+ else
+ {
+ mMouseDownTimer.reset();
+ }
+ bool down = true;
+ //handleMouse() loops back to LLViewerWindow::handleAnyMouseClick
+ return gViewerInput.handleMouse(window, pos, mask, CLICK_LEFT, down);
+}
+
+bool LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ // try handling as a double-click first, then a single-click if that
+ // wasn't handled.
+ bool down = true;
+ if (gViewerInput.handleMouse(window, pos, mask, CLICK_DOUBLELEFT, down))
+ {
+ return true;
+ }
+ return handleMouseDown(window, pos, mask);
+}
+
+bool LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ if (mMouseDownTimer.getStarted())
+ {
+ mMouseDownTimer.stop();
+ }
+ bool down = false;
+ return gViewerInput.handleMouse(window, pos, mask, CLICK_LEFT, down);
+}
+bool LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ bool down = true;
+ return gViewerInput.handleMouse(window, pos, mask, CLICK_RIGHT, down);
+}
+
+bool LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ bool down = false;
+ return gViewerInput.handleMouse(window, pos, mask, CLICK_RIGHT, down);
+}
+
+bool LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ bool down = true;
+ gViewerInput.handleMouse(window, pos, mask, CLICK_MIDDLE, down);
+
+ // Always handled as far as the OS is concerned.
+ return true;
+}
+
+LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, LLWindowCallbacks::DragNDropAction action, std::string data)
+{
+ LLWindowCallbacks::DragNDropResult result = LLWindowCallbacks::DND_NONE;
+
+ const bool prim_media_dnd_enabled = gSavedSettings.getBOOL("PrimMediaDragNDrop");
+ const bool slurl_dnd_enabled = gSavedSettings.getBOOL("SLURLDragNDrop");
+
+ if ( prim_media_dnd_enabled || slurl_dnd_enabled )
+ {
+ switch(action)
+ {
+ // Much of the handling for these two cases is the same.
+ case LLWindowCallbacks::DNDA_TRACK:
+ case LLWindowCallbacks::DNDA_DROPPED:
+ case LLWindowCallbacks::DNDA_START_TRACKING:
+ {
+ bool drop = (LLWindowCallbacks::DNDA_DROPPED == action);
+
+ if (slurl_dnd_enabled)
+ {
+ LLSLURL dropped_slurl(data);
+ if(dropped_slurl.isSpatial())
+ {
+ if (drop)
+ {
+ LLURLDispatcher::dispatch( dropped_slurl.getSLURLString(), LLCommandHandler::NAV_TYPE_CLICKED, NULL, true );
+ return LLWindowCallbacks::DND_MOVE;
+ }
+ return LLWindowCallbacks::DND_COPY;
+ }
+ }
+
+ if (prim_media_dnd_enabled)
+ {
+ LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY,
+ true /* pick_transparent */,
+ false /* pick_rigged */);
+
+ S32 object_face = pick_info.mObjectFace;
+ std::string url = data;
+
+ LL_DEBUGS() << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << LL_ENDL;
+
+ LLVOVolume *obj = dynamic_cast<LLVOVolume*>(static_cast<LLViewerObject*>(pick_info.getObject()));
+
+ if (obj && !obj->getRegion()->getCapability("ObjectMedia").empty())
+ {
+ LLTextureEntry *te = obj->getTE(object_face);
+
+ // can modify URL if we can modify the object or we have navigate permissions
+ bool allow_modify_url = obj->permModify() || obj->hasMediaPermission( te->getMediaData(), LLVOVolume::MEDIA_PERM_INTERACT );
+
+ if (te && allow_modify_url )
+ {
+ if (drop)
+ {
+ // object does NOT have media already
+ if ( ! te->hasMedia() )
+ {
+ // we are allowed to modify the object
+ if ( obj->permModify() )
+ {
+ // Create new media entry
+ LLSD media_data;
+ // XXX Should we really do Home URL too?
+ media_data[LLMediaEntry::HOME_URL_KEY] = url;
+ media_data[LLMediaEntry::CURRENT_URL_KEY] = url;
+ media_data[LLMediaEntry::AUTO_PLAY_KEY] = true;
+ obj->syncMediaData(object_face, media_data, true, true);
+ // XXX This shouldn't be necessary, should it ?!?
+ if (obj->getMediaImpl(object_face))
+ obj->getMediaImpl(object_face)->navigateReload();
+ obj->sendMediaDataUpdate();
+
+ result = LLWindowCallbacks::DND_COPY;
+ }
+ }
+ else
+ // object HAS media already
+ {
+ // URL passes the whitelist
+ if (te->getMediaData()->checkCandidateUrl( url ) )
+ {
+ // just navigate to the URL
+ if (obj->getMediaImpl(object_face))
+ {
+ obj->getMediaImpl(object_face)->navigateTo(url);
+ }
+ else
+ {
+ // This is very strange. Navigation should
+ // happen via the Impl, but we don't have one.
+ // This sends it to the server, which /should/
+ // trigger us getting it. Hopefully.
+ LLSD media_data;
+ media_data[LLMediaEntry::CURRENT_URL_KEY] = url;
+ obj->syncMediaData(object_face, media_data, true, true);
+ obj->sendMediaDataUpdate();
+ }
+ result = LLWindowCallbacks::DND_LINK;
+
+ }
+ }
+ LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
+ mDragHoveredObject = NULL;
+
+ }
+ else
+ {
+ // Check the whitelist, if there's media (otherwise just show it)
+ if (te->getMediaData() == NULL || te->getMediaData()->checkCandidateUrl(url))
+ {
+ if ( obj != mDragHoveredObject)
+ {
+ // Highlight the dragged object
+ LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
+ mDragHoveredObject = obj;
+ LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject);
+ }
+ result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK;
+
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case LLWindowCallbacks::DNDA_STOP_TRACKING:
+ // The cleanup case below will make sure things are unhilighted if necessary.
+ break;
+ }
+
+ if (prim_media_dnd_enabled &&
+ result == LLWindowCallbacks::DND_NONE && !mDragHoveredObject.isNull())
+ {
+ LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
+ mDragHoveredObject = NULL;
+ }
+ }
+
+ return result;
+}
+
+bool LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ bool down = false;
+ gViewerInput.handleMouse(window, pos, mask, CLICK_MIDDLE, down);
+
+ // Always handled as far as the OS is concerned.
+ return true;
+}
+
+bool LLViewerWindow::handleOtherMouse(LLWindow *window, LLCoordGL pos, MASK mask, S32 button, bool down)
+{
+ switch (button)
+ {
+ case 4:
+ gViewerInput.handleMouse(window, pos, mask, CLICK_BUTTON4, down);
+ break;
+ case 5:
+ gViewerInput.handleMouse(window, pos, mask, CLICK_BUTTON5, down);
+ break;
+ default:
+ break;
+ }
+
+ // Always handled as far as the OS is concerned.
+ return true;
+}
+
+bool LLViewerWindow::handleOtherMouseDown(LLWindow *window, LLCoordGL pos, MASK mask, S32 button)
+{
+ return handleOtherMouse(window, pos, mask, button, true);
+}
+
+bool LLViewerWindow::handleOtherMouseUp(LLWindow *window, LLCoordGL pos, MASK mask, S32 button)
+{
+ return handleOtherMouse(window, pos, mask, button, false);
+}
+
+// WARNING: this is potentially called multiple times per frame
+void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ S32 x = pos.mX;
+ S32 y = pos.mY;
+
+ x = ll_round((F32)x / mDisplayScale.mV[VX]);
+ y = ll_round((F32)y / mDisplayScale.mV[VY]);
+
+ mMouseInWindow = true;
+
+ // Save mouse point for access during idle() and display()
+
+ LLCoordGL mouse_point(x, y);
+
+ if (mouse_point != mCurrentMousePoint)
+ {
+ LLUI::getInstance()->resetMouseIdleTimer();
+ }
+
+ saveLastMouse(mouse_point);
+
+ mWindow->showCursorFromMouseMove();
+
+ if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME
+ && !gDisconnected)
+ {
+ gAgent.clearAFK();
+ }
+}
+
+void LLViewerWindow::handleMouseDragged(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ if (mMouseDownTimer.getStarted())
+ {
+ if (mMouseDownTimer.getElapsedTimeF32() > 0.1)
+ {
+ mAllowMouseDragging = true;
+ mMouseDownTimer.stop();
+ }
+ }
+ if(mAllowMouseDragging || !LLToolCamera::getInstance()->hasMouseCapture())
+ {
+ handleMouseMove(window, pos, mask);
+ }
+}
+
+void LLViewerWindow::handleMouseLeave(LLWindow *window)
+{
+ // Note: we won't get this if we have captured the mouse.
+ llassert( gFocusMgr.getMouseCapture() == NULL );
+ mMouseInWindow = false;
+ LLToolTipMgr::instance().blockToolTips();
+}
+
+bool LLViewerWindow::handleCloseRequest(LLWindow *window)
+{
+ // User has indicated they want to close, but we may need to ask
+ // about modified documents.
+ LLAppViewer::instance()->userQuit();
+ // Don't quit immediately
+ return false;
+}
+
+void LLViewerWindow::handleQuit(LLWindow *window)
+{
+ if (gNonInteractive)
+ {
+ LLAppViewer::instance()->requestQuit();
+ }
+ else
+ {
+ LL_INFOS() << "Window forced quit" << LL_ENDL;
+ LLAppViewer::instance()->forceQuit();
+ }
+}
+
+void LLViewerWindow::handleResize(LLWindow *window, S32 width, S32 height)
+{
+ reshape(width, height);
+ mResDirty = true;
+}
+
+// The top-level window has gained focus (e.g. via ALT-TAB)
+void LLViewerWindow::handleFocus(LLWindow *window)
+{
+ gFocusMgr.setAppHasFocus(true);
+ LLModalDialog::onAppFocusGained();
+
+ gAgent.onAppFocusGained();
+ LLToolMgr::getInstance()->onAppFocusGained();
+
+ // See if we're coming in with modifier keys held down
+ if (gKeyboard)
+ {
+ gKeyboard->resetMaskKeys();
+ }
+
+ // resume foreground running timer
+ // since we artifically limit framerate when not frontmost
+ gForegroundTime.unpause();
+}
+
+// The top-level window has lost focus (e.g. via ALT-TAB)
+void LLViewerWindow::handleFocusLost(LLWindow *window)
+{
+ gFocusMgr.setAppHasFocus(false);
+ //LLModalDialog::onAppFocusLost();
+ LLToolMgr::getInstance()->onAppFocusLost();
+ gFocusMgr.setMouseCapture( NULL );
+
+ if (gMenuBarView)
+ {
+ // stop ALT-key access to menu
+ gMenuBarView->resetMenuTrigger();
+ }
+
+ // restore mouse cursor
+ showCursor();
+ getWindow()->setMouseClipping(false);
+
+ // If losing focus while keys are down, handle them as
+ // an 'up' to correctly release states, then reset states
+ if (gKeyboard)
+ {
+ gKeyboard->resetKeyDownAndHandle();
+ gKeyboard->resetKeys();
+ }
+
+ // pause timer that tracks total foreground running time
+ gForegroundTime.pause();
+}
+
+
+bool LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, bool repeated)
+{
+ // Handle non-consuming global keybindings, like voice
+ // Never affects event processing.
+ gViewerInput.handleGlobalBindsKeyDown(key, mask);
+
+ if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME)
+ {
+ gAgent.clearAFK();
+ }
+
+ // *NOTE: We want to interpret KEY_RETURN later when it arrives as
+ // a Unicode char, not as a keydown. Otherwise when client frame
+ // rate is really low, hitting return sends your chat text before
+ // it's all entered/processed.
+ if (key == KEY_RETURN && mask == MASK_NONE)
+ {
+ // RIDER: although, at times some of the controlls (in particular the CEF viewer
+ // would like to know about the KEYDOWN for an enter key... so ask and pass it along.
+ LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+ if (keyboard_focus && !keyboard_focus->wantsReturnKey())
+ return false;
+ }
+
+ // remaps, handles ignored cases and returns back to viewer window.
+ return gViewerInput.handleKey(key, mask, repeated);
+}
+
+bool LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask)
+{
+ // Handle non-consuming global keybindings, like voice
+ // Never affects event processing.
+ gViewerInput.handleGlobalBindsKeyUp(key, mask);
+
+ // Let the inspect tool code check for ALT key to set LLToolSelectRect active instead LLToolCamera
+ LLToolCompInspect * tool_inspectp = LLToolCompInspect::getInstance();
+ if (LLToolMgr::getInstance()->getCurrentTool() == tool_inspectp)
+ {
+ tool_inspectp->keyUp(key, mask);
+ }
+
+ return gViewerInput.handleKeyUp(key, mask);
+}
+
+void LLViewerWindow::handleScanKey(KEY key, bool key_down, bool key_up, bool key_level)
+{
+ LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
+ gViewerInput.scanKey(key, key_down, key_up, key_level);
+ return; // Be clear this function returns nothing
+}
+
+
+
+
+bool LLViewerWindow::handleActivate(LLWindow *window, bool activated)
+{
+ if (activated)
+ {
+ mActive = true;
+ send_agent_resume();
+ gAgent.clearAFK();
+
+ // Unmute audio
+ audio_update_volume();
+ }
+ else
+ {
+ mActive = false;
+
+ // if the user has chosen to go Away automatically after some time, then go Away when minimizing
+ if (gSavedSettings.getS32("AFKTimeout"))
+ {
+ gAgent.setAFK();
+ }
+
+ // SL-53351: Make sure we're not in mouselook when minimised, to prevent control issues
+ if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+
+ send_agent_pause();
+
+ // Mute audio
+ audio_update_volume();
+ }
+ return true;
+}
+
+bool LLViewerWindow::handleActivateApp(LLWindow *window, bool activating)
+{
+ //if (!activating) gAgentCamera.changeCameraToDefault();
+
+ LLViewerJoystick::getInstance()->setNeedsReset(true);
+ return false;
+}
+
+
+void LLViewerWindow::handleMenuSelect(LLWindow *window, S32 menu_item)
+{
+}
+
+
+bool LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height)
+{
+ // *TODO: Enable similar information output for other platforms? DK 2011-02-18
+#if LL_WINDOWS
+ if (gHeadlessClient)
+ {
+ HWND window_handle = (HWND)window->getPlatformWindow();
+ PAINTSTRUCT ps;
+ HDC hdc;
+
+ RECT wnd_rect;
+ wnd_rect.left = 0;
+ wnd_rect.top = 0;
+ wnd_rect.bottom = 200;
+ wnd_rect.right = 500;
+
+ hdc = BeginPaint(window_handle, &ps);
+ //SetBKColor(hdc, RGB(255, 255, 255));
+ FillRect(hdc, &wnd_rect, CreateSolidBrush(RGB(255, 255, 255)));
+
+ std::string temp_str;
+ LLTrace::Recording& recording = LLViewerStats::instance().getRecording();
+ temp_str = llformat( "FPS %3.1f Phy FPS %2.1f Time Dil %1.3f", /* Flawfinder: ignore */
+ recording.getPerSec(LLStatViewer::FPS), //mFPSStat.getMeanPerSec(),
+ recording.getLastValue(LLStatViewer::SIM_PHYSICS_FPS),
+ recording.getLastValue(LLStatViewer::SIM_TIME_DILATION));
+ S32 len = temp_str.length();
+ TextOutA(hdc, 0, 0, temp_str.c_str(), len);
+
+
+ LLVector3d pos_global = gAgent.getPositionGlobal();
+ temp_str = llformat( "Avatar pos %6.1lf %6.1lf %6.1lf", pos_global.mdV[0], pos_global.mdV[1], pos_global.mdV[2]);
+ len = temp_str.length();
+ TextOutA(hdc, 0, 25, temp_str.c_str(), len);
+
+ TextOutA(hdc, 0, 50, "Set \"HeadlessClient FALSE\" in settings.ini file to reenable", 61);
+ EndPaint(window_handle, &ps);
+ return true;
+ }
+#endif
+ return false;
+}
+
+
+void LLViewerWindow::handleScrollWheel(LLWindow *window, S32 clicks)
+{
+ handleScrollWheel( clicks );
+}
+
+void LLViewerWindow::handleScrollHWheel(LLWindow *window, S32 clicks)
+{
+ handleScrollHWheel(clicks);
+}
+
+void LLViewerWindow::handleWindowBlock(LLWindow *window)
+{
+ send_agent_pause();
+}
+
+void LLViewerWindow::handleWindowUnblock(LLWindow *window)
+{
+ send_agent_resume();
+}
+
+void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data)
+{
+ const S32 SLURL_MESSAGE_TYPE = 0;
+ switch (data_type)
+ {
+ case SLURL_MESSAGE_TYPE:
+ // received URL
+ std::string url = (const char*)data;
+ LLMediaCtrl* web = NULL;
+ const bool trusted_browser = false;
+ // don't treat slapps coming from external browsers as "clicks" as this would bypass throttling
+ if (LLURLDispatcher::dispatch(url, LLCommandHandler::NAV_TYPE_EXTERNAL, web, trusted_browser))
+ {
+ // bring window to foreground, as it has just been "launched" from a URL
+ mWindow->bringToFront();
+ }
+ break;
+ }
+}
+
+bool LLViewerWindow::handleTimerEvent(LLWindow *window)
+{
+ //TODO: just call this every frame from gatherInput instead of using a convoluted 30fps timer callback
+ if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ {
+ LLViewerJoystick::getInstance()->updateStatus();
+ return true;
+ }
+ return false;
+}
+
+bool LLViewerWindow::handleDeviceChange(LLWindow *window)
+{
+ // give a chance to use a joystick after startup (hot-plugging)
+ if (!LLViewerJoystick::getInstance()->isJoystickInitialized() )
+ {
+ LLViewerJoystick::getInstance()->init(true);
+ return true;
+ }
+ return false;
+}
+
+bool LLViewerWindow::handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height)
+{
+ if (ui_scale_factor >= MIN_UI_SCALE && ui_scale_factor <= MAX_UI_SCALE)
+ {
+ LLViewerWindow::reshape(window_width, window_height);
+ mResDirty = true;
+ return true;
+ }
+ else
+ {
+ LL_WARNS() << "DPI change caused UI scale to go out of bounds: " << ui_scale_factor << LL_ENDL;
+ return false;
+ }
+}
+
+bool LLViewerWindow::handleWindowDidChangeScreen(LLWindow *window)
+{
+ LLCoordScreen window_rect;
+ mWindow->getSize(&window_rect);
+ reshape(window_rect.mX, window_rect.mY);
+ return true;
+}
+
+void LLViewerWindow::handlePingWatchdog(LLWindow *window, const char * msg)
+{
+ LLAppViewer::instance()->pingMainloopTimeout(msg);
+}
+
+
+void LLViewerWindow::handleResumeWatchdog(LLWindow *window)
+{
+ LLAppViewer::instance()->resumeMainloopTimeout();
+}
+
+void LLViewerWindow::handlePauseWatchdog(LLWindow *window)
+{
+ LLAppViewer::instance()->pauseMainloopTimeout();
+}
+
+//virtual
+std::string LLViewerWindow::translateString(const char* tag)
+{
+ return LLTrans::getString( std::string(tag) );
+}
+
+//virtual
+std::string LLViewerWindow::translateString(const char* tag,
+ const std::map<std::string, std::string>& args)
+{
+ // LLTrans uses a special subclass of std::string for format maps,
+ // but we must use std::map<> in these callbacks, otherwise we create
+ // a dependency between LLWindow and LLFormatMapString. So copy the data.
+ LLStringUtil::format_map_t args_copy;
+ std::map<std::string,std::string>::const_iterator it = args.begin();
+ for ( ; it != args.end(); ++it)
+ {
+ args_copy[it->first] = it->second;
+ }
+ return LLTrans::getString( std::string(tag), args_copy);
+}
+
+//
+// Classes
+//
+LLViewerWindow::LLViewerWindow(const Params& p)
+: mWindow(NULL),
+ mActive(true),
+ mUIVisible(true),
+ mWindowRectRaw(0, p.height, p.width, 0),
+ mWindowRectScaled(0, p.height, p.width, 0),
+ mWorldViewRectRaw(0, p.height, p.width, 0),
+ mLeftMouseDown(false),
+ mMiddleMouseDown(false),
+ mRightMouseDown(false),
+ mMouseInWindow( false ),
+ mAllowMouseDragging(true),
+ mMouseDownTimer(),
+ mLastMask( MASK_NONE ),
+ mToolStored( NULL ),
+ mHideCursorPermanent( false ),
+ mCursorHidden(false),
+ mIgnoreActivate( false ),
+ mResDirty(false),
+ mStatesDirty(false),
+ mCurrResolutionIndex(0),
+ mProgressView(NULL)
+{
+ // gKeyboard is still NULL, so it doesn't do LLWindowListener any good to
+ // pass its value right now. Instead, pass it a nullary function that
+ // will, when we later need it, return the value of gKeyboard.
+ // boost::lambda::var() constructs such a functor on the fly.
+ mWindowListener.reset(new LLWindowListener(this, boost::lambda::var(gKeyboard)));
+ mViewerWindowListener.reset(new LLViewerWindowListener(this));
+
+ mSystemChannel.reset(new LLNotificationChannel("System", "Visible", LLNotificationFilters::includeEverything));
+ mCommunicationChannel.reset(new LLCommunicationChannel("Communication", "Visible"));
+ mAlertsChannel.reset(new LLNotificationsUI::LLViewerAlertHandler("VW_alerts", "alert"));
+ mModalAlertsChannel.reset(new LLNotificationsUI::LLViewerAlertHandler("VW_alertmodal", "alertmodal"));
+
+ bool ignore = gSavedSettings.getBOOL("IgnoreAllNotifications");
+ LLNotifications::instance().setIgnoreAllNotifications(ignore);
+ if (ignore)
+ {
+ LL_INFOS() << "NOTE: ALL NOTIFICATIONS THAT OCCUR WILL GET ADDED TO IGNORE LIST FOR LATER RUNS." << LL_ENDL;
+ }
+
+
+ /*
+ LLWindowCallbacks* callbacks,
+ const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags,
+ bool fullscreen,
+ bool clearBg,
+ bool disable_vsync,
+ bool ignore_pixel_depth,
+ U32 fsaa_samples)
+ */
+ // create window
+
+ U32 max_core_count = gSavedSettings.getU32("EmulateCoreCount");
+ F32 max_gl_version = gSavedSettings.getF32("RenderMaxOpenGLVersion");
+
+ LLControlVariable* vram_control = gSavedSettings.getControl("RenderMaxVRAMBudget");
+ U32 max_vram = vram_control->getValue().asInteger();
+ mMaxVRAMControlConnection = vram_control->getSignal()->connect(
+ [this](LLControlVariable* control, const LLSD& new_val, const LLSD& old_val)
+ {
+ if (mWindow) mWindow->setMaxVRAMMegabytes(new_val.asInteger());
+ });
+
+
+ mWindow = LLWindowManager::createWindow(this,
+ p.title, p.name, p.x, p.y, p.width, p.height, 0,
+ p.fullscreen,
+ gHeadlessClient,
+ gSavedSettings.getBOOL("RenderVSyncEnable"),
+ !gHeadlessClient,
+ p.ignore_pixel_depth,
+ 0,
+ max_core_count,
+ max_vram,
+ max_gl_version); //don't use window level anti-aliasing
+
+ if (NULL == mWindow)
+ {
+ LLSplashScreen::update(LLTrans::getString("StartupRequireDriverUpdate"));
+
+ LL_WARNS("Window") << "Failed to create window, to be shutting Down, be sure your graphics driver is updated." << LL_ENDL ;
+
+ ms_sleep(5000) ; //wait for 5 seconds.
+
+ LLSplashScreen::update(LLTrans::getString("ShuttingDown"));
+#if LL_LINUX
+ LL_WARNS() << "Unable to create window, be sure screen is set at 32-bit color and your graphics driver is configured correctly. See README-linux.txt for further information."
+ << LL_ENDL;
+#else
+ LL_WARNS("Window") << "Unable to create window, be sure screen is set at 32-bit color in Control Panels->Display->Settings"
+ << LL_ENDL;
+#endif
+ LLAppViewer::instance()->fastQuit(1);
+ }
+ else if (!LLViewerShaderMgr::sInitialized)
+ {
+ //immediately initialize shaders
+ LLViewerShaderMgr::sInitialized = true;
+ LLViewerShaderMgr::instance()->setShaders();
+ }
+
+ if (!LLAppViewer::instance()->restoreErrorTrap())
+ {
+ // this always happens, so downgrading it to INFO
+ LL_INFOS("Window") << " Someone took over my signal/exception handler (post createWindow; normal)" << LL_ENDL;
+ }
+
+ const bool do_not_enforce = false;
+ mWindow->setMinSize(p.min_width, p.min_height, do_not_enforce); // root view not set
+ LLCoordScreen scr;
+ mWindow->getSize(&scr);
+
+ // Reset UI scale factor on first run if OS's display scaling is not 100%
+ if (gSavedSettings.getBOOL("ResetUIScaleOnFirstRun"))
+ {
+ if (mWindow->getSystemUISize() != 1.f)
+ {
+ gSavedSettings.setF32("UIScaleFactor", 1.f);
+ }
+ gSavedSettings.setBOOL("ResetUIScaleOnFirstRun", false);
+ }
+
+ // Get the real window rect the window was created with (since there are various OS-dependent reasons why
+ // the size of a window or fullscreen context may have been adjusted slightly...)
+ F32 ui_scale_factor = llclamp(gSavedSettings.getF32("UIScaleFactor") * mWindow->getSystemUISize(), MIN_UI_SCALE, MAX_UI_SCALE);
+
+ mDisplayScale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
+ mDisplayScale *= ui_scale_factor;
+ LLUI::setScaleFactor(mDisplayScale);
+
+ {
+ LLCoordWindow size;
+ mWindow->getSize(&size);
+ mWindowRectRaw.set(0, size.mY, size.mX, 0);
+ mWindowRectScaled.set(0, ll_round((F32)size.mY / mDisplayScale.mV[VY]), ll_round((F32)size.mX / mDisplayScale.mV[VX]), 0);
+ }
+
+ LLFontManager::initClass();
+ // Init font system, load default fonts and generate basic glyphs
+ // currently it takes aprox. 0.5 sec and we would load these fonts anyway
+ // before login screen.
+ LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"),
+ mDisplayScale.mV[VX],
+ mDisplayScale.mV[VY],
+ gDirUtilp->getAppRODataDir());
+
+ //
+ // We want to set this stuff up BEFORE we initialize the pipeline, so we can turn off
+ // stuff like AGP if we think that it'll crash the viewer.
+ //
+ LL_DEBUGS("Window") << "Loading feature tables." << LL_ENDL;
+
+ // Initialize OpenGL Renderer
+ LLVertexBuffer::initClass(mWindow);
+ LL_INFOS("RenderInit") << "LLVertexBuffer initialization done." << LL_ENDL ;
+ if (!gGL.init(true))
+ {
+ LLError::LLUserWarningMsg::show(LLTrans::getString("MBVideoDrvErr"));
+ LL_ERRS() << "gGL not initialized" << LL_ENDL;
+ }
+
+ if (LLFeatureManager::getInstance()->isSafe()
+ || (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion())
+ || (gSavedSettings.getString("LastGPUString") != LLFeatureManager::getInstance()->getGPUString())
+ || (gSavedSettings.getBOOL("ProbeHardwareOnStartup")))
+ {
+ LLFeatureManager::getInstance()->applyRecommendedSettings();
+ gSavedSettings.setBOOL("ProbeHardwareOnStartup", false);
+ }
+
+ // If we crashed while initializng GL stuff last time, disable certain features
+ if (gSavedSettings.getBOOL("RenderInitError"))
+ {
+ mInitAlert = "DisplaySettingsNoShaders";
+ LLFeatureManager::getInstance()->setGraphicsLevel(0, false);
+ gSavedSettings.setU32("RenderQualityPerformance", 0);
+ }
+
+ // Init the image list. Must happen after GL is initialized and before the images that
+ // LLViewerWindow needs are requested, as well as before LLViewerMedia starts updating images.
+ LLImageGL::initClass(mWindow, LLViewerTexture::MAX_GL_IMAGE_CATEGORY, false, gSavedSettings.getBOOL("RenderGLMultiThreadedTextures"), gSavedSettings.getBOOL("RenderGLMultiThreadedMedia"));
+ gTextureList.init();
+ LLViewerTextureManager::init() ;
+ gBumpImageList.init();
+
+ // Create container for all sub-views
+ LLView::Params rvp;
+ rvp.name("root");
+ rvp.rect(mWindowRectScaled);
+ rvp.mouse_opaque(false);
+ rvp.follows.flags(FOLLOWS_NONE);
+ mRootView = LLUICtrlFactory::create<LLRootView>(rvp);
+ LLUI::getInstance()->setRootView(mRootView);
+
+ // Make avatar head look forward at start
+ mCurrentMousePoint.mX = getWindowWidthScaled() / 2;
+ mCurrentMousePoint.mY = getWindowHeightScaled() / 2;
+
+ gShowOverlayTitle = gSavedSettings.getBOOL("ShowOverlayTitle");
+ mOverlayTitle = gSavedSettings.getString("OverlayTitle");
+ // Can't have spaces in settings.ini strings, so use underscores instead and convert them.
+ LLStringUtil::replaceChar(mOverlayTitle, '_', ' ');
+
+ mDebugText = new LLDebugText(this);
+
+ mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale);
+}
+
+std::string LLViewerWindow::getLastSnapshotDir()
+{
+ return sSnapshotDir;
+}
+
+void LLViewerWindow::initGLDefaults()
+{
+ // RN: Need this for translation and stretch manip.
+ gBox.prerender();
+}
+
+struct MainPanel : public LLPanel
+{
+};
+
+void LLViewerWindow::initBase()
+{
+ S32 height = getWindowHeightScaled();
+ S32 width = getWindowWidthScaled();
+
+ LLRect full_window(0, height, width, 0);
+
+ ////////////////////
+ //
+ // Set the gamma
+ //
+
+ F32 gamma = gSavedSettings.getF32("RenderGamma");
+ if (gamma != 0.0f)
+ {
+ getWindow()->setGamma(gamma);
+ }
+
+ // Create global views
+
+ // Login screen and main_view.xml need edit menus for preferences and browser
+ LL_DEBUGS("AppInit") << "initializing edit menu" << LL_ENDL;
+ initialize_edit_menu();
+
+ LLFontGL::loadCommonFonts();
+
+ // Create the floater view at the start so that other views can add children to it.
+ // (But wait to add it as a child of the root view so that it will be in front of the
+ // other views.)
+ MainPanel* main_view = new MainPanel();
+ if (!main_view->buildFromFile("main_view.xml"))
+ {
+ LL_ERRS() << "Failed to initialize viewer: Viewer couldn't process file main_view.xml, "
+ << "if this problem happens again, please validate your installation." << LL_ENDL;
+ }
+ main_view->setShape(full_window);
+ getRootView()->addChild(main_view);
+
+ // placeholder widget that controls where "world" is rendered
+ mWorldViewPlaceholder = main_view->getChildView("world_view_rect")->getHandle();
+ mPopupView = main_view->getChild<LLPopupView>("popup_holder");
+ mHintHolder = main_view->getChild<LLView>("hint_holder")->getHandle();
+ mLoginPanelHolder = main_view->getChild<LLView>("login_panel_holder")->getHandle();
+
+ // Create the toolbar view
+ // Get a pointer to the toolbar view holder
+ LLPanel* panel_holder = main_view->getChild<LLPanel>("toolbar_view_holder");
+ // Load the toolbar view from file
+ gToolBarView = LLUICtrlFactory::getInstance()->createFromFile<LLToolBarView>("panel_toolbar_view.xml", panel_holder, LLDefaultChildRegistry::instance());
+ if (!gToolBarView)
+ {
+ LL_ERRS() << "Failed to initialize viewer: Viewer couldn't process file panel_toolbar_view.xml, "
+ << "if this problem happens again, please validate your installation." << LL_ENDL;
+ }
+ gToolBarView->setShape(panel_holder->getLocalRect());
+ // Hide the toolbars for the moment: we'll make them visible after logging in world (see LLViewerWindow::initWorldUI())
+ gToolBarView->setVisible(false);
+
+ // Constrain floaters to inside the menu and status bar regions.
+ gFloaterView = main_view->getChild<LLFloaterView>("Floater View");
+ for (S32 i = 0; i < LLToolBarEnums::TOOLBAR_COUNT; ++i)
+ {
+ LLToolBar * toolbarp = gToolBarView->getToolbar((LLToolBarEnums::EToolBarLocation)i);
+ if (toolbarp)
+ {
+ toolbarp->getCenterLayoutPanel()->setReshapeCallback(boost::bind(&LLFloaterView::setToolbarRect, gFloaterView, _1, _2));
+ }
+ }
+ gFloaterView->setFloaterSnapView(main_view->getChild<LLView>("floater_snap_region")->getHandle());
+ gSnapshotFloaterView = main_view->getChild<LLSnapshotFloaterView>("Snapshot Floater View");
+
+ const F32 CHAT_PERSIST_TIME = 20.f;
+
+ // Console
+ llassert( !gConsole );
+ LLConsole::Params cp;
+ cp.name("console");
+ cp.max_lines(gSavedSettings.getS32("ConsoleBufferSize"));
+ cp.rect(getChatConsoleRect());
+ cp.persist_time(CHAT_PERSIST_TIME);
+ cp.font_size_index(gSavedSettings.getS32("ChatFontSize"));
+ cp.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
+ gConsole = LLUICtrlFactory::create<LLConsole>(cp);
+ getRootView()->addChild(gConsole);
+
+ // optionally forward warnings to chat console/chat floater
+ // for qa runs and dev builds
+#if !LL_RELEASE_FOR_DOWNLOAD
+ RecordToChatConsole::getInstance()->startRecorder();
+#else
+ if(gSavedSettings.getBOOL("QAMode"))
+ {
+ RecordToChatConsole::getInstance()->startRecorder();
+ }
+#endif
+
+ gDebugView = getRootView()->getChild<LLDebugView>("DebugView");
+ gDebugView->init();
+ gToolTipView = getRootView()->getChild<LLToolTipView>("tooltip view");
+
+ // Initialize do not disturb response message when logged in
+ LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLFloaterPreference::initDoNotDisturbResponse));
+
+ // Add the progress bar view (startup view), which overrides everything
+ mProgressView = getRootView()->findChild<LLProgressView>("progress_view");
+ setShowProgress(false);
+ setProgressCancelButtonVisible(false);
+
+ gMenuHolder = getRootView()->getChild<LLViewerMenuHolderGL>("Menu Holder");
+ LLMenuGL::sMenuContainer = gMenuHolder;
+}
+
+void LLViewerWindow::initWorldUI()
+{
+ if (gNonInteractive)
+ {
+ gIMMgr = LLIMMgr::getInstance();
+ LLNavigationBar::getInstance();
+ gFloaterView->pushVisibleAll(false);
+ return;
+ }
+
+ S32 height = mRootView->getRect().getHeight();
+ S32 width = mRootView->getRect().getWidth();
+ LLRect full_window(0, height, width, 0);
+
+
+ gIMMgr = LLIMMgr::getInstance();
+
+ //getRootView()->sendChildToFront(gFloaterView);
+ //getRootView()->sendChildToFront(gSnapshotFloaterView);
+
+ if (!gNonInteractive)
+ {
+ LLPanel* chiclet_container = getRootView()->getChild<LLPanel>("chiclet_container");
+ LLChicletBar* chiclet_bar = LLChicletBar::getInstance();
+ chiclet_bar->setShape(chiclet_container->getLocalRect());
+ chiclet_bar->setFollowsAll();
+ chiclet_container->addChild(chiclet_bar);
+ chiclet_container->setVisible(true);
+ }
+
+ LLRect morph_view_rect = full_window;
+ morph_view_rect.stretch( -STATUS_BAR_HEIGHT );
+ morph_view_rect.mTop = full_window.mTop - 32;
+ LLMorphView::Params mvp;
+ mvp.name("MorphView");
+ mvp.rect(morph_view_rect);
+ mvp.visible(false);
+ gMorphView = LLUICtrlFactory::create<LLMorphView>(mvp);
+ getRootView()->addChild(gMorphView);
+
+ LLWorldMapView::initClass();
+
+ // Force gFloaterWorldMap to initialize
+ LLFloaterReg::getInstance("world_map");
+
+ // Force gFloaterTools to initialize
+ LLFloaterReg::getInstance("build");
+
+ LLNavigationBar* navbar = LLNavigationBar::getInstance();
+ if (!gStatusBar)
+ {
+ // Status bar
+ LLPanel* status_bar_container = getRootView()->getChild<LLPanel>("status_bar_container");
+ gStatusBar = new LLStatusBar(status_bar_container->getLocalRect());
+ gStatusBar->setFollows(FOLLOWS_LEFT | FOLLOWS_TOP | FOLLOWS_RIGHT);
+ gStatusBar->setShape(status_bar_container->getLocalRect());
+ // sync bg color with menu bar
+ gStatusBar->setBackgroundColor(gMenuBarView->getBackgroundColor().get());
+ // add InBack so that gStatusBar won't be drawn over menu
+ status_bar_container->addChildInBack(gStatusBar, 2/*tab order, after menu*/);
+ status_bar_container->setVisible(true);
+
+ // Navigation bar
+ LLView* nav_bar_container = getRootView()->getChild<LLView>("nav_bar_container");
+
+ navbar->setShape(nav_bar_container->getLocalRect());
+ navbar->setBackgroundColor(gMenuBarView->getBackgroundColor().get());
+ nav_bar_container->addChild(navbar);
+ nav_bar_container->setVisible(true);
+ }
+ else
+ {
+ LLPanel* status_bar_container = getRootView()->getChild<LLPanel>("status_bar_container");
+ LLView* nav_bar_container = getRootView()->getChild<LLView>("nav_bar_container");
+ status_bar_container->setVisible(true);
+ nav_bar_container->setVisible(true);
+ }
+
+ if (!gSavedSettings.getBOOL("ShowNavbarNavigationPanel"))
+ {
+ navbar->setVisible(false);
+ }
+ else
+ {
+ reshapeStatusBarContainer();
+ }
+
+
+ // Top Info bar
+ LLPanel* topinfo_bar_container = getRootView()->getChild<LLPanel>("topinfo_bar_container");
+ LLPanelTopInfoBar* topinfo_bar = LLPanelTopInfoBar::getInstance();
+
+ topinfo_bar->setShape(topinfo_bar_container->getLocalRect());
+
+ topinfo_bar_container->addChild(topinfo_bar);
+ topinfo_bar_container->setVisible(true);
+
+ if (!gSavedSettings.getBOOL("ShowMiniLocationPanel"))
+ {
+ topinfo_bar->setVisible(false);
+ }
+
+ if ( gHUDView == NULL )
+ {
+ LLRect hud_rect = full_window;
+ hud_rect.mBottom += 50;
+ if (gMenuBarView && gMenuBarView->isInVisibleChain())
+ {
+ hud_rect.mTop -= gMenuBarView->getRect().getHeight();
+ }
+ gHUDView = new LLHUDView(hud_rect);
+ getRootView()->addChild(gHUDView);
+ getRootView()->sendChildToBack(gHUDView);
+ }
+
+ LLPanel* panel_ssf_container = getRootView()->getChild<LLPanel>("state_management_buttons_container");
+
+ LLPanelStandStopFlying* panel_stand_stop_flying = LLPanelStandStopFlying::getInstance();
+ panel_ssf_container->addChild(panel_stand_stop_flying);
+
+ LLPanelHideBeacon* panel_hide_beacon = LLPanelHideBeacon::getInstance();
+ panel_ssf_container->addChild(panel_hide_beacon);
+
+ panel_ssf_container->setVisible(true);
+
+ LLMenuOptionPathfindingRebakeNavmesh::getInstance()->initialize();
+
+ // Load and make the toolbars visible
+ // Note: we need to load the toolbars only *after* the user is logged in and IW
+ if (gToolBarView)
+ {
+ gToolBarView->loadToolbars();
+ gToolBarView->setVisible(true);
+ }
+
+ if (!gNonInteractive)
+ {
+ LLMediaCtrl* destinations = LLFloaterReg::getInstance("destinations")->getChild<LLMediaCtrl>("destination_guide_contents");
+ if (destinations)
+ {
+ destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
+ std::string url = gSavedSettings.getString("DestinationGuideURL");
+ url = LLWeb::expandURLSubstitutions(url, LLSD());
+ destinations->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
+ }
+ LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents");
+ if (avatar_picker)
+ {
+ avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
+ std::string url = gSavedSettings.getString("AvatarPickerURL");
+ url = LLWeb::expandURLSubstitutions(url, LLSD());
+ avatar_picker->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
+ }
+ }
+}
+
+// Destroy the UI
+void LLViewerWindow::shutdownViews()
+{
+ // clean up warning logger
+ RecordToChatConsole::getInstance()->stopRecorder();
+ LL_INFOS() << "Warning logger is cleaned." << LL_ENDL ;
+
+ gFocusMgr.unlockFocus();
+ gFocusMgr.setMouseCapture(NULL);
+ gFocusMgr.setKeyboardFocus(NULL);
+ gFocusMgr.setTopCtrl(NULL);
+ if (mWindow)
+ {
+ mWindow->allowLanguageTextInput(NULL, false);
+ }
+
+ delete mDebugText;
+ mDebugText = NULL;
+
+ LL_INFOS() << "DebugText deleted." << LL_ENDL ;
+
+ // Cleanup global views
+ if (gMorphView)
+ {
+ gMorphView->setVisible(false);
+ }
+ LL_INFOS() << "Global views cleaned." << LL_ENDL ;
+
+ LLNotificationsUI::LLToast::cleanupToasts();
+ LL_INFOS() << "Leftover toast cleaned up." << LL_ENDL;
+
+ // DEV-40930: Clear sModalStack. Otherwise, any LLModalDialog left open
+ // will crump with LL_ERRS.
+ LLModalDialog::shutdownModals();
+ LL_INFOS() << "LLModalDialog shut down." << LL_ENDL;
+
+ // destroy the nav bar, not currently part of gViewerWindow
+ // *TODO: Make LLNavigationBar part of gViewerWindow
+ LLNavigationBar::deleteSingleton();
+ LL_INFOS() << "LLNavigationBar destroyed." << LL_ENDL ;
+
+ // destroy menus after instantiating navbar above, as it needs
+ // access to gMenuHolder
+ cleanup_menus();
+ LL_INFOS() << "menus destroyed." << LL_ENDL ;
+
+ view_listener_t::cleanup();
+ LL_INFOS() << "view listeners destroyed." << LL_ENDL ;
+
+ // Clean up pointers that are going to be invalid. (todo: check sMenuContainer)
+ mProgressView = NULL;
+ mPopupView = NULL;
+
+ // Delete all child views.
+ delete mRootView;
+ mRootView = NULL;
+ LL_INFOS() << "RootView deleted." << LL_ENDL ;
+
+ LLMenuOptionPathfindingRebakeNavmesh::getInstance()->quit();
+
+ // Automatically deleted as children of mRootView. Fix the globals.
+ gStatusBar = NULL;
+ gIMMgr = NULL;
+ gToolTipView = NULL;
+
+ gToolBarView = NULL;
+ gFloaterView = NULL;
+ gMorphView = NULL;
+
+ gHUDView = NULL;
+}
+
+void LLViewerWindow::shutdownGL()
+{
+ //--------------------------------------------------------
+ // Shutdown GL cleanly. Order is very important here.
+ //--------------------------------------------------------
+ LLFontGL::destroyDefaultFonts();
+ SUBSYSTEM_CLEANUP(LLFontManager);
+ stop_glerror();
+
+ gSky.cleanup();
+ stop_glerror();
+
+ LL_INFOS() << "Cleaning up pipeline" << LL_ENDL;
+ gPipeline.cleanup();
+ stop_glerror();
+
+ //MUST clean up pipeline before cleaning up wearables
+ LL_INFOS() << "Cleaning up wearables" << LL_ENDL;
+ LLWearableList::instance().cleanup() ;
+
+ gTextureList.shutdown();
+ stop_glerror();
+
+ gBumpImageList.shutdown();
+ stop_glerror();
+
+ LLWorldMapView::cleanupTextures();
+
+ LLViewerTextureManager::cleanup() ;
+ SUBSYSTEM_CLEANUP(LLImageGL) ;
+
+ LL_INFOS() << "All textures and llimagegl images are destroyed!" << LL_ENDL ;
+
+ LL_INFOS() << "Cleaning up select manager" << LL_ENDL;
+ LLSelectMgr::getInstance()->cleanup();
+
+ LL_INFOS() << "Stopping GL during shutdown" << LL_ENDL;
+ stopGL(false);
+ stop_glerror();
+
+ gGL.shutdown();
+
+ SUBSYSTEM_CLEANUP(LLVertexBuffer);
+
+ LL_INFOS() << "LLVertexBuffer cleaned." << LL_ENDL ;
+}
+
+// shutdownViews() and shutdownGL() need to be called first
+LLViewerWindow::~LLViewerWindow()
+{
+ LL_INFOS() << "Destroying Window" << LL_ENDL;
+ destroyWindow();
+
+ delete mDebugText;
+ mDebugText = NULL;
+
+ if (LLViewerShaderMgr::sInitialized)
+ {
+ LLViewerShaderMgr::releaseInstance();
+ LLViewerShaderMgr::sInitialized = false;
+ }
+
+ mMaxVRAMControlConnection.disconnect();
+}
+
+
+void LLViewerWindow::setCursor( ECursorType c )
+{
+ mWindow->setCursor( c );
+}
+
+void LLViewerWindow::showCursor()
+{
+ mWindow->showCursor();
+
+ mCursorHidden = false;
+}
+
+void LLViewerWindow::hideCursor()
+{
+ // And hide the cursor
+ mWindow->hideCursor();
+
+ mCursorHidden = true;
+}
+
+void LLViewerWindow::sendShapeToSim()
+{
+ LLMessageSystem* msg = gMessageSystem;
+ if(!msg) return;
+ msg->newMessageFast(_PREHASH_AgentHeightWidth);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addU32Fast(_PREHASH_CircuitCode, gMessageSystem->mOurCircuitCode);
+ msg->nextBlockFast(_PREHASH_HeightWidthBlock);
+ msg->addU32Fast(_PREHASH_GenCounter, 0);
+ U16 height16 = (U16) mWorldViewRectRaw.getHeight();
+ U16 width16 = (U16) mWorldViewRectRaw.getWidth();
+ msg->addU16Fast(_PREHASH_Height, height16);
+ msg->addU16Fast(_PREHASH_Width, width16);
+ gAgent.sendReliableMessage();
+}
+
+// Must be called after window is created to set up agent
+// camera variables and UI variables.
+void LLViewerWindow::reshape(S32 width, S32 height)
+{
+ // Destroying the window at quit time generates spurious
+ // reshape messages. We don't care about these, and we
+ // don't want to send messages because the message system
+ // may have been destructed.
+ if (!LLApp::isExiting())
+ {
+ gWindowResized = true;
+
+ // update our window rectangle
+ mWindowRectRaw.mRight = mWindowRectRaw.mLeft + width;
+ mWindowRectRaw.mTop = mWindowRectRaw.mBottom + height;
+
+ //glViewport(0, 0, width, height );
+
+ LLViewerCamera * camera = LLViewerCamera::getInstance(); // simpleton, might not exist
+ if (height > 0 && camera)
+ {
+ camera->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
+ camera->setAspect( getWorldViewAspectRatio() );
+ }
+
+ calcDisplayScale();
+
+ bool display_scale_changed = mDisplayScale != LLUI::getScaleFactor();
+ LLUI::setScaleFactor(mDisplayScale);
+
+ // update our window rectangle
+ mWindowRectScaled.mRight = mWindowRectScaled.mLeft + ll_round((F32)width / mDisplayScale.mV[VX]);
+ mWindowRectScaled.mTop = mWindowRectScaled.mBottom + ll_round((F32)height / mDisplayScale.mV[VY]);
+
+ setup2DViewport();
+
+ // Inform lower views of the change
+ // round up when converting coordinates to make sure there are no gaps at edge of window
+ LLView::sForceReshape = display_scale_changed;
+ mRootView->reshape(llceil((F32)width / mDisplayScale.mV[VX]), llceil((F32)height / mDisplayScale.mV[VY]));
+ if (display_scale_changed)
+ {
+ // Needs only a 'scale change' update, everything else gets handled by LLLayoutStack::updateClass()
+ LLPanelLogin::reshapePanel();
+ }
+ LLView::sForceReshape = false;
+
+ // clear font width caches
+ if (display_scale_changed)
+ {
+ LLHUDObject::reshapeAll();
+ }
+
+ sendShapeToSim();
+
+ // store new settings for the mode we are in, regardless
+ bool maximized = mWindow->getMaximized();
+ gSavedSettings.setBOOL("WindowMaximized", maximized);
+
+ if (!maximized)
+ {
+ U32 min_window_width=gSavedSettings.getU32("MinWindowWidth");
+ U32 min_window_height=gSavedSettings.getU32("MinWindowHeight");
+ // tell the OS specific window code about min window size
+ mWindow->setMinSize(min_window_width, min_window_height);
+
+ LLCoordScreen window_rect;
+ if (!gNonInteractive && mWindow->getSize(&window_rect))
+ {
+ // Only save size if not maximized
+ gSavedSettings.setU32("WindowWidth", window_rect.mX);
+ gSavedSettings.setU32("WindowHeight", window_rect.mY);
+ }
+ }
+
+ sample(LLStatViewer::WINDOW_WIDTH, width);
+ sample(LLStatViewer::WINDOW_HEIGHT, height);
+
+ LLLayoutStack::updateClass();
+ }
+}
+
+
+// Hide normal UI when a logon fails
+void LLViewerWindow::setNormalControlsVisible( bool visible )
+{
+ if(LLChicletBar::instanceExists())
+ {
+ LLChicletBar::getInstance()->setVisible(visible);
+ LLChicletBar::getInstance()->setEnabled(visible);
+ }
+
+ if ( gMenuBarView )
+ {
+ gMenuBarView->setVisible( visible );
+ gMenuBarView->setEnabled( visible );
+
+ // ...and set the menu color appropriately.
+ setMenuBackgroundColor(gAgent.getGodLevel() > GOD_NOT,
+ LLGridManager::getInstance()->isInProductionGrid());
+ }
+
+ if ( gStatusBar )
+ {
+ gStatusBar->setVisible( visible );
+ gStatusBar->setEnabled( visible );
+ }
+
+ LLNavigationBar* navbarp = LLUI::getInstance()->getRootView()->findChild<LLNavigationBar>("navigation_bar");
+ if (navbarp)
+ {
+ // when it's time to show navigation bar we need to ensure that the user wants to see it
+ // i.e. ShowNavbarNavigationPanel option is true
+ navbarp->setVisible( visible && gSavedSettings.getBOOL("ShowNavbarNavigationPanel") );
+ }
+}
+
+void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid)
+{
+ LLSD args;
+ LLColor4 new_bg_color;
+
+ // god more important than project, proj more important than grid
+ if ( god_mode )
+ {
+ if ( LLGridManager::getInstance()->isInProductionGrid() )
+ {
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuBarGodBgColor" );
+ }
+ else
+ {
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionGodBgColor" );
+ }
+ }
+ else
+ {
+ switch (LLVersionInfo::instance().getViewerMaturity())
+ {
+ case LLVersionInfo::TEST_VIEWER:
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuBarTestBgColor" );
+ break;
+
+ case LLVersionInfo::PROJECT_VIEWER:
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuBarProjectBgColor" );
+ break;
+
+ case LLVersionInfo::BETA_VIEWER:
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuBarBetaBgColor" );
+ break;
+
+ case LLVersionInfo::RELEASE_VIEWER:
+ if(!LLGridManager::getInstance()->isInProductionGrid())
+ {
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" );
+ }
+ else
+ {
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuBarBgColor" );
+ }
+ break;
+ }
+ }
+
+ if(gMenuBarView)
+ {
+ gMenuBarView->setBackgroundColor( new_bg_color );
+ }
+
+ if(gStatusBar)
+ {
+ gStatusBar->setBackgroundColor( new_bg_color );
+ }
+}
+
+void LLViewerWindow::drawDebugText()
+{
+ gUIProgram.bind();
+ gGL.color4f(1,1,1,1);
+ gGL.pushMatrix();
+ gGL.pushUIMatrix();
+ {
+ // scale view by UI global scale factor and aspect ratio correction factor
+ gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
+ mDebugText->draw();
+ }
+ gGL.popUIMatrix();
+ gGL.popMatrix();
+
+ gGL.flush();
+ gUIProgram.unbind();
+}
+
+void LLViewerWindow::draw()
+{
+
+//#if LL_DEBUG
+ LLView::sIsDrawing = true;
+//#endif
+ stop_glerror();
+
+ LLUI::setLineWidth(1.f);
+
+ LLUI::setLineWidth(1.f);
+ // Reset any left-over transforms
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+
+ gGL.loadIdentity();
+
+ //S32 screen_x, screen_y;
+
+ if (!gSavedSettings.getBOOL("RenderUIBuffer"))
+ {
+ LLView::sDirtyRect = getWindowRectScaled();
+ }
+
+ // HACK for timecode debugging
+ if (gSavedSettings.getBOOL("DisplayTimecode"))
+ {
+ // draw timecode block
+ std::string text;
+
+ gGL.loadIdentity();
+
+ microsecondsToTimecodeString(gFrameTime,text);
+ const LLFontGL* font = LLFontGL::getFontSansSerif();
+ font->renderUTF8(text, 0,
+ ll_round((getWindowWidthScaled()/2)-100.f),
+ ll_round((getWindowHeightScaled()-60.f)),
+ LLColor4( 1.f, 1.f, 1.f, 1.f ),
+ LLFontGL::LEFT, LLFontGL::TOP);
+ }
+
+ // Draw all nested UI views.
+ // No translation needed, this view is glued to 0,0
+
+ gUIProgram.bind();
+ gGL.color4f(1, 1, 1, 1);
+
+ gGL.pushMatrix();
+ LLUI::pushMatrix();
+ {
+
+ // scale view by UI global scale factor and aspect ratio correction factor
+ gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
+
+ LLVector2 old_scale_factor = LLUI::getScaleFactor();
+ // apply camera zoom transform (for high res screenshots)
+ F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
+ S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
+ if (zoom_factor > 1.f)
+ {
+ //decompose subregion number to x and y values
+ int pos_y = sub_region / llceil(zoom_factor);
+ int pos_x = sub_region - (pos_y*llceil(zoom_factor));
+ // offset for this tile
+ gGL.translatef((F32)getWindowWidthScaled() * -(F32)pos_x,
+ (F32)getWindowHeightScaled() * -(F32)pos_y,
+ 0.f);
+ gGL.scalef(zoom_factor, zoom_factor, 1.f);
+ LLUI::getScaleFactor() *= zoom_factor;
+ }
+
+ // Draw tool specific overlay on world
+ LLToolMgr::getInstance()->getCurrentTool()->draw();
+
+ if( gAgentCamera.cameraMouselook() || LLFloaterCamera::inFreeCameraMode() )
+ {
+ drawMouselookInstructions();
+ stop_glerror();
+ }
+
+ // Draw all nested UI views.
+ // No translation needed, this view is glued to 0,0
+ mRootView->draw();
+
+ if (LLView::sDebugRects)
+ {
+ gToolTipView->drawStickyRect();
+ }
+
+ // Draw optional on-top-of-everyone view
+ LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+ if (top_ctrl && top_ctrl->getVisible())
+ {
+ S32 screen_x, screen_y;
+ top_ctrl->localPointToScreen(0, 0, &screen_x, &screen_y);
+
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ LLUI::pushMatrix();
+ LLUI::translate( (F32) screen_x, (F32) screen_y);
+ top_ctrl->draw();
+ LLUI::popMatrix();
+ }
+
+
+ if( gShowOverlayTitle && !mOverlayTitle.empty() )
+ {
+ // Used for special titles such as "Second Life - Special E3 2003 Beta"
+ const S32 DIST_FROM_TOP = 20;
+ LLFontGL::getFontSansSerifBig()->renderUTF8(
+ mOverlayTitle, 0,
+ ll_round( getWindowWidthScaled() * 0.5f),
+ getWindowHeightScaled() - DIST_FROM_TOP,
+ LLColor4(1, 1, 1, 0.4f),
+ LLFontGL::HCENTER, LLFontGL::TOP);
+ }
+
+ LLUI::setScaleFactor(old_scale_factor);
+ }
+ LLUI::popMatrix();
+ gGL.popMatrix();
+
+ gUIProgram.unbind();
+
+ LLView::sIsDrawing = false;
+}
+
+// Takes a single keyup event, usually when UI is visible
+bool LLViewerWindow::handleKeyUp(KEY key, MASK mask)
+{
+ if (LLSetKeyBindDialog::recordKey(key, mask, false))
+ {
+ LL_DEBUGS() << "KeyUp handled by LLSetKeyBindDialog" << LL_ENDL;
+ LLViewerEventRecorder::instance().logKeyEvent(key, mask);
+ return true;
+ }
+
+ LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+
+ if (keyboard_focus
+ && !(mask & (MASK_CONTROL | MASK_ALT))
+ && !gFocusMgr.getKeystrokesOnly())
+ {
+ // We have keyboard focus, and it's not an accelerator
+ if (keyboard_focus && keyboard_focus->wantsKeyUpKeyDown())
+ {
+ return keyboard_focus->handleKeyUp(key, mask, false);
+ }
+ else if (key < 0x80)
+ {
+ // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first.
+ return (gFocusMgr.getKeyboardFocus() != NULL);
+ }
+ }
+
+ if (keyboard_focus)
+ {
+ if (keyboard_focus->handleKeyUp(key, mask, false))
+ {
+ LL_DEBUGS() << "LLviewerWindow::handleKeyUp - in 'traverse up' - no loops seen... just called keyboard_focus->handleKeyUp an it returned true" << LL_ENDL;
+ LLViewerEventRecorder::instance().logKeyEvent(key, mask);
+ return true;
+ }
+ else {
+ LL_DEBUGS() << "LLviewerWindow::handleKeyUp - in 'traverse up' - no loops seen... just called keyboard_focus->handleKeyUp an it returned false" << LL_ENDL;
+ }
+ }
+
+ // Try for a new-format gesture
+ if (LLGestureMgr::instance().triggerGestureRelease(key, mask))
+ {
+ LL_DEBUGS() << "LLviewerWindow::handleKey new gesture release feature" << LL_ENDL;
+ LLViewerEventRecorder::instance().logKeyEvent(key,mask);
+ return true;
+ }
+ //Old format gestures do not support this, so no need to implement it.
+
+ // don't pass keys on to world when something in ui has focus
+ return gFocusMgr.childHasKeyboardFocus(mRootView)
+ || LLMenuGL::getKeyboardMode()
+ || (gMenuBarView && gMenuBarView->getHighlightedItem() && gMenuBarView->getHighlightedItem()->isActive());
+}
+
+// Takes a single keydown event, usually when UI is visible
+bool LLViewerWindow::handleKey(KEY key, MASK mask)
+{
+ // hide tooltips on keypress
+ LLToolTipMgr::instance().blockToolTips();
+
+ // Menus get handled on key down instead of key up
+ // so keybindings have to be recorded before that
+ if (LLSetKeyBindDialog::recordKey(key, mask, true))
+ {
+ LL_DEBUGS() << "Key handled by LLSetKeyBindDialog" << LL_ENDL;
+ LLViewerEventRecorder::instance().logKeyEvent(key,mask);
+ return true;
+ }
+
+ LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+
+ if (keyboard_focus
+ && !gFocusMgr.getKeystrokesOnly())
+ {
+ //Most things should fall through, but mouselook is an exception,
+ //don't switch to mouselook if any floater has focus
+ if ((key == KEY_MOUSELOOK) && !(mask & (MASK_CONTROL | MASK_ALT)))
+ {
+ return true;
+ }
+
+ LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(keyboard_focus);
+ if (cur_focus && cur_focus->acceptsTextInput())
+ {
+#ifdef LL_WINDOWS
+ // On windows Alt Gr key generates additional Ctrl event, as result handling situations
+ // like 'AltGr + D' will result in 'Alt+Ctrl+D'. If it results in WM_CHAR, don't let it
+ // pass into menu or it will trigger 'develop' menu assigned to this combination on top
+ // of character handling.
+ // Alt Gr can be additionally modified by Shift
+ const MASK alt_gr = MASK_CONTROL | MASK_ALT;
+ LLWindowWin32 *window = static_cast<LLWindowWin32*>(mWindow);
+ U32 raw_key = window->getRawWParam();
+ if ((mask & alt_gr) != 0
+ && ((raw_key >= 0x30 && raw_key <= 0x5A) //0-9, plus normal chartacters
+ || (raw_key >= 0xBA && raw_key <= 0xE4)) // Misc/OEM characters that can be covered by AltGr, ex: -, =, ~
+ && (GetKeyState(VK_RMENU) & 0x8000) != 0
+ && (GetKeyState(VK_RCONTROL) & 0x8000) == 0) // ensure right control is not pressed, only left one
+ {
+ // Alt Gr key is represented as right alt and left control.
+ // Any alt+ctrl combination is treated as Alt Gr by TranslateMessage() and
+ // will generate a WM_CHAR message, but here we only treat virtual Alt Graph
+ // key by checking if this specific combination has unicode char.
+ //
+ // I decided to handle only virtual RAlt+LCtrl==AltGr combination to minimize
+ // impact on menu, but the right way might be to handle all Alt+Ctrl calls.
+
+ BYTE keyboard_state[256];
+ if (GetKeyboardState(keyboard_state))
+ {
+ const int char_count = 6;
+ wchar_t chars[char_count];
+ HKL layout = GetKeyboardLayout(0);
+ // ToUnicodeEx changes buffer state on OS below Win10, which is undesirable,
+ // but since we already did a TranslateMessage() in gatherInput(), this
+ // should have no negative effect
+ // ToUnicodeEx works with virtual key codes
+ int res = ToUnicodeEx(raw_key, 0, keyboard_state, chars, char_count, 1 << 2 /*do not modify buffer flag*/, layout);
+ if (res == 1 && chars[0] >= 0x20)
+ {
+ // Let it fall through to character handler and get a WM_CHAR.
+ return true;
+ }
+ }
+ }
+#endif
+
+ if (!(mask & (MASK_CONTROL | MASK_ALT)))
+ {
+ // We have keyboard focus, and it's not an accelerator
+ if (keyboard_focus && keyboard_focus->wantsKeyUpKeyDown())
+ {
+ return keyboard_focus->handleKey(key, mask, false);
+ }
+ else if (key < 0x80)
+ {
+ // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first.
+ return true;
+ }
+ }
+ }
+ }
+
+ // let menus handle navigation keys for navigation
+ if ((gMenuBarView && gMenuBarView->handleKey(key, mask, true))
+ ||(gLoginMenuBarView && gLoginMenuBarView->handleKey(key, mask, true))
+ ||(gMenuHolder && gMenuHolder->handleKey(key, mask, true)))
+ {
+ LL_DEBUGS() << "LLviewerWindow::handleKey handle nav keys for nav" << LL_ENDL;
+ LLViewerEventRecorder::instance().logKeyEvent(key,mask);
+ return true;
+ }
+
+
+ // give menus a chance to handle modified (Ctrl, Alt) shortcut keys before current focus
+ // as long as focus isn't locked
+ if (mask & (MASK_CONTROL | MASK_ALT) && !gFocusMgr.focusLocked())
+ {
+ // Check the current floater's menu first, if it has one.
+ if (gFocusMgr.keyboardFocusHasAccelerators()
+ && keyboard_focus
+ && keyboard_focus->handleKey(key,mask,false))
+ {
+ LLViewerEventRecorder::instance().logKeyEvent(key,mask);
+ return true;
+ }
+
+ if (gAgent.isInitialized()
+ && (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE || gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL)
+ && gMenuBarView
+ && gMenuBarView->handleAcceleratorKey(key, mask))
+ {
+ LLViewerEventRecorder::instance().logKeyEvent(key, mask);
+ return true;
+ }
+
+ if (gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask))
+ {
+ LLViewerEventRecorder::instance().logKeyEvent(key,mask);
+ return true;
+ }
+ }
+
+ // give floaters first chance to handle TAB key
+ // so frontmost floater gets focus
+ // if nothing has focus, go to first or last UI element as appropriate
+ if (key == KEY_TAB && (mask & MASK_CONTROL || keyboard_focus == NULL))
+ {
+ LL_WARNS() << "LLviewerWindow::handleKey give floaters first chance at tab key " << LL_ENDL;
+ if (gMenuHolder) gMenuHolder->hideMenus();
+
+ // if CTRL-tabbing (and not just TAB with no focus), go into window cycle mode
+ gFloaterView->setCycleMode((mask & MASK_CONTROL) != 0);
+
+ // do CTRL-TAB and CTRL-SHIFT-TAB logic
+ if (mask & MASK_SHIFT)
+ {
+ mRootView->focusPrevRoot();
+ }
+ else
+ {
+ mRootView->focusNextRoot();
+ }
+ LLViewerEventRecorder::instance().logKeyEvent(key,mask);
+ return true;
+ }
+ // hidden edit menu for cut/copy/paste
+ if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask))
+ {
+ LLViewerEventRecorder::instance().logKeyEvent(key,mask);
+ return true;
+ }
+
+ LLFloater* focused_floaterp = gFloaterView->getFocusedFloater();
+ std::string focusedFloaterName = (focused_floaterp ? focused_floaterp->getInstanceName() : "");
+
+ if( keyboard_focus )
+ {
+ if ((focusedFloaterName == "nearby_chat") || (focusedFloaterName == "im_container") || (focusedFloaterName == "impanel"))
+ {
+ if (gSavedSettings.getBOOL("ArrowKeysAlwaysMove"))
+ {
+ // let Control-Up and Control-Down through for chat line history,
+ if (!(key == KEY_UP && mask == MASK_CONTROL)
+ && !(key == KEY_DOWN && mask == MASK_CONTROL)
+ && !(key == KEY_UP && mask == MASK_ALT)
+ && !(key == KEY_DOWN && mask == MASK_ALT))
+ {
+ switch(key)
+ {
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_PAGE_UP:
+ case KEY_PAGE_DOWN:
+ case KEY_HOME:
+ case KEY_END:
+ // when chatbar is empty or ArrowKeysAlwaysMove set,
+ // pass arrow keys on to avatar...
+ return false;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (keyboard_focus->handleKey(key, mask, false))
+ {
+
+ LL_DEBUGS() << "LLviewerWindow::handleKey - in 'traverse up' - no loops seen... just called keyboard_focus->handleKey an it returned true" << LL_ENDL;
+ LLViewerEventRecorder::instance().logKeyEvent(key,mask);
+ return true;
+ } else {
+ LL_DEBUGS() << "LLviewerWindow::handleKey - in 'traverse up' - no loops seen... just called keyboard_focus->handleKey an it returned false" << LL_ENDL;
+ }
+ }
+
+ if( LLToolMgr::getInstance()->getCurrentTool()->handleKey(key, mask) )
+ {
+ LL_DEBUGS() << "LLviewerWindow::handleKey toolbar handling?" << LL_ENDL;
+ LLViewerEventRecorder::instance().logKeyEvent(key,mask);
+ return true;
+ }
+
+ // Try for a new-format gesture
+ if (LLGestureMgr::instance().triggerGesture(key, mask))
+ {
+ LL_DEBUGS() << "LLviewerWindow::handleKey new gesture feature" << LL_ENDL;
+ LLViewerEventRecorder::instance().logKeyEvent(key,mask);
+ return true;
+ }
+
+ // See if this is a gesture trigger. If so, eat the key and
+ // don't pass it down to the menus.
+ if (gGestureList.trigger(key, mask))
+ {
+ LL_DEBUGS() << "LLviewerWindow::handleKey check gesture trigger" << LL_ENDL;
+ LLViewerEventRecorder::instance().logKeyEvent(key,mask);
+ return true;
+ }
+
+ // If "Pressing letter keys starts local chat" option is selected, we are not in mouselook,
+ // no view has keyboard focus, this is a printable character key (and no modifier key is
+ // pressed except shift), then give focus to nearby chat (STORM-560)
+ if ( LLStartUp::getStartupState() >= STATE_STARTED &&
+ gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() &&
+ !keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) )
+ {
+ // Initialize nearby chat if it's missing
+ LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
+ if (!nearby_chat)
+ {
+ LLSD name("im_container");
+ LLFloaterReg::toggleInstanceOrBringToFront(name);
+ }
+
+ LLChatEntry* chat_editor = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat")->getChatBox();
+ if (chat_editor)
+ {
+ // passing NULL here, character will be added later when it is handled by character handler.
+ nearby_chat->startChat(NULL);
+ return true;
+ }
+ }
+
+ // give menus a chance to handle unmodified accelerator keys
+ if (gAgent.isInitialized()
+ && (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE || gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL)
+ && gMenuBarView
+ && gMenuBarView->handleAcceleratorKey(key, mask))
+ {
+ LLViewerEventRecorder::instance().logKeyEvent(key, mask);
+ return true;
+ }
+
+ if (gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask))
+ {
+ return true;
+ }
+
+ // don't pass keys on to world when something in ui has focus
+ return gFocusMgr.childHasKeyboardFocus(mRootView)
+ || LLMenuGL::getKeyboardMode()
+ || (gMenuBarView && gMenuBarView->getHighlightedItem() && gMenuBarView->getHighlightedItem()->isActive());
+}
+
+
+bool LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
+{
+ // HACK: We delay processing of return keys until they arrive as a Unicode char,
+ // so that if you're typing chat text at low frame rate, we don't send the chat
+ // until all keystrokes have been entered. JC
+ // HACK: Numeric keypad <enter> on Mac is Unicode 3
+ // HACK: Control-M on Windows is Unicode 13
+ if ((uni_char == 13 && mask != MASK_CONTROL)
+ || (uni_char == 3 && mask == MASK_NONE) )
+ {
+ if (mask != MASK_ALT)
+ {
+ // remaps, handles ignored cases and returns back to viewer window.
+ return gViewerInput.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
+ }
+ }
+
+ // let menus handle navigation (jump) keys
+ if (gMenuBarView && gMenuBarView->handleUnicodeChar(uni_char, true))
+ {
+ return true;
+ }
+
+ // Traverses up the hierarchy
+ LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+ if( keyboard_focus )
+ {
+ if (keyboard_focus->handleUnicodeChar(uni_char, false))
+ {
+ return true;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+
+void LLViewerWindow::handleScrollWheel(S32 clicks)
+{
+ LLUI::getInstance()->resetMouseIdleTimer();
+
+ LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
+ if( mouse_captor )
+ {
+ S32 local_x;
+ S32 local_y;
+ mouse_captor->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
+ mouse_captor->handleScrollWheel(local_x, local_y, clicks);
+ if (LLView::sDebugMouseHandling)
+ {
+ LL_INFOS() << "Scroll Wheel handled by captor " << mouse_captor->getName() << LL_ENDL;
+ }
+ return;
+ }
+
+ LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+ if (top_ctrl)
+ {
+ S32 local_x;
+ S32 local_y;
+ top_ctrl->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
+ if (top_ctrl->handleScrollWheel(local_x, local_y, clicks)) return;
+ }
+
+ if (mRootView->handleScrollWheel(mCurrentMousePoint.mX, mCurrentMousePoint.mY, clicks) )
+ {
+ if (LLView::sDebugMouseHandling)
+ {
+ LL_INFOS() << "Scroll Wheel" << LLView::sMouseHandlerMessage << LL_ENDL;
+ }
+ return;
+ }
+ else if (LLView::sDebugMouseHandling)
+ {
+ LL_INFOS() << "Scroll Wheel not handled by view" << LL_ENDL;
+ }
+
+ // Zoom the camera in and out behavior
+
+ if(top_ctrl == 0
+ && getWorldViewRectScaled().pointInRect(mCurrentMousePoint.mX, mCurrentMousePoint.mY)
+ && gAgentCamera.isInitialized())
+ gAgentCamera.handleScrollWheel(clicks);
+
+ return;
+}
+
+void LLViewerWindow::handleScrollHWheel(S32 clicks)
+{
+ if (LLAppViewer::instance()->quitRequested())
+ {
+ return;
+ }
+
+ LLUI::getInstance()->resetMouseIdleTimer();
+
+ LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
+ if (mouse_captor)
+ {
+ S32 local_x;
+ S32 local_y;
+ mouse_captor->screenPointToLocal(mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y);
+ mouse_captor->handleScrollHWheel(local_x, local_y, clicks);
+ if (LLView::sDebugMouseHandling)
+ {
+ LL_INFOS() << "Scroll Horizontal Wheel handled by captor " << mouse_captor->getName() << LL_ENDL;
+ }
+ return;
+ }
+
+ LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+ if (top_ctrl)
+ {
+ S32 local_x;
+ S32 local_y;
+ top_ctrl->screenPointToLocal(mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y);
+ if (top_ctrl->handleScrollHWheel(local_x, local_y, clicks)) return;
+ }
+
+ if (mRootView->handleScrollHWheel(mCurrentMousePoint.mX, mCurrentMousePoint.mY, clicks))
+ {
+ if (LLView::sDebugMouseHandling)
+ {
+ LL_INFOS() << "Scroll Horizontal Wheel" << LLView::sMouseHandlerMessage << LL_ENDL;
+ }
+ return;
+ }
+ else if (LLView::sDebugMouseHandling)
+ {
+ LL_INFOS() << "Scroll Horizontal Wheel not handled by view" << LL_ENDL;
+ }
+
+ return;
+}
+
+void LLViewerWindow::addPopup(LLView* popup)
+{
+ if (mPopupView)
+ {
+ mPopupView->addPopup(popup);
+ }
+}
+
+void LLViewerWindow::removePopup(LLView* popup)
+{
+ if (mPopupView)
+ {
+ mPopupView->removePopup(popup);
+ }
+}
+
+void LLViewerWindow::clearPopups()
+{
+ if (mPopupView)
+ {
+ mPopupView->clearPopups();
+ }
+}
+
+void LLViewerWindow::moveCursorToCenter()
+{
+ if (! gSavedSettings.getBOOL("DisableMouseWarp"))
+ {
+ S32 x = getWorldViewWidthScaled() / 2;
+ S32 y = getWorldViewHeightScaled() / 2;
+
+ LLUI::getInstance()->setMousePositionScreen(x, y);
+
+ //on a forced move, all deltas get zeroed out to prevent jumping
+ mCurrentMousePoint.set(x,y);
+ mLastMousePoint.set(x,y);
+ mCurrentMouseDelta.set(0,0);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Hover handlers
+//
+
+void append_xui_tooltip(LLView* viewp, LLToolTip::Params& params)
+{
+ if (viewp)
+ {
+ if (!params.styled_message.empty())
+ {
+ params.styled_message.add().text("\n---------\n");
+ }
+ LLView::root_to_view_iterator_t end_tooltip_it = viewp->endRootToView();
+ // NOTE: we skip "root" since it is assumed
+ for (LLView::root_to_view_iterator_t tooltip_it = ++viewp->beginRootToView();
+ tooltip_it != end_tooltip_it;
+ ++tooltip_it)
+ {
+ LLView* viewp = *tooltip_it;
+
+ params.styled_message.add().text(viewp->getName());
+
+ LLPanel* panelp = dynamic_cast<LLPanel*>(viewp);
+ if (panelp && !panelp->getXMLFilename().empty())
+ {
+ params.styled_message.add()
+ .text("(" + panelp->getXMLFilename() + ")")
+ .style.color(LLColor4(0.7f, 0.7f, 1.f, 1.f));
+ }
+ params.styled_message.add().text("/");
+ }
+ }
+}
+
+static LLTrace::BlockTimerStatHandle ftm("Update UI");
+
+// Update UI based on stored mouse position from mouse-move
+// event processing.
+void LLViewerWindow::updateUI()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(ftm);
+
+ static std::string last_handle_msg;
+
+ if (gLoggedInTime.getStarted())
+ {
+ const F32 DESTINATION_GUIDE_HINT_TIMEOUT = 1200.f;
+ const F32 SIDE_PANEL_HINT_TIMEOUT = 300.f;
+ if (gLoggedInTime.getElapsedTimeF32() > DESTINATION_GUIDE_HINT_TIMEOUT)
+ {
+ LLFirstUse::notUsingDestinationGuide();
+ }
+ if (gLoggedInTime.getElapsedTimeF32() > SIDE_PANEL_HINT_TIMEOUT)
+ {
+ LLFirstUse::notUsingSidePanel();
+ }
+ }
+
+ LLConsole::updateClass();
+
+ // animate layout stacks so we have up to date rect for world view
+ LLLayoutStack::updateClass();
+
+ // use full window for world view when not rendering UI
+ bool world_view_uses_full_window = gAgentCamera.cameraMouselook() || !gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ updateWorldViewRect(world_view_uses_full_window);
+
+ LLView::sMouseHandlerMessage.clear();
+
+ S32 x = mCurrentMousePoint.mX;
+ S32 y = mCurrentMousePoint.mY;
+
+ MASK mask = gKeyboard->currentMask(true);
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
+ {
+ gDebugRaycastFaceHit = -1;
+ gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, false, false, true, false,
+ &gDebugRaycastFaceHit,
+ &gDebugRaycastIntersection,
+ &gDebugRaycastTexCoord,
+ &gDebugRaycastNormal,
+ &gDebugRaycastTangent,
+ &gDebugRaycastStart,
+ &gDebugRaycastEnd);
+
+ gDebugRaycastParticle = gPipeline.lineSegmentIntersectParticle(gDebugRaycastStart, gDebugRaycastEnd, &gDebugRaycastParticleIntersection, NULL);
+ }
+
+ updateMouseDelta();
+ updateKeyboardFocus();
+
+ bool handled = false;
+
+ LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+ LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
+ LLView* captor_view = dynamic_cast<LLView*>(mouse_captor);
+
+ //FIXME: only include captor and captor's ancestors if mouse is truly over them --RN
+
+ //build set of views containing mouse cursor by traversing UI hierarchy and testing
+ //screen rect against mouse cursor
+ view_handle_set_t mouse_hover_set;
+
+ // constraint mouse enter events to children of mouse captor
+ LLView* root_view = captor_view;
+
+ // if mouse captor doesn't exist or isn't a LLView
+ // then allow mouse enter events on entire UI hierarchy
+ if (!root_view)
+ {
+ root_view = mRootView;
+ }
+
+ static LLCachedControl<bool> dump_menu_holder(gSavedSettings, "DumpMenuHolderSize", false);
+ if (dump_menu_holder)
+ {
+ static bool init = false;
+ static LLFrameTimer child_count_timer;
+ static std::vector <std::string> child_vec;
+ if (!init)
+ {
+ child_count_timer.resetWithExpiry(5.f);
+ init = true;
+ }
+ if (child_count_timer.hasExpired())
+ {
+ LL_INFOS() << "gMenuHolder child count: " << gMenuHolder->getChildCount() << LL_ENDL;
+ std::vector<std::string> local_child_vec;
+ LLView::child_list_t child_list = *gMenuHolder->getChildList();
+ for (auto child : child_list)
+ {
+ local_child_vec.emplace_back(child->getName());
+ }
+ if (!local_child_vec.empty() && local_child_vec != child_vec)
+ {
+ std::vector<std::string> out_vec;
+ std::sort(local_child_vec.begin(), local_child_vec.end());
+ std::sort(child_vec.begin(), child_vec.end());
+ std::set_difference(child_vec.begin(), child_vec.end(), local_child_vec.begin(), local_child_vec.end(), std::inserter(out_vec, out_vec.begin()));
+ if (!out_vec.empty())
+ {
+ LL_INFOS() << "gMenuHolder removal diff size: '"<<out_vec.size() <<"' begin_child_diff";
+ for (auto str : out_vec)
+ {
+ LL_CONT << " : " << str;
+ }
+ LL_CONT << " : end_child_diff" << LL_ENDL;
+ }
+
+ out_vec.clear();
+ std::set_difference(local_child_vec.begin(), local_child_vec.end(), child_vec.begin(), child_vec.end(), std::inserter(out_vec, out_vec.begin()));
+ if (!out_vec.empty())
+ {
+ LL_INFOS() << "gMenuHolder addition diff size: '" << out_vec.size() << "' begin_child_diff";
+ for (auto str : out_vec)
+ {
+ LL_CONT << " : " << str;
+ }
+ LL_CONT << " : end_child_diff" << LL_ENDL;
+ }
+ child_vec.swap(local_child_vec);
+ }
+ child_count_timer.resetWithExpiry(5.f);
+ }
+ }
+
+ // only update mouse hover set when UI is visible (since we shouldn't send hover events to invisible UI
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ // include all ancestors of captor_view as automatically having mouse
+ if (captor_view)
+ {
+ LLView* captor_parent_view = captor_view->getParent();
+ while(captor_parent_view)
+ {
+ mouse_hover_set.insert(captor_parent_view->getHandle());
+ captor_parent_view = captor_parent_view->getParent();
+ }
+ }
+
+ // aggregate visible views that contain mouse cursor in display order
+ LLPopupView::popup_list_t popups = mPopupView->getCurrentPopups();
+
+ for(LLPopupView::popup_list_t::iterator popup_it = popups.begin(); popup_it != popups.end(); ++popup_it)
+ {
+ LLView* popup = popup_it->get();
+ if (popup && popup->calcScreenBoundingRect().pointInRect(x, y))
+ {
+ // iterator over contents of top_ctrl, and throw into mouse_hover_set
+ for (LLView::tree_iterator_t it = popup->beginTreeDFS();
+ it != popup->endTreeDFS();
+ ++it)
+ {
+ LLView* viewp = *it;
+ if (viewp->getVisible()
+ && viewp->calcScreenBoundingRect().pointInRect(x, y))
+ {
+ // we have a view that contains the mouse, add it to the set
+ mouse_hover_set.insert(viewp->getHandle());
+ }
+ else
+ {
+ // skip this view and all of its children
+ it.skipDescendants();
+ }
+ }
+ }
+ }
+
+ // while the top_ctrl contains the mouse cursor, only it and its descendants will receive onMouseEnter events
+ if (top_ctrl && top_ctrl->calcScreenBoundingRect().pointInRect(x, y))
+ {
+ // iterator over contents of top_ctrl, and throw into mouse_hover_set
+ for (LLView::tree_iterator_t it = top_ctrl->beginTreeDFS();
+ it != top_ctrl->endTreeDFS();
+ ++it)
+ {
+ LLView* viewp = *it;
+ if (viewp->getVisible()
+ && viewp->calcScreenBoundingRect().pointInRect(x, y))
+ {
+ // we have a view that contains the mouse, add it to the set
+ mouse_hover_set.insert(viewp->getHandle());
+ }
+ else
+ {
+ // skip this view and all of its children
+ it.skipDescendants();
+ }
+ }
+ }
+ else
+ {
+ // walk UI tree in depth-first order
+ for (LLView::tree_iterator_t it = root_view->beginTreeDFS();
+ it != root_view->endTreeDFS();
+ ++it)
+ {
+ LLView* viewp = *it;
+ // calculating the screen rect involves traversing the parent, so this is less than optimal
+ if (viewp->getVisible()
+ && viewp->calcScreenBoundingRect().pointInRect(x, y))
+ {
+
+ // if this view is mouse opaque, nothing behind it should be in mouse_hover_set
+ if (viewp->getMouseOpaque())
+ {
+ // constrain further iteration to children of this widget
+ it = viewp->beginTreeDFS();
+ }
+
+ // we have a view that contains the mouse, add it to the set
+ mouse_hover_set.insert(viewp->getHandle());
+ }
+ else
+ {
+ // skip this view and all of its children
+ it.skipDescendants();
+ }
+ }
+ }
+ }
+
+ typedef std::vector<LLHandle<LLView> > view_handle_list_t;
+
+ // call onMouseEnter() on all views which contain the mouse cursor but did not before
+ view_handle_list_t mouse_enter_views;
+ std::set_difference(mouse_hover_set.begin(), mouse_hover_set.end(),
+ mMouseHoverViews.begin(), mMouseHoverViews.end(),
+ std::back_inserter(mouse_enter_views));
+ for (view_handle_list_t::iterator it = mouse_enter_views.begin();
+ it != mouse_enter_views.end();
+ ++it)
+ {
+ LLView* viewp = it->get();
+ if (viewp)
+ {
+ LLRect view_screen_rect = viewp->calcScreenRect();
+ viewp->onMouseEnter(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask);
+ }
+ }
+
+ // call onMouseLeave() on all views which no longer contain the mouse cursor
+ view_handle_list_t mouse_leave_views;
+ std::set_difference(mMouseHoverViews.begin(), mMouseHoverViews.end(),
+ mouse_hover_set.begin(), mouse_hover_set.end(),
+ std::back_inserter(mouse_leave_views));
+ for (view_handle_list_t::iterator it = mouse_leave_views.begin();
+ it != mouse_leave_views.end();
+ ++it)
+ {
+ LLView* viewp = it->get();
+ if (viewp)
+ {
+ LLRect view_screen_rect = viewp->calcScreenRect();
+ viewp->onMouseLeave(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask);
+ }
+ }
+
+ // store resulting hover set for next frame
+ swap(mMouseHoverViews, mouse_hover_set);
+
+ // only handle hover events when UI is enabled
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+
+ if( mouse_captor )
+ {
+ // Pass hover events to object capturing mouse events.
+ S32 local_x;
+ S32 local_y;
+ mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
+ handled = mouse_captor->handleHover(local_x, local_y, mask);
+ if (LLView::sDebugMouseHandling)
+ {
+ LL_INFOS() << "Hover handled by captor " << mouse_captor->getName() << LL_ENDL;
+ }
+
+ if( !handled )
+ {
+ LL_DEBUGS("UserInput") << "hover not handled by mouse captor" << LL_ENDL;
+ }
+ }
+ else
+ {
+ if (top_ctrl)
+ {
+ S32 local_x, local_y;
+ top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
+ handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleHover(local_x, local_y, mask);
+ }
+
+ if ( !handled )
+ {
+ // x and y are from last time mouse was in window
+ // mMouseInWindow tracks *actual* mouse location
+ if (mMouseInWindow && mRootView->handleHover(x, y, mask) )
+ {
+ if (LLView::sDebugMouseHandling && LLView::sMouseHandlerMessage != last_handle_msg)
+ {
+ last_handle_msg = LLView::sMouseHandlerMessage;
+ LL_INFOS() << "Hover" << LLView::sMouseHandlerMessage << LL_ENDL;
+ }
+ handled = true;
+ }
+ else if (LLView::sDebugMouseHandling)
+ {
+ if (last_handle_msg != LLStringUtil::null)
+ {
+ last_handle_msg.clear();
+ LL_INFOS() << "Hover not handled by view" << LL_ENDL;
+ }
+ }
+ }
+
+ if (!handled)
+ {
+ LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
+
+ if(mMouseInWindow && tool)
+ {
+ handled = tool->handleHover(x, y, mask);
+ }
+ }
+ }
+
+ // Show a new tool tip (or update one that is already shown)
+ bool tool_tip_handled = false;
+ std::string tool_tip_msg;
+ if( handled
+ && !mWindow->isCursorHidden())
+ {
+ LLRect screen_sticky_rect = mRootView->getLocalRect();
+ S32 local_x, local_y;
+
+ static LLCachedControl<bool> debug_show_xui_names(gSavedSettings, "DebugShowXUINames", 0);
+ if (debug_show_xui_names)
+ {
+ LLToolTip::Params params;
+
+ LLView* tooltip_view = mRootView;
+ LLView::tree_iterator_t end_it = mRootView->endTreeDFS();
+ for (LLView::tree_iterator_t it = mRootView->beginTreeDFS(); it != end_it; ++it)
+ {
+ LLView* viewp = *it;
+ LLRect screen_rect;
+ viewp->localRectToScreen(viewp->getLocalRect(), &screen_rect);
+ if (!(viewp->getVisible()
+ && screen_rect.pointInRect(x, y)))
+ {
+ it.skipDescendants();
+ }
+ // only report xui names for LLUICtrls,
+ // and blacklist the various containers we don't care about
+ else if (dynamic_cast<LLUICtrl*>(viewp)
+ && viewp != gMenuHolder
+ && viewp != gFloaterView
+ && viewp != gConsole)
+ {
+ if (dynamic_cast<LLFloater*>(viewp))
+ {
+ // constrain search to descendants of this (frontmost) floater
+ // by resetting iterator
+ it = viewp->beginTreeDFS();
+ }
+
+ // if we are in a new part of the tree (not a descendent of current tooltip_view)
+ // then push the results for tooltip_view and start with a new potential view
+ // NOTE: this emulates visiting only the leaf nodes that meet our criteria
+ if (!viewp->hasAncestor(tooltip_view))
+ {
+ append_xui_tooltip(tooltip_view, params);
+ screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
+ }
+ tooltip_view = viewp;
+ }
+ }
+
+ append_xui_tooltip(tooltip_view, params);
+ params.styled_message.add().text("\n");
+
+ screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
+
+ params.sticky_rect = screen_sticky_rect;
+ params.max_width = 400;
+
+ LLToolTipMgr::instance().show(params);
+ }
+ // if there is a mouse captor, nothing else gets a tooltip
+ else if (mouse_captor)
+ {
+ mouse_captor->screenPointToLocal(x, y, &local_x, &local_y);
+ tool_tip_handled = mouse_captor->handleToolTip(local_x, local_y, mask);
+ }
+ else
+ {
+ // next is top_ctrl
+ if (!tool_tip_handled && top_ctrl)
+ {
+ top_ctrl->screenPointToLocal(x, y, &local_x, &local_y);
+ tool_tip_handled = top_ctrl->handleToolTip(local_x, local_y, mask );
+ }
+
+ if (!tool_tip_handled)
+ {
+ local_x = x; local_y = y;
+ tool_tip_handled = mRootView->handleToolTip(local_x, local_y, mask );
+ }
+
+ LLTool* current_tool = LLToolMgr::getInstance()->getCurrentTool();
+ if (!tool_tip_handled && current_tool)
+ {
+ current_tool->screenPointToLocal(x, y, &local_x, &local_y);
+ tool_tip_handled = current_tool->handleToolTip(local_x, local_y, mask );
+ }
+ }
+ }
+ }
+ else
+ { // just have tools handle hover when UI is turned off
+ LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
+
+ if(mMouseInWindow && tool)
+ {
+ handled = tool->handleHover(x, y, mask);
+ }
+ }
+
+ updateLayout();
+
+ mLastMousePoint = mCurrentMousePoint;
+
+ // cleanup unused selections when no modal dialogs are open
+ if (LLModalDialog::activeCount() == 0)
+ {
+ LLViewerParcelMgr::getInstance()->deselectUnused();
+ }
+
+ if (LLModalDialog::activeCount() == 0)
+ {
+ LLSelectMgr::getInstance()->deselectUnused();
+ }
+}
+
+
+void LLViewerWindow::updateLayout()
+{
+ LLTool* tool = LLToolMgr::getInstance()->getCurrentTool();
+ if (gFloaterTools != NULL
+ && tool != NULL
+ && tool != gToolNull
+ && tool != LLToolCompInspect::getInstance()
+ && tool != LLToolDragAndDrop::getInstance()
+ && !gSavedSettings.getBOOL("FreezeTime"))
+ {
+ // Suppress the toolbox view if our source tool was the pie tool,
+ // and we've overridden to something else.
+ bool suppress_toolbox =
+ (LLToolMgr::getInstance()->getBaseTool() == LLToolPie::getInstance()) &&
+ (LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance());
+
+ LLMouseHandler *captor = gFocusMgr.getMouseCapture();
+ // With the null, inspect, or drag and drop tool, don't muck
+ // with visibility.
+
+ if (gFloaterTools->isMinimized()
+ || (tool != LLToolPie::getInstance() // not default tool
+ && tool != LLToolCompGun::getInstance() // not coming out of mouselook
+ && !suppress_toolbox // not override in third person
+ && LLToolMgr::getInstance()->getCurrentToolset()->isShowFloaterTools()
+ && (!captor || dynamic_cast<LLView*>(captor) != NULL))) // not dragging
+ {
+ // Force floater tools to be visible (unless minimized)
+ if (!gFloaterTools->getVisible())
+ {
+ gFloaterTools->openFloater();
+ }
+ // Update the location of the blue box tool popup
+ LLCoordGL select_center_screen;
+ MASK mask = gKeyboard->currentMask(true);
+ gFloaterTools->updatePopup( select_center_screen, mask );
+ }
+ else
+ {
+ gFloaterTools->setVisible(false);
+ }
+ //gMenuBarView->setItemVisible("BuildTools", gFloaterTools->getVisible());
+ }
+
+ // Always update console
+ if(gConsole)
+ {
+ LLRect console_rect = getChatConsoleRect();
+ gConsole->reshape(console_rect.getWidth(), console_rect.getHeight());
+ gConsole->setRect(console_rect);
+ }
+}
+
+void LLViewerWindow::updateMouseDelta()
+{
+#if LL_WINDOWS
+ LLCoordCommon delta;
+ mWindow->getCursorDelta(&delta);
+ S32 dx = delta.mX;
+ S32 dy = delta.mY;
+#else
+ S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::getScaleFactor().mV[VX]);
+ S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::getScaleFactor().mV[VY]);
+#endif
+
+ //RN: fix for asynchronous notification of mouse leaving window not working
+ LLCoordWindow mouse_pos;
+ mWindow->getCursorPosition(&mouse_pos);
+ if (mouse_pos.mX < 0 ||
+ mouse_pos.mY < 0 ||
+ mouse_pos.mX > mWindowRectRaw.getWidth() ||
+ mouse_pos.mY > mWindowRectRaw.getHeight())
+ {
+ mMouseInWindow = false;
+ }
+ else
+ {
+ mMouseInWindow = true;
+ }
+
+ LLVector2 mouse_vel;
+
+ if (gSavedSettings.getBOOL("MouseSmooth"))
+ {
+ static F32 fdx = 0.f;
+ static F32 fdy = 0.f;
+
+ F32 amount = 16.f;
+ fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds.value()*amount,1.f);
+ fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds.value()*amount,1.f);
+
+ mCurrentMouseDelta.set(ll_round(fdx), ll_round(fdy));
+ mouse_vel.setVec(fdx,fdy);
+ }
+ else
+ {
+ mCurrentMouseDelta.set(dx, dy);
+ mouse_vel.setVec((F32) dx, (F32) dy);
+ }
+
+ sample(sMouseVelocityStat, mouse_vel.magVec());
+}
+
+void LLViewerWindow::updateKeyboardFocus()
+{
+ if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ gFocusMgr.setKeyboardFocus(NULL);
+ }
+
+ // clean up current focus
+ LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
+ if (cur_focus)
+ {
+ if (!cur_focus->isInVisibleChain() || !cur_focus->isInEnabledChain())
+ {
+ // don't release focus, just reassign so that if being given
+ // to a sibling won't call onFocusLost on all the ancestors
+ // gFocusMgr.releaseFocusIfNeeded(cur_focus);
+
+ LLUICtrl* parent = cur_focus->getParentUICtrl();
+ const LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot();
+ bool new_focus_found = false;
+ while(parent)
+ {
+ if (parent->isCtrl()
+ && (parent->hasTabStop() || parent == focus_root)
+ && !parent->getIsChrome()
+ && parent->isInVisibleChain()
+ && parent->isInEnabledChain())
+ {
+ if (!parent->focusFirstItem())
+ {
+ parent->setFocus(true);
+ }
+ new_focus_found = true;
+ break;
+ }
+ parent = parent->getParentUICtrl();
+ }
+
+ // if we didn't find a better place to put focus, just release it
+ // hasFocus() will return true if and only if we didn't touch focus since we
+ // are only moving focus higher in the hierarchy
+ if (!new_focus_found)
+ {
+ cur_focus->setFocus(false);
+ }
+ }
+ else if (cur_focus->isFocusRoot())
+ {
+ // focus roots keep trying to delegate focus to their first valid descendant
+ // this assumes that focus roots are not valid focus holders on their own
+ cur_focus->focusFirstItem();
+ }
+ }
+
+ // last ditch force of edit menu to selection manager
+ if (LLEditMenuHandler::gEditMenuHandler == NULL && LLSelectMgr::getInstance()->getSelection()->getObjectCount())
+ {
+ LLEditMenuHandler::gEditMenuHandler = LLSelectMgr::getInstance();
+ }
+
+ if (gFloaterView->getCycleMode())
+ {
+ // sync all floaters with their focus state
+ gFloaterView->highlightFocusedFloater();
+ gSnapshotFloaterView->highlightFocusedFloater();
+ MASK mask = gKeyboard->currentMask(true);
+ if ((mask & MASK_CONTROL) == 0)
+ {
+ // control key no longer held down, finish cycle mode
+ gFloaterView->setCycleMode(false);
+
+ gFloaterView->syncFloaterTabOrder();
+ }
+ else
+ {
+ // user holding down CTRL, don't update tab order of floaters
+ }
+ }
+ else
+ {
+ // update focused floater
+ gFloaterView->highlightFocusedFloater();
+ gSnapshotFloaterView->highlightFocusedFloater();
+ // make sure floater visible order is in sync with tab order
+ gFloaterView->syncFloaterTabOrder();
+ }
+}
+
+static LLTrace::BlockTimerStatHandle FTM_UPDATE_WORLD_VIEW("Update World View");
+void LLViewerWindow::updateWorldViewRect(bool use_full_window)
+{
+ LL_RECORD_BLOCK_TIME(FTM_UPDATE_WORLD_VIEW);
+
+ // start off using whole window to render world
+ LLRect new_world_rect = mWindowRectRaw;
+
+ if (!use_full_window && mWorldViewPlaceholder.get())
+ {
+ new_world_rect = mWorldViewPlaceholder.get()->calcScreenRect();
+ // clamp to at least a 1x1 rect so we don't try to allocate zero width gl buffers
+ new_world_rect.mTop = llmax(new_world_rect.mTop, new_world_rect.mBottom + 1);
+ new_world_rect.mRight = llmax(new_world_rect.mRight, new_world_rect.mLeft + 1);
+
+ new_world_rect.mLeft = ll_round((F32)new_world_rect.mLeft * mDisplayScale.mV[VX]);
+ new_world_rect.mRight = ll_round((F32)new_world_rect.mRight * mDisplayScale.mV[VX]);
+ new_world_rect.mBottom = ll_round((F32)new_world_rect.mBottom * mDisplayScale.mV[VY]);
+ new_world_rect.mTop = ll_round((F32)new_world_rect.mTop * mDisplayScale.mV[VY]);
+ }
+
+ if (mWorldViewRectRaw != new_world_rect)
+ {
+ mWorldViewRectRaw = new_world_rect;
+ gResizeScreenTexture = true;
+ LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
+ LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() );
+
+ LLRect old_world_rect_scaled = mWorldViewRectScaled;
+ mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale);
+
+ // sending a signal with a new WorldView rect
+ mOnWorldViewRectUpdated(old_world_rect_scaled, mWorldViewRectScaled);
+ }
+}
+
+void LLViewerWindow::saveLastMouse(const LLCoordGL &point)
+{
+ // Store last mouse location.
+ // If mouse leaves window, pretend last point was on edge of window
+
+ if (point.mX < 0)
+ {
+ mCurrentMousePoint.mX = 0;
+ }
+ else if (point.mX > getWindowWidthScaled())
+ {
+ mCurrentMousePoint.mX = getWindowWidthScaled();
+ }
+ else
+ {
+ mCurrentMousePoint.mX = point.mX;
+ }
+
+ if (point.mY < 0)
+ {
+ mCurrentMousePoint.mY = 0;
+ }
+ else if (point.mY > getWindowHeightScaled() )
+ {
+ mCurrentMousePoint.mY = getWindowHeightScaled();
+ }
+ else
+ {
+ mCurrentMousePoint.mY = point.mY;
+ }
+}
+
+
+// Draws the selection outlines for the currently selected objects
+// Must be called after displayObjects is called, which sets the mGLName parameter
+// NOTE: This function gets called 3 times:
+// render_ui_3d: false, false, true
+// render_hud_elements: false, false, false
+void LLViewerWindow::renderSelections( bool for_gl_pick, bool pick_parcel_walls, bool for_hud )
+{
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+
+ if (!for_hud && !for_gl_pick)
+ {
+ // Call this once and only once
+ LLSelectMgr::getInstance()->updateSilhouettes();
+ }
+
+ // Draw fence around land selections
+ if (for_gl_pick)
+ {
+ if (pick_parcel_walls)
+ {
+ LLViewerParcelMgr::getInstance()->renderParcelCollision();
+ }
+ }
+ else if (( for_hud && selection->getSelectType() == SELECT_TYPE_HUD) ||
+ (!for_hud && selection->getSelectType() != SELECT_TYPE_HUD))
+ {
+ LLSelectMgr::getInstance()->renderSilhouettes(for_hud);
+
+ stop_glerror();
+
+ // setup HUD render
+ if (selection->getSelectType() == SELECT_TYPE_HUD && LLSelectMgr::getInstance()->getSelection()->getObjectCount())
+ {
+ LLBBox hud_bbox = gAgentAvatarp->getHUDBBox();
+
+ // set up transform to encompass bounding box of HUD
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+ F32 depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
+ gGL.ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, depth);
+
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+ gGL.loadMatrix(OGL_TO_CFR_ROTATION); // Load Cory's favorite reference frame
+ gGL.translatef(-hud_bbox.getCenterLocal().mV[VX] + (depth *0.5f), 0.f, 0.f);
+ }
+
+ // Render light for editing
+ if (LLSelectMgr::sRenderLightRadius && LLToolMgr::getInstance()->inEdit())
+ {
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ LLGLEnable gls_blend(GL_BLEND);
+ LLGLEnable gls_cull(GL_CULL_FACE);
+ LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.pushMatrix();
+ if (selection->getSelectType() == SELECT_TYPE_HUD)
+ {
+ F32 zoom = gAgentCamera.mHUDCurZoom;
+ gGL.scalef(zoom, zoom, zoom);
+ }
+
+ struct f : public LLSelectedObjectFunctor
+ {
+ virtual bool apply(LLViewerObject* object)
+ {
+ LLDrawable* drawable = object->mDrawable;
+ if (drawable && drawable->isLight())
+ {
+ LLVOVolume* vovolume = drawable->getVOVolume();
+ gGL.pushMatrix();
+
+ LLVector3 center = drawable->getPositionAgent();
+ gGL.translatef(center[0], center[1], center[2]);
+ F32 scale = vovolume->getLightRadius();
+ gGL.scalef(scale, scale, scale);
+
+ LLColor4 color(vovolume->getLightSRGBColor(), .5f);
+ gGL.color4fv(color.mV);
+
+ //F32 pixel_area = 100000.f;
+ // Render Outside
+ gSphere.render();
+
+ // Render Inside
+ glCullFace(GL_FRONT);
+ gSphere.render();
+ glCullFace(GL_BACK);
+
+ gGL.popMatrix();
+ }
+ return true;
+ }
+ } func;
+ LLSelectMgr::getInstance()->getSelection()->applyToObjects(&func);
+
+ gGL.popMatrix();
+ }
+
+ // NOTE: The average position for the axis arrows of the selected objects should
+ // not be recalculated at this time. If they are, then group rotations will break.
+
+ // Draw arrows at average center of all selected objects
+ LLTool* tool = LLToolMgr::getInstance()->getCurrentTool();
+ if (tool)
+ {
+ if(tool->isAlwaysRendered())
+ {
+ tool->render();
+ }
+ else
+ {
+ if( !LLSelectMgr::getInstance()->getSelection()->isEmpty() )
+ {
+ bool all_selected_objects_move;
+ bool all_selected_objects_modify;
+ // Note: This might be costly to do on each frame and when a lot of objects are selected
+ // we might be better off with some kind of memory for selection and/or states, consider
+ // optimizing, perhaps even some kind of selection generation at level of LLSelectMgr to
+ // make whole viewer benefit.
+ LLSelectMgr::getInstance()->selectGetEditMoveLinksetPermissions(all_selected_objects_move, all_selected_objects_modify);
+
+ bool draw_handles = true;
+
+ if (tool == LLToolCompTranslate::getInstance() && !all_selected_objects_move && !LLSelectMgr::getInstance()->isMovableAvatarSelected())
+ {
+ draw_handles = false;
+ }
+
+ if (tool == LLToolCompRotate::getInstance() && !all_selected_objects_move && !LLSelectMgr::getInstance()->isMovableAvatarSelected())
+ {
+ draw_handles = false;
+ }
+
+ if ( !all_selected_objects_modify && tool == LLToolCompScale::getInstance() )
+ {
+ draw_handles = false;
+ }
+
+ if( draw_handles )
+ {
+ tool->render();
+ }
+ }
+ }
+ if (selection->getSelectType() == SELECT_TYPE_HUD && selection->getObjectCount())
+ {
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+ stop_glerror();
+ }
+ }
+ }
+}
+
+// Return a point near the clicked object representative of the place the object was clicked.
+LLVector3d LLViewerWindow::clickPointInWorldGlobal(S32 x, S32 y_from_bot, LLViewerObject* clicked_object) const
+{
+ // create a normalized vector pointing from the camera center into the
+ // world at the location of the mouse click
+ LLVector3 mouse_direction_global = mouseDirectionGlobal( x, y_from_bot );
+
+ LLVector3d relative_object = clicked_object->getPositionGlobal() - gAgentCamera.getCameraPositionGlobal();
+
+ // make mouse vector as long as object vector, so it touchs a point near
+ // where the user clicked on the object
+ mouse_direction_global *= (F32) relative_object.magVec();
+
+ LLVector3d new_pos;
+ new_pos.setVec(mouse_direction_global);
+ // transform mouse vector back to world coords
+ new_pos += gAgentCamera.getCameraPositionGlobal();
+
+ return new_pos;
+}
+
+
+bool LLViewerWindow::clickPointOnSurfaceGlobal(const S32 x, const S32 y, LLViewerObject *objectp, LLVector3d &point_global) const
+{
+ bool intersect = false;
+
+// U8 shape = objectp->mPrimitiveCode & LL_PCODE_BASE_MASK;
+ if (!intersect)
+ {
+ point_global = clickPointInWorldGlobal(x, y, objectp);
+ LL_INFOS() << "approx intersection at " << (objectp->getPositionGlobal() - point_global) << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS() << "good intersection at " << (objectp->getPositionGlobal() - point_global) << LL_ENDL;
+ }
+
+ return intersect;
+}
+
+void LLViewerWindow::pickAsync( S32 x,
+ S32 y_from_bot,
+ MASK mask,
+ void (*callback)(const LLPickInfo& info),
+ bool pick_transparent,
+ bool pick_rigged,
+ bool pick_unselectable,
+ bool pick_reflection_probes)
+{
+ // "Show Debug Alpha" means no object actually transparent
+ bool in_build_mode = LLFloaterReg::instanceVisible("build");
+ if (LLDrawPoolAlpha::sShowDebugAlpha
+ || (in_build_mode && gSavedSettings.getBOOL("SelectInvisibleObjects")))
+ {
+ pick_transparent = true;
+ }
+
+ LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, pick_rigged, false, pick_reflection_probes, pick_unselectable, true, callback);
+ schedulePick(pick_info);
+}
+
+void LLViewerWindow::schedulePick(LLPickInfo& pick_info)
+{
+ if (mPicks.size() >= 1024 || mWindow->getMinimized())
+ { //something went wrong, picks are being scheduled but not processed
+
+ if (pick_info.mPickCallback)
+ {
+ pick_info.mPickCallback(pick_info);
+ }
+
+ return;
+ }
+ mPicks.push_back(pick_info);
+
+ // delay further event processing until we receive results of pick
+ // only do this for async picks so that handleMouseUp won't be called
+ // until the pick triggered in handleMouseDown has been processed, for example
+ mWindow->delayInputProcessing();
+}
+
+
+void LLViewerWindow::performPick()
+{
+ if (!mPicks.empty())
+ {
+ std::vector<LLPickInfo>::iterator pick_it;
+ for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it)
+ {
+ pick_it->fetchResults();
+ }
+
+ mLastPick = mPicks.back();
+ mPicks.clear();
+ }
+}
+
+void LLViewerWindow::returnEmptyPicks()
+{
+ std::vector<LLPickInfo>::iterator pick_it;
+ for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it)
+ {
+ mLastPick = *pick_it;
+ // just trigger callback with empty results
+ if (pick_it->mPickCallback)
+ {
+ pick_it->mPickCallback(*pick_it);
+ }
+ }
+ mPicks.clear();
+}
+
+// Performs the GL object/land pick.
+LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, bool pick_transparent, bool pick_rigged, bool pick_particle, bool pick_unselectable, bool pick_reflection_probe)
+{
+ bool in_build_mode = LLFloaterReg::instanceVisible("build");
+ if ((in_build_mode && gSavedSettings.getBOOL("SelectInvisibleObjects")) || LLDrawPoolAlpha::sShowDebugAlpha)
+ {
+ // build mode allows interaction with all transparent objects
+ // "Show Debug Alpha" means no object actually transparent
+ pick_transparent = true;
+ }
+
+ // shortcut queueing in mPicks and just update mLastPick in place
+ MASK key_mask = gKeyboard->currentMask(true);
+ mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), key_mask, pick_transparent, pick_rigged, pick_particle, pick_reflection_probe, true, false, NULL);
+ mLastPick.fetchResults();
+
+ return mLastPick;
+}
+
+LLHUDIcon* LLViewerWindow::cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 depth,
+ LLVector4a* intersection)
+{
+ S32 x = mouse_x;
+ S32 y = mouse_y;
+
+ if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position
+ {
+ x = getCurrentMouseX();
+ y = getCurrentMouseY();
+ }
+
+ // world coordinates of mouse
+ // VECTORIZE THIS
+ LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
+ LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin();
+ LLVector3 mouse_world_start = mouse_point_global;
+ LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth;
+
+ LLVector4a start, end;
+ start.load3(mouse_world_start.mV);
+ end.load3(mouse_world_end.mV);
+
+ return LLHUDIcon::lineSegmentIntersectAll(start, end, intersection);
+}
+
+LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 depth,
+ LLViewerObject *this_object,
+ S32 this_face,
+ bool pick_transparent,
+ bool pick_rigged,
+ bool pick_unselectable,
+ bool pick_reflection_probe,
+ S32* face_hit,
+ LLVector4a *intersection,
+ LLVector2 *uv,
+ LLVector4a *normal,
+ LLVector4a *tangent,
+ LLVector4a* start,
+ LLVector4a* end)
+{
+ S32 x = mouse_x;
+ S32 y = mouse_y;
+
+ if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position
+ {
+ x = getCurrentMouseX();
+ y = getCurrentMouseY();
+ }
+
+ // HUD coordinates of mouse
+ LLVector3 mouse_point_hud = mousePointHUD(x, y);
+ LLVector3 mouse_hud_start = mouse_point_hud - LLVector3(depth, 0, 0);
+ LLVector3 mouse_hud_end = mouse_point_hud + LLVector3(depth, 0, 0);
+
+ // world coordinates of mouse
+ LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
+ LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin();
+
+ //get near clip plane
+ LLVector3 n = LLViewerCamera::getInstance()->getAtAxis();
+ LLVector3 p = mouse_point_global + n * LLViewerCamera::getInstance()->getNear();
+
+ //project mouse point onto plane
+ LLVector3 pos;
+ line_plane(mouse_point_global, mouse_direction_global, p, n, pos);
+ mouse_point_global = pos;
+
+ LLVector3 mouse_world_start = mouse_point_global;
+ LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth;
+
+ if (!LLViewerJoystick::getInstance()->getOverrideCamera())
+ { //always set raycast intersection to mouse_world_end unless
+ //flycam is on (for DoF effect)
+ gDebugRaycastIntersection.load3(mouse_world_end.mV);
+ }
+
+ LLVector4a mw_start;
+ mw_start.load3(mouse_world_start.mV);
+ LLVector4a mw_end;
+ mw_end.load3(mouse_world_end.mV);
+
+ LLVector4a mh_start;
+ mh_start.load3(mouse_hud_start.mV);
+ LLVector4a mh_end;
+ mh_end.load3(mouse_hud_end.mV);
+
+ if (start)
+ {
+ *start = mw_start;
+ }
+
+ if (end)
+ {
+ *end = mw_end;
+ }
+
+ LLViewerObject* found = NULL;
+
+ if (this_object) // check only this object
+ {
+ if (this_object->isHUDAttachment()) // is a HUD object?
+ {
+ if (this_object->lineSegmentIntersect(mh_start, mh_end, this_face, pick_transparent, pick_rigged, pick_unselectable,
+ face_hit, intersection, uv, normal, tangent))
+ {
+ found = this_object;
+ }
+ }
+ else // is a world object
+ {
+ if ((pick_reflection_probe || !this_object->isReflectionProbe())
+ && this_object->lineSegmentIntersect(mw_start, mw_end, this_face, pick_transparent, pick_rigged, pick_unselectable,
+ face_hit, intersection, uv, normal, tangent))
+ {
+ found = this_object;
+ }
+ }
+ }
+ else // check ALL objects
+ {
+ found = gPipeline.lineSegmentIntersectInHUD(mh_start, mh_end, pick_transparent,
+ face_hit, intersection, uv, normal, tangent);
+
+ if (!found) // if not found in HUD, look in world:
+ {
+ found = gPipeline.lineSegmentIntersectInWorld(mw_start, mw_end, pick_transparent, pick_rigged, pick_unselectable, pick_reflection_probe,
+ face_hit, intersection, uv, normal, tangent);
+ if (found && !pick_transparent)
+ {
+ gDebugRaycastIntersection = *intersection;
+ }
+ }
+ }
+
+ return found;
+}
+
+// Returns unit vector relative to camera
+// indicating direction of point on screen x,y
+LLVector3 LLViewerWindow::mouseDirectionGlobal(const S32 x, const S32 y) const
+{
+ // find vertical field of view
+ F32 fov = LLViewerCamera::getInstance()->getView();
+
+ // find world view center in scaled ui coordinates
+ F32 center_x = getWorldViewRectScaled().getCenterX();
+ F32 center_y = getWorldViewRectScaled().getCenterY();
+
+ // calculate pixel distance to screen
+ F32 distance = ((F32)getWorldViewHeightScaled() * 0.5f) / (tan(fov / 2.f));
+
+ // calculate click point relative to middle of screen
+ F32 click_x = x - center_x;
+ F32 click_y = y - center_y;
+
+ // compute mouse vector
+ LLVector3 mouse_vector = distance * LLViewerCamera::getInstance()->getAtAxis()
+ - click_x * LLViewerCamera::getInstance()->getLeftAxis()
+ + click_y * LLViewerCamera::getInstance()->getUpAxis();
+
+ mouse_vector.normVec();
+
+ return mouse_vector;
+}
+
+LLVector3 LLViewerWindow::mousePointHUD(const S32 x, const S32 y) const
+{
+ // find screen resolution
+ S32 height = getWorldViewHeightScaled();
+
+ // find world view center
+ F32 center_x = getWorldViewRectScaled().getCenterX();
+ F32 center_y = getWorldViewRectScaled().getCenterY();
+
+ // remap with uniform scale (1/height) so that top is -0.5, bottom is +0.5
+ F32 hud_x = -((F32)x - center_x) / height;
+ F32 hud_y = ((F32)y - center_y) / height;
+
+ return LLVector3(0.f, hud_x/gAgentCamera.mHUDCurZoom, hud_y/gAgentCamera.mHUDCurZoom);
+}
+
+// Returns unit vector relative to camera in camera space
+// indicating direction of point on screen x,y
+LLVector3 LLViewerWindow::mouseDirectionCamera(const S32 x, const S32 y) const
+{
+ // find vertical field of view
+ F32 fov_height = LLViewerCamera::getInstance()->getView();
+ F32 fov_width = fov_height * LLViewerCamera::getInstance()->getAspect();
+
+ // find screen resolution
+ S32 height = getWorldViewHeightScaled();
+ S32 width = getWorldViewWidthScaled();
+
+ // find world view center
+ F32 center_x = getWorldViewRectScaled().getCenterX();
+ F32 center_y = getWorldViewRectScaled().getCenterY();
+
+ // calculate click point relative to middle of screen
+ F32 click_x = (((F32)x - center_x) / (F32)width) * fov_width * -1.f;
+ F32 click_y = (((F32)y - center_y) / (F32)height) * fov_height;
+
+ // compute mouse vector
+ LLVector3 mouse_vector = LLVector3(0.f, 0.f, -1.f);
+ LLQuaternion mouse_rotate;
+ mouse_rotate.setQuat(click_y, click_x, 0.f);
+
+ mouse_vector = mouse_vector * mouse_rotate;
+ // project to z = -1 plane;
+ mouse_vector = mouse_vector * (-1.f / mouse_vector.mV[VZ]);
+
+ return mouse_vector;
+}
+
+
+
+bool LLViewerWindow::mousePointOnPlaneGlobal(LLVector3d& point, const S32 x, const S32 y,
+ const LLVector3d &plane_point_global,
+ const LLVector3 &plane_normal_global)
+{
+ LLVector3d mouse_direction_global_d;
+
+ mouse_direction_global_d.setVec(mouseDirectionGlobal(x,y));
+ LLVector3d plane_normal_global_d;
+ plane_normal_global_d.setVec(plane_normal_global);
+ F64 plane_mouse_dot = (plane_normal_global_d * mouse_direction_global_d);
+ LLVector3d plane_origin_camera_rel = plane_point_global - gAgentCamera.getCameraPositionGlobal();
+ F64 mouse_look_at_scale = (plane_normal_global_d * plane_origin_camera_rel)
+ / plane_mouse_dot;
+ if (llabs(plane_mouse_dot) < 0.00001)
+ {
+ // if mouse is parallel to plane, return closest point on line through plane origin
+ // that is parallel to camera plane by scaling mouse direction vector
+ // by distance to plane origin, modulated by deviation of mouse direction from plane origin
+ LLVector3d plane_origin_dir = plane_origin_camera_rel;
+ plane_origin_dir.normVec();
+
+ mouse_look_at_scale = plane_origin_camera_rel.magVec() / (plane_origin_dir * mouse_direction_global_d);
+ }
+
+ point = gAgentCamera.getCameraPositionGlobal() + mouse_look_at_scale * mouse_direction_global_d;
+
+ return mouse_look_at_scale > 0.0;
+}
+
+
+// Returns global position
+bool LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d *land_position_global, bool ignore_distance)
+{
+ LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
+ F32 mouse_dir_scale;
+ bool hit_land = false;
+ LLViewerRegion *regionp;
+ F32 land_z;
+ const F32 FIRST_PASS_STEP = 1.0f; // meters
+ const F32 SECOND_PASS_STEP = 0.1f; // meters
+ const F32 draw_distance = ignore_distance ? MAX_FAR_CLIP : gAgentCamera.mDrawDistance;
+ LLVector3d camera_pos_global;
+
+ camera_pos_global = gAgentCamera.getCameraPositionGlobal();
+ LLVector3d probe_point_global;
+ LLVector3 probe_point_region;
+
+ // walk forwards to find the point
+ for (mouse_dir_scale = FIRST_PASS_STEP; mouse_dir_scale < draw_distance; mouse_dir_scale += FIRST_PASS_STEP)
+ {
+ LLVector3d mouse_direction_global_d;
+ mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale);
+ probe_point_global = camera_pos_global + mouse_direction_global_d;
+
+ regionp = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global);
+
+ if (!regionp)
+ {
+ // ...we're outside the world somehow
+ continue;
+ }
+
+ S32 i = (S32) (probe_point_region.mV[VX]/regionp->getLand().getMetersPerGrid());
+ S32 j = (S32) (probe_point_region.mV[VY]/regionp->getLand().getMetersPerGrid());
+ S32 grids_per_edge = (S32) regionp->getLand().mGridsPerEdge;
+ if ((i >= grids_per_edge) || (j >= grids_per_edge))
+ {
+ //LL_INFOS() << "LLViewerWindow::mousePointOnLand probe_point is out of region" << LL_ENDL;
+ continue;
+ }
+
+ land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
+
+ //LL_INFOS() << "mousePointOnLand initial z " << land_z << LL_ENDL;
+
+ if (probe_point_region.mV[VZ] < land_z)
+ {
+ // ...just went under land
+
+ // cout << "under land at " << probe_point << " scale " << mouse_vec_scale << endl;
+
+ hit_land = true;
+ break;
+ }
+ }
+
+
+ if (hit_land)
+ {
+ // Don't go more than one step beyond where we stopped above.
+ // This can't just be "mouse_vec_scale" because floating point error
+ // will stop the loop before the last increment.... X - 1.0 + 0.1 + 0.1 + ... + 0.1 != X
+ F32 stop_mouse_dir_scale = mouse_dir_scale + FIRST_PASS_STEP;
+
+ // take a step backwards, then walk forwards again to refine position
+ for ( mouse_dir_scale -= FIRST_PASS_STEP; mouse_dir_scale <= stop_mouse_dir_scale; mouse_dir_scale += SECOND_PASS_STEP)
+ {
+ LLVector3d mouse_direction_global_d;
+ mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale);
+ probe_point_global = camera_pos_global + mouse_direction_global_d;
+
+ regionp = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global);
+
+ if (!regionp)
+ {
+ // ...we're outside the world somehow
+ continue;
+ }
+
+ /*
+ i = (S32) (local_probe_point.mV[VX]/regionp->getLand().getMetersPerGrid());
+ j = (S32) (local_probe_point.mV[VY]/regionp->getLand().getMetersPerGrid());
+ if ((i >= regionp->getLand().mGridsPerEdge) || (j >= regionp->getLand().mGridsPerEdge))
+ {
+ // LL_INFOS() << "LLViewerWindow::mousePointOnLand probe_point is out of region" << LL_ENDL;
+ continue;
+ }
+ land_z = regionp->getLand().mSurfaceZ[ i + j * (regionp->getLand().mGridsPerEdge) ];
+ */
+
+ land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
+
+ //LL_INFOS() << "mousePointOnLand refine z " << land_z << LL_ENDL;
+
+ if (probe_point_region.mV[VZ] < land_z)
+ {
+ // ...just went under land again
+
+ *land_position_global = probe_point_global;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+// Saves an image to the harddrive as "SnapshotX" where X >= 1.
+void LLViewerWindow::saveImageNumbered(LLImageFormatted *image, bool force_picker, const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb)
+{
+ if (!image)
+ {
+ LL_WARNS() << "No image to save" << LL_ENDL;
+ return;
+ }
+ std::string extension("." + image->getExtension());
+ LLImageFormatted* formatted_image = image;
+ // Get a base file location if needed.
+ if (force_picker || !isSnapshotLocSet())
+ {
+ std::string proposed_name(sSnapshotBaseName);
+
+ // getSaveFile will append an appropriate extension to the proposed name, based on the ESaveFilter constant passed in.
+ LLFilePicker::ESaveFilter pick_type;
+
+ if (extension == ".j2c")
+ pick_type = LLFilePicker::FFSAVE_J2C;
+ else if (extension == ".bmp")
+ pick_type = LLFilePicker::FFSAVE_BMP;
+ else if (extension == ".jpg")
+ pick_type = LLFilePicker::FFSAVE_JPEG;
+ else if (extension == ".png")
+ pick_type = LLFilePicker::FFSAVE_PNG;
+ else if (extension == ".tga")
+ pick_type = LLFilePicker::FFSAVE_TGA;
+ else
+ pick_type = LLFilePicker::FFSAVE_ALL;
+
+ LLFilePickerReplyThread::startPicker(boost::bind(&LLViewerWindow::onDirectorySelected, this, _1, formatted_image, success_cb, failure_cb), pick_type, proposed_name,
+ boost::bind(&LLViewerWindow::onSelectionFailure, this, failure_cb));
+ }
+ else
+ {
+ saveImageLocal(formatted_image, success_cb, failure_cb);
+ }
+}
+
+void LLViewerWindow::onDirectorySelected(const std::vector<std::string>& filenames, LLImageFormatted *image, const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb)
+{
+ // Copy the directory + file name
+ std::string filepath = filenames[0];
+
+ gSavedPerAccountSettings.setString("SnapshotBaseName", gDirUtilp->getBaseFileName(filepath, true));
+ gSavedPerAccountSettings.setString("SnapshotBaseDir", gDirUtilp->getDirName(filepath));
+ saveImageLocal(image, success_cb, failure_cb);
+}
+
+void LLViewerWindow::onSelectionFailure(const snapshot_saved_signal_t::slot_type& failure_cb)
+{
+ failure_cb();
+}
+
+
+void LLViewerWindow::saveImageLocal(LLImageFormatted *image, const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb)
+{
+ std::string lastSnapshotDir = LLViewerWindow::getLastSnapshotDir();
+ if (lastSnapshotDir.empty())
+ {
+ failure_cb();
+ return;
+ }
+
+// Check if there is enough free space to save snapshot
+#ifdef LL_WINDOWS
+ boost::filesystem::path b_path(utf8str_to_utf16str(lastSnapshotDir));
+#else
+ boost::filesystem::path b_path(lastSnapshotDir);
+#endif
+ if (!boost::filesystem::is_directory(b_path))
+ {
+ LLSD args;
+ args["PATH"] = lastSnapshotDir;
+ LLNotificationsUtil::add("SnapshotToLocalDirNotExist", args);
+ resetSnapshotLoc();
+ failure_cb();
+ return;
+ }
+ boost::filesystem::space_info b_space = boost::filesystem::space(b_path);
+ if (b_space.free < image->getDataSize())
+ {
+ LLSD args;
+ args["PATH"] = lastSnapshotDir;
+
+ std::string needM_bytes_string;
+ LLResMgr::getInstance()->getIntegerString(needM_bytes_string, (image->getDataSize()) >> 10);
+ args["NEED_MEMORY"] = needM_bytes_string;
+
+ std::string freeM_bytes_string;
+ LLResMgr::getInstance()->getIntegerString(freeM_bytes_string, (b_space.free) >> 10);
+ args["FREE_MEMORY"] = freeM_bytes_string;
+
+ LLNotificationsUtil::add("SnapshotToComputerFailed", args);
+
+ failure_cb();
+ }
+
+ // Look for an unused file name
+ bool is_snapshot_name_loc_set = isSnapshotLocSet();
+ std::string filepath;
+ S32 i = 1;
+ S32 err = 0;
+ std::string extension("." + image->getExtension());
+ do
+ {
+ filepath = sSnapshotDir;
+ filepath += gDirUtilp->getDirDelimiter();
+ filepath += sSnapshotBaseName;
+
+ if (is_snapshot_name_loc_set)
+ {
+ filepath += llformat("_%.3d",i);
+ }
+
+ filepath += extension;
+
+ llstat stat_info;
+ err = LLFile::stat( filepath, &stat_info );
+ i++;
+ }
+ while( -1 != err // Search until the file is not found (i.e., stat() gives an error).
+ && is_snapshot_name_loc_set); // Or stop if we are rewriting.
+
+ LL_INFOS() << "Saving snapshot to " << filepath << LL_ENDL;
+ if (image->save(filepath))
+ {
+ playSnapshotAnimAndSound();
+ success_cb();
+ }
+ else
+ {
+ failure_cb();
+ }
+}
+
+void LLViewerWindow::resetSnapshotLoc()
+{
+ gSavedPerAccountSettings.setString("SnapshotBaseDir", std::string());
+}
+
+// static
+void LLViewerWindow::movieSize(S32 new_width, S32 new_height)
+{
+ LLCoordWindow size;
+ LLCoordWindow new_size(new_width, new_height);
+ gViewerWindow->getWindow()->getSize(&size);
+ if ( size != new_size )
+ {
+ gViewerWindow->getWindow()->setSize(new_size);
+ }
+}
+
+bool LLViewerWindow::saveSnapshot(const std::string& filepath, S32 image_width, S32 image_height, bool show_ui, bool show_hud, bool do_rebuild, LLSnapshotModel::ESnapshotLayerType type, LLSnapshotModel::ESnapshotFormat format)
+{
+ LL_INFOS() << "Saving snapshot to: " << filepath << LL_ENDL;
+
+ LLPointer<LLImageRaw> raw = new LLImageRaw;
+ bool success = rawSnapshot(raw, image_width, image_height, true, false, show_ui, show_hud, do_rebuild);
+
+ if (success)
+ {
+ U8 image_codec = IMG_CODEC_BMP;
+ switch (format)
+ {
+ case LLSnapshotModel::SNAPSHOT_FORMAT_PNG:
+ image_codec = IMG_CODEC_PNG;
+ break;
+ case LLSnapshotModel::SNAPSHOT_FORMAT_JPEG:
+ image_codec = IMG_CODEC_JPEG;
+ break;
+ default:
+ image_codec = IMG_CODEC_BMP;
+ break;
+ }
+
+ LLPointer<LLImageFormatted> formated_image = LLImageFormatted::createFromType(image_codec);
+ success = formated_image->encode(raw, 0.0f);
+ if (success)
+ {
+ success = formated_image->save(filepath);
+ }
+ else
+ {
+ LL_WARNS() << "Unable to encode snapshot of format " << format << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_WARNS() << "Unable to capture raw snapshot" << LL_ENDL;
+ }
+
+ return success;
+}
+
+
+void LLViewerWindow::playSnapshotAnimAndSound()
+{
+ if (gSavedSettings.getBOOL("QuietSnapshotsToDisk"))
+ {
+ return;
+ }
+ gAgent.sendAnimationRequest(ANIM_AGENT_SNAPSHOT, ANIM_REQUEST_START);
+ send_sound_trigger(LLUUID(gSavedSettings.getString("UISndSnapshot")), 1.0f);
+}
+
+bool LLViewerWindow::isSnapshotLocSet() const
+{
+ std::string snapshot_dir = sSnapshotDir;
+ return !snapshot_dir.empty();
+}
+
+void LLViewerWindow::resetSnapshotLoc() const
+{
+ gSavedPerAccountSettings.setString("SnapshotBaseDir", std::string());
+}
+
+bool LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, bool show_ui, bool show_hud, bool do_rebuild, bool no_post, LLSnapshotModel::ESnapshotLayerType type)
+{
+ return rawSnapshot(raw, preview_width, preview_height, false, false, show_ui, show_hud, do_rebuild, no_post, type);
+}
+
+// Saves the image from the screen to a raw image
+// Since the required size might be bigger than the available screen, this method rerenders the scene in parts (called subimages) and copy
+// the results over to the final raw image.
+bool LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height,
+ bool keep_window_aspect, bool is_texture, bool show_ui, bool show_hud, bool do_rebuild, bool no_post, LLSnapshotModel::ESnapshotLayerType type, S32 max_size)
+{
+ if (!raw)
+ {
+ return false;
+ }
+
+ //check if there is enough memory for the snapshot image
+ if(image_width * image_height > (1 << 22)) //if snapshot image is larger than 2K by 2K
+ {
+ if(!LLMemory::tryToAlloc(NULL, image_width * image_height * 3))
+ {
+ LL_WARNS() << "No enough memory to take the snapshot with size (w : h): " << image_width << " : " << image_height << LL_ENDL ;
+ return false ; //there is no enough memory for taking this snapshot.
+ }
+ }
+
+ // PRE SNAPSHOT
+ gSnapshotNoPost = no_post;
+ gDisplaySwapBuffers = false;
+
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // stencil buffer is deprecated | GL_STENCIL_BUFFER_BIT);
+ setCursor(UI_CURSOR_WAIT);
+
+ // Hide all the UI widgets first and draw a frame
+ bool prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
+
+ if ( prev_draw_ui != show_ui)
+ {
+ LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ }
+
+ bool hide_hud = !show_hud && LLPipeline::sShowHUDAttachments;
+ if (hide_hud)
+ {
+ LLPipeline::sShowHUDAttachments = false;
+ }
+
+ // if not showing ui, use full window to render world view
+ updateWorldViewRect(!show_ui);
+
+ // Copy screen to a buffer
+ // crop sides or top and bottom, if taking a snapshot of different aspect ratio
+ // from window
+ LLRect window_rect = show_ui ? getWindowRectRaw() : getWorldViewRectRaw();
+
+ S32 snapshot_width = window_rect.getWidth();
+ S32 snapshot_height = window_rect.getHeight();
+ // SNAPSHOT
+ S32 window_width = snapshot_width;
+ S32 window_height = snapshot_height;
+
+ // Note: Scaling of the UI is currently *not* supported so we limit the output size if UI is requested
+ if (show_ui)
+ {
+ // If the user wants the UI, limit the output size to the available screen size
+ image_width = llmin(image_width, window_width);
+ image_height = llmin(image_height, window_height);
+ }
+
+ S32 original_width = 0;
+ S32 original_height = 0;
+ bool reset_deferred = false;
+
+ LLRenderTarget scratch_space;
+
+ F32 scale_factor = 1.0f ;
+ if (!keep_window_aspect || (image_width > window_width) || (image_height > window_height))
+ {
+ if ((image_width <= gGLManager.mGLMaxTextureSize && image_height <= gGLManager.mGLMaxTextureSize) &&
+ (image_width > window_width || image_height > window_height) && LLPipeline::sRenderDeferred && !show_ui)
+ {
+ U32 color_fmt = type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGBA;
+ if (scratch_space.allocate(image_width, image_height, color_fmt, true))
+ {
+ original_width = gPipeline.mRT->deferredScreen.getWidth();
+ original_height = gPipeline.mRT->deferredScreen.getHeight();
+
+ if (gPipeline.allocateScreenBuffer(image_width, image_height))
+ {
+ window_width = image_width;
+ window_height = image_height;
+ snapshot_width = image_width;
+ snapshot_height = image_height;
+ reset_deferred = true;
+ mWorldViewRectRaw.set(0, image_height, image_width, 0);
+ LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
+ LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() );
+ scratch_space.bindTarget();
+ }
+ else
+ {
+ scratch_space.release();
+ gPipeline.allocateScreenBuffer(original_width, original_height);
+ }
+ }
+ }
+
+ if (!reset_deferred)
+ {
+ // if image cropping or need to enlarge the scene, compute a scale_factor
+ F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ;
+ snapshot_width = (S32)(ratio * image_width) ;
+ snapshot_height = (S32)(ratio * image_height) ;
+ scale_factor = llmax(1.0f, 1.0f / ratio) ;
+ }
+ }
+
+ if (show_ui && scale_factor > 1.f)
+ {
+ // Note: we should never get there...
+ LL_WARNS() << "over scaling UI not supported." << LL_ENDL;
+ }
+
+ S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f);
+ S32 buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f);
+
+ S32 image_buffer_x = llfloor(snapshot_width * scale_factor) ;
+ S32 image_buffer_y = llfloor(snapshot_height * scale_factor) ;
+
+ if ((image_buffer_x > max_size) || (image_buffer_y > max_size)) // boundary check to avoid memory overflow
+ {
+ scale_factor *= llmin((F32)max_size / image_buffer_x, (F32)max_size / image_buffer_y) ;
+ image_buffer_x = llfloor(snapshot_width * scale_factor) ;
+ image_buffer_y = llfloor(snapshot_height * scale_factor) ;
+ }
+
+ LLImageDataLock lock(raw);
+
+ if ((image_buffer_x > 0) && (image_buffer_y > 0))
+ {
+ raw->resize(image_buffer_x, image_buffer_y, 3);
+ }
+ else
+ {
+ return false;
+ }
+
+ if (raw->isBufferInvalid())
+ {
+ return false;
+ }
+
+ bool high_res = scale_factor >= 2.f; // Font scaling is slow, only do so if rez is much higher
+ if (high_res && show_ui)
+ {
+ // Note: we should never get there...
+ LL_WARNS() << "High res UI snapshot not supported. " << LL_ENDL;
+ /*send_agent_pause();
+ //rescale fonts
+ initFonts(scale_factor);
+ LLHUDObject::reshapeAll();*/
+ }
+
+ S32 output_buffer_offset_y = 0;
+
+ F32 depth_conversion_factor_1 = (LLViewerCamera::getInstance()->getFar() + LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear());
+ F32 depth_conversion_factor_2 = (LLViewerCamera::getInstance()->getFar() - LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear());
+
+ // Subimages are in fact partial rendering of the final view. This happens when the final view is bigger than the screen.
+ // In most common cases, scale_factor is 1 and there's no more than 1 iteration on x and y
+ for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y)
+ {
+ S32 subimage_y_offset = llclamp(buffer_y_offset - (subimage_y * window_height), 0, window_height);;
+ // handle fractional columns
+ U32 read_height = llmax(0, (window_height - subimage_y_offset) -
+ llmax(0, (window_height * (subimage_y + 1)) - (buffer_y_offset + raw->getHeight())));
+
+ S32 output_buffer_offset_x = 0;
+ for (int subimage_x = 0; subimage_x < scale_factor; ++subimage_x)
+ {
+ gDisplaySwapBuffers = false;
+ gDepthDirty = true;
+
+ S32 subimage_x_offset = llclamp(buffer_x_offset - (subimage_x * window_width), 0, window_width);
+ // handle fractional rows
+ U32 read_width = llmax(0, (window_width - subimage_x_offset) -
+ llmax(0, (window_width * (subimage_x + 1)) - (buffer_x_offset + raw->getWidth())));
+
+ // Skip rendering and sampling altogether if either width or height is degenerated to 0 (common in cropping cases)
+ if (read_width && read_height)
+ {
+ const U32 subfield = subimage_x+(subimage_y*llceil(scale_factor));
+ display(do_rebuild, scale_factor, subfield, true);
+
+ if (!LLPipeline::sRenderDeferred)
+ {
+ // Required for showing the GUI in snapshots and performing bloom composite overlay
+ // Call even if show_ui is false
+ render_ui(scale_factor, subfield);
+ swap();
+ }
+
+ for (U32 out_y = 0; out_y < read_height ; out_y++)
+ {
+ S32 output_buffer_offset = (
+ (out_y * (raw->getWidth())) // ...plus iterated y...
+ + (window_width * subimage_x) // ...plus subimage start in x...
+ + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y...
+ - output_buffer_offset_x // ...minus buffer padding x...
+ - (output_buffer_offset_y * (raw->getWidth())) // ...minus buffer padding y...
+ ) * raw->getComponents();
+
+ // Ping the watchdog thread every 100 lines to keep us alive (arbitrary number, feel free to change)
+ if (out_y % 100 == 0)
+ {
+ LLAppViewer::instance()->pingMainloopTimeout("LLViewerWindow::rawSnapshot");
+ }
+ // disable use of glReadPixels when doing nVidia nSight graphics debugging
+ if (!LLRender::sNsightDebugSupport)
+ {
+ if (type == LLSnapshotModel::SNAPSHOT_TYPE_COLOR)
+ {
+ glReadPixels(
+ subimage_x_offset, out_y + subimage_y_offset,
+ read_width, 1,
+ GL_RGB, GL_UNSIGNED_BYTE,
+ raw->getData() + output_buffer_offset
+ );
+ }
+ else // LLSnapshotModel::SNAPSHOT_TYPE_DEPTH
+ {
+ LLPointer<LLImageRaw> depth_line_buffer = new LLImageRaw(read_width, 1, sizeof(GL_FLOAT)); // need to store floating point values
+ glReadPixels(
+ subimage_x_offset, out_y + subimage_y_offset,
+ read_width, 1,
+ GL_DEPTH_COMPONENT, GL_FLOAT,
+ depth_line_buffer->getData()// current output pixel is beginning of buffer...
+ );
+
+ for (S32 i = 0; i < (S32)read_width; i++)
+ {
+ F32 depth_float = *(F32*)(depth_line_buffer->getData() + (i * sizeof(F32)));
+
+ F32 linear_depth_float = 1.f / (depth_conversion_factor_1 - (depth_float * depth_conversion_factor_2));
+ U8 depth_byte = F32_to_U8(linear_depth_float, LLViewerCamera::getInstance()->getNear(), LLViewerCamera::getInstance()->getFar());
+ // write converted scanline out to result image
+ for (S32 j = 0; j < raw->getComponents(); j++)
+ {
+ *(raw->getData() + output_buffer_offset + (i * raw->getComponents()) + j) = depth_byte;
+ }
+ }
+ }
+ }
+ }
+ }
+ output_buffer_offset_x += subimage_x_offset;
+ stop_glerror();
+ }
+ output_buffer_offset_y += subimage_y_offset;
+ }
+
+ gDisplaySwapBuffers = false;
+ gSnapshotNoPost = false;
+ gDepthDirty = true;
+
+ // POST SNAPSHOT
+ if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ }
+
+ if (hide_hud)
+ {
+ LLPipeline::sShowHUDAttachments = true;
+ }
+
+ /*if (high_res)
+ {
+ initFonts(1.f);
+ LLHUDObject::reshapeAll();
+ }*/
+
+ // Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding)
+ // Note: this formula depends on the number of components being 3. Not obvious, but it's correct.
+ image_width += (image_width * 3) % 4;
+
+ bool ret = true ;
+ // Resize image
+ if(llabs(image_width - image_buffer_x) > 4 || llabs(image_height - image_buffer_y) > 4)
+ {
+ ret = raw->scale( image_width, image_height );
+ }
+ else if(image_width != image_buffer_x || image_height != image_buffer_y)
+ {
+ ret = raw->scale( image_width, image_height, false );
+ }
+
+ setCursor(UI_CURSOR_ARROW);
+
+ if (do_rebuild)
+ {
+ // If we had to do a rebuild, that means that the lists of drawables to be rendered
+ // was empty before we started.
+ // Need to reset these, otherwise we call state sort on it again when render gets called the next time
+ // and we stand a good chance of crashing on rebuild because the render drawable arrays have multiple copies of
+ // objects on them.
+ gPipeline.resetDrawOrders();
+ }
+
+ if (reset_deferred)
+ {
+ mWorldViewRectRaw = window_rect;
+ LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
+ LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() );
+ scratch_space.flush();
+ scratch_space.release();
+ gPipeline.allocateScreenBuffer(original_width, original_height);
+
+ }
+
+ if (high_res)
+ {
+ send_agent_resume();
+ }
+
+ return ret;
+}
+
+bool LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_height, const int num_render_passes)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
+ gDisplaySwapBuffers = false;
+
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // stencil buffer is deprecated | GL_STENCIL_BUFFER_BIT);
+ setCursor(UI_CURSOR_WAIT);
+
+ bool prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ if (prev_draw_ui)
+ {
+ LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ }
+
+ bool hide_hud = LLPipeline::sShowHUDAttachments;
+ if (hide_hud)
+ {
+ LLPipeline::sShowHUDAttachments = false;
+ }
+
+ LLRect window_rect = getWorldViewRectRaw();
+
+ S32 original_width = LLPipeline::sRenderDeferred ? gPipeline.mRT->deferredScreen.getWidth() : gViewerWindow->getWorldViewWidthRaw();
+ S32 original_height = LLPipeline::sRenderDeferred ? gPipeline.mRT->deferredScreen.getHeight() : gViewerWindow->getWorldViewHeightRaw();
+
+ LLRenderTarget scratch_space;
+ U32 color_fmt = GL_RGBA;
+ if (scratch_space.allocate(image_width, image_height, color_fmt, true))
+ {
+ if (gPipeline.allocateScreenBuffer(image_width, image_height))
+ {
+ mWorldViewRectRaw.set(0, image_height, image_width, 0);
+
+ scratch_space.bindTarget();
+ }
+ else
+ {
+ scratch_space.release();
+ gPipeline.allocateScreenBuffer(original_width, original_height);
+ }
+ }
+
+ // we render the scene more than once since this helps
+ // greatly with the objects not being drawn in the
+ // snapshot when they are drawn in the scene. This is
+ // evident when you set this value via the debug setting
+ // called 360CaptureNumRenderPasses to 1. The theory is
+ // that the missing objects are caused by the sUseOcclusion
+ // property in pipeline but that the use in pipeline.cpp
+ // lags by a frame or two so rendering more than once
+ // appears to help a lot.
+ for (int i = 0; i < num_render_passes; ++i)
+ {
+ // turning this flag off here prohibits the screen swap
+ // to present the new page to the viewer - this stops
+ // the black flash in between captures when the number
+ // of render passes is more than 1. We need to also
+ // set it here because code in LLViewerDisplay resets
+ // it to true each time.
+ gDisplaySwapBuffers = false;
+
+ // actually render the scene
+ const U32 subfield = 0;
+ const bool do_rebuild = true;
+ const F32 zoom = 1.0;
+ const bool for_snapshot = true;
+ display(do_rebuild, zoom, subfield, for_snapshot);
+ }
+
+ LLImageDataSharedLock lock(raw);
+
+ glReadPixels(
+ 0, 0,
+ image_width,
+ image_height,
+ GL_RGB, GL_UNSIGNED_BYTE,
+ raw->getData()
+ );
+ stop_glerror();
+
+ gDisplaySwapBuffers = false;
+ gDepthDirty = true;
+
+ if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ if (prev_draw_ui)
+ {
+ LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ }
+ }
+
+ if (hide_hud)
+ {
+ LLPipeline::sShowHUDAttachments = true;
+ }
+
+ setCursor(UI_CURSOR_ARROW);
+
+ gPipeline.resetDrawOrders();
+ mWorldViewRectRaw = window_rect;
+ scratch_space.flush();
+ scratch_space.release();
+ gPipeline.allocateScreenBuffer(original_width, original_height);
+
+ return true;
+}
+
+void display_cube_face();
+
+bool LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 cubeIndex, S32 face, F32 near_clip, bool dynamic_render)
+{
+ // NOTE: implementation derived from LLFloater360Capture::capture360Images() and simpleSnapshot
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
+ LL_PROFILE_GPU_ZONE("cubeSnapshot");
+ llassert(LLPipeline::sRenderDeferred);
+ llassert(!gCubeSnapshot); //assert a snapshot isn't already in progress
+
+ U32 res = gPipeline.mRT->deferredScreen.getWidth();
+
+ //llassert(res <= gPipeline.mRT->deferredScreen.getWidth());
+ //llassert(res <= gPipeline.mRT->deferredScreen.getHeight());
+
+ // save current view/camera settings so we can restore them afterwards
+ S32 old_occlusion = LLPipeline::sUseOcclusion;
+
+ // set new parameters specific to the 360 requirements
+ LLPipeline::sUseOcclusion = 0;
+ LLViewerCamera* camera = LLViewerCamera::getInstance();
+
+ LLViewerCamera saved_camera = LLViewerCamera::instance();
+ glh::matrix4f saved_proj = get_current_projection();
+ glh::matrix4f saved_mod = get_current_modelview();
+
+ // camera constants for the square, cube map capture image
+ camera->setAspect(1.0); // must set aspect ratio first to avoid undesirable clamping of vertical FoV
+ camera->setViewNoBroadcast(F_PI_BY_TWO);
+ camera->yaw(0.0);
+ camera->setOrigin(origin);
+ camera->setNear(near_clip);
+
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // stencil buffer is deprecated | GL_STENCIL_BUFFER_BIT);
+
+ U32 dynamic_render_types[] = {
+ LLPipeline::RENDER_TYPE_AVATAR,
+ LLPipeline::RENDER_TYPE_CONTROL_AV,
+ LLPipeline::RENDER_TYPE_PARTICLES
+ };
+ constexpr U32 dynamic_render_type_count = sizeof(dynamic_render_types) / sizeof(U32);
+ bool prev_dynamic_render_type[dynamic_render_type_count];
+
+
+ if (!dynamic_render)
+ {
+ for (int i = 0; i < dynamic_render_type_count; ++i)
+ {
+ prev_dynamic_render_type[i] = gPipeline.hasRenderType(dynamic_render_types[i]);
+ if (prev_dynamic_render_type[i])
+ {
+ gPipeline.toggleRenderType(dynamic_render_types[i]);
+ }
+ }
+ }
+
+ bool prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ if (prev_draw_ui)
+ {
+ LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ }
+
+ bool hide_hud = LLPipeline::sShowHUDAttachments;
+ if (hide_hud)
+ {
+ LLPipeline::sShowHUDAttachments = false;
+ }
+ LLRect window_rect = getWorldViewRectRaw();
+
+ mWorldViewRectRaw.set(0, res, res, 0);
+
+ // these are the 6 directions we will point the camera, see LLCubeMapArray::sTargets
+ LLVector3 look_dirs[6] = {
+ LLVector3(1, 0, 0),
+ LLVector3(-1, 0, 0),
+ LLVector3(0, 1, 0),
+ LLVector3(0, -1, 0),
+ LLVector3(0, 0, 1),
+ LLVector3(0, 0, -1)
+ };
+
+ LLVector3 look_upvecs[6] = {
+ LLVector3(0, -1, 0),
+ LLVector3(0, -1, 0),
+ LLVector3(0, 0, 1),
+ LLVector3(0, 0, -1),
+ LLVector3(0, -1, 0),
+ LLVector3(0, -1, 0)
+ };
+
+ // for each of six sides of cubemap
+ //for (int i = 0; i < 6; ++i)
+ int i = face;
+ {
+ // set up camera to look in each direction
+ camera->lookDir(look_dirs[i], look_upvecs[i]);
+
+ // turning this flag off here prohibits the screen swap
+ // to present the new page to the viewer - this stops
+ // the black flash in between captures when the number
+ // of render passes is more than 1. We need to also
+ // set it here because code in LLViewerDisplay resets
+ // it to true each time.
+ gDisplaySwapBuffers = false;
+
+ // actually render the scene
+ gCubeSnapshot = true;
+ display_cube_face();
+ gCubeSnapshot = false;
+ }
+
+ gDisplaySwapBuffers = true;
+
+ if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ if (prev_draw_ui)
+ {
+ LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ }
+ }
+
+ if (!dynamic_render)
+ {
+ for (int i = 0; i < dynamic_render_type_count; ++i)
+ {
+ if (prev_dynamic_render_type[i])
+ {
+ gPipeline.toggleRenderType(dynamic_render_types[i]);
+ }
+ }
+ }
+
+ if (hide_hud)
+ {
+ LLPipeline::sShowHUDAttachments = true;
+ }
+
+ gPipeline.resetDrawOrders();
+ mWorldViewRectRaw = window_rect;
+
+ // restore original view/camera/avatar settings settings
+ *camera = saved_camera;
+ set_current_modelview(saved_mod);
+ set_current_projection(saved_proj);
+ setup3DViewport();
+ LLPipeline::sUseOcclusion = old_occlusion;
+
+ // ====================================================
+ return true;
+}
+
+void LLViewerWindow::destroyWindow()
+{
+ if (mWindow)
+ {
+ LLWindowManager::destroyWindow(mWindow);
+ }
+ mWindow = NULL;
+}
+
+
+void LLViewerWindow::drawMouselookInstructions()
+{
+ // Draw instructions for mouselook ("Press ESC to return to World View" partially transparent at the bottom of the screen.)
+ const std::string instructions = LLTrans::getString("LeaveMouselook");
+ const LLFontGL* font = LLFontGL::getFont(LLFontDescriptor("SansSerif", "Large", LLFontGL::BOLD));
+
+ //to be on top of Bottom bar when it is opened
+ const S32 INSTRUCTIONS_PAD = 50;
+
+ font->renderUTF8(
+ instructions, 0,
+ getWorldViewRectScaled().getCenterX(),
+ getWorldViewRectScaled().mBottom + INSTRUCTIONS_PAD,
+ LLColor4( 1.0f, 1.0f, 1.0f, 0.5f ),
+ LLFontGL::HCENTER, LLFontGL::TOP,
+ LLFontGL::NORMAL,LLFontGL::DROP_SHADOW);
+}
+
+void* LLViewerWindow::getPlatformWindow() const
+{
+ return mWindow->getPlatformWindow();
+}
+
+void* LLViewerWindow::getMediaWindow() const
+{
+ return mWindow->getMediaWindow();
+}
+
+void LLViewerWindow::focusClient() const
+{
+ return mWindow->focusClient();
+}
+
+LLRootView* LLViewerWindow::getRootView() const
+{
+ return mRootView;
+}
+
+LLRect LLViewerWindow::getWorldViewRectScaled() const
+{
+ return mWorldViewRectScaled;
+}
+
+S32 LLViewerWindow::getWorldViewHeightScaled() const
+{
+ return mWorldViewRectScaled.getHeight();
+}
+
+S32 LLViewerWindow::getWorldViewWidthScaled() const
+{
+ return mWorldViewRectScaled.getWidth();
+}
+
+
+S32 LLViewerWindow::getWorldViewHeightRaw() const
+{
+ return mWorldViewRectRaw.getHeight();
+}
+
+S32 LLViewerWindow::getWorldViewWidthRaw() const
+{
+ return mWorldViewRectRaw.getWidth();
+}
+
+S32 LLViewerWindow::getWindowHeightScaled() const
+{
+ return mWindowRectScaled.getHeight();
+}
+
+S32 LLViewerWindow::getWindowWidthScaled() const
+{
+ return mWindowRectScaled.getWidth();
+}
+
+S32 LLViewerWindow::getWindowHeightRaw() const
+{
+ return mWindowRectRaw.getHeight();
+}
+
+S32 LLViewerWindow::getWindowWidthRaw() const
+{
+ return mWindowRectRaw.getWidth();
+}
+
+void LLViewerWindow::setup2DRender()
+{
+ // setup ortho camera
+ gl_state_for_2d(mWindowRectRaw.getWidth(), mWindowRectRaw.getHeight());
+ setup2DViewport();
+}
+
+void LLViewerWindow::setup2DViewport(S32 x_offset, S32 y_offset)
+{
+ gGLViewport[0] = mWindowRectRaw.mLeft + x_offset;
+ gGLViewport[1] = mWindowRectRaw.mBottom + y_offset;
+ gGLViewport[2] = mWindowRectRaw.getWidth();
+ gGLViewport[3] = mWindowRectRaw.getHeight();
+ glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+}
+
+
+void LLViewerWindow::setup3DRender()
+{
+ // setup perspective camera
+ LLViewerCamera::getInstance()->setPerspective(NOT_FOR_SELECTION, mWorldViewRectRaw.mLeft, mWorldViewRectRaw.mBottom, mWorldViewRectRaw.getWidth(), mWorldViewRectRaw.getHeight(), false, LLViewerCamera::getInstance()->getNear(), MAX_FAR_CLIP*2.f);
+ setup3DViewport();
+}
+
+void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
+ gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset;
+ gGLViewport[1] = mWorldViewRectRaw.mBottom + y_offset;
+ gGLViewport[2] = mWorldViewRectRaw.getWidth();
+ gGLViewport[3] = mWorldViewRectRaw.getHeight();
+ glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+}
+
+void LLViewerWindow::revealIntroPanel()
+{
+ if (mProgressView)
+ {
+ mProgressView->revealIntroPanel();
+ }
+}
+
+void LLViewerWindow::initTextures(S32 location_id)
+{
+ if (mProgressView)
+ {
+ mProgressView->initTextures(location_id, LLGridManager::getInstance()->isInProductionGrid());
+ }
+}
+
+void LLViewerWindow::setShowProgress(const bool show)
+{
+ if (mProgressView)
+ {
+ mProgressView->setVisible(show);
+ }
+}
+
+void LLViewerWindow::setStartupComplete()
+{
+ if (mProgressView)
+ {
+ mProgressView->setStartupComplete();
+ }
+}
+
+bool LLViewerWindow::getShowProgress() const
+{
+ return (mProgressView && mProgressView->getVisible());
+}
+
+void LLViewerWindow::setProgressString(const std::string& string)
+{
+ if (mProgressView)
+ {
+ mProgressView->setText(string);
+ }
+}
+
+void LLViewerWindow::setProgressMessage(const std::string& msg)
+{
+ if(mProgressView)
+ {
+ mProgressView->setMessage(msg);
+ }
+}
+
+void LLViewerWindow::setProgressPercent(const F32 percent)
+{
+ if (mProgressView)
+ {
+ mProgressView->setPercent(percent);
+ }
+}
+
+void LLViewerWindow::setProgressCancelButtonVisible( bool b, const std::string& label )
+{
+ if (mProgressView)
+ {
+ mProgressView->setCancelButtonVisible( b, label );
+ }
+}
+
+LLProgressView *LLViewerWindow::getProgressView() const
+{
+ return mProgressView;
+}
+
+void LLViewerWindow::dumpState()
+{
+ LL_INFOS() << "LLViewerWindow Active " << S32(mActive) << LL_ENDL;
+ LL_INFOS() << "mWindow visible " << S32(mWindow->getVisible())
+ << " minimized " << S32(mWindow->getMinimized())
+ << LL_ENDL;
+}
+
+void LLViewerWindow::stopGL(bool save_state)
+{
+ //Note: --bao
+ //if not necessary, do not change the order of the function calls in this function.
+ //if change something, make sure it will not break anything.
+ //especially be careful to put anything behind gTextureList.destroyGL(save_state);
+ if (!gGLManager.mIsDisabled)
+ {
+ LL_INFOS() << "Shutting down GL..." << LL_ENDL;
+
+ // Pause texture decode threads (will get unpaused during main loop)
+ LLAppViewer::getTextureCache()->pause();
+ LLAppViewer::getTextureFetch()->pause();
+
+ gSky.destroyGL();
+ stop_glerror();
+
+ LLManipTranslate::destroyGL() ;
+ stop_glerror();
+
+ gBumpImageList.destroyGL();
+ stop_glerror();
+
+ LLFontGL::destroyAllGL();
+ stop_glerror();
+
+ LLVOAvatar::destroyGL();
+ stop_glerror();
+
+ LLVOPartGroup::destroyGL();
+
+ LLViewerDynamicTexture::destroyGL();
+ stop_glerror();
+
+ if (gPipeline.isInit())
+ {
+ gPipeline.destroyGL();
+ }
+
+ gBox.cleanupGL();
+
+ if(gPostProcess)
+ {
+ gPostProcess->invalidate();
+ }
+
+ gTextureList.destroyGL(save_state);
+ stop_glerror();
+
+ gGLManager.mIsDisabled = true;
+ stop_glerror();
+
+ //unload shader's
+ while (LLGLSLShader::sInstances.size())
+ {
+ LLGLSLShader* shader = *(LLGLSLShader::sInstances.begin());
+ shader->unload();
+ }
+ }
+}
+
+void LLViewerWindow::restoreGL(const std::string& progress_message)
+{
+ //Note: --bao
+ //if not necessary, do not change the order of the function calls in this function.
+ //if change something, make sure it will not break anything.
+ //especially, be careful to put something before gTextureList.restoreGL();
+ if (gGLManager.mIsDisabled)
+ {
+ LL_INFOS() << "Restoring GL..." << LL_ENDL;
+ gGLManager.mIsDisabled = false;
+
+ initGLDefaults();
+ LLGLState::restoreGL();
+
+ gTextureList.restoreGL();
+
+ // for future support of non-square pixels, and fonts that are properly stretched
+ //LLFontGL::destroyDefaultFonts();
+ initFonts();
+
+ gSky.restoreGL();
+ gPipeline.restoreGL();
+ LLManipTranslate::restoreGL();
+
+ gBumpImageList.restoreGL();
+ LLViewerDynamicTexture::restoreGL();
+ LLVOAvatar::restoreGL();
+ LLVOPartGroup::restoreGL();
+
+ gResizeScreenTexture = true;
+ gWindowResized = true;
+
+ if (isAgentAvatarValid() && gAgentAvatarp->isEditingAppearance())
+ {
+ LLVisualParamHint::requestHintUpdates();
+ }
+
+ if (!progress_message.empty())
+ {
+ gRestoreGLTimer.reset();
+ gRestoreGL = true;
+ setShowProgress(true);
+ setProgressString(progress_message);
+ }
+ LL_INFOS() << "...Restoring GL done" << LL_ENDL;
+ if(!LLAppViewer::instance()->restoreErrorTrap())
+ {
+ LL_WARNS() << " Someone took over my signal/exception handler (post restoreGL)!" << LL_ENDL;
+ }
+
+ }
+}
+
+void LLViewerWindow::initFonts(F32 zoom_factor)
+{
+ LLFontGL::destroyAllGL();
+ // Initialize with possibly different zoom factor
+
+ LLFontManager::initClass();
+
+ LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"),
+ mDisplayScale.mV[VX] * zoom_factor,
+ mDisplayScale.mV[VY] * zoom_factor,
+ gDirUtilp->getAppRODataDir());
+}
+
+void LLViewerWindow::requestResolutionUpdate()
+{
+ mResDirty = true;
+}
+
+static LLTrace::BlockTimerStatHandle FTM_WINDOW_CHECK_SETTINGS("Window Settings");
+
+void LLViewerWindow::checkSettings()
+{
+ LL_RECORD_BLOCK_TIME(FTM_WINDOW_CHECK_SETTINGS);
+ if (mStatesDirty)
+ {
+ gGL.refreshState();
+ LLViewerShaderMgr::instance()->setShaders();
+ mStatesDirty = false;
+ }
+
+ // We want to update the resolution AFTER the states getting refreshed not before.
+ if (mResDirty)
+ {
+ reshape(getWindowWidthRaw(), getWindowHeightRaw());
+ mResDirty = false;
+ }
+}
+
+void LLViewerWindow::restartDisplay(bool show_progress_bar)
+{
+ LL_INFOS() << "Restaring GL" << LL_ENDL;
+ stopGL();
+ if (show_progress_bar)
+ {
+ restoreGL(LLTrans::getString("ProgressChangingResolution"));
+ }
+ else
+ {
+ restoreGL();
+ }
+}
+
+bool LLViewerWindow::changeDisplaySettings(LLCoordScreen size, bool enable_vsync, bool show_progress_bar)
+{
+ //bool was_maximized = gSavedSettings.getBOOL("WindowMaximized");
+
+ //gResizeScreenTexture = true;
+
+
+ //U32 fsaa = gSavedSettings.getU32("RenderFSAASamples");
+ //U32 old_fsaa = mWindow->getFSAASamples();
+
+ // if not maximized, use the request size
+ if (!mWindow->getMaximized())
+ {
+ mWindow->setSize(size);
+ }
+
+ //if (fsaa == old_fsaa)
+ {
+ return true;
+ }
+
+/*
+
+ // Close floaters that don't handle settings change
+ LLFloaterReg::hideInstance("snapshot");
+
+ bool result_first_try = false;
+ bool result_second_try = false;
+
+ LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+ send_agent_pause();
+ LL_INFOS() << "Stopping GL during changeDisplaySettings" << LL_ENDL;
+ stopGL();
+ mIgnoreActivate = true;
+ LLCoordScreen old_size;
+ LLCoordScreen old_pos;
+ mWindow->getSize(&old_size);
+
+ //mWindow->setFSAASamples(fsaa);
+
+ result_first_try = mWindow->switchContext(false, size, disable_vsync);
+ if (!result_first_try)
+ {
+ // try to switch back
+ //mWindow->setFSAASamples(old_fsaa);
+ result_second_try = mWindow->switchContext(false, old_size, disable_vsync);
+
+ if (!result_second_try)
+ {
+ // we are stuck...try once again with a minimal resolution?
+ send_agent_resume();
+ mIgnoreActivate = false;
+ return false;
+ }
+ }
+ send_agent_resume();
+
+ LL_INFOS() << "Restoring GL during resolution change" << LL_ENDL;
+ if (show_progress_bar)
+ {
+ restoreGL(LLTrans::getString("ProgressChangingResolution"));
+ }
+ else
+ {
+ restoreGL();
+ }
+
+ if (!result_first_try)
+ {
+ LLSD args;
+ args["RESX"] = llformat("%d",size.mX);
+ args["RESY"] = llformat("%d",size.mY);
+ LLNotificationsUtil::add("ResolutionSwitchFail", args);
+ size = old_size; // for reshape below
+ }
+
+ bool success = result_first_try || result_second_try;
+
+ if (success)
+ {
+ // maximize window if was maximized, else reposition
+ if (was_maximized)
+ {
+ mWindow->maximize();
+ }
+ else
+ {
+ S32 windowX = gSavedSettings.getS32("WindowX");
+ S32 windowY = gSavedSettings.getS32("WindowY");
+
+ mWindow->setPosition(LLCoordScreen ( windowX, windowY ) );
+ }
+ }
+
+ mIgnoreActivate = false;
+ gFocusMgr.setKeyboardFocus(keyboard_focus);
+
+ return success;
+
+ */
+}
+
+F32 LLViewerWindow::getWorldViewAspectRatio() const
+{
+ F32 world_aspect = (F32)mWorldViewRectRaw.getWidth() / (F32)mWorldViewRectRaw.getHeight();
+ return world_aspect;
+}
+
+void LLViewerWindow::calcDisplayScale()
+{
+ F32 ui_scale_factor = llclamp(gSavedSettings.getF32("UIScaleFactor") * mWindow->getSystemUISize(), MIN_UI_SCALE, MAX_UI_SCALE);
+ LLVector2 display_scale;
+ display_scale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
+ display_scale *= ui_scale_factor;
+
+ // limit minimum display scale
+ if (display_scale.mV[VX] < MIN_DISPLAY_SCALE || display_scale.mV[VY] < MIN_DISPLAY_SCALE)
+ {
+ display_scale *= MIN_DISPLAY_SCALE / llmin(display_scale.mV[VX], display_scale.mV[VY]);
+ }
+
+ if (display_scale != mDisplayScale)
+ {
+ LL_INFOS() << "Setting display scale to " << display_scale << " for ui scale: " << ui_scale_factor << LL_ENDL;
+
+ mDisplayScale = display_scale;
+ // Init default fonts
+ initFonts();
+ }
+}
+
+//static
+LLRect LLViewerWindow::calcScaledRect(const LLRect & rect, const LLVector2& display_scale)
+{
+ LLRect res = rect;
+ res.mLeft = ll_round((F32)res.mLeft / display_scale.mV[VX]);
+ res.mRight = ll_round((F32)res.mRight / display_scale.mV[VX]);
+ res.mBottom = ll_round((F32)res.mBottom / display_scale.mV[VY]);
+ res.mTop = ll_round((F32)res.mTop / display_scale.mV[VY]);
+
+ return res;
+}
+
+S32 LLViewerWindow::getChatConsoleBottomPad()
+{
+ S32 offset = 0;
+
+ if(gToolBarView)
+ offset += gToolBarView->getBottomToolbar()->getRect().getHeight();
+
+ return offset;
+}
+
+LLRect LLViewerWindow::getChatConsoleRect()
+{
+ LLRect full_window(0, getWindowHeightScaled(), getWindowWidthScaled(), 0);
+ LLRect console_rect = full_window;
+
+ const S32 CONSOLE_PADDING_TOP = 24;
+ const S32 CONSOLE_PADDING_LEFT = 24;
+ const S32 CONSOLE_PADDING_RIGHT = 10;
+
+ console_rect.mTop -= CONSOLE_PADDING_TOP;
+ console_rect.mBottom += getChatConsoleBottomPad();
+
+ console_rect.mLeft += CONSOLE_PADDING_LEFT;
+
+ static const bool CHAT_FULL_WIDTH = gSavedSettings.getBOOL("ChatFullWidth");
+
+ if (CHAT_FULL_WIDTH)
+ {
+ console_rect.mRight -= CONSOLE_PADDING_RIGHT;
+ }
+ else
+ {
+ // Make console rect somewhat narrow so having inventory open is
+ // less of a problem.
+ console_rect.mRight = console_rect.mLeft + 2 * getWindowWidthScaled() / 3;
+ }
+
+ return console_rect;
+}
+
+void LLViewerWindow::reshapeStatusBarContainer()
+{
+ LLPanel* status_bar_container = getRootView()->getChild<LLPanel>("status_bar_container");
+ LLView* nav_bar_container = getRootView()->getChild<LLView>("nav_bar_container");
+
+ S32 new_height = status_bar_container->getRect().getHeight();
+ S32 new_width = status_bar_container->getRect().getWidth();
+
+ if (gSavedSettings.getBOOL("ShowNavbarNavigationPanel"))
+ {
+ // Navigation bar is outside visible area, expand status_bar_container to show it
+ new_height += nav_bar_container->getRect().getHeight();
+ }
+ else
+ {
+ // collapse status_bar_container
+ new_height -= nav_bar_container->getRect().getHeight();
+ }
+ status_bar_container->reshape(new_width, new_height, true);
+}
+
+void LLViewerWindow::resetStatusBarContainer()
+{
+ LLNavigationBar* navbar = LLNavigationBar::getInstance();
+ if (gSavedSettings.getBOOL("ShowNavbarNavigationPanel") || navbar->getVisible())
+ {
+ // was previously showing navigation bar
+ LLView* nav_bar_container = getRootView()->getChild<LLView>("nav_bar_container");
+ LLPanel* status_bar_container = getRootView()->getChild<LLPanel>("status_bar_container");
+ S32 new_height = status_bar_container->getRect().getHeight();
+ S32 new_width = status_bar_container->getRect().getWidth();
+ new_height -= nav_bar_container->getRect().getHeight();
+ status_bar_container->reshape(new_width, new_height, true);
+ }
+}
+//----------------------------------------------------------------------------
+
+
+void LLViewerWindow::setUIVisibility(bool visible)
+{
+ mUIVisible = visible;
+
+ if (!visible)
+ {
+ gAgentCamera.changeCameraToThirdPerson(false);
+ gFloaterView->hideAllFloaters();
+ }
+ else
+ {
+ gFloaterView->showHiddenFloaters();
+ }
+
+ if (gToolBarView)
+ {
+ gToolBarView->setToolBarsVisible(visible);
+ }
+
+ LLNavigationBar::getInstance()->setVisible(visible ? gSavedSettings.getBOOL("ShowNavbarNavigationPanel") : false);
+ LLPanelTopInfoBar::getInstance()->setVisible(visible? gSavedSettings.getBOOL("ShowMiniLocationPanel") : false);
+ mRootView->getChildView("status_bar_container")->setVisible(visible);
+}
+
+bool LLViewerWindow::getUIVisibility()
+{
+ return mUIVisible;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// LLPickInfo
+//
+LLPickInfo::LLPickInfo()
+ : mKeyMask(MASK_NONE),
+ mPickCallback(NULL),
+ mPickType(PICK_INVALID),
+ mWantSurfaceInfo(false),
+ mObjectFace(-1),
+ mUVCoords(-1.f, -1.f),
+ mSTCoords(-1.f, -1.f),
+ mXYCoords(-1, -1),
+ mIntersection(),
+ mNormal(),
+ mTangent(),
+ mBinormal(),
+ mHUDIcon(NULL),
+ mPickTransparent(false),
+ mPickRigged(false),
+ mPickParticle(false)
+{
+}
+
+LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos,
+ MASK keyboard_mask,
+ bool pick_transparent,
+ bool pick_rigged,
+ bool pick_particle,
+ bool pick_reflection_probe,
+ bool pick_uv_coords,
+ bool pick_unselectable,
+ void (*pick_callback)(const LLPickInfo& pick_info))
+ : mMousePt(mouse_pos),
+ mKeyMask(keyboard_mask),
+ mPickCallback(pick_callback),
+ mPickType(PICK_INVALID),
+ mWantSurfaceInfo(pick_uv_coords),
+ mObjectFace(-1),
+ mUVCoords(-1.f, -1.f),
+ mSTCoords(-1.f, -1.f),
+ mXYCoords(-1, -1),
+ mNormal(),
+ mTangent(),
+ mBinormal(),
+ mHUDIcon(NULL),
+ mPickTransparent(pick_transparent),
+ mPickRigged(pick_rigged),
+ mPickParticle(pick_particle),
+ mPickReflectionProbe(pick_reflection_probe),
+ mPickUnselectable(pick_unselectable)
+{
+}
+
+void LLPickInfo::fetchResults()
+{
+
+ S32 face_hit = -1;
+ LLVector4a intersection, normal;
+ LLVector4a tangent;
+
+ LLVector2 uv;
+
+ LLHUDIcon* hit_icon = gViewerWindow->cursorIntersectIcon(mMousePt.mX, mMousePt.mY, 512.f, &intersection);
+
+ LLVector4a origin;
+ origin.load3(LLViewerCamera::getInstance()->getOrigin().mV);
+ F32 icon_dist = 0.f;
+ LLVector4a start;
+ LLVector4a end;
+ LLVector4a particle_end;
+
+ if (hit_icon)
+ {
+ LLVector4a delta;
+ delta.setSub(intersection, origin);
+ icon_dist = delta.getLength3().getF32();
+ }
+
+ LLViewerObject* hit_object = gViewerWindow->cursorIntersect(mMousePt.mX, mMousePt.mY, 512.f,
+ NULL, -1, mPickTransparent, mPickRigged, mPickUnselectable, mPickReflectionProbe, &face_hit,
+ &intersection, &uv, &normal, &tangent, &start, &end);
+
+ mPickPt = mMousePt;
+
+ U32 te_offset = face_hit > -1 ? face_hit : 0;
+
+ if (mPickParticle)
+ { //get the end point of line segement to use for particle raycast
+ if (hit_object)
+ {
+ particle_end = intersection;
+ }
+ else
+ {
+ particle_end = end;
+ }
+ }
+
+ LLViewerObject* objectp = hit_object;
+
+
+ LLVector4a delta;
+ delta.setSub(origin, intersection);
+
+ if (hit_icon &&
+ (!objectp ||
+ icon_dist < delta.getLength3().getF32()))
+ {
+ // was this name referring to a hud icon?
+ mHUDIcon = hit_icon;
+ mPickType = PICK_ICON;
+ mPosGlobal = mHUDIcon->getPositionGlobal();
+
+ }
+ else if (objectp)
+ {
+ if( objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH )
+ {
+ // Hit land
+ mPickType = PICK_LAND;
+ mObjectID.setNull(); // land has no id
+
+ // put global position into land_pos
+ LLVector3d land_pos;
+ if (!gViewerWindow->mousePointOnLandGlobal(mPickPt.mX, mPickPt.mY, &land_pos, mPickUnselectable))
+ {
+ // The selected point is beyond the draw distance or is otherwise
+ // not selectable. Return before calling mPickCallback().
+ return;
+ }
+
+ // Fudge the land focus a little bit above ground.
+ mPosGlobal = land_pos + LLVector3d::z_axis * 0.1f;
+ }
+ else
+ {
+ if(isFlora(objectp))
+ {
+ mPickType = PICK_FLORA;
+ }
+ else
+ {
+ mPickType = PICK_OBJECT;
+ }
+
+ LLVector3 v_intersection(intersection.getF32ptr());
+
+ mObjectOffset = gAgentCamera.calcFocusOffset(objectp, v_intersection, mPickPt.mX, mPickPt.mY);
+ mObjectID = objectp->mID;
+ mObjectFace = (te_offset == NO_FACE) ? -1 : (S32)te_offset;
+
+
+
+ mPosGlobal = gAgent.getPosGlobalFromAgent(v_intersection);
+
+ if (mWantSurfaceInfo)
+ {
+ getSurfaceInfo();
+ }
+ }
+ }
+
+ if (mPickParticle)
+ { //search for closest particle to click origin out to intersection point
+ S32 part_face = -1;
+
+ LLVOPartGroup* group = gPipeline.lineSegmentIntersectParticle(start, particle_end, NULL, &part_face);
+ if (group)
+ {
+ mParticleOwnerID = group->getPartOwner(part_face);
+ mParticleSourceID = group->getPartSource(part_face);
+ }
+ }
+
+ if (mPickCallback)
+ {
+ mPickCallback(*this);
+ }
+}
+
+LLPointer<LLViewerObject> LLPickInfo::getObject() const
+{
+ return gObjectList.findObject( mObjectID );
+}
+
+void LLPickInfo::updateXYCoords()
+{
+ if (mObjectFace > -1)
+ {
+ const LLTextureEntry* tep = getObject()->getTE(mObjectFace);
+ LLPointer<LLViewerTexture> imagep = LLViewerTextureManager::getFetchedTexture(tep->getID());
+ if(mUVCoords.mV[VX] >= 0.f && mUVCoords.mV[VY] >= 0.f && imagep.notNull())
+ {
+ mXYCoords.mX = ll_round(mUVCoords.mV[VX] * (F32)imagep->getWidth());
+ mXYCoords.mY = ll_round((1.f - mUVCoords.mV[VY]) * (F32)imagep->getHeight());
+ }
+ }
+}
+
+void LLPickInfo::getSurfaceInfo()
+{
+ // set values to uninitialized - this is what we return if no intersection is found
+ mObjectFace = -1;
+ mUVCoords = LLVector2(-1, -1);
+ mSTCoords = LLVector2(-1, -1);
+ mXYCoords = LLCoordScreen(-1, -1);
+ mIntersection = LLVector3(0,0,0);
+ mNormal = LLVector3(0,0,0);
+ mBinormal = LLVector3(0,0,0);
+ mTangent = LLVector4(0,0,0,0);
+
+ LLVector4a tangent;
+ LLVector4a intersection;
+ LLVector4a normal;
+
+ tangent.clear();
+ normal.clear();
+ intersection.clear();
+
+ LLViewerObject* objectp = getObject();
+
+ if (objectp)
+ {
+ if (gViewerWindow->cursorIntersect(ll_round((F32)mMousePt.mX), ll_round((F32)mMousePt.mY), 1024.f,
+ objectp, -1, mPickTransparent, mPickRigged, mPickUnselectable, mPickReflectionProbe,
+ &mObjectFace,
+ &intersection,
+ &mSTCoords,
+ &normal,
+ &tangent))
+ {
+ // if we succeeded with the intersect above, compute the texture coordinates:
+
+ if (objectp->mDrawable.notNull() && mObjectFace > -1)
+ {
+ LLFace* facep = objectp->mDrawable->getFace(mObjectFace);
+ if (facep)
+ {
+ mUVCoords = facep->surfaceToTexture(mSTCoords, intersection, normal);
+ }
+ }
+
+ mIntersection.set(intersection.getF32ptr());
+ mNormal.set(normal.getF32ptr());
+ mTangent.set(tangent.getF32ptr());
+
+ //extrapoloate binormal from normal and tangent
+
+ LLVector4a binormal;
+ binormal.setCross3(normal, tangent);
+ binormal.mul(tangent.getF32ptr()[3]);
+
+ mBinormal.set(binormal.getF32ptr());
+
+ mBinormal.normalize();
+ mNormal.normalize();
+ mTangent.normalize();
+
+ // and XY coords:
+ updateXYCoords();
+
+ }
+ }
+}
+
+//static
+bool LLPickInfo::isFlora(LLViewerObject* object)
+{
+ if (!object) return false;
+
+ LLPCode pcode = object->getPCode();
+
+ if( (LL_PCODE_LEGACY_GRASS == pcode)
+ || (LL_PCODE_LEGACY_TREE == pcode)
+ || (LL_PCODE_TREE_NEW == pcode))
+ {
+ return true;
+ }
+ return false;
+}