diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/llviewerwindow.cpp | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (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.cpp | 12801 |
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;
+}
|