diff options
Diffstat (limited to 'indra/newview/llviewerwindow.cpp')
-rw-r--r-- | indra/newview/llviewerwindow.cpp | 4961 |
1 files changed, 2292 insertions, 2669 deletions
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 900fd6fc8b..a0a3380441 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2,63 +2,68 @@ * @file llviewerwindow.cpp * @brief Implementation of the LLViewerWindow class. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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 "llpanellogin.h" #include "llviewerwindow.h" +#if LL_WINDOWS +#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally +#endif + // system library includes #include <stdio.h> #include <iostream> #include <fstream> +#include <algorithm> + +#include "llagent.h" +#include "llagentcamera.h" +#include "llfloaterreg.h" +#include "llpanellogin.h" +#include "llviewerkeyboard.h" +#include "llviewermenu.h" #include "llviewquery.h" #include "llxmltree.h" +#include "llslurl.h" //#include "llviewercamera.h" -#include "llglimmediate.h" +#include "llrender.h" #include "llvoiceclient.h" // for push-to-talk button handling -#ifdef SABINRIG -#include "cbw.h" -#endif //SABINRIG - // // TODO: Many of these includes are unnecessary. Remove them. // // linden library includes -#include "audioengine.h" // mute on minimize +#include "llaudioengine.h" // mute on minimize #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" @@ -71,13 +76,13 @@ #include "lltimer.h" #include "timing.h" #include "llviewermenu.h" +#include "lltooltip.h" +#include "llmediaentry.h" +#include "llurldispatcher.h" // newview includes #include "llagent.h" -#include "llalertdialog.h" #include "llbox.h" -#include "llcameraview.h" -#include "llchatbar.h" #include "llconsole.h" #include "llviewercontrol.h" #include "llcylinder.h" @@ -91,61 +96,56 @@ #include "llface.h" #include "llfeaturemanager.h" #include "llfilepicker.h" +#include "llfirstuse.h" #include "llfloater.h" -#include "llfloateractivespeakers.h" #include "llfloaterbuildoptions.h" #include "llfloaterbuyland.h" -#include "llfloaterchat.h" -#include "llfloaterchatterbox.h" -#include "llfloatercustomize.h" -#include "llfloatereditui.h" // HACK JAMESDEBUG for ui editor +#include "llfloatercamera.h" #include "llfloaterland.h" #include "llfloaterinspect.h" #include "llfloatermap.h" -#include "llfloatermute.h" #include "llfloaternamedesc.h" #include "llfloaterpreference.h" #include "llfloatersnapshot.h" #include "llfloatertools.h" #include "llfloaterworldmap.h" #include "llfocusmgr.h" -#include "llframestatview.h" +#include "llfontfreetype.h" #include "llgesturemgr.h" #include "llglheaders.h" -#include "llhippo.h" -#include "llhoverview.h" +#include "lltooltip.h" #include "llhudmanager.h" +#include "llhudobject.h" #include "llhudview.h" #include "llimagebmp.h" #include "llimagej2c.h" -#include "llinventoryview.h" +#include "llimageworker.h" #include "llkeyboard.h" #include "lllineeditor.h" #include "llmenugl.h" #include "llmodaldialog.h" #include "llmorphview.h" #include "llmoveview.h" -#include "llnotify.h" -#include "lloverlaybar.h" +#include "llnavigationbar.h" +#include "llpopupview.h" #include "llpreviewtexture.h" #include "llprogressview.h" #include "llresmgr.h" -#include "llrootview.h" +#include "llsidetray.h" #include "llselectmgr.h" -#include "llsphere.h" +#include "llrootview.h" +#include "llrendersphere.h" #include "llstartup.h" #include "llstatusbar.h" #include "llstatview.h" #include "llsurface.h" #include "llsurfacepatch.h" -#include "llimview.h" #include "lltexlayer.h" #include "lltextbox.h" #include "lltexturecache.h" #include "lltexturefetch.h" #include "lltextureview.h" #include "lltool.h" -#include "lltoolbar.h" #include "lltoolcomp.h" #include "lltooldraganddrop.h" #include "lltoolface.h" @@ -154,97 +154,85 @@ #include "lltoolmgr.h" #include "lltoolmorph.h" #include "lltoolpie.h" -#include "lltoolplacer.h" -#include "lltoolselect.h" #include "lltoolselectland.h" -#include "lltoolview.h" -#include "llvieweruictrlfactory.h" -#include "lluploaddialog.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 "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerinventory.h" #include "llviewerkeyboard.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 "llvoavatar.h" +#include "llvoavatarself.h" #include "llvovolume.h" #include "llworld.h" #include "llworldmapview.h" #include "pipeline.h" #include "llappviewer.h" -#include "llurlsimstring.h" #include "llviewerdisplay.h" #include "llspatialpartition.h" +#include "llviewerjoystick.h" +#include "llviewernetwork.h" +#include "llpostprocess.h" +#include "llbottomtray.h" +#include "llnearbychatbar.h" +#include "llagentui.h" +#include "llwearablelist.h" + +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llnotificationmanager.h" + +#include "llfloaternotificationsconsole.h" + +#include "llnearbychat.h" +#include "llviewerwindowlistener.h" +#include "llpaneltopinfobar.h" #if LL_WINDOWS -#include "llwindebug.h" #include <tchar.h> // For Unicode conversion methods #endif // // Globals // -void render_ui_and_swap_if_needed(); -void render_ui_and_swap(); -LLBottomPanel* gBottomPanel = NULL; +void render_ui(F32 zoom_factor = 1.f, int subfield = 0); extern BOOL gDebugClicks; extern BOOL gDisplaySwapBuffers; +extern BOOL gDepthDirty; extern BOOL gResizeScreenTexture; -extern S32 gJamesInt; LLViewerWindow *gViewerWindow = NULL; -LLVelocityBar *gVelocityBar = NULL; - -LLVector3d gLastHitPosGlobal; -LLVector3d gLastHitObjectOffset; -LLUUID gLastHitObjectID; -S32 gLastHitObjectFace = -1; -BOOL gLastHitLand = FALSE; -F32 gLastHitUCoord; -F32 gLastHitVCoord; - -LLVector3d gLastHitNonFloraPosGlobal; -LLVector3d gLastHitNonFloraObjectOffset; -LLUUID gLastHitNonFloraObjectID; -S32 gLastHitNonFloraObjectFace = -1; -BOOL gLastHitParcelWall = FALSE; - -S32 gLastHitUIElement = 0; -LLHUDIcon* gLastHitHUDIcon = NULL; - -BOOL gDebugSelect = FALSE; -U8 gLastPickAlpha = 255; -BOOL gUseGLPick = FALSE; - -// On the next pick pass (whenever that happens) -// should we try to pick individual faces? -// Cleared to FALSE every time a pick happens. -BOOL gPickFaces = FALSE; - -LLFrameTimer gMouseIdleTimer; LLFrameTimer gAwayTimer; LLFrameTimer gAwayTriggerTimer; -LLFrameTimer gAlphaFadeTimer; BOOL gShowOverlayTitle = FALSE; -BOOL gPickTransparent = TRUE; -BOOL gDebugFastUIRender = FALSE; +LLViewerObject* gDebugRaycastObject = NULL; +LLVector3 gDebugRaycastIntersection; +LLVector2 gDebugRaycastTexCoord; +LLVector3 gDebugRaycastNormal; +LLVector3 gDebugRaycastBinormal; +S32 gDebugRaycastFaceHit; // HUD display lines in lower right BOOL gDisplayWindInfo = FALSE; BOOL gDisplayCameraPos = FALSE; -BOOL gDisplayNearestWater = FALSE; BOOL gDisplayFOV = FALSE; +BOOL gDisplayBadge = FALSE; S32 CHAT_BAR_HEIGHT = 28; S32 OVERLAY_BAR_HEIGHT = 20; @@ -256,121 +244,36 @@ const F32 MIN_AFK_TIME = 2.f; // minimum time after setting away state before co const F32 MAX_FAST_FRAME_TIME = 0.5f; const F32 FAST_FRAME_INCREMENT = 0.1f; -const S32 PICK_HALF_WIDTH = 5; -const S32 PICK_DIAMETER = 2 * PICK_HALF_WIDTH+1; - -const F32 MIN_DISPLAY_SCALE = 0.85f; - -const S32 CONSOLE_BOTTOM_PAD = 40; - -#ifdef SABINRIG -/// ALL RIG STUFF -bool rigControl = false; -bool voltDisplay = true; -bool nominalX = false; -bool nominalY = false; -static F32 nomerX = 0.0f; -static F32 nomerY = 0.0f; -const BOARD_NUM = 0; // rig stuff! -const ADRANGE = BIP10VOLTS; // rig stuff! -static unsigned short DataVal; // rig stuff! -static F32 oldValueX = 0; -static F32 newValueX = 50; -static F32 oldValueY = 0; -static F32 newValueY = 50; -static S32 mouseX = 50; -static S32 mouseY = 50; -static float VoltageX = 50; // rig stuff! -static float VoltageY = 50; // rig stuff! -static float nVoltX = 0; -static float nVoltY = 0; -static F32 temp1 = 50.f; -static F32 temp2 = 20.f; -LLCoordGL new_gl; -#endif //SABINRIG - -char LLViewerWindow::sSnapshotBaseName[LL_MAX_PATH]; -char LLViewerWindow::sSnapshotDir[LL_MAX_PATH]; - -char LLViewerWindow::sMovieBaseName[LL_MAX_PATH]; - -extern void toggle_debug_menus(void*); - -#ifdef SABINRIG -// static -void LLViewerWindow::printFeedback() -{ - if(rigControl == true) - { - cbAIn (BOARD_NUM, 0, ADRANGE, &DataVal); - cbToEngUnits (BOARD_NUM,ADRANGE,DataVal,&VoltageX); //Convert raw to voltage for X-axis - cbAIn (BOARD_NUM, 1, ADRANGE, &DataVal); - cbToEngUnits (BOARD_NUM,ADRANGE,DataVal,&VoltageY); //Convert raw to voltage for Y-axis - if(voltDisplay == true) - { - llinfos << "Current Voltages - X:" << VoltageX << " Y:" << VoltageY << llendl; //Display voltage - } - - if(nVoltX == 0) - { - nVoltX = VoltageX; - nVoltY = VoltageY; //First time setup of nominal values. - } - - newValueX = VoltageX; - newValueY = VoltageY; //Take in current voltage and set to a separate value for adjustment. - - mouseX = mCurrentMousePoint.mX; - mouseY = mCurrentMousePoint.mY; //Take in current cursor position and set to separate value for adjustment. - - if( abs(newValueX - nVoltX) > nomerX ) - { - if( (newValueX - oldValueX) < 0) - { - mouseX += (S32)( ((newValueX - oldValueX)*.5)) * -temp; - } - else - { - mouseX += (S32)( ((newValueX - oldValueX)*.5) * temp1); - } - } - else - { - mouseX = getWindowWidth() / 2; - } - if( abs(newValueY - nVoltY) > nomerY ) - { - if( (newValueY - oldValueY) < 0) - { - mouseY += (S32)( ((newValueY - oldValueY)*(newValueY - oldValueY)) * -temp2); - } - else - { - mouseY += (S32)( ((newValueY - oldValueY)*(newValueY - oldValueY)) * temp2); - } - } - else - { - mouseY = getWindowHeight() / 2; - } - //mouseX += (S32)( (newValueX - nVoltX) * temp1 + 0.5 ); - // (newValueX - oldValueX) = difference between current position and nominal position - // * temp1 = the amplification of the number that sets sensitivity - // + 0.5 = fixes rounding errors - +const F32 MIN_DISPLAY_SCALE = 0.75f; - //mouseY += (S32)( (newValueY - nVoltY) * temp2 + 0.5 ); //Algorithm to adjust voltage for mouse adjustment. +std::string LLViewerWindow::sSnapshotBaseName; +std::string LLViewerWindow::sSnapshotDir; - oldValueX = newValueX; - oldValueY = newValueY; +std::string LLViewerWindow::sMovieBaseName; - new_gl.mX = mouseX; - new_gl.mY = mouseY; //Setup final coordinate to move mouse to. +class RecordToChatConsole : public LLError::Recorder, public LLSingleton<RecordToChatConsole> +{ +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 - setCursorPosition(new_gl); //Set final cursor position + // 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); + //} + //} } -} -#endif //SABINRIG +}; //////////////////////////////////////////////////////////////////////////// // @@ -414,7 +317,7 @@ public: mTextColor = LLColor4( 0.86f, 0.86f, 0.86f, 1.f ); // Draw stuff growing up from right lower corner of screen - U32 xpos = mWindow->getWindowWidth() - 350; + U32 xpos = mWindow->getWindowWidthScaled() - 350; U32 ypos = 64; const U32 y_inc = 20; @@ -430,7 +333,9 @@ public: 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(" Debug %d: %d:%02d:%02d", idx, hours,mins,secs)); ypos += y_inc2; + std::string label = gDebugTimerLabel[idx]; + if (label.empty()) label = llformat("Debug: %d", idx); + addText(xpos, ypos, llformat(" %s: %d:%02d:%02d", label.c_str(), hours,mins,secs)); ypos += y_inc2; } F32 time = gFrameTimeSeconds; @@ -456,9 +361,9 @@ public: agent_center_text = llformat("AgentCenter %f %f %f", (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ])); - if (gAgent.getAvatarObject()) + if (isAgentAvatarValid()) { - tvector = gAgent.getPosGlobalFromAgent(gAgent.getAvatarObject()->mRoot.getWorldPosition()); + 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])); } @@ -476,11 +381,11 @@ public: agent_left_text = llformat("AgentLeftAxis %f %f %f", (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ])); - tvector = gAgent.getCameraPositionGlobal(); + 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(gCamera->getAtAxis()); + 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])); @@ -514,9 +419,21 @@ public: } if (gDisplayFOV) { - addText(xpos, ypos, llformat("FOV: %2.1f deg", RAD_TO_DEG * gCamera->getView())); + 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")) { if (gPipeline.getUseVertexShaders() == 0) @@ -560,7 +477,7 @@ public: if (gPipeline.mBatchCount > 0) { addText(xpos, ypos, llformat("Batch min/max/mean: %d/%d/%d", gPipeline.mMinBatchSize, gPipeline.mMaxBatchSize, - gPipeline.mMeanBatchSize)); + gPipeline.mTrianglesDrawn/gPipeline.mBatchCount)); gPipeline.mMinBatchSize = gPipeline.mMaxBatchSize; gPipeline.mMaxBatchSize = 0; @@ -568,6 +485,10 @@ public: } 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; @@ -577,9 +498,46 @@ public: ypos += y_inc; + addText(xpos,ypos, llformat("%d Lights visible", LLPipeline::sVisibleLightCount)); + + ypos += y_inc; + LLVertexBuffer::sBindCount = LLImageGL::sBindCount = LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount = - gPipeline.mNumVisibleNodes = 0; + gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0; + } + if (gSavedSettings.getBOOL("DebugShowRenderMatrices")) + { + addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[12], gGLProjection[13], gGLProjection[14], gGLProjection[15])); + ypos += y_inc; + + addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[8], gGLProjection[9], gGLProjection[10], gGLProjection[11])); + ypos += y_inc; + + addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[4], gGLProjection[5], gGLProjection[6], gGLProjection[7])); + ypos += y_inc; + + addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[0], gGLProjection[1], gGLProjection[2], gGLProjection[3])); + ypos += y_inc; + + addText(xpos, ypos, "Projection Matrix"); + ypos += y_inc; + + + addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[12], gGLModelView[13], gGLModelView[14], gGLModelView[15])); + ypos += y_inc; + + addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[8], gGLModelView[9], gGLModelView[10], gGLModelView[11])); + ypos += y_inc; + + addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[4], gGLModelView[5], gGLModelView[6], gGLModelView[7])); + ypos += y_inc; + + addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[0], gGLModelView[1], gGLModelView[2], gGLModelView[3])); + ypos += y_inc; + + addText(xpos, ypos, "View Matrix"); + ypos += y_inc; } if (gSavedSettings.getBOOL("DebugShowColor")) { @@ -590,7 +548,7 @@ public: ypos += y_inc; } // only display these messages if we are actually rendering beacons at this moment - if (LLPipeline::getRenderBeacons(NULL) && LLPipeline::getProcessBeacons(NULL)) + if (LLPipeline::getRenderBeacons(NULL) && LLFloaterReg::instanceVisible("beacons")) { if (LLPipeline::getRenderParticleBeacons(NULL)) { @@ -632,9 +590,9 @@ public: iter != mLineList.end(); ++iter) { const Line& line = *iter; - LLFontGL::sMonospace->renderUTF8(line.text, 0, (F32)line.x, (F32)line.y, mTextColor, + LLFontGL::getFontMonospace()->renderUTF8(line.text, 0, (F32)line.x, (F32)line.y, mTextColor, LLFontGL::LEFT, LLFontGL::TOP, - LLFontGL::NORMAL, S32_MAX, S32_MAX, NULL, FALSE); + LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); } mLineList.clear(); } @@ -651,295 +609,159 @@ void LLViewerWindow::updateDebugText() // LLViewerWindow // -BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) +BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down) { + const char* buttonname = ""; + const char* buttonstatestr = ""; S32 x = pos.mX; S32 y = pos.mY; x = llround((F32)x / mDisplayScale.mV[VX]); y = llround((F32)y / mDisplayScale.mV[VY]); - LLView::sMouseHandlerMessage = ""; - - if (gDebugClicks) - { - llinfos << "ViewerWindow left mouse down at " << x << "," << y << llendl; - } + // only send mouse clicks to UI if UI is visible + if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { - if (gMenuBarView) - { - // stop ALT-key access to menu - gMenuBarView->resetMenuTrigger(); - } - - mLeftMouseDown = TRUE; - - // Make sure we get a coresponding mouseup event, even if the mouse leaves the window - mWindow->captureMouse(); - - // Indicate mouse was active - gMouseIdleTimer.reset(); - - // Hide tooltips on mousedown - if( mToolTip ) - { - mToolTipBlocked = TRUE; - mToolTip->setVisible( FALSE ); - } - - // Also hide hover info on mousedown - if (gHoverView) - { - gHoverView->cancelHover(); - } - - if (gToolMgr) - { - // Don't let the user move the mouse out of the window until mouse up. - if( gToolMgr->getCurrentTool()->clipMouseWhenDown() ) - { - mWindow->setMouseClipping(TRUE); - } - } - - 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) + if (down) { - llinfos << "Left Mouse Down handled by captor " << mouse_captor->getName() << llendl; - } - - return mouse_captor->handleMouseDown(local_x, local_y, mask); - } - - // Topmost view gets a chance before the hierarchy - LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - if (top_ctrl) - { - S32 local_x, local_y; - top_ctrl->screenPointToLocal( x, y, &local_x, &local_y ); - if (top_ctrl->pointInView(local_x, local_y)) - { - return top_ctrl->handleMouseDown(local_x, local_y, mask); + buttonstatestr = "down" ; } else { - setTopCtrl(NULL); + buttonstatestr = "up" ; } - } - - // Give the UI views a chance to process the click - if( mRootView->handleMouseDown(x, y, mask) ) - { - if (LLView::sDebugMouseHandling) + + switch (clicktype) { - llinfos << "Left Mouse Down" << LLView::sMouseHandlerMessage << llendl; + case LLMouseHandler::CLICK_LEFT: + mLeftMouseDown = down; + buttonname = "Left"; + break; + case LLMouseHandler::CLICK_RIGHT: + mRightMouseDown = down; + buttonname = "Right"; + break; + case LLMouseHandler::CLICK_MIDDLE: + mMiddleMouseDown = down; + buttonname = "Middle"; + break; + case LLMouseHandler::CLICK_DOUBLELEFT: + mLeftMouseDown = down; + buttonname = "Left Double Click"; + break; } - return TRUE; - } - else if (LLView::sDebugMouseHandling) - { - llinfos << "Left Mouse Down not handled by view" << llendl; - } - - if (gDisconnected) - { - return FALSE; - } + + LLView::sMouseHandlerMessage.clear(); - if (gToolMgr) - { - if(gToolMgr->getCurrentTool()->handleMouseDown( x, y, mask ) ) + if (gMenuBarView) { - // This is necessary to force clicks in the world to cause edit - // boxes that might have keyboard focus to relinquish it, and hence - // cause a commit to update their value. JC - gFocusMgr.setKeyboardFocus(NULL); - return TRUE; + // stop ALT-key access to menu + gMenuBarView->resetMenuTrigger(); } - } - return FALSE; -} - -BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask) -{ - S32 x = pos.mX; - S32 y = pos.mY; - x = llround((F32)x / mDisplayScale.mV[VX]); - y = llround((F32)y / mDisplayScale.mV[VY]); - - LLView::sMouseHandlerMessage = ""; + if (gDebugClicks) + { + llinfos << "ViewerWindow " << buttonname << " mouse " << buttonstatestr << " at " << x << "," << y << llendl; + } - if (gDebugClicks) - { - llinfos << "ViewerWindow left mouse double-click at " << x << "," << y << llendl; - } + // Make sure we get a corresponding mouseup event, even if the mouse leaves the window + if (down) + mWindow->captureMouse(); + else + mWindow->releaseMouse(); - mLeftMouseDown = TRUE; + // Indicate mouse was active + LLUI::resetMouseIdleTimer(); - // Hide tooltips - if( mToolTip ) - { - mToolTip->setVisible( FALSE ); - } + // 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) + LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); + if( mouse_captor ) { - llinfos << "Left Mouse Down handled by captor " << mouse_captor->getName() << llendl; + S32 local_x; + S32 local_y; + mouse_captor->screenPointToLocal( x, y, &local_x, &local_y ); + if (LLView::sDebugMouseHandling) + { + llinfos << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << llendl; + } + return mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down); } - return mouse_captor->handleDoubleClick(local_x, local_y, mask); - } + // Topmost view gets a chance before the hierarchy + //LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); + //if (top_ctrl) + //{ + // S32 local_x, local_y; + // top_ctrl->screenPointToLocal( x, y, &local_x, &local_y ); + // if (top_ctrl->pointInView(local_x, local_y)) + // { + // return top_ctrl->handleAnyMouseClick(local_x, local_y, mask, clicktype, down) ; + // } + // else + // { + // if (down) + // { + // gFocusMgr.setTopCtrl(NULL); + // } + // } + //} - // Check for hit on UI. - LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - if (top_ctrl) - { - S32 local_x, local_y; - top_ctrl->screenPointToLocal( x, y, &local_x, &local_y ); - if (top_ctrl->pointInView(local_x, local_y)) + // Give the UI views a chance to process the click + if( mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) ) { - return top_ctrl->handleDoubleClick(local_x, local_y, mask); + if (LLView::sDebugMouseHandling) + { + llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLView::sMouseHandlerMessage << llendl; + } + return TRUE; } - else + else if (LLView::sDebugMouseHandling) { - setTopCtrl(NULL); + llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl; } } - if (mRootView->handleDoubleClick(x, y, mask)) + // Do not allow tool manager to handle mouseclicks if we have disconnected + if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) ) { - if (LLView::sDebugMouseHandling) - { - llinfos << "Left Mouse Down" << LLView::sMouseHandlerMessage << llendl; - } return TRUE; } - else if (LLView::sDebugMouseHandling) - { - llinfos << "Left Mouse Down not handled by view" << llendl; - } + - // Why is this here? JC 9/3/2002 - if (gNoRender) - { - 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) +{ + BOOL down = TRUE; + return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); +} - if (gToolMgr) +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 (handleAnyMouseClick(window, pos, mask, + LLMouseHandler::CLICK_DOUBLELEFT, down)) { - if(gToolMgr->getCurrentTool()->handleDoubleClick( x, y, mask ) ) - { - return TRUE; - } + return TRUE; } - - // if we got this far and nothing handled a double click, pass a normal mouse down return handleMouseDown(window, pos, mask); } BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { - S32 x = pos.mX; - S32 y = pos.mY; - x = llround((F32)x / mDisplayScale.mV[VX]); - y = llround((F32)y / mDisplayScale.mV[VY]); - - LLView::sMouseHandlerMessage = ""; - - if (gDebugClicks) - { - llinfos << "ViewerWindow left mouse up" << llendl; - } - - mLeftMouseDown = FALSE; - - // Indicate mouse was active - gMouseIdleTimer.reset(); - - // Hide tooltips on mouseup - if( mToolTip ) - { - mToolTip->setVisible( FALSE ); - } - - // Also hide hover info on mouseup - if (gHoverView) gHoverView->cancelHover(); - - BOOL handled = FALSE; - - mWindow->releaseMouse(); - - LLTool *tool = NULL; - if (gToolMgr) - { - tool = gToolMgr->getCurrentTool(); - - if( tool->clipMouseWhenDown() ) - { - mWindow->setMouseClipping(FALSE); - } - } - - 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) - { - llinfos << "Left Mouse Up handled by captor " << mouse_captor->getName() << llendl; - } - - return mouse_captor->handleMouseUp(local_x, local_y, mask); - } - - LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - 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->handleMouseUp(local_x, local_y, mask); - } - - if( !handled ) - { - handled = mRootView->handleMouseUp(x, y, mask); - } - - if (LLView::sDebugMouseHandling) - { - if (handled) - { - llinfos << "Left Mouse Up" << LLView::sMouseHandlerMessage << llendl; - } - else - { - llinfos << "Left Mouse Up not handled by view" << llendl; - } - } - - if( !handled ) - { - if (tool) - { - handled = tool->handleMouseUp(x, y, mask); - } - } - - // Always handled as far as the OS is concerned. - return TRUE; + BOOL down = FALSE; + return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); } @@ -950,106 +772,19 @@ BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK x = llround((F32)x / mDisplayScale.mV[VX]); y = llround((F32)y / mDisplayScale.mV[VY]); - LLView::sMouseHandlerMessage = ""; - - if (gDebugClicks) - { - llinfos << "ViewerWindow right mouse down at " << x << "," << y << llendl; - } - - if (gMenuBarView) - { - // stop ALT-key access to menu - gMenuBarView->resetMenuTrigger(); - } - - mRightMouseDown = TRUE; - - // Make sure we get a coresponding mouseup event, even if the mouse leaves the window - mWindow->captureMouse(); - - // Hide tooltips - if( mToolTip ) - { - mToolTip->setVisible( FALSE ); - } - - // Also hide hover info on mousedown - if (gHoverView) - { - gHoverView->cancelHover(); - } - - if (gToolMgr) - { - // Don't let the user move the mouse out of the window until mouse up. - if( gToolMgr->getCurrentTool()->clipMouseWhenDown() ) - { - mWindow->setMouseClipping(TRUE); - } - } - - 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) - { - llinfos << "Right Mouse Down handled by captor " << mouse_captor->getName() << llendl; - } - return mouse_captor->handleRightMouseDown(local_x, local_y, mask); - } - - LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - if (top_ctrl) - { - S32 local_x, local_y; - top_ctrl->screenPointToLocal( x, y, &local_x, &local_y ); - if (top_ctrl->pointInView(local_x, local_y)) - { - return top_ctrl->handleRightMouseDown(local_x, local_y, mask); - } - else - { - setTopCtrl(NULL); - } - } - - if( mRootView->handleRightMouseDown(x, y, mask) ) - { - if (LLView::sDebugMouseHandling) - { - llinfos << "Right Mouse Down" << LLView::sMouseHandlerMessage << llendl; - } - return TRUE; - } - else if (LLView::sDebugMouseHandling) - { - llinfos << "Right Mouse Down not handled by view" << llendl; - } - - if (gToolMgr) - { - if(gToolMgr->getCurrentTool()->handleRightMouseDown( x, y, mask ) ) - { - // This is necessary to force clicks in the world to cause edit - // boxes that might have keyboard focus to relinquish it, and hence - // cause a commit to update their value. JC - gFocusMgr.setKeyboardFocus(NULL); - return TRUE; - } - } + BOOL down = TRUE; + BOOL handle = handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down); + if (handle) + return handle; // *HACK: this should be rolled into the composite tool logic, not // hardcoded at the top level. - if (gToolPie && (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgent.getCameraMode()) ) + if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance()) { // 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. - gToolPie->handleRightMouseDown(x, y, mask); + LLToolPie::getInstance()->handleRightMouseDown(x, y, mask); // show_context_menu( x, y, mask ); } @@ -1058,114 +793,175 @@ BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { - S32 x = pos.mX; - S32 y = pos.mY; - x = llround((F32)x / mDisplayScale.mV[VX]); - y = llround((F32)y / mDisplayScale.mV[VY]); - - LLView::sMouseHandlerMessage = ""; - - // Don't care about caps lock for mouse events. - if (gDebugClicks) - { - llinfos << "ViewerWindow right mouse up" << llendl; - } + BOOL down = FALSE; + return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down); +} - mRightMouseDown = FALSE; +BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) +{ + BOOL down = TRUE; + LLVoiceClient::getInstance()->middleMouseState(true); + handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down); + + // Always handled as far as the OS is concerned. + return TRUE; +} - // Indicate mouse was active - gMouseIdleTimer.reset(); +LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, LLWindowCallbacks::DragNDropAction action, std::string data) +{ + LLWindowCallbacks::DragNDropResult result = LLWindowCallbacks::DND_NONE; - // Hide tooltips on mouseup - if( mToolTip ) + 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 ) { - mToolTip->setVisible( FALSE ); - } + 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(), NULL, true ); + return LLWindowCallbacks::DND_MOVE; + } + return LLWindowCallbacks::DND_COPY; + } + } - // Also hide hover info on mouseup - if (gHoverView) gHoverView->cancelHover(); + if (prim_media_dnd_enabled) + { + LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ ); - BOOL handled = FALSE; + LLUUID object_id = pick_info.getObjectID(); + S32 object_face = pick_info.mObjectFace; + std::string url = data; - mWindow->releaseMouse(); + lldebugs << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl; - LLTool *tool = NULL; - if (gToolMgr) - { - tool = gToolMgr->getCurrentTool(); + LLVOVolume *obj = dynamic_cast<LLVOVolume*>(static_cast<LLViewerObject*>(pick_info.getObject())); + + if (obj && !obj->getRegion()->getCapability("ObjectMedia").empty()) + { + LLTextureEntry *te = obj->getTE(object_face); - if( tool->clipMouseWhenDown() ) - { - mWindow->setMouseClipping(FALSE); - } - } + // 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 ); - 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) - { - llinfos << "Right Mouse Up handled by captor " << mouse_captor->getName() << llendl; + 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; } - return mouse_captor->handleRightMouseUp(local_x, local_y, mask); - } - - LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - 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->handleRightMouseUp(local_x, local_y, mask); - } - - if( !handled ) - { - handled = mRootView->handleRightMouseUp(x, y, mask); - } - if (LLView::sDebugMouseHandling) - { - if (handled) - { - llinfos << "Right Mouse Up" << LLView::sMouseHandlerMessage << llendl; - } - else + if (prim_media_dnd_enabled && + result == LLWindowCallbacks::DND_NONE && !mDragHoveredObject.isNull()) { - llinfos << "Right Mouse Up not handled by view" << llendl; + LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); + mDragHoveredObject = NULL; } } - - if( !handled ) - { - if (tool) - { - handled = tool->handleRightMouseUp(x, y, mask); - } - } - - // Always handled as far as the OS is concerned. - return TRUE; -} - -BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) -{ - gVoiceClient->middleMouseState(true); - - // Always handled as far as the OS is concerned. - return TRUE; + + return result; } - + BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { - gVoiceClient->middleMouseState(false); - - // Always handled as far as the OS is concerned. + BOOL down = FALSE; + LLVoiceClient::getInstance()->middleMouseState(false); + handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down); + + // Always handled as far as the OS is concerned. return TRUE; } +// WARNING: this is potentially called multiple times per frame void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask) { S32 x = pos.mX; @@ -1178,13 +974,14 @@ void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask // Save mouse point for access during idle() and display() - LLCoordGL prev_saved_mouse_point = mCurrentMousePoint; LLCoordGL mouse_point(x, y); - saveLastMouse(mouse_point); - BOOL mouse_actually_moved = !gFocusMgr.getMouseCapture() && // mouse is not currenty captured - ((prev_saved_mouse_point.mX != mCurrentMousePoint.mX) || (prev_saved_mouse_point.mY != mCurrentMousePoint.mY)); // mouse moved from last recorded position - gMouseIdleTimer.reset(); + if (mouse_point != mCurrentMousePoint) + { + LLUI::resetMouseIdleTimer(); + } + + saveLastMouse(mouse_point); mWindow->showCursorFromMouseMove(); @@ -1192,21 +989,6 @@ void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask { gAgent.clearAFK(); } - - if(mToolTip && mouse_actually_moved) - { - mToolTipBlocked = FALSE; // Blocking starts on keyboard events and (only) ends here. - if( mToolTip->getVisible() && !mToolTipStickyRect.pointInRect( x, y ) ) - { - mToolTip->setVisible( FALSE ); - } - } - - // Activate the hover picker on mouse move. - if (gHoverView) - { - gHoverView->setTyping(FALSE); - } } void LLViewerWindow::handleMouseLeave(LLWindow *window) @@ -1214,10 +996,7 @@ void LLViewerWindow::handleMouseLeave(LLWindow *window) // Note: we won't get this if we have captured the mouse. llassert( gFocusMgr.getMouseCapture() == NULL ); mMouseInWindow = FALSE; - if (mToolTip) - { - mToolTip->setVisible( FALSE ); - } + LLToolTipMgr::instance().blockToolTips(); } BOOL LLViewerWindow::handleCloseRequest(LLWindow *window) @@ -1237,6 +1016,7 @@ void LLViewerWindow::handleQuit(LLWindow *window) 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) @@ -1246,12 +1026,7 @@ void LLViewerWindow::handleFocus(LLWindow *window) LLModalDialog::onAppFocusGained(); gAgent.onAppFocusGained(); - if (gToolMgr) - { - gToolMgr->onAppFocusGained(); - } - - gShowTextEditCursor = TRUE; + LLToolMgr::getInstance()->onAppFocusGained(); // See if we're coming in with modifier keys held down if (gKeyboard) @@ -1269,10 +1044,7 @@ void LLViewerWindow::handleFocusLost(LLWindow *window) { gFocusMgr.setAppHasFocus(FALSE); //LLModalDialog::onAppFocusLost(); - if( gToolMgr ) - { - gToolMgr->onAppFocusLost(); - } + LLToolMgr::getInstance()->onAppFocusLost(); gFocusMgr.setMouseCapture( NULL ); if (gMenuBarView) @@ -1282,13 +1054,8 @@ void LLViewerWindow::handleFocusLost(LLWindow *window) } // restore mouse cursor - gViewerWindow->showCursor(); - gViewerWindow->getWindow()->setMouseClipping(FALSE); - - // JC - Leave keyboard focus, so if you're popping in and out editing - // a script, you don't have to click in the editor again and again. - // gFocusMgr.setKeyboardFocus( NULL ); - gShowTextEditCursor = FALSE; + showCursor(); + getWindow()->setMouseClipping(FALSE); // If losing focus while keys are down, reset them. if (gKeyboard) @@ -1304,7 +1071,7 @@ void LLViewerWindow::handleFocusLost(LLWindow *window) BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated) { // Let the voice chat code check for its PTT key. Note that this never affects event processing. - gVoiceClient->keyDown(key, mask); + LLVoiceClient::getInstance()->keyDown(key, mask); if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME) { @@ -1326,7 +1093,7 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated) BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask) { // Let the voice chat code check for its PTT key. Note that this never affects event processing. - gVoiceClient->keyUp(key, mask); + LLVoiceClient::getInstance()->keyUp(key, mask); return FALSE; } @@ -1334,6 +1101,7 @@ BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask) void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) { + LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true); return gViewerKeyboard.scanKey(key, key_down, key_up, key_level); } @@ -1347,55 +1115,41 @@ BOOL LLViewerWindow::handleActivate(LLWindow *window, BOOL activated) mActive = TRUE; send_agent_resume(); gAgent.clearAFK(); - if (mWindow->getFullscreen() && !mIgnoreActivate) - { - if (!LLApp::isExiting() ) - { - if (LLStartUp::getStartupState() >= STATE_STARTED) - { - // if we're in world, show a progress bar to hide reloading of textures - llinfos << "Restoring GL during activate" << llendl; - restoreGL("Restoring..."); - } - else - { - // otherwise restore immediately - restoreGL(); - } - } - else - { - llwarns << "Activating while quitting" << llendl; - } - } - + // Unmute audio audio_update_volume(); } else { mActive = FALSE; - if (gAllowIdleAFK) + + if (gSavedSettings.getS32("AFKTimeout")) { gAgent.setAFK(); } // SL-53351: Make sure we're not in mouselook when minimised, to prevent control issues - gAgent.changeCameraToDefault(); - - send_agent_pause(); - - if (mWindow->getFullscreen() && !mIgnoreActivate) + if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK) { - llinfos << "Stopping GL during deactivation" << llendl; - stopGL(); + 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) { @@ -1421,24 +1175,19 @@ BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S //SetBKColor(hdc, RGB(255, 255, 255)); FillRect(hdc, &wnd_rect, CreateSolidBrush(RGB(255, 255, 255))); - LLString name_str; - gAgent.getName(name_str); - - S32 len; - char temp_str[255]; /* Flawfinder: ignore */ - snprintf(temp_str, sizeof(temp_str), "%s FPS %3.1f Phy FPS %2.1f Time Dil %1.3f", /* Flawfinder: ignore */ - name_str.c_str(), - gViewerStats->mFPSStat.getMeanPerSec(), - gViewerStats->mSimPhysicsFPS.getPrev(0), - gViewerStats->mSimTimeDilation.getPrev(0)); - len = strlen(temp_str); /* Flawfinder: ignore */ - TextOutA(hdc, 0, 0, temp_str, len); + std::string temp_str; + temp_str = llformat( "FPS %3.1f Phy FPS %2.1f Time Dil %1.3f", /* Flawfinder: ignore */ + LLViewerStats::getInstance()->mFPSStat.getMeanPerSec(), + LLViewerStats::getInstance()->mSimPhysicsFPS.getPrev(0), + LLViewerStats::getInstance()->mSimTimeDilation.getPrev(0)); + S32 len = temp_str.length(); + TextOutA(hdc, 0, 0, temp_str.c_str(), len); LLVector3d pos_global = gAgent.getPositionGlobal(); - snprintf(temp_str, sizeof(temp_str), "Avatar pos %6.1lf %6.1lf %6.1lf", pos_global.mdV[0], pos_global.mdV[1], pos_global.mdV[2]); /* Flawfinder: ignore */ - len = strlen(temp_str); /* Flawfinder: ignore */ - TextOutA(hdc, 0, 25, temp_str, len); + 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 \"DisableRendering FALSE\" in settings.ini file to reenable", 61); EndPaint(window_handle, &ps); @@ -1451,7 +1200,7 @@ BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S void LLViewerWindow::handleScrollWheel(LLWindow *window, S32 clicks) { - gViewerWindow->handleScrollWheel( clicks ); + handleScrollWheel( clicks ); } void LLViewerWindow::handleWindowBlock(LLWindow *window) @@ -1472,8 +1221,9 @@ void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data) case SLURL_MESSAGE_TYPE: // received URL std::string url = (const char*)data; - const bool from_external_browser = true; - if (LLURLDispatcher::dispatch(url, from_external_browser)) + LLMediaCtrl* web = NULL; + const bool trusted_browser = false; + if (LLURLDispatcher::dispatch(url, web, trusted_browser)) { // bring window to foreground, as it has just been "launched" from a URL mWindow->bringToFront(); @@ -1482,63 +1232,132 @@ void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data) } } +BOOL LLViewerWindow::handleTimerEvent(LLWindow *window) +{ + 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; +} + +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( - char* title, char* name, + const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, - BOOL fullscreen, BOOL ignore_pixel_depth) + BOOL fullscreen, BOOL ignore_pixel_depth) // fullscreen is no longer used : + mWindow(NULL), mActive(TRUE), - mWantFullscreen(fullscreen), - mShowFullscreenProgress(FALSE), - mWindowRect(0, height, width, 0), - mVirtualWindowRect(0, height, width, 0), + mWindowRectRaw(0, height, width, 0), + mWindowRectScaled(0, height, width, 0), + mWorldViewRectRaw(0, height, width, 0), mLeftMouseDown(FALSE), + mMiddleMouseDown(FALSE), mRightMouseDown(FALSE), - mToolTip(NULL), - mToolTipBlocked(FALSE), mMouseInWindow( FALSE ), mLastMask( MASK_NONE ), mToolStored( NULL ), - mSuppressToolbox( FALSE ), mHideCursorPermanent( FALSE ), - mPickPending(FALSE), - mIgnoreActivate( FALSE ) + mCursorHidden(FALSE), + mIgnoreActivate( FALSE ), + mResDirty(false), + mStatesDirty(false), + mCurrResolutionIndex(0), + mViewerWindowListener(new LLViewerWindowListener(this)), + mProgressView(NULL) { - // Default to application directory. - strcpy(LLViewerWindow::sSnapshotBaseName, "Snapshot"); /* Flawfinder: ignore */ - strcpy(LLViewerWindow::sMovieBaseName, "SLmovie"); /* Flawfinder: ignore */ - LLViewerWindow::sSnapshotDir[0] = '\0'; + LLNotificationChannel::buildChannel("VW_alerts", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alert")); + LLNotificationChannel::buildChannel("VW_alertmodal", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alertmodal")); + + LLNotifications::instance().getChannel("VW_alerts")->connectChanged(&LLViewerWindow::onAlert); + LLNotifications::instance().getChannel("VW_alertmodal")->connectChanged(&LLViewerWindow::onAlert); + LLNotifications::instance().setIgnoreAllNotifications(gSavedSettings.getBOOL("IgnoreAllNotifications")); + llinfos << "NOTE: ALL NOTIFICATIONS THAT OCCUR WILL GET ADDED TO IGNORE LIST FOR LATER RUNS." << llendl; + // Default to application directory. + LLViewerWindow::sSnapshotBaseName = "Snapshot"; + LLViewerWindow::sMovieBaseName = "SLmovie"; + resetSnapshotLoc(); // create window - mWindow = LLWindowManager::createWindow( + mWindow = LLWindowManager::createWindow(this, title, name, x, y, width, height, 0, fullscreen, gNoRender, gSavedSettings.getBOOL("DisableVerticalSync"), !gNoRender, - ignore_pixel_depth); -#if LL_WINDOWS - if (!LLWinDebug::setupExceptionHandler()) + ignore_pixel_depth, + 0); //gSavedSettings.getU32("RenderFSAASamples")); + + if (!LLAppViewer::instance()->restoreErrorTrap()) { - llwarns << " Someone took over my exception handler (post createWindow)!" << llendl; + LL_WARNS("Window") << " Someone took over my signal/exception handler (post createWindow)!" << LL_ENDL; } -#endif + if (NULL == mWindow) { - LLSplashScreen::update("Shutting down..."); + LLSplashScreen::update(LLTrans::getString("ShuttingDown")); #if LL_LINUX || LL_SOLARIS llwarns << "Unable to create window, be sure screen is set at 32-bit color and your graphics driver is configured correctly. See README-linux.txt or README-solaris.txt for further information." << llendl; #else - llwarns << "Unable to create window, be sure screen is set at 32-bit color in Control Panels->Display->Settings" - << llendl; + 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()->forceExit(1); } @@ -1554,8 +1373,8 @@ LLViewerWindow::LLViewerWindow( { LLCoordWindow size; mWindow->getSize(&size); - mWindowRect.set(0, size.mY, size.mX, 0); - mVirtualWindowRect.set(0, llround((F32)size.mY / mDisplayScale.mV[VY]), llround((F32)size.mX / mDisplayScale.mV[VX]), 0); + mWindowRectRaw.set(0, size.mY, size.mX, 0); + mWindowRectScaled.set(0, llround((F32)size.mY / mDisplayScale.mV[VY]), llround((F32)size.mX / mDisplayScale.mV[VX]), 0); } LLFontManager::initClass(); @@ -1564,23 +1383,24 @@ LLViewerWindow::LLViewerWindow( // 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. // - llinfos << "Loading feature tables." << llendl; + LL_DEBUGS("Window") << "Loading feature tables." << LL_ENDL; - gFeatureManagerp->init(); + LLFeatureManager::getInstance()->init(); // Initialize OpenGL Renderer - if (!gFeatureManagerp->isFeatureAvailable("RenderVBOEnable") || + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderVBOEnable") || !gGLManager.mHasVertexBufferObject) { gSavedSettings.setBOOL("RenderVBOEnable", FALSE); } LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable")); - if (gFeatureManagerp->isSafe() - || (gSavedSettings.getS32("LastFeatureVersion") != gFeatureManagerp->getVersion()) + if (LLFeatureManager::getInstance()->isSafe() + || (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion()) + || (gSavedSettings.getS32("LastGPUClass") != LLFeatureManager::getInstance()->getGPUClass()) || (gSavedSettings.getBOOL("ProbeHardwareOnStartup"))) { - gFeatureManagerp->applyRecommendedSettings(); + LLFeatureManager::getInstance()->applyRecommendedSettings(); gSavedSettings.setBOOL("ProbeHardwareOnStartup", FALSE); } @@ -1588,55 +1408,55 @@ LLViewerWindow::LLViewerWindow( if (gSavedSettings.getBOOL("RenderInitError")) { mInitAlert = "DisplaySettingsNoShaders"; - gFeatureManagerp->setGraphicsLevel(0, false); + LLFeatureManager::getInstance()->setGraphicsLevel(0, false); gSavedSettings.setU32("RenderQualityPerformance", 0); - } - // set callbacks - mWindow->setCallbacks(this); - // Init the image list. Must happen after GL is initialized and before the images that // LLViewerWindow needs are requested. - gImageList.init(); - LLViewerImage::initClass(); + LLImageGL::initClass(LLViewerTexture::MAX_GL_IMAGE_CATEGORY) ; + gTextureList.init(); + LLViewerTextureManager::init() ; gBumpImageList.init(); - + + // Init font system, but don't actually load the fonts yet + // because our window isn't onscreen and they take several + // seconds to parse. + LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"), + mDisplayScale.mV[VX], + mDisplayScale.mV[VY], + gDirUtilp->getAppRODataDir(), + LLUI::getXUIPaths()); + // Create container for all sub-views - mRootView = new LLRootView("root", mVirtualWindowRect, FALSE); - - if (!gNoRender) - { - // Init default fonts - initFonts(); - } - - // Init Resource Manager - gResMgr = new LLResMgr(); + LLView::Params rvp; + rvp.name("root"); + rvp.rect(mWindowRectScaled); + rvp.mouse_opaque(false); + rvp.follows.flags(FOLLOWS_NONE); + mRootView = LLUICtrlFactory::create<LLRootView>(rvp); + LLUI::setRootView(mRootView); // Make avatar head look forward at start - mCurrentMousePoint.mX = getWindowWidth() / 2; - mCurrentMousePoint.mY = getWindowHeight() / 2; - - mPickBuffer = new U8[PICK_DIAMETER * PICK_DIAMETER * 4]; + 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. - LLString::replaceChar(mOverlayTitle, '_', ' '); - - LLAlertDialog::setDisplayCallback(alertCallback); // call this before calling any modal dialogs + LLStringUtil::replaceChar(mOverlayTitle, '_', ' '); // sync the keyboard's setting with the saved setting gSavedSettings.getControl("NumpadControl")->firePropertyChanged(); mDebugText = new LLDebugText(this); + mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale); } void LLViewerWindow::initGLDefaults() { - gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gGL.setSceneBlendType(LLRender::BT_ALPHA); glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ); F32 ambient[4] = {0.f,0.f,0.f,0.f }; @@ -1647,14 +1467,14 @@ void LLViewerWindow::initGLDefaults() glPixelStorei(GL_PACK_ALIGNMENT,1); glPixelStorei(GL_UNPACK_ALIGNMENT,1); - glEnable(GL_TEXTURE_2D); + gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); // lights for objects glShadeModel( GL_SMOOTH ); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); glCullFace(GL_BACK); @@ -1665,15 +1485,17 @@ void LLViewerWindow::initGLDefaults() gCylinder.prerender(); } +struct MainPanel : public LLPanel +{ +}; + void LLViewerWindow::initBase() { - S32 height = getWindowHeight(); - S32 width = getWindowWidth(); + S32 height = getWindowHeightScaled(); + S32 width = getWindowWidthScaled(); LLRect full_window(0, height, width, 0); - adjustRectanglesForFirstUse(full_window); - //////////////////// // // Set the gamma @@ -1682,7 +1504,7 @@ void LLViewerWindow::initBase() F32 gamma = gSavedSettings.getF32("RenderGamma"); if (gamma != 0.0f) { - gViewerWindow->getWindow()->setGamma(gamma); + getWindow()->setGamma(gamma); } // Create global views @@ -1690,313 +1512,225 @@ void LLViewerWindow::initBase() // 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(); + main_view->buildFromFile("main_view.xml"); + 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(); + mNonSideTrayView = main_view->getChildView("non_side_tray_view")->getHandle(); + mFloaterViewHolder = main_view->getChildView("floater_view_holder")->getHandle(); + mPopupView = main_view->findChild<LLPopupView>("popup_holder"); + mHintHolder = main_view->getChild<LLView>("hint_holder")->getHandle(); // Constrain floaters to inside the menu and status bar regions. - LLRect floater_view_rect = full_window; - // make space for menu bar if we have one - floater_view_rect.mTop -= MENU_BAR_HEIGHT; - floater_view_rect.mBottom += STATUS_BAR_HEIGHT + 12 + 16 + 2; - - // Check for non-first startup - S32 floater_view_bottom = gSavedSettings.getS32("FloaterViewBottom"); - if (floater_view_bottom >= 0) - { - floater_view_rect.mBottom = floater_view_bottom; - } - gFloaterView = new LLFloaterView("Floater View", floater_view_rect ); - gFloaterView->setVisible(TRUE); - - gSnapshotFloaterView = new LLSnapshotFloaterView("Snapshot Floater View", full_window); - gSnapshotFloaterView->setVisible(TRUE); + gFloaterView = main_view->getChild<LLFloaterView>("Floater View"); + gSnapshotFloaterView = main_view->getChild<LLSnapshotFloaterView>("Snapshot Floater View"); + // Console llassert( !gConsole ); - LLRect console_rect = full_window; - console_rect.mTop -= 24; - console_rect.mBottom += STATUS_BAR_HEIGHT + 12 + 16 + 12; - console_rect.mLeft += 24; //gSavedSettings.getS32("StatusBarButtonWidth") + gSavedSettings.getS32("StatusBarPad"); - - if (gSavedSettings.getBOOL("ChatFullWidth")) + 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 + LLError::addRecorder(RecordToChatConsole::getInstance()); +#else + if(gSavedSettings.getBOOL("QAMode")) { - console_rect.mRight -= 10; + LLError::addRecorder(RecordToChatConsole::getInstance()); } - else - { - // Make console rect somewhat narrow so having inventory open is - // less of a problem. - console_rect.mRight = console_rect.mLeft + 2 * width / 3; - } - - gConsole = new LLConsole( - "console", - gSavedSettings.getS32("ConsoleBufferSize"), - console_rect, - gSavedSettings.getS32("ChatFontSize"), - gSavedSettings.getF32("ChatPersistTime") ); - gConsole->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM); - mRootView->addChild(gConsole); - - // Debug view over the console - gDebugView = new LLDebugView("gDebugView", full_window); - gDebugView->setFollowsAll(); - gDebugView->setVisible(TRUE); - mRootView->addChild(gDebugView); - - // Add floater view at the end so it will be on top, and give it tab priority over others - mRootView->addChild(gFloaterView, -1); - mRootView->addChild(gSnapshotFloaterView); - - // notify above floaters! - LLRect notify_rect = full_window; - //notify_rect.mTop -= 24; - notify_rect.mBottom += STATUS_BAR_HEIGHT; - gNotifyBoxView = new LLNotifyBoxView("notify_container", notify_rect, FALSE, FOLLOWS_ALL); - mRootView->addChild(gNotifyBoxView, -2); - - // Tooltips go above floaters - mToolTip = new LLTextBox( "tool tip", LLRect(0, 1, 1, 0 ) ); - mToolTip->setHPad( 4 ); - mToolTip->setVPad( 2 ); - mToolTip->setColor( gColors.getColor( "ToolTipTextColor" ) ); - mToolTip->setBorderColor( gColors.getColor( "ToolTipBorderColor" ) ); - mToolTip->setBorderVisible( FALSE ); - mToolTip->setBackgroundColor( gColors.getColor( "ToolTipBgColor" ) ); - mToolTip->setBackgroundVisible( TRUE ); - mToolTip->setFontStyle(LLFontGL::NORMAL); - mToolTip->setBorderDropshadowVisible( TRUE ); - mToolTip->setVisible( FALSE ); +#endif + + gDebugView = getRootView()->getChild<LLDebugView>("DebugView"); + gDebugView->init(); + gToolTipView = getRootView()->getChild<LLToolTipView>("tooltip view"); + + // Initialize busy response message when logged in + LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLFloaterPreference::initBusyResponse)); // Add the progress bar view (startup view), which overrides everything - mProgressView = new LLProgressView("ProgressView", full_window); - mRootView->addChild(mProgressView); + mProgressView = getRootView()->findChild<LLProgressView>("progress_view"); setShowProgress(FALSE); - setProgressCancelButtonVisible(FALSE, ""); -} + setProgressCancelButtonVisible(FALSE); + gMenuHolder = getRootView()->getChild<LLViewerMenuHolderGL>("Menu Holder"); -void adjust_rect_top_left(const LLString& control, const LLRect& window) -{ - LLRect r = gSavedSettings.getRect(control); - if (r.mLeft == 0 && r.mBottom == 0) - { - r.setLeftTopAndSize(0, window.getHeight(), r.getWidth(), r.getHeight()); - gSavedSettings.setRect(control, r); - } -} - -void adjust_rect_top_right(const LLString& control, const LLRect& window) -{ - LLRect r = gSavedSettings.getRect(control); - if (r.mLeft == 0 && r.mBottom == 0) - { - r.setLeftTopAndSize(window.getWidth() - r.getWidth(), - window.getHeight(), - r.getWidth(), - r.getHeight()); - gSavedSettings.setRect(control, r); - } -} + LLMenuGL::sMenuContainer = gMenuHolder; -void adjust_rect_bottom_center(const LLString& control, const LLRect& window) -{ - LLRect r = gSavedSettings.getRect(control); - if (r.mLeft == 0 && r.mBottom == 0) - { - // *TODO: Adjust based on XUI XML - const S32 TOOLBAR_HEIGHT = 64; - r.setOriginAndSize( - window.getWidth()/2 - r.getWidth()/2, - TOOLBAR_HEIGHT, - r.getWidth(), - r.getHeight()); - gSavedSettings.setRect(control, r); - } } -void adjust_rect_centered_partial_zoom(const LLString& control, - const LLRect& window) -{ - LLRect rect = gSavedSettings.getRect(control); - // Only adjust on first use - if (rect.mLeft == 0 && rect.mBottom == 0) - { - S32 width = window.getWidth(); - S32 height = window.getHeight(); - rect.set(0, height-STATUS_BAR_HEIGHT, width, TOOL_BAR_HEIGHT); - // Make floater fill 80% of window, leaving 20% padding on - // the sides. - const F32 ZOOM_FRACTION = 0.8f; - S32 dx = (S32)(width * (1.f - ZOOM_FRACTION)); - S32 dy = (S32)(height * (1.f - ZOOM_FRACTION)); - rect.stretch(-dx/2, -dy/2); - gSavedSettings.setRect(control, rect); - } -} - - -// Many rectangles can't be placed until we know the screen size. -// These rectangles have their bottom-left corner as 0,0 -void LLViewerWindow::adjustRectanglesForFirstUse(const LLRect& window) +void LLViewerWindow::initWorldUI() { - LLRect r; - - adjust_rect_bottom_center("FloaterMoveRect2", window); - - adjust_rect_bottom_center("FloaterCameraRect2", window); + S32 height = mRootView->getRect().getHeight(); + S32 width = mRootView->getRect().getWidth(); + LLRect full_window(0, height, width, 0); - adjust_rect_top_left("FloaterCustomizeAppearanceRect", window); - adjust_rect_top_left("FloaterLandRect5", window); + gIMMgr = LLIMMgr::getInstance(); - adjust_rect_top_left("FloaterHUDRect", window); + //getRootView()->sendChildToFront(gFloaterView); + //getRootView()->sendChildToFront(gSnapshotFloaterView); - adjust_rect_top_left("FloaterFindRect2", window); + // new bottom panel + LLPanel* bottom_tray_container = getRootView()->getChild<LLPanel>("bottom_tray_container"); + LLBottomTray* bottom_tray = LLBottomTray::getInstance(); + bottom_tray->setShape(bottom_tray_container->getLocalRect()); + bottom_tray->setFollowsAll(); + bottom_tray_container->addChild(bottom_tray); + bottom_tray_container->setVisible(TRUE); - adjust_rect_top_left("FloaterGestureRect2", window); + 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); - adjust_rect_top_right("FloaterMiniMapRect", window); + LLWorldMapView::initClass(); - adjust_rect_top_right("FloaterLagMeter", window); - - adjust_rect_top_left("FloaterBuildOptionsRect", window); + // Force gFloaterWorldMap to initialize + LLFloaterReg::getInstance("world_map"); + + // Force gFloaterTools to initialize + LLFloaterReg::getInstance("build"); + LLFloaterReg::hideInstance("build"); + + // Status bar + LLPanel* status_bar_container = getRootView()->getChild<LLPanel>("status_bar_container"); + gStatusBar = new LLStatusBar(status_bar_container->getLocalRect()); + gStatusBar->setFollowsAll(); + gStatusBar->setShape(status_bar_container->getLocalRect()); + // sync bg color with menu bar + gStatusBar->setBackgroundColor( gMenuBarView->getBackgroundColor().get() ); + status_bar_container->addChild(gStatusBar); + status_bar_container->setVisible(TRUE); + + // Navigation bar + LLPanel* nav_bar_container = getRootView()->getChild<LLPanel>("nav_bar_container"); + + LLNavigationBar* navbar = LLNavigationBar::getInstance(); + navbar->setShape(nav_bar_container->getLocalRect()); + navbar->setBackgroundColor(gMenuBarView->getBackgroundColor().get()); + nav_bar_container->addChild(navbar); + nav_bar_container->setVisible(TRUE); + + if (!gSavedSettings.getBOOL("ShowNavbarNavigationPanel")) + { + navbar->showNavigationPanel(FALSE); + } - // bottom-right - r = gSavedSettings.getRect("FloaterInventoryRect"); - if (r.mLeft == 0 && r.mBottom == 0) + if (!gSavedSettings.getBOOL("ShowNavbarFavoritesPanel")) { - r.setOriginAndSize( - window.getWidth() - r.getWidth(), - 0, - r.getWidth(), - r.getHeight()); - gSavedSettings.setRect("FloaterInventoryRect", r); + navbar->showFavoritesPanel(FALSE); } -} + // Top Info bar + LLPanel* topinfo_bar_container = getRootView()->getChild<LLPanel>("topinfo_bar_container"); + LLPanelTopInfoBar* topinfo_bar = LLPanelTopInfoBar::getInstance(); -void LLViewerWindow::initWorldUI() -{ - pre_init_menus(); + topinfo_bar->setShape(topinfo_bar_container->getLocalRect()); - S32 height = mRootView->getRect().getHeight(); - S32 width = mRootView->getRect().getWidth(); - LLRect full_window(0, height, width, 0); + topinfo_bar_container->addChild(topinfo_bar); + topinfo_bar_container->setVisible(TRUE); - if ( gBottomPanel == NULL ) // Don't re-enter if objects are alreay created + if (!gSavedSettings.getBOOL("ShowMiniLocationPanel")) { - // panel containing chatbar, toolbar, and overlay, over floaters - gBottomPanel = new LLBottomPanel(mRootView->getRect()); - mRootView->addChild(gBottomPanel); - - // View for hover information - gHoverView = new LLHoverView("gHoverView", full_window); - gHoverView->setVisible(TRUE); - mRootView->addChild(gHoverView); - - // - // Map - // - // TODO: Move instance management into class - gFloaterMap = new LLFloaterMap("Map"); - gFloaterMap->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT); - - // keep onscreen - gFloaterView->adjustToFitScreen(gFloaterMap, FALSE); - - gIMMgr = LLIMMgr::getInstance(); + topinfo_bar->setVisible(FALSE); + } - if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) + if ( gHUDView == NULL ) + { + LLRect hud_rect = full_window; + hud_rect.mBottom += 50; + if (gMenuBarView) { - LLFloaterChat::getInstance(LLSD())->loadHistory(); + hud_rect.mTop -= gMenuBarView->getRect().getHeight(); } + gHUDView = new LLHUDView(hud_rect); + // put behind everything else in the UI + getRootView()->addChildInBack(gHUDView); + } - LLRect morph_view_rect = full_window; - morph_view_rect.stretch( -STATUS_BAR_HEIGHT ); - morph_view_rect.mTop = full_window.mTop - 32; - gMorphView = new LLMorphView("gMorphView", morph_view_rect ); - mRootView->addChild(gMorphView); - gMorphView->setVisible(FALSE); - - gFloaterMute = LLFloaterMute::getInstance(); - - LLWorldMapView::initClass(); - - adjust_rect_centered_partial_zoom("FloaterWorldMapRect2", full_window); - - gFloaterWorldMap = new LLFloaterWorldMap(); - gFloaterWorldMap->setVisible(FALSE); - - // - // Tools for building - // - - // Toolbox floater - init_menus(); - - gFloaterTools = new LLFloaterTools(); - gFloaterTools->setVisible(FALSE); - - // Status bar - S32 menu_bar_height = gMenuBarView->getRect().getHeight(); - LLRect root_rect = gViewerWindow->getRootView()->getRect(); - LLRect status_rect(0, root_rect.getHeight(), root_rect.getWidth(), root_rect.getHeight() - menu_bar_height); - gStatusBar = new LLStatusBar("status", status_rect); - gStatusBar->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP); - - gStatusBar->reshape(root_rect.getWidth(), gStatusBar->getRect().getHeight(), TRUE); - gStatusBar->translate(0, root_rect.getHeight() - gStatusBar->getRect().getHeight()); - // sync bg color with menu bar - gStatusBar->setBackgroundColor( gMenuBarView->getBackgroundColor() ); - - LLFloaterChatterBox::createInstance(LLSD()); - - gViewerWindow->getRootView()->addChild(gStatusBar); + LLPanel* panel_ssf_container = getRootView()->getChild<LLPanel>("stand_stop_flying_container"); + LLPanelStandStopFlying* panel_stand_stop_flying = LLPanelStandStopFlying::getInstance(); + panel_ssf_container->addChild(panel_stand_stop_flying); + panel_ssf_container->setVisible(TRUE); - // menu holder appears on top to get first pass at all mouse events - gViewerWindow->getRootView()->sendChildToFront(gMenuHolder); - } + // put sidetray in container + LLPanel* side_tray_container = getRootView()->getChild<LLPanel>("side_tray_container"); + LLSideTray* sidetrayp = LLSideTray::getInstance(); + sidetrayp->setShape(side_tray_container->getLocalRect()); + // don't follow right edge to avoid spurious resizes, since we are using a fixed width layout + sidetrayp->setFollows(FOLLOWS_LEFT|FOLLOWS_TOP|FOLLOWS_BOTTOM); + side_tray_container->addChild(sidetrayp); + side_tray_container->setVisible(FALSE); + + // put sidetray buttons in their own panel + LLPanel* buttons_panel = sidetrayp->getButtonsPanel(); + LLPanel* buttons_panel_container = getRootView()->getChild<LLPanel>("side_bar_tabs"); + buttons_panel->setShape(buttons_panel_container->getLocalRect()); + buttons_panel->setFollowsAll(); + buttons_panel_container->addChild(buttons_panel); } - -LLViewerWindow::~LLViewerWindow() +// Destroy the UI +void LLViewerWindow::shutdownViews() { + // clean up warning logger + LLError::removeRecorder(RecordToChatConsole::getInstance()); + delete mDebugText; + mDebugText = NULL; - gSavedSettings.setS32("FloaterViewBottom", gFloaterView->getRect().mBottom); - // Cleanup global views if (gMorphView) { gMorphView->setVisible(FALSE); } + + // DEV-40930: Clear sModalStack. Otherwise, any LLModalDialog left open + // will crump with LL_ERRS. + LLModalDialog::shutdownModals(); + // destroy the nav bar, not currently part of gViewerWindow + // *TODO: Make LLNavigationBar part of gViewerWindow + delete LLNavigationBar::getInstance(); + + // destroy menus after instantiating navbar above, as it needs + // access to gMenuHolder + cleanup_menus(); + // Delete all child views. delete mRootView; mRootView = NULL; // Automatically deleted as children of mRootView. Fix the globals. - gFloaterTools = NULL; gStatusBar = NULL; - gFloaterCamera = NULL; gIMMgr = NULL; - gHoverView = NULL; - - gFloaterView = NULL; - gMorphView = NULL; + gToolTipView = NULL; - gFloaterMute = NULL; + gFloaterView = NULL; + gMorphView = NULL; - gFloaterMap = NULL; gHUDView = NULL; +} - gNotifyBoxView = NULL; - - delete mToolTip; - mToolTip = NULL; - - delete gResMgr; - gResMgr = NULL; - +void LLViewerWindow::shutdownGL() +{ //-------------------------------------------------------- // Shutdown GL cleanly. Order is very important here. //-------------------------------------------------------- @@ -2007,7 +1741,9 @@ LLViewerWindow::~LLViewerWindow() gSky.cleanup(); stop_glerror(); - gImageList.shutdown(); + LLWearableList::instance().cleanup() ; + + gTextureList.shutdown(); stop_glerror(); gBumpImageList.shutdown(); @@ -2019,16 +1755,13 @@ LLViewerWindow::~LLViewerWindow() gPipeline.cleanup(); stop_glerror(); - LLViewerImage::cleanupClass(); - - delete[] mPickBuffer; - mPickBuffer = NULL; + LLViewerTextureManager::cleanup() ; + LLImageGL::cleanupClass() ; - if (gSelectMgr) - { - llinfos << "Cleaning up select manager" << llendl; - gSelectMgr->cleanup(); - } + llinfos << "All textures and llimagegl images are destroyed!" << llendl ; + + llinfos << "Cleaning up select manager" << llendl; + LLSelectMgr::getInstance()->cleanup(); LLVertexBuffer::cleanupClass(); @@ -2039,9 +1772,17 @@ LLViewerWindow::~LLViewerWindow() stop_glerror(); } + gGL.shutdown(); +} +// shutdownViews() and shutdownGL() need to be called first +LLViewerWindow::~LLViewerWindow() +{ llinfos << "Destroying Window" << llendl; destroyWindow(); + + delete mDebugText; + mDebugText = NULL; } @@ -2053,18 +1794,16 @@ void LLViewerWindow::setCursor( ECursorType c ) void LLViewerWindow::showCursor() { mWindow->showCursor(); + + mCursorHidden = FALSE; } void LLViewerWindow::hideCursor() { - // Hide tooltips - if(mToolTip ) mToolTip->setVisible( FALSE ); - - // Also hide hover info - if (gHoverView) gHoverView->cancelHover(); - // And hide the cursor mWindow->hideCursor(); + + mCursorHidden = TRUE; } void LLViewerWindow::sendShapeToSim() @@ -2078,8 +1817,8 @@ void LLViewerWindow::sendShapeToSim() msg->addU32Fast(_PREHASH_CircuitCode, gMessageSystem->mOurCircuitCode); msg->nextBlockFast(_PREHASH_HeightWidthBlock); msg->addU32Fast(_PREHASH_GenCounter, 0); - U16 height16 = (U16) mWindowRect.getHeight(); - U16 width16 = (U16) mWindowRect.getWidth(); + U16 height16 = (U16) mWorldViewRectRaw.getHeight(); + U16 width16 = (U16) mWorldViewRectRaw.getWidth(); msg->addU16Fast(_PREHASH_Height, height16); msg->addU16Fast(_PREHASH_Width, width16); gAgent.sendReliableMessage(); @@ -2100,35 +1839,28 @@ void LLViewerWindow::reshape(S32 width, S32 height) return; } - glViewport(0, 0, width, height ); + // update our window rectangle + mWindowRectRaw.mRight = mWindowRectRaw.mLeft + width; + mWindowRectRaw.mTop = mWindowRectRaw.mBottom + height; + + //glViewport(0, 0, width, height ); - if (height > 0 && gCamera) + if (height > 0) { - gCamera->setViewHeightInPixels( height ); - if (mWindow->getFullscreen()) - { - // force to 4:3 aspect for odd resolutions - gCamera->setAspect( getDisplayAspectRatio() ); - } - else - { - gCamera->setAspect( width / (F32) height); - } + LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() ); + LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() ); } - // update our window rectangle - mWindowRect.mRight = mWindowRect.mLeft + width; - mWindowRect.mTop = mWindowRect.mBottom + height; calcDisplayScale(); BOOL display_scale_changed = mDisplayScale != LLUI::sGLScaleFactor; LLUI::setScaleFactor(mDisplayScale); // update our window rectangle - mVirtualWindowRect.mRight = mVirtualWindowRect.mLeft + llround((F32)width / mDisplayScale.mV[VX]); - mVirtualWindowRect.mTop = mVirtualWindowRect.mBottom + llround((F32)height / mDisplayScale.mV[VY]); + mWindowRectScaled.mRight = mWindowRectScaled.mLeft + llround((F32)width / mDisplayScale.mV[VX]); + mWindowRectScaled.mTop = mWindowRectScaled.mBottom + llround((F32)height / mDisplayScale.mV[VY]); - setupViewport(); + setup2DViewport(); // Inform lower views of the change // round up when converting coordinates to make sure there are no gaps at edge of window @@ -2139,39 +1871,26 @@ void LLViewerWindow::reshape(S32 width, S32 height) // clear font width caches if (display_scale_changed) { - LLHUDText::reshape(); + LLHUDObject::reshapeAll(); } sendShapeToSim(); - - // store the mode the user wants (even if not there yet) - gSavedSettings.setBOOL("FullScreen", mWantFullscreen); - // store new settings for the mode we are in, regardless - if (mWindow->getFullscreen()) - { - gSavedSettings.setS32("FullScreenWidth", width); - gSavedSettings.setS32("FullScreenHeight", height); - } - else - { - // Only save size if not maximized - BOOL maximized = mWindow->getMaximized(); - gSavedSettings.setBOOL("WindowMaximized", maximized); + // Only save size if not maximized + BOOL maximized = mWindow->getMaximized(); + gSavedSettings.setBOOL("WindowMaximized", maximized); - LLCoordScreen window_size; - if (!maximized - && mWindow->getSize(&window_size)) - { - gSavedSettings.setS32("WindowWidth", window_size.mX); - gSavedSettings.setS32("WindowHeight", window_size.mY); - } + LLCoordScreen window_size; + if (!maximized + && mWindow->getSize(&window_size)) + { + gSavedSettings.setS32("WindowWidth", window_size.mX); + gSavedSettings.setS32("WindowHeight", window_size.mY); } - gViewerStats->setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width); - gViewerStats->setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height); - gResizeScreenTexture = TRUE; + LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width); + LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height); } } @@ -2179,10 +1898,10 @@ void LLViewerWindow::reshape(S32 width, S32 height) // Hide normal UI when a logon fails void LLViewerWindow::setNormalControlsVisible( BOOL visible ) { - if ( gBottomPanel ) + if(LLBottomTray::instanceExists()) { - gBottomPanel->setVisible( visible ); - gBottomPanel->setEnabled( visible ); + LLBottomTray::getInstance()->setVisible(visible); + LLBottomTray::getInstance()->setEnabled(visible); } if ( gMenuBarView ) @@ -2192,7 +1911,7 @@ void LLViewerWindow::setNormalControlsVisible( BOOL visible ) // ...and set the menu color appropriately. setMenuBackgroundColor(gAgent.getGodLevel() > GOD_NOT, - LLAppViewer::instance()->isInProductionGrid()); + LLGridManager::getInstance()->isInProductionGrid()); } if ( gStatusBar ) @@ -2200,28 +1919,43 @@ void LLViewerWindow::setNormalControlsVisible( BOOL visible ) gStatusBar->setVisible( visible ); gStatusBar->setEnabled( visible ); } + + LLNavigationBar* navbarp = LLUI::getRootView()->findChild<LLNavigationBar>("navigation_bar"); + if (navbarp) + { + navbarp->setVisible( visible ); + } } void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid) { - LLString::format_map_t args; + LLSD args; LLColor4 new_bg_color; - if(god_mode && LLAppViewer::instance()->isInProductionGrid()) + // no l10n problem because channel is always an english string + std::string channel = LLVersionInfo::getChannel(); + bool isProject = (channel.find("Project") != std::string::npos); + + // god more important than project, proj more important than grid + if(god_mode && LLGridManager::getInstance()->isInProductionGrid()) { - new_bg_color = gColors.getColor( "MenuBarGodBgColor" ); + new_bg_color = LLUIColorTable::instance().getColor( "MenuBarGodBgColor" ); } - else if(god_mode && !LLAppViewer::instance()->isInProductionGrid()) + else if(god_mode && !LLGridManager::getInstance()->isInProductionGrid()) { - new_bg_color = gColors.getColor( "MenuNonProductionGodBgColor" ); + new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionGodBgColor" ); } - else if(!god_mode && !LLAppViewer::instance()->isInProductionGrid()) + else if (!god_mode && isProject) + { + new_bg_color = LLUIColorTable::instance().getColor( "MenuBarProjectBgColor" ); + } + else if(!god_mode && !LLGridManager::getInstance()->isInProductionGrid()) { - new_bg_color = gColors.getColor( "MenuNonProductionBgColor" ); + new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" ); } else { - new_bg_color = gColors.getColor( "MenuBarBgColor" ); + new_bg_color = LLUIColorTable::instance().getColor( "MenuBarBgColor" ); } if(gMenuBarView) @@ -2237,32 +1971,29 @@ void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid) void LLViewerWindow::drawDebugText() { - gGL.start(); + gGL.color4f(1,1,1,1); gGL.pushMatrix(); + gGL.pushUIMatrix(); { // scale view by UI global scale factor and aspect ratio correction factor - glScalef(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f); + gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f); mDebugText->draw(); } + gGL.popUIMatrix(); gGL.popMatrix(); - gGL.stop(); + + gGL.flush(); } void LLViewerWindow::draw() { -#if LL_DEBUG +//#if LL_DEBUG LLView::sIsDrawing = TRUE; -#endif +//#endif stop_glerror(); LLUI::setLineWidth(1.f); - //popup alerts from the UI - LLAlertInfo alert; - while (LLPanel::nextAlert(alert)) - { - alertXml(alert.mLabel, alert.mArgs); - } LLUI::setLineWidth(1.f); // Reset any left-over transforms @@ -2272,19 +2003,24 @@ void LLViewerWindow::draw() //S32 screen_x, screen_y; + if (!gSavedSettings.getBOOL("RenderUIBuffer")) + { + LLUI::sDirtyRect = getWindowRectScaled(); + } + // HACK for timecode debugging if (gSavedSettings.getBOOL("DisplayTimecode")) { // draw timecode block - char text[256]; /* Flawfinder: ignore */ + std::string text; glLoadIdentity(); microsecondsToTimecodeString(gFrameTime,text); - const LLFontGL* font = gResMgr->getRes( LLFONT_SANSSERIF ); + const LLFontGL* font = LLFontGL::getFontSansSerif(); font->renderUTF8(text, 0, - llround((getWindowWidth()/2)-100.f), - llround((getWindowHeight()-60.f)), + llround((getWindowWidthScaled()/2)-100.f), + llround((getWindowHeightScaled()-60.f)), LLColor4( 1.f, 1.f, 1.f, 1.f ), LLFontGL::LEFT, LLFontGL::TOP); } @@ -2293,37 +2029,33 @@ void LLViewerWindow::draw() // No translation needed, this view is glued to 0,0 gGL.pushMatrix(); + LLUI::pushMatrix(); { + // scale view by UI global scale factor and aspect ratio correction factor - glScalef(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f); + gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f); LLVector2 old_scale_factor = LLUI::sGLScaleFactor; - if (gCamera) + // 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) { - // apply camera zoom transform (for high res screenshots) - F32 zoom_factor = gCamera->getZoomFactor(); - S16 sub_region = gCamera->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 - glTranslatef((F32)gViewerWindow->getWindowWidth() * -(F32)pos_x, - (F32)gViewerWindow->getWindowHeight() * -(F32)pos_y, - 0.f); - glScalef(zoom_factor, zoom_factor, 1.f); - LLUI::sGLScaleFactor *= zoom_factor; - } + //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 + glTranslatef((F32)getWindowWidthScaled() * -(F32)pos_x, + (F32)getWindowHeightScaled() * -(F32)pos_y, + 0.f); + glScalef(zoom_factor, zoom_factor, 1.f); + LLUI::sGLScaleFactor *= zoom_factor; } - if (gToolMgr) - { - // Draw tool specific overlay on world - gToolMgr->getCurrentTool()->draw(); - } + // Draw tool specific overlay on world + LLToolMgr::getInstance()->getCurrentTool()->draw(); - if( gAgent.cameraMouselook() ) + if( gAgentCamera.cameraMouselook() || LLFloaterCamera::inFreeCameraMode() ) { drawMouselookInstructions(); stop_glerror(); @@ -2333,6 +2065,11 @@ void LLViewerWindow::draw() // 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()) @@ -2347,192 +2084,134 @@ void LLViewerWindow::draw() LLUI::popMatrix(); } - // Draw tooltips - // Adjust their rectangle so they don't go off the top or bottom - // of the screen. - if( mToolTip && mToolTip->getVisible() ) - { - glMatrixMode(GL_MODELVIEW); - LLUI::pushMatrix(); - { - S32 tip_height = mToolTip->getRect().getHeight(); - - S32 screen_x, screen_y; - mToolTip->localPointToScreen(0, -24 - tip_height, - &screen_x, &screen_y); - - // If tooltip would draw off the bottom of the screen, - // show it from the cursor tip position. - if (screen_y < tip_height) - { - mToolTip->localPointToScreen(0, 0, &screen_x, &screen_y); - } - LLUI::translate( (F32) screen_x, (F32) screen_y, 0); - mToolTip->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::sSansSerifBig->renderUTF8( + LLFontGL::getFontSansSerifBig()->renderUTF8( mOverlayTitle, 0, - llround( gViewerWindow->getWindowWidth() * 0.5f), - gViewerWindow->getWindowHeight() - DIST_FROM_TOP, + llround( getWindowWidthScaled() * 0.5f), + getWindowHeightScaled() - DIST_FROM_TOP, LLColor4(1, 1, 1, 0.4f), LLFontGL::HCENTER, LLFontGL::TOP); } LLUI::sGLScaleFactor = old_scale_factor; } + LLUI::popMatrix(); gGL.popMatrix(); -#if LL_DEBUG +//#if LL_DEBUG LLView::sIsDrawing = FALSE; -#endif +//#endif } // Takes a single keydown event, usually when UI is visible BOOL LLViewerWindow::handleKey(KEY key, MASK mask) { - if (gFocusMgr.getKeyboardFocus() && !(mask & (MASK_CONTROL | MASK_ALT))) + // hide tooltips on keypress + LLToolTipMgr::instance().blockToolTips(); + + if (gFocusMgr.getKeyboardFocus() + && !(mask & (MASK_CONTROL | MASK_ALT)) + && !gFocusMgr.getKeystrokesOnly()) { // We have keyboard focus, and it's not an accelerator - 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.childHasKeyboardFocus(mRootView); + return (gFocusMgr.getKeyboardFocus() != NULL); } } - // HACK look for UI editing keys - if (LLView::sEditingUI) + // 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))) { - if (LLFloaterEditUI::handleKey(key, mask)) - { - return TRUE; - } - } - - // Hide tooltips on keypress - if(mToolTip ) - { - mToolTipBlocked = TRUE; // block until next time mouse is moved - mToolTip->setVisible( FALSE ); - } - - // Also hide hover info on keypress - if (gHoverView) - { - gHoverView->cancelHover(); - - gHoverView->setTyping(TRUE); + return TRUE; } - // Explicit hack for debug menu. - if ((MASK_ALT & mask) && - (MASK_CONTROL & mask) && - ('D' == key || 'd' == key)) - { - toggle_debug_menus(NULL); - } + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); - // Explicit hack for debug menu. - if ((mask == (MASK_SHIFT | MASK_CONTROL)) && - ('G' == key || 'g' == key)) + // 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()) { - if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP) //on splash page + // Check the current floater's menu first, if it has one. + if (gFocusMgr.keyboardFocusHasAccelerators() + && keyboard_focus + && keyboard_focus->handleKey(key,mask,FALSE)) { - BOOL visible = ! gSavedSettings.getBOOL("ForceShowGrid"); - gSavedSettings.setBOOL("ForceShowGrid", visible); + return TRUE; + } - // Initialize visibility (and don't force visibility - use prefs) - LLPanelLogin::refreshLocation( false ); + if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask)) + ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask))) + { + return TRUE; } } - // Example "bug" for bug reporter web page - if ((MASK_SHIFT & mask) - && (MASK_ALT & mask) - && (MASK_CONTROL & mask) - && ('H' == key || 'h' == key)) + // 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 || gFocusMgr.getKeyboardFocus() == NULL)) { - trigger_hippo_bug(NULL); - } + if (gMenuHolder) gMenuHolder->hideMenus(); - // handle escape key - if (key == KEY_ESCAPE && mask == MASK_NONE) - { - 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) { - return TRUE; + mRootView->focusPrevRoot(); } - - //if quit from menu, turn off the Keyboardmode for the menu. - if(LLMenuGL::getKeyboardMode()) - LLMenuGL::setKeyboardMode(FALSE); - - if (gFocusMgr.getTopCtrl()) + else { - gFocusMgr.setTopCtrl(NULL); - return TRUE; + mRootView->focusNextRoot(); } - - // *TODO: get this to play well with mouselook and hidden - // cursor modes, etc, and re-enable. - //if (gFocusMgr.getMouseCapture()) - //{ - // gFocusMgr.setMouseCapture(NULL); - // return TRUE; - //} - } - - // let menus handle navigation keys - if (gMenuBarView && gMenuBarView->handleKey(key, mask, TRUE)) - { return TRUE; } - // let menus handle navigation keys - if (gLoginMenuBarView && gLoginMenuBarView->handleKey(key, mask, TRUE)) + // hidden edit menu for cut/copy/paste + if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask)) { return TRUE; } // Traverses up the hierarchy - LLUICtrl* keyboard_focus = gFocusMgr.getKeyboardFocus(); if( keyboard_focus ) { + LLLineEditor* chat_editor = LLBottomTray::instanceExists() ? LLBottomTray::getInstance()->getNearbyChatBar()->getChatBox() : NULL; // arrow keys move avatar while chatting hack - if (gChatBar && gChatBar->inputEditorHasFocus()) + if (chat_editor && chat_editor->hasFocus()) { - if (gChatBar->getCurrentChat().empty() || gSavedSettings.getBOOL("ArrowKeysMoveAvatar")) + // If text field is empty, there's no point in trying to move + // cursor with arrow keys, so allow movement + if (chat_editor->getText().empty() + || gSavedSettings.getBOOL("ArrowKeysAlwaysMove")) { - switch(key) + // let Control-Up and Control-Down through for chat line history, + if (!(key == KEY_UP && mask == MASK_CONTROL) + && !(key == KEY_DOWN && mask == MASK_CONTROL)) { - case KEY_LEFT: - case KEY_RIGHT: - case KEY_UP: - // let CTRL UP through for chat line history - if( MASK_CONTROL == mask ) - { - break; - } - case KEY_DOWN: - // let CTRL DOWN through for chat line history - if( MASK_CONTROL == mask ) + 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: + // when chatbar is empty or ArrowKeysAlwaysMove set, + // pass arrow keys on to avatar... + return FALSE; + default: break; } - case KEY_PAGE_UP: - case KEY_PAGE_DOWN: - case KEY_HOME: - // when chatbar is empty or ArrowKeysMoveAvatar set, pass arrow keys on to avatar... - return FALSE; - default: - break; } } } @@ -2543,16 +2222,13 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) } } - if (gToolMgr) + if( LLToolMgr::getInstance()->getCurrentTool()->handleKey(key, mask) ) { - if( gToolMgr->getCurrentTool()->handleKey(key, mask) ) - { - return TRUE; - } + return TRUE; } // Try for a new-format gesture - if (gGestureManager.triggerGesture(key, mask)) + if (LLGestureMgr::instance().triggerGesture(key, mask)) { return TRUE; } @@ -2564,50 +2240,10 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) return TRUE; } - // Topmost view gets a chance before the hierarchy - // *FIX: get rid of this? - LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - if (top_ctrl) - { - if( top_ctrl->handleKey( key, mask, TRUE ) ) - { - return TRUE; - } - } - - // give floaters first chance to handle TAB key - // so frontmost floater gets focus - if (key == KEY_TAB) - { - // if nothing has focus, go to first or last UI element as appropriate - if (mask & MASK_CONTROL || gFocusMgr.getKeyboardFocus() == NULL) - { - 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(); - } - return TRUE; - } - } - - // give menus a chance to handle keys - if (gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask)) - { - return TRUE; - } - - // give menus a chance to handle keys - if (gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask)) + // give menus a chance to handle unmodified accelerator keys + if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask)) + ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask))) { return TRUE; } @@ -2639,7 +2275,7 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask) } // Traverses up the hierarchy - LLView* keyboard_focus = gFocusMgr.getKeyboardFocus(); + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); if( keyboard_focus ) { if (keyboard_focus->handleUnicodeChar(uni_char, FALSE)) @@ -2647,12 +2283,12 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask) return TRUE; } - // Topmost view gets a chance before the hierarchy - LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - if (top_ctrl && top_ctrl->handleUnicodeChar( uni_char, FALSE ) ) - { - return TRUE; - } + //// Topmost view gets a chance before the hierarchy + //LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); + //if (top_ctrl && top_ctrl->handleUnicodeChar( uni_char, FALSE ) ) + //{ + // return TRUE; + //} return TRUE; } @@ -2663,16 +2299,10 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask) void LLViewerWindow::handleScrollWheel(S32 clicks) { - LLView::sMouseHandlerMessage = ""; - - gMouseIdleTimer.reset(); - - // Hide tooltips - if( mToolTip ) - { - mToolTip->setVisible( FALSE ); - } + LLView::sMouseHandlerMessage.clear(); + LLUI::resetMouseIdleTimer(); + LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); if( mouse_captor ) { @@ -2709,384 +2339,639 @@ void LLViewerWindow::handleScrollWheel(S32 clicks) llinfos << "Scroll Wheel not handled by view" << llendl; } - if (gWorldPointer) + // 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::addPopup(LLView* popup) +{ + if (mPopupView) { - // Zoom the camera in and out behavior - gAgent.handleScrollWheel(clicks); + mPopupView->addPopup(popup); } +} - return; +void LLViewerWindow::removePopup(LLView* popup) +{ + if (mPopupView) + { + mPopupView->removePopup(popup); + } +} + +void LLViewerWindow::clearPopups() +{ + if (mPopupView) + { + mPopupView->clearPopups(); + } } void LLViewerWindow::moveCursorToCenter() { - S32 x = mVirtualWindowRect.getWidth() / 2; - S32 y = mVirtualWindowRect.getHeight() / 2; + if (! gSavedSettings.getBOOL("DisableMouseWarp")) + { + S32 x = getWorldViewWidthScaled() / 2; + S32 y = getWorldViewHeightScaled() / 2; - //on a forced move, all deltas get zeroed out to prevent jumping - mCurrentMousePoint.set(x,y); - mLastMousePoint.set(x,y); - mCurrentMouseDelta.set(0,0); + //on a forced move, all deltas get zeroed out to prevent jumping + mCurrentMousePoint.set(x,y); + mLastMousePoint.set(x,y); + mCurrentMouseDelta.set(0,0); - LLUI::setCursorPositionScreen(x, y); + LLUI::setMousePositionScreen(x, y); + } } + ////////////////////////////////////////////////////////////////////// // // 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("/"); + } + } +} + // Update UI based on stored mouse position from mouse-move // event processing. -BOOL LLViewerWindow::handlePerFrameHover() +void LLViewerWindow::updateUI() { - static std::string last_handle_msg; + static LLFastTimer::DeclareTimer ftm("Update UI"); + LLFastTimer t(ftm); - LLView::sMouseHandlerMessage = ""; + static std::string last_handle_msg; - //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 > mWindowRect.getWidth() || - mouse_pos.mY > mWindowRect.getHeight()) - { - mMouseInWindow = FALSE; - } - else + if (gLoggedInTime.getStarted()) { - mMouseInWindow = TRUE; + if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("DestinationGuideHintTimeout")) + { + LLFirstUse::notUsingDestinationGuide(); + } + if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("SidePanelHintTimeout")) + { + LLFirstUse::notUsingSidePanel(); + } } - S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::sGLScaleFactor.mV[VX]); - S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::sGLScaleFactor.mV[VY]); + LLConsole::updateClass(); - LLVector2 mouse_vel; + // animate layout stacks so we have up to date rect for world view + LLLayoutStack::updateClass(); - if (gSavedSettings.getBOOL("MouseSmooth")) - { - static F32 fdx = 0.f; - static F32 fdy = 0.f; + // 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); - F32 amount = 16.f; - fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f); - fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f); + LLView::sMouseHandlerMessage.clear(); - mCurrentMouseDelta.set(llround(fdx), llround(fdy)); - mouse_vel.setVec(fdx,fdy); - } - else + S32 x = mCurrentMousePoint.mX; + S32 y = mCurrentMousePoint.mY; + MASK mask = gKeyboard->currentMask(TRUE); + + if (gNoRender) { - mCurrentMouseDelta.set(dx, dy); - mouse_vel.setVec((F32) dx, (F32) dy); + return; } - - mMouseVelocityStat.addValue(mouse_vel.magVec()); - if (gNoRender) + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) { - return TRUE; + gDebugRaycastFaceHit = -1; + gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, + &gDebugRaycastFaceHit, + &gDebugRaycastIntersection, + &gDebugRaycastTexCoord, + &gDebugRaycastNormal, + &gDebugRaycastBinormal); } - S32 x = mCurrentMousePoint.mX; - S32 y = mCurrentMousePoint.mY; - MASK mask = gKeyboard->currentMask(TRUE); + updateMouseDelta(); + updateKeyboardFocus(); - // clean up current focus - LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus(); - if (cur_focus) + BOOL handled = FALSE; + + BOOL handled_by_top_ctrl = 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) { - if (!cur_focus->isInVisibleChain() || !cur_focus->isInEnabledChain()) + root_view = mRootView; + } + + // 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) { - gFocusMgr.releaseFocusIfNeeded(cur_focus); + 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(); + } + } - LLUICtrl* parent = cur_focus->getParentUICtrl(); - const LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot(); - while(parent) + // 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)) { - if (parent->isCtrl() && - (parent->hasTabStop() || parent == focus_root) && - !parent->getIsChrome() && - parent->isInVisibleChain() && - parent->isInEnabledChain()) + // iterator over contents of top_ctrl, and throw into mouse_hover_set + for (LLView::tree_iterator_t it = popup->beginTreeDFS(); + it != popup->endTreeDFS(); + ++it) { - if (!parent->focusFirstItem()) + LLView* viewp = *it; + if (viewp->getVisible() + && viewp->calcScreenBoundingRect().pointInRect(x, y)) { - parent->setFocus(TRUE); + // 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(); } - break; } - parent = parent->getParentUICtrl(); } } - else if (cur_focus->isFocusRoot()) + + // 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)) { - // 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(); + // 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)) + { - gPipeline.sRenderProcessBeacons = FALSE; - KEY key = gKeyboard->currentKey(); - if (((mask & MASK_CONTROL) && ('N' == key || 'n' == key)) || gSavedSettings.getBOOL("BeaconAlwaysOn")) - { - gPipeline.sRenderProcessBeacons = TRUE; + // 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(); + } + } + } } - BOOL handled = FALSE; - - BOOL handled_by_top_ctrl = FALSE; - LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); + typedef std::vector<LLHandle<LLView> > view_handle_list_t; - LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); - if( mouse_captor ) + // 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) { - // 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) + LLView* viewp = it->get(); + if (viewp) { - llinfos << "Hover handled by captor " << mouse_captor->getName() << llendl; + LLRect view_screen_rect = viewp->calcScreenRect(); + viewp->onMouseEnter(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask); } + } - if( !handled ) + // 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) { - lldebugst(LLERR_USER_INPUT) << "hover not handled by mouse captor" << llendl; + LLRect view_screen_rect = viewp->calcScreenRect(); + viewp->onMouseLeave(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask); } } - else - { - if (top_ctrl) + + // 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 ) { - 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); - handled_by_top_ctrl = TRUE; - } + // 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) + { + llinfos << "Hover handled by captor " << mouse_captor->getName() << llendl; + } - if ( !handled ) + if( !handled ) + { + lldebugst(LLERR_USER_INPUT) << "hover not handled by mouse captor" << llendl; + } + } + else { - // x and y are from last time mouse was in window - // mMouseInWindow tracks *actual* mouse location - if (mMouseInWindow && mRootView->handleHover(x, y, mask) ) + if (top_ctrl) { - if (LLView::sDebugMouseHandling && LLView::sMouseHandlerMessage != last_handle_msg) + 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); + handled_by_top_ctrl = TRUE; + } + + 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; + llinfos << "Hover" << LLView::sMouseHandlerMessage << llendl; + } + handled = TRUE; + } + else if (LLView::sDebugMouseHandling) { - last_handle_msg = LLView::sMouseHandlerMessage; - llinfos << "Hover" << LLView::sMouseHandlerMessage << llendl; + if (last_handle_msg != LLStringUtil::null) + { + last_handle_msg.clear(); + llinfos << "Hover not handled by view" << llendl; + } } - handled = TRUE; } - else if (LLView::sDebugMouseHandling) + + if (!handled) { - if (last_handle_msg != "") + LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); + + if(mMouseInWindow && tool) { - last_handle_msg = ""; - llinfos << "Hover not handled by view" << llendl; + handled = tool->handleHover(x, y, mask); } } } - if( !handled ) + // 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()) { - lldebugst(LLERR_USER_INPUT) << "hover not handled by top view or root" << llendl; - } - } + LLRect screen_sticky_rect = mRootView->getLocalRect(); + S32 local_x, local_y; - // *NOTE: sometimes tools handle the mouse as a captor, so this - // logic is a little confusing - LLTool *tool = NULL; - if (gToolMgr && gHoverView && gCamera) - { - tool = gToolMgr->getCurrentTool(); + if (gSavedSettings.getBOOL("DebugShowXUINames")) + { + LLToolTip::Params params; - if(!handled && tool) - { - handled = tool->handleHover(x, y, mask); + 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); + screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect()); + + params.sticky_rect = screen_sticky_rect; + params.max_width = 400; - if (!mWindow->isCursorHidden()) + LLToolTipMgr::instance().show(params); + } + // if there is a mouse captor, nothing else gets a tooltip + else if (mouse_captor) { - gHoverView->updateHover(tool); + mouse_captor->screenPointToLocal(x, y, &local_x, &local_y); + tool_tip_handled = mouse_captor->handleToolTip(local_x, local_y, mask); } - } - else + 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) { - // Cancel hovering if any UI element handled the event. - gHoverView->cancelHover(); + handled = tool->handleHover(x, y, mask); } + } - // Suppress the toolbox view if our source tool was the pie tool, - // and we've overridden to something else. - mSuppressToolbox = - (gToolMgr->getBaseTool() == gToolPie) && - (gToolMgr->getCurrentTool() != gToolPie); + updateLayout(); - } + mLastMousePoint = mCurrentMousePoint; - //llinfos << (mToolTipBlocked ? "BLOCKED" : "NOT BLOCKED") << llendl; - // Show a new tool tip (or update one that is alrady shown) - BOOL tool_tip_handled = FALSE; - LLString tool_tip_msg; - F32 tooltip_delay = gSavedSettings.getF32( "ToolTipDelay" ); - //HACK: hack for tool-based tooltips which need to pop up more quickly - //Also for show xui names as tooltips debug mode - if ((mouse_captor && !mouse_captor->isView()) || LLUI::sShowXUINames) + // cleanup unused selections when no modal dialogs are open + if (LLModalDialog::activeCount() == 0) { - tooltip_delay = gSavedSettings.getF32( "DragAndDropToolTipDelay" ); + LLViewerParcelMgr::getInstance()->deselectUnused(); } - if( handled && - !mToolTipBlocked && - (gMouseIdleTimer.getElapsedTimeF32() > tooltip_delay) && - !mWindow->isCursorHidden() ) + + if (LLModalDialog::activeCount() == 0) { - LLRect screen_sticky_rect; + LLSelectMgr::getInstance()->deselectUnused(); + } +} - if (mouse_captor) - { - S32 local_x, local_y; - mouse_captor->screenPointToLocal( x, y, &local_x, &local_y ); - tool_tip_handled = mouse_captor->handleToolTip( local_x, local_y, tool_tip_msg, &screen_sticky_rect ); - } - else if (handled_by_top_ctrl) - { - S32 local_x, local_y; - top_ctrl->screenPointToLocal( x, y, &local_x, &local_y ); - tool_tip_handled = top_ctrl->handleToolTip( local_x, local_y, tool_tip_msg, &screen_sticky_rect ); - } - else - { - tool_tip_handled = mRootView->handleToolTip(x, y, tool_tip_msg, &screen_sticky_rect ); - } - if( tool_tip_handled && !tool_tip_msg.empty() ) - { - mToolTipStickyRect = screen_sticky_rect; - mToolTip->setWrappedText( tool_tip_msg, 200 ); - mToolTip->reshapeToFitText(); - mToolTip->setOrigin( x, y ); - LLRect virtual_window_rect(0, getWindowHeight(), getWindowWidth(), 0); - mToolTip->translateIntoRect( virtual_window_rect, FALSE ); - mToolTip->setVisible( TRUE ); - } - } - - if (tool && tool != gToolNull && tool != gToolInspect && tool != gToolDragAndDrop && !gSavedSettings.getBOOL("FreezeTime")) +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 != gToolPie // not default tool - && tool != gToolGun // not coming out of mouselook - && !mSuppressToolbox // not override in third person - && gToolMgr->getCurrentToolset() != gFaceEditToolset // not special mode - && gToolMgr->getCurrentToolset() != gMouselookToolset - && (!captor || captor->isView())) // not dragging - ) + 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() != gFaceEditToolset // not special mode + && LLToolMgr::getInstance()->getCurrentToolset() != gMouselookToolset + && (!captor || dynamic_cast<LLView*>(captor) != NULL))) // not dragging { // Force floater tools to be visible (unless minimized) if (!gFloaterTools->getVisible()) { - gFloaterTools->open(); /* Flawfinder: ignore */ + gFloaterTools->openFloater(); } // Update the location of the blue box tool popup LLCoordGL select_center_screen; - gFloaterTools->updatePopup( select_center_screen, mask ); + gFloaterTools->updatePopup( select_center_screen, gKeyboard->currentMask(TRUE) ); } else { gFloaterTools->setVisible(FALSE); } - // In the future we may wish to hide the tools menu unless you - // are building. JC - //gMenuBarView->setItemVisible("Tools", gFloaterTools->getVisible()); - //gMenuBarView->arrange(); + //gMenuBarView->setItemVisible("BuildTools", gFloaterTools->getVisible()); } - if (gToolBar) + + // Always update console + if(gConsole) { - gToolBar->refresh(); + LLRect console_rect = getChatConsoleRect(); + gConsole->reshape(console_rect.getWidth(), console_rect.getHeight()); + gConsole->setRect(console_rect); } +} + +void LLViewerWindow::updateMouseDelta() +{ + S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::sGLScaleFactor.mV[VX]); + S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::sGLScaleFactor.mV[VY]); - if (gChatBar) + //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()) { - gChatBar->refresh(); + mMouseInWindow = FALSE; } - - if (gOverlayBar) + else { - gOverlayBar->refresh(); + mMouseInWindow = TRUE; } - // Update rectangles for the various toolbars - if (gOverlayBar && gNotifyBoxView && gConsole && gToolBar) + LLVector2 mouse_vel; + + if (gSavedSettings.getBOOL("MouseSmooth")) { - LLRect bar_rect(-1, STATUS_BAR_HEIGHT, getWindowWidth()+1, -1); + static F32 fdx = 0.f; + static F32 fdy = 0.f; - LLRect notify_box_rect = gNotifyBoxView->getRect(); - notify_box_rect.mBottom = bar_rect.mBottom; - gNotifyBoxView->reshape(notify_box_rect.getWidth(), notify_box_rect.getHeight()); - gNotifyBoxView->setRect(notify_box_rect); + F32 amount = 16.f; + fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f); + fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f); - // make sure floaters snap to visible rect by adjusting floater view rect - LLRect floater_rect = gFloaterView->getRect(); - if (floater_rect.mBottom != bar_rect.mBottom+1) - { - floater_rect.mBottom = bar_rect.mBottom+1; - // Don't bounce the floaters up and down. - gFloaterView->reshape(floater_rect.getWidth(), floater_rect.getHeight(), - TRUE, ADJUST_VERTICAL_NO); - gFloaterView->setRect(floater_rect); - } + mCurrentMouseDelta.set(llround(fdx), llround(fdy)); + mouse_vel.setVec(fdx,fdy); + } + else + { + mCurrentMouseDelta.set(dx, dy); + mouse_vel.setVec((F32) dx, (F32) dy); + } + + mMouseVelocityStat.addValue(mouse_vel.magVec()); +} - // snap floaters to top of chat bar/button strip - LLView* chatbar_and_buttons = gOverlayBar->getChild<LLView>("chatbar_and_buttons", TRUE); - // find top of chatbar and strate buttons, if either are visible - if (chatbar_and_buttons && !chatbar_and_buttons->getLocalBoundingRect().isNull()) - { - // convert top/left corner of chatbar/buttons container to gFloaterView-relative coordinates - S32 top, left; - chatbar_and_buttons->localPointToOtherView( - chatbar_and_buttons->getLocalBoundingRect().mLeft, - chatbar_and_buttons->getLocalBoundingRect().mTop, - &left, - &top, - gFloaterView); - gFloaterView->setSnapOffsetBottom(top); - } - else if (gToolBar->getVisible()) +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()) { - S32 top, left; - gToolBar->localPointToOtherView( - gToolBar->getLocalBoundingRect().mLeft, - gToolBar->getLocalBoundingRect().mTop, - &left, - &top, - gFloaterView); - gFloaterView->setSnapOffsetBottom(top); + // 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(); + while(parent) + { + if (parent->isCtrl() && + (parent->hasTabStop() || parent == focus_root) && + !parent->getIsChrome() && + parent->isInVisibleChain() && + parent->isInEnabledChain()) + { + if (!parent->focusFirstItem()) + { + parent->setFocus(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 (cur_focus->hasFocus()) + { + cur_focus->setFocus(FALSE); + } } - else + else if (cur_focus->isFocusRoot()) { - gFloaterView->setSnapOffsetBottom(0); + // 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(); } - - // Always update console - LLRect console_rect = gConsole->getRect(); - console_rect.mBottom = gHUDView->getRect().mBottom + CONSOLE_BOTTOM_PAD; - gConsole->reshape(console_rect.getWidth(), console_rect.getHeight()); - gConsole->setRect(console_rect); } - mLastMousePoint = mCurrentMousePoint; - // last ditch force of edit menu to selection manager - if (LLEditMenuHandler::gEditMenuHandler == NULL && gSelectMgr && gSelectMgr->getSelection()->getObjectCount()) + if (LLEditMenuHandler::gEditMenuHandler == NULL && LLSelectMgr::getInstance()->getSelection()->getObjectCount()) { - LLEditMenuHandler::gEditMenuHandler = gSelectMgr; + LLEditMenuHandler::gEditMenuHandler = LLSelectMgr::getInstance(); } if (gFloaterView->getCycleMode()) @@ -3115,25 +3000,51 @@ BOOL LLViewerWindow::handlePerFrameHover() gFloaterView->syncFloaterTabOrder(); } - if (gSavedSettings.getBOOL("ChatBarStealsFocus") && gChatBar && gFocusMgr.getKeyboardFocus() == NULL && gChatBar->getVisible()) + if(LLSideTray::instanceCreated())//just getInstance will create sidetray. we don't want this + LLSideTray::getInstance()->highlightFocused(); +} + +static LLFastTimer::DeclareTimer FTM_UPDATE_WORLD_VIEW("Update World View"); +void LLViewerWindow::updateWorldViewRect(bool use_full_window) +{ + LLFastTimer ft(FTM_UPDATE_WORLD_VIEW); + + // start off using whole window to render world + LLRect new_world_rect = mWindowRectRaw; + + if (use_full_window == false && mWorldViewPlaceholder.get()) { - gChatBar->startChat(NULL); + 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 = llround((F32)new_world_rect.mLeft * mDisplayScale.mV[VX]); + new_world_rect.mRight = llround((F32)new_world_rect.mRight * mDisplayScale.mV[VX]); + new_world_rect.mBottom = llround((F32)new_world_rect.mBottom * mDisplayScale.mV[VY]); + new_world_rect.mTop = llround((F32)new_world_rect.mTop * mDisplayScale.mV[VY]); } - // cleanup unused selections when no modal dialogs are open - if (gParcelMgr && LLModalDialog::activeCount() == 0) + if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE) { - gParcelMgr->deselectUnused(); + // use right edge of window, ignoring sidebar + new_world_rect.mRight = mWindowRectRaw.mRight; } - if (gSelectMgr && LLModalDialog::activeCount() == 0) + if (mWorldViewRectRaw != new_world_rect) { - gSelectMgr->deselectUnused(); - } + mWorldViewRectRaw = new_world_rect; + gResizeScreenTexture = TRUE; + LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() ); + LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() ); - return handled; -} + 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) { @@ -3143,9 +3054,9 @@ void LLViewerWindow::saveLastMouse(const LLCoordGL &point) { mCurrentMousePoint.mX = 0; } - else if (point.mX > getWindowWidth()) + else if (point.mX > getWindowWidthScaled()) { - mCurrentMousePoint.mX = getWindowWidth(); + mCurrentMousePoint.mX = getWindowWidthScaled(); } else { @@ -3156,9 +3067,9 @@ void LLViewerWindow::saveLastMouse(const LLCoordGL &point) { mCurrentMousePoint.mY = 0; } - else if (point.mY > getWindowHeight() ) + else if (point.mY > getWindowHeightScaled() ) { - mCurrentMousePoint.mY = getWindowHeight(); + mCurrentMousePoint.mY = getWindowHeightScaled(); } else { @@ -3171,16 +3082,15 @@ void LLViewerWindow::saveLastMouse(const LLCoordGL &point) // 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 -// renderObjectsForSelect: TRUE, pick_parcel_wall, FALSE // render_hud_elements: FALSE, FALSE, FALSE void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, BOOL for_hud ) { - LLObjectSelectionHandle selection = gSelectMgr->getSelection(); + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); if (!for_hud && !for_gl_pick) { // Call this once and only once - gSelectMgr->updateSilhouettes(); + LLSelectMgr::getInstance()->updateSilhouettes(); } // Draw fence around land selections @@ -3188,27 +3098,27 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, { if (pick_parcel_walls) { - gParcelMgr->renderParcelCollision(); + LLViewerParcelMgr::getInstance()->renderParcelCollision(); } } else if (( for_hud && selection->getSelectType() == SELECT_TYPE_HUD) || (!for_hud && selection->getSelectType() != SELECT_TYPE_HUD)) { - gSelectMgr->renderSilhouettes(for_hud); + LLSelectMgr::getInstance()->renderSilhouettes(for_hud); stop_glerror(); // setup HUD render - if (selection->getSelectType() == SELECT_TYPE_HUD && gSelectMgr->getSelection()->getObjectCount()) + if (selection->getSelectType() == SELECT_TYPE_HUD && LLSelectMgr::getInstance()->getSelection()->getObjectCount()) { - LLBBox hud_bbox = gAgent.getAvatarObject()->getHUDBBox(); + LLBBox hud_bbox = gAgentAvatarp->getHUDBBox(); // set up transform to encompass bounding box of HUD glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); F32 depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f); - glOrtho(-0.5f * gCamera->getAspect(), 0.5f * gCamera->getAspect(), -0.5f, 0.5f, 0.f, depth); + glOrtho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, depth); glMatrixMode(GL_MODELVIEW); glPushMatrix(); @@ -3218,9 +3128,9 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, } // Render light for editing - if (LLSelectMgr::sRenderLightRadius && gToolMgr->inEdit()) + if (LLSelectMgr::sRenderLightRadius && LLToolMgr::getInstance()->inEdit()) { - LLImageGL::unbindTexture(0); + 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); @@ -3228,7 +3138,7 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, glPushMatrix(); if (selection->getSelectType() == SELECT_TYPE_HUD) { - F32 zoom = gAgent.getAvatarObject()->mHUDCurZoom; + F32 zoom = gAgentCamera.mHUDCurZoom; glScalef(zoom, zoom, zoom); } @@ -3264,7 +3174,7 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, return true; } } func; - gSelectMgr->getSelection()->applyToObjects(&func); + LLSelectMgr::getInstance()->getSelection()->applyToObjects(&func); glPopMatrix(); } @@ -3273,7 +3183,7 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, // 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 = gToolMgr->getCurrentTool(); + LLTool* tool = LLToolMgr::getInstance()->getCurrentTool(); if (tool) { if(tool->isAlwaysRendered()) @@ -3282,15 +3192,15 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, } else { - if( !gSelectMgr->getSelection()->isEmpty() ) + if( !LLSelectMgr::getInstance()->getSelection()->isEmpty() ) { BOOL moveable_object_selected = FALSE; BOOL all_selected_objects_move = TRUE; BOOL all_selected_objects_modify = TRUE; BOOL selecting_linked_set = !gSavedSettings.getBOOL("EditLinkedParts"); - for (LLObjectSelection::iterator iter = gSelectMgr->getSelection()->begin(); - iter != gSelectMgr->getSelection()->end(); iter++) + for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin(); + iter != LLSelectMgr::getInstance()->getSelection()->end(); iter++) { LLSelectNode* nodep = *iter; LLViewerObject* object = nodep->getObject(); @@ -3306,17 +3216,17 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, BOOL draw_handles = TRUE; - if (tool == gToolTranslate && (!moveable_object_selected || !all_selected_objects_move)) + if (tool == LLToolCompTranslate::getInstance() && (!moveable_object_selected || !all_selected_objects_move)) { draw_handles = FALSE; } - if (tool == gToolRotate && (!moveable_object_selected || !all_selected_objects_move)) + if (tool == LLToolCompRotate::getInstance() && (!moveable_object_selected || !all_selected_objects_move)) { draw_handles = FALSE; } - if ( !all_selected_objects_modify && tool == gToolStretch ) + if ( !all_selected_objects_modify && tool == LLToolCompScale::getInstance() ) { draw_handles = FALSE; } @@ -3347,7 +3257,7 @@ LLVector3d LLViewerWindow::clickPointInWorldGlobal(S32 x, S32 y_from_bot, LLView // world at the location of the mouse click LLVector3 mouse_direction_global = mouseDirectionGlobal( x, y_from_bot ); - LLVector3d relative_object = clicked_object->getPositionGlobal() - gAgent.getCameraPositionGlobal(); + 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 @@ -3356,7 +3266,7 @@ LLVector3d LLViewerWindow::clickPointInWorldGlobal(S32 x, S32 y_from_bot, LLView LLVector3d new_pos; new_pos.setVec(mouse_direction_global); // transform mouse vector back to world coords - new_pos += gAgent.getCameraPositionGlobal(); + new_pos += gAgentCamera.getCameraPositionGlobal(); return new_pos; } @@ -3380,490 +3290,206 @@ BOOL LLViewerWindow::clickPointOnSurfaceGlobal(const S32 x, const S32 y, LLViewe return intersect; } -void LLViewerWindow::hitObjectOrLandGlobalAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(S32 x, S32 y, MASK mask), BOOL pick_transparent, BOOL pick_parcel_walls) +void LLViewerWindow::pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(const LLPickInfo& info), BOOL pick_transparent) { if (gNoRender) { return; } - render_ui_and_swap_if_needed(); - glClear(GL_DEPTH_BUFFER_BIT); - gDisplaySwapBuffers = FALSE; - - S32 scaled_x = llround((F32)x * mDisplayScale.mV[VX]); - S32 scaled_y = llround((F32)y_from_bot * mDisplayScale.mV[VY]); - - BOOL in_build_mode = gFloaterTools && gFloaterTools->getVisible(); + BOOL in_build_mode = LLFloaterReg::instanceVisible("build"); if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha) { // build mode allows interaction with all transparent objects // "Show Debug Alpha" means no object actually transparent pick_transparent = TRUE; } - gPickTransparent = pick_transparent; - - gUseGLPick = FALSE; - mPickCallback = callback; - - // Default to not hitting anything - gLastHitPosGlobal.zeroVec(); - gLastHitObjectOffset.zeroVec(); - gLastHitObjectID.setNull(); - gLastHitObjectFace = -1; - - gLastHitNonFloraPosGlobal.zeroVec(); - gLastHitNonFloraObjectOffset.zeroVec(); - gLastHitNonFloraObjectID.setNull(); - gLastHitNonFloraObjectFace = -1; - - gLastHitParcelWall = FALSE; - - LLCamera pick_camera; - pick_camera.setOrigin(gCamera->getOrigin()); - pick_camera.setOriginAndLookAt(gCamera->getOrigin(), - gCamera->getUpAxis(), - gCamera->getOrigin() + mouseDirectionGlobal(x, y_from_bot)); - pick_camera.setView(0.5f*DEG_TO_RAD); - pick_camera.setNear(gCamera->getNear()); - pick_camera.setFar(gCamera->getFar()); - pick_camera.setAspect(1.f); - - // save our drawing state - // *TODO: should we be saving using the new method here using - // glh_get_current_projection/glh_set_current_projection? -brad - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - // build perspective transform and picking viewport - // Perform pick on a PICK_DIAMETER x PICK_DIAMETER pixel region around cursor point. - // Don't limit the select distance for this pick. - // make viewport big enough to handle antialiased frame buffers - gCamera->setPerspective(FOR_SELECTION, scaled_x - (PICK_HALF_WIDTH + 2), scaled_y - (PICK_HALF_WIDTH + 2), PICK_DIAMETER + 4, PICK_DIAMETER + 4, FALSE); - // make viewport big enough to handle antialiased frame buffers - gGLViewport[0] = scaled_x - (PICK_HALF_WIDTH + 2); - gGLViewport[1] = scaled_y - (PICK_HALF_WIDTH + 2); - gGLViewport[2] = PICK_DIAMETER + 4; - gGLViewport[3] = PICK_DIAMETER + 4; - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); - LLViewerCamera::updateFrustumPlanes(pick_camera); - stop_glerror(); - - glClearColor(0.f, 0.f, 0.f, 0.f); - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - //glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - // Draw the objects so the user can select them. - // The starting ID is 1, since land is zero. - gObjectList.renderObjectsForSelect(pick_camera, pick_parcel_walls); - - stop_glerror(); - - // restore drawing state - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - setupViewport(); - - mPickPoint.set(x, y_from_bot); - mPickOffset.set(0, 0); - mPickMask = mask; - mPickPending = TRUE; - - // delay further event processing until we receive results of pick - mWindow->delayInputProcessing(); + LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, TRUE, callback); + schedulePick(pick_info); } -void LLViewerWindow::hitUIElementImmediate(S32 x, S32 y, void (*callback)(S32 x, S32 y, MASK mask)) +void LLViewerWindow::schedulePick(LLPickInfo& pick_info) { - // Performs the GL UI pick. - // Stores its results in global, gLastHitUIElement - if (gNoRender) - { - return; - } + 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); + } - hitUIElementAsync(x, y, gKeyboard->currentMask(TRUE), NULL); - performPick(); - if (callback) - { - callback(x, y, gKeyboard->currentMask(TRUE)); - } -} - -//RN: this currently doesn't do anything -void LLViewerWindow::hitUIElementAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(S32 x, S32 y, MASK mask)) -{ - if (gNoRender) - { return; } - -// F32 delta_time = gAlphaFadeTimer.getElapsedTimeAndResetF32(); - - gUseGLPick = FALSE; - mPickCallback = callback; - - // Default to not hitting anything - gLastHitUIElement = 0; - - LLCamera pick_camera; - pick_camera.setOrigin(gCamera->getOrigin()); - pick_camera.setOriginAndLookAt(gCamera->getOrigin(), - gCamera->getUpAxis(), - gCamera->getOrigin() + mouseDirectionGlobal(x, y_from_bot)); - pick_camera.setView(0.5f*DEG_TO_RAD); - pick_camera.setNear(gCamera->getNear()); - pick_camera.setFar(gCamera->getFar()); - pick_camera.setAspect(1.f); - - // save our drawing state - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); + mPicks.push_back(pick_info); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - // build orthogonal transform and picking viewport - // Perform pick on a PICK_DIAMETER x PICK_DIAMETER pixel region around cursor point. - // Don't limit the select distance for this pick. - gViewerWindow->setup2DRender(); - const LLVector2& display_scale = gViewerWindow->getDisplayScale(); - glScalef(display_scale.mV[VX], display_scale.mV[VY], 1.f); - - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - // make viewport big enough to handle antialiased frame buffers - glViewport(x - (PICK_HALF_WIDTH + 2), y_from_bot - (PICK_HALF_WIDTH + 2), PICK_DIAMETER + 4, PICK_DIAMETER + 4); - stop_glerror(); - - glClearColor(0.f, 0.f, 0.f, 0.f); - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - - // Draw the objects so the user can select them. - // The starting ID is 1, since land is zero. - //gViewerWindow->drawForSelect(); - - stop_glerror(); - - // restore drawing state - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - setupViewport(); - - mPickPoint.set(x, y_from_bot); - mPickOffset.set(0, 0); - mPickMask = mask; - mPickPending = TRUE; + // 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 (gNoRender || !mPickPending) + if (gNoRender) { return; } - mPickPending = FALSE; - U32 te_offset = NO_FACE; - - // find pick region that is fully onscreen - LLCoordGL scaled_pick_point = mPickPoint; - scaled_pick_point.mX = llclamp(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX]), PICK_HALF_WIDTH, gViewerWindow->getWindowDisplayWidth() - PICK_HALF_WIDTH); - scaled_pick_point.mY = llclamp(llround((F32)mPickPoint.mY * mDisplayScale.mV[VY]), PICK_HALF_WIDTH, gViewerWindow->getWindowDisplayHeight() - PICK_HALF_WIDTH); - - glReadPixels(scaled_pick_point.mX - PICK_HALF_WIDTH, scaled_pick_point.mY - PICK_HALF_WIDTH, PICK_DIAMETER, PICK_DIAMETER, GL_RGBA, GL_UNSIGNED_BYTE, mPickBuffer); - - S32 pixel_index = PICK_HALF_WIDTH * PICK_DIAMETER + PICK_HALF_WIDTH; - S32 name = (U32)mPickBuffer[(pixel_index * 4) + 0] << 16 | (U32)mPickBuffer[(pixel_index * 4) + 1] << 8 | (U32)mPickBuffer[(pixel_index * 4) + 2]; - gLastPickAlpha = mPickBuffer[(pixel_index * 4) + 3]; - - if (name >= (S32)GL_NAME_UI_RESERVED && name < (S32)GL_NAME_INDEX_OFFSET) + if (!mPicks.empty()) { - // hit a UI element - gLastHitUIElement = name; - if (mPickCallback) + std::vector<LLPickInfo>::iterator pick_it; + for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it) { - mPickCallback(mPickPoint.mX, mPickPoint.mY, mPickMask); + pick_it->fetchResults(); } - } - //imdebug("rgba rbga=bbba b=8 w=%d h=%d %p", PICK_DIAMETER, PICK_DIAMETER, mPickBuffer); - - S32 x_offset = mPickPoint.mX - llround((F32)scaled_pick_point.mX / mDisplayScale.mV[VX]); - S32 y_offset = mPickPoint.mY - llround((F32)scaled_pick_point.mY / mDisplayScale.mV[VY]); + mLastPick = mPicks.back(); + mPicks.clear(); + } +} - - // we hit nothing, scan surrounding pixels for something useful - if (!name) +void LLViewerWindow::returnEmptyPicks() +{ + std::vector<LLPickInfo>::iterator pick_it; + for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it) { - S32 closest_distance = 10000; - //S32 closest_pick_name = 0; - for (S32 col = 0; col < PICK_DIAMETER; col++) + mLastPick = *pick_it; + // just trigger callback with empty results + if (pick_it->mPickCallback) { - for (S32 row = 0; row < PICK_DIAMETER; row++) - { - S32 distance_squared = (llabs(col - x_offset - PICK_HALF_WIDTH) * llabs(col - x_offset - PICK_HALF_WIDTH)) + (llabs(row - y_offset - PICK_HALF_WIDTH) * llabs(row - y_offset - PICK_HALF_WIDTH)); - pixel_index = row * PICK_DIAMETER + col; - S32 test_name = (U32)mPickBuffer[(pixel_index * 4) + 0] << 16 | (U32)mPickBuffer[(pixel_index * 4) + 1] << 8 | (U32)mPickBuffer[(pixel_index * 4) + 2]; - gLastPickAlpha = mPickBuffer[(pixel_index * 4) + 3]; - if (test_name && distance_squared < closest_distance) - { - closest_distance = distance_squared; - name = test_name; - gLastPickAlpha = mPickBuffer[(pixel_index * 4) + 3]; - mPickOffset.mX = col - PICK_HALF_WIDTH; - mPickOffset.mY = row - PICK_HALF_WIDTH; - } - } + pick_it->mPickCallback(*pick_it); } } + mPicks.clear(); +} - if (name) - { - mPickPoint.mX += llround((F32)mPickOffset.mX * mDisplayScale.mV[VX]); - mPickPoint.mY += llround((F32)mPickOffset.mY * mDisplayScale.mV[VY]); - } - - if (gPickFaces) +// Performs the GL object/land pick. +LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_transparent) +{ + if (gNoRender) { - te_offset = ((U32)name >> 20); - name &= 0x000fffff; - // don't clear gPickFaces, as we still need to check for UV coordinates + return LLPickInfo(); } - LLViewerObject *objectp = NULL; - - // Frontmost non-foreground object that isn't trees or grass - LLViewerObject* nonflora_objectp = NULL; - S32 nonflora_name = -1; - S32 nonflora_te_offset = NO_FACE; - - if (name == (S32)GL_NAME_PARCEL_WALL) + BOOL in_build_mode = LLFloaterReg::instanceVisible("build"); + if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha) { - gLastHitParcelWall = TRUE; + // build mode allows interaction with all transparent objects + // "Show Debug Alpha" means no object actually transparent + pick_transparent = TRUE; } - gLastHitHUDIcon = NULL; + // shortcut queueing in mPicks and just update mLastPick in place + mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), gKeyboard->currentMask(TRUE), pick_transparent, TRUE, NULL); + mLastPick.fetchResults(); - objectp = gObjectList.getSelectedObject(name); - if (objectp) - { - LLViewerObject* parent = (LLViewerObject*)(objectp->getParent()); - if (NULL == parent) { - // if you are the parent - parent = objectp; - } - if (objectp->mbCanSelect) - { - te_offset = (te_offset == 16) ? NO_FACE : te_offset; - - // If the hit object isn't a plant, store it as the frontmost non-flora object. - LLPCode pcode = objectp->getPCode(); - if( (LL_PCODE_LEGACY_GRASS != pcode) && - (LL_PCODE_LEGACY_TREE != pcode) && - (LL_PCODE_TREE_NEW != pcode)) - { - nonflora_objectp = objectp; - nonflora_name = name; - nonflora_te_offset = te_offset; - } - } - else - { - //llinfos << "Hit object you can't select" << llendl; - } - } - else - { - // was this name referring to a hud icon? - gLastHitHUDIcon = LLHUDIcon::handlePick(name); - } - - analyzeHit( - mPickPoint.mX, mPickPoint.mY, objectp, te_offset, - &gLastHitObjectID, &gLastHitObjectFace, &gLastHitPosGlobal, &gLastHitLand, &gLastHitUCoord, &gLastHitVCoord ); + return mLastPick; +} - if (objectp && !gLastHitObjectID.isNull()) - { - gLastHitObjectOffset = gAgent.calcFocusOffset(objectp, mPickPoint.mX, mPickPoint.mY); - } +LLHUDIcon* LLViewerWindow::cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 depth, + LLVector3* intersection) +{ + S32 x = mouse_x; + S32 y = mouse_y; - if( objectp == nonflora_objectp ) + if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position { - gLastHitNonFloraObjectID = gLastHitObjectID; - gLastHitNonFloraObjectFace = gLastHitObjectFace; - gLastHitNonFloraPosGlobal = gLastHitPosGlobal; - gLastHitNonFloraObjectOffset= gLastHitObjectOffset; + x = getCurrentMouseX(); + y = getCurrentMouseY(); } - else - { - analyzeHit( mPickPoint.mX, mPickPoint.mY, nonflora_objectp, nonflora_te_offset, - &gLastHitNonFloraObjectID, &gLastHitNonFloraObjectFace, &gLastHitNonFloraPosGlobal, - &gLastHitLand, &gLastHitUCoord, &gLastHitVCoord); - if( nonflora_objectp ) - { - gLastHitNonFloraObjectOffset = gAgent.calcFocusOffset(nonflora_objectp, mPickPoint.mX, mPickPoint.mY); - } - } + // world coordinates of mouse + 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; - if (mPickCallback) - { - mPickCallback(mPickPoint.mX, mPickPoint.mY, mPickMask); - } + return LLHUDIcon::lineSegmentIntersectAll(mouse_world_start, mouse_world_end, intersection); - gPickFaces = FALSE; + } -// Performs the GL object/land pick. -// Stores its results in globals, gHit* -void LLViewerWindow::hitObjectOrLandGlobalImmediate(S32 x, S32 y_from_bot, void (*callback)(S32 x, S32 y, MASK mask), BOOL pick_transparent) +LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 depth, + LLViewerObject *this_object, + S32 this_face, + BOOL pick_transparent, + S32* face_hit, + LLVector3 *intersection, + LLVector2 *uv, + LLVector3 *normal, + LLVector3 *binormal) { - if (gNoRender) - { - return; - } - - hitObjectOrLandGlobalAsync(x, y_from_bot, gKeyboard->currentMask(TRUE), NULL, pick_transparent); - performPick(); - if (callback) + S32 x = mouse_x; + S32 y = mouse_y; + + if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position { - callback(x, y_from_bot, gKeyboard->currentMask(TRUE)); + x = getCurrentMouseX(); + y = getCurrentMouseY(); } -} -LLViewerObject* LLViewerWindow::getObjectUnderCursor(const F32 depth) -{ - S32 x = getCurrentMouseX(); - S32 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); - LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y); - LLVector3 camera_pos_global = gCamera->getOrigin(); - LLVector3 pick_end = camera_pos_global + mouse_direction_global * depth; - LLVector3 collision_point; - return gPipeline.pickObject(camera_pos_global, pick_end, collision_point); -} - -void LLViewerWindow::analyzeHit( - S32 x, // input - S32 y_from_bot, // input - LLViewerObject* objectp, // input - U32 te_offset, // input - LLUUID* hit_object_id_p,// output - S32* hit_face_p, // output - LLVector3d* hit_pos_p, // output - BOOL* hit_land, // output - F32* hit_u_coord, // output - F32* hit_v_coord) // output -{ - // Clean up inputs - S32 face = -1; + // world coordinates of mouse + LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y); + LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin(); - if (te_offset != NO_FACE ) - { - face = te_offset; - } + //get near clip plane + LLVector3 n = LLViewerCamera::getInstance()->getAtAxis(); + LLVector3 p = mouse_point_global + n * LLViewerCamera::getInstance()->getNear(); - *hit_land = FALSE; + //project mouse point onto plane + LLVector3 pos; + line_plane(mouse_point_global, mouse_direction_global, p, n, pos); + mouse_point_global = pos; - if (objectp) + LLVector3 mouse_world_start = mouse_point_global; + LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth; + + + LLViewerObject* found = NULL; + + if (this_object) // check only this object { - if( objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH ) + if (this_object->isHUDAttachment()) // is a HUD object? { - // Hit land - *hit_land = TRUE; - - // put global position into land_pos - LLVector3d land_pos; - if (mousePointOnLandGlobal(x, y_from_bot, &land_pos)) + if (this_object->lineSegmentIntersect(mouse_hud_start, mouse_hud_end, this_face, pick_transparent, + face_hit, intersection, uv, normal, binormal)) { - *hit_object_id_p = LLUUID::null; - *hit_face_p = -1; - - // Fudge the land focus a little bit above ground. - *hit_pos_p = land_pos + LLVector3d(0.f, 0.f, 0.1f); - //llinfos << "DEBUG Hit Land " << *hit_pos_p << llendl; - return; + found = this_object; } - else - { - //llinfos << "Hit land but couldn't find position" << llendl; - // Fall through to "Didn't hit anything" } - } - else + + else // is a world object { - *hit_object_id_p = objectp->mID; - *hit_face_p = face; - - // Hit an object - if (objectp->isAvatar()) + if (this_object->lineSegmentIntersect(mouse_world_start, mouse_world_end, this_face, pick_transparent, + face_hit, intersection, uv, normal, binormal)) { - *hit_pos_p = gAgent.getPosGlobalFromAgent(((LLVOAvatar*)objectp)->mPelvisp->getWorldPosition()); + found = this_object; } - else if (objectp->mDrawable.notNull()) - { - *hit_pos_p = gAgent.getPosGlobalFromAgent(objectp->getRenderPosition()); } - else - { - // regular object - *hit_pos_p = objectp->getPositionGlobal(); } - if (gPickFaces && face > -1 && - objectp->mDrawable.notNull() && objectp->getPCode() == LL_PCODE_VOLUME && - face < objectp->mDrawable->getNumFaces()) + else // check ALL objects { - // render red-blue gradient to get 1/256 precision - // then render green grid to get final 1/4096 precision - S32 scaled_x = llround((F32)x * mDisplayScale.mV[VX]); - S32 scaled_y = llround((F32)y_from_bot * mDisplayScale.mV[VY]); - const S32 UV_PICK_WIDTH = 41; - const S32 UV_PICK_HALF_WIDTH = (UV_PICK_WIDTH - 1) / 2; - U8 uv_pick_buffer[UV_PICK_WIDTH * UV_PICK_WIDTH * 4]; - S32 pick_face = face; - LLFace* facep = objectp->mDrawable->getFace(pick_face); - gCamera->setPerspective(FOR_SELECTION, scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, FALSE); - glViewport(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH); - gPipeline.renderFaceForUVSelect(facep); - - glReadPixels(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, GL_RGBA, GL_UNSIGNED_BYTE, uv_pick_buffer); - U8* center_pixel = &uv_pick_buffer[4 * ((UV_PICK_WIDTH * UV_PICK_HALF_WIDTH) + UV_PICK_HALF_WIDTH + 1)]; - *hit_u_coord = (F32)((center_pixel[VGREEN] & 0xf) + (16.f * center_pixel[VRED])) / 4095.f; - *hit_v_coord = (F32)((center_pixel[VGREEN] >> 4) + (16.f * center_pixel[VBLUE])) / 4095.f; - } - else + found = gPipeline.lineSegmentIntersectInHUD(mouse_hud_start, mouse_hud_end, pick_transparent, + face_hit, intersection, uv, normal, binormal); + + if (!found) // if not found in HUD, look in world: + { - *hit_u_coord = 0.f; - *hit_v_coord = 0.f; + found = gPipeline.lineSegmentIntersectInWorld(mouse_world_start, mouse_world_end, pick_transparent, + face_hit, intersection, uv, normal, binormal); } - //llinfos << "DEBUG Hit Object " << *hit_pos_p << llendl; - return; - } } - // Didn't hit anything. - *hit_object_id_p = LLUUID::null; - *hit_face_p = -1; - *hit_pos_p = LLVector3d::zero; - *hit_u_coord = 0.f; - *hit_v_coord = 0.f; - //llinfos << "DEBUG Hit Nothing " << llendl; + return found; } // Returns unit vector relative to camera @@ -3871,45 +3497,64 @@ void LLViewerWindow::analyzeHit( LLVector3 LLViewerWindow::mouseDirectionGlobal(const S32 x, const S32 y) const { // find vertical field of view - F32 fov = gCamera->getView(); + F32 fov = LLViewerCamera::getInstance()->getView(); - // find screen resolution - S32 height = getWindowHeight(); - S32 width = getWindowWidth(); + // 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 = (height / 2.f) / (tan(fov / 2.f)); + F32 distance = ((F32)getWorldViewHeightScaled() * 0.5f) / (tan(fov / 2.f)); // calculate click point relative to middle of screen - F32 click_x = x - width / 2.f; - F32 click_y = y - height / 2.f; + F32 click_x = x - center_x; + F32 click_y = y - center_y; // compute mouse vector - LLVector3 mouse_vector = distance * gCamera->getAtAxis() - - click_x * gCamera->getLeftAxis() - + click_y * gCamera->getUpAxis(); + 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 = gCamera->getView(); - F32 fov_width = fov_height * gCamera->getAspect(); + F32 fov_height = LLViewerCamera::getInstance()->getView(); + F32 fov_width = fov_height * LLViewerCamera::getInstance()->getAspect(); // find screen resolution - S32 height = getWindowHeight(); - S32 width = getWindowWidth(); + 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 / (F32)width) - 0.5f) * fov_width * -1.f; - F32 click_y = (((F32)y / (F32)height) - 0.5f) * fov_height; + 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); @@ -3935,7 +3580,7 @@ BOOL LLViewerWindow::mousePointOnPlaneGlobal(LLVector3d& point, const S32 x, con 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 - gAgent.getCameraPositionGlobal(); + 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) @@ -3949,7 +3594,7 @@ BOOL LLViewerWindow::mousePointOnPlaneGlobal(LLVector3d& point, const S32 x, con mouse_look_at_scale = plane_origin_camera_rel.magVec() / (plane_origin_dir * mouse_direction_global_d); } - point = gAgent.getCameraPositionGlobal() + mouse_look_at_scale * mouse_direction_global_d; + point = gAgentCamera.getCameraPositionGlobal() + mouse_look_at_scale * mouse_direction_global_d; return mouse_look_at_scale > 0.0; } @@ -3967,18 +3612,18 @@ BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d const F32 SECOND_PASS_STEP = 0.1f; // meters LLVector3d camera_pos_global; - camera_pos_global = gAgent.getCameraPositionGlobal(); + 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 < gAgent.mDrawDistance; mouse_dir_scale += FIRST_PASS_STEP) + for (mouse_dir_scale = FIRST_PASS_STEP; mouse_dir_scale < gAgentCamera.mDrawDistance; 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 = gWorldPointer->resolveRegionGlobal(probe_point_region, probe_point_global); + regionp = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global); if (!regionp) { @@ -4025,7 +3670,7 @@ BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale); probe_point_global = camera_pos_global + mouse_direction_global_d; - regionp = gWorldPointer->resolveRegionGlobal(probe_point_region, probe_point_global); + regionp = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global); if (!regionp) { @@ -4062,123 +3707,81 @@ BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d } // Saves an image to the harddrive as "SnapshotX" where X >= 1. -BOOL LLViewerWindow::saveImageNumbered(LLImageRaw *raw, const LLString& extension_in) +BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image) { - if (! raw) + if (!image) { return FALSE; } - LLString extension(extension_in); - if (extension.empty()) - { - extension = (gSavedSettings.getBOOL("CompressSnapshotsToDisk")) ? ".j2c" : ".bmp"; - } - LLFilePicker::ESaveFilter pick_type; + std::string extension("." + image->getExtension()); 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; // ??? - // Get a directory if this is the first time. - if (strlen(sSnapshotDir) == 0) /* Flawfinder: ignore */ + // Get a base file location if needed. + if ( ! isSnapshotLocSet()) { - LLString proposed_name( sSnapshotBaseName ); - proposed_name.append( extension ); + std::string proposed_name( sSnapshotBaseName ); + + // getSaveFile will append an appropriate extension to the proposed name, based on the ESaveFilter constant passed in. // pick a directory in which to save LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getSaveFile(pick_type, proposed_name.c_str())) + if (!picker.getSaveFile(pick_type, proposed_name)) { // Clicked cancel return FALSE; } // Copy the directory + file name - char directory[LL_MAX_PATH]; /* Flawfinder: ignore */ - strncpy(directory, picker.getFirstFile(), LL_MAX_PATH -1); /* Flawfinder: ignore */ - directory[LL_MAX_PATH -1] = '\0'; - - // Smash the file extension - S32 length = strlen(directory); /* Flawfinder: ignore */ - S32 index = length; + std::string filepath = picker.getFirstFile(); - // Back up over extension - index -= extension.length(); - if (index >= 0 && directory[index] == '.') - { - directory[index] = '\0'; - } - else - { - index = length; - } - - // Find trailing backslash - while (index >= 0 && directory[index] != gDirUtilp->getDirDelimiter()[0]) - { - index--; - } - - // If we found one, truncate the string there - if (index >= 0) - { - if (index + 1 <= length) - { - strncpy(LLViewerWindow::sSnapshotBaseName, directory + index + 1, LL_MAX_PATH -1); /* Flawfinder: ignore */ - LLViewerWindow::sSnapshotBaseName[LL_MAX_PATH -1] = '\0'; - } - - index++; - directory[index] = '\0'; - strncpy(LLViewerWindow::sSnapshotDir, directory, LL_MAX_PATH -1); /* Flawfinder: ignore */ - LLViewerWindow::sSnapshotDir[LL_MAX_PATH -1] = '\0'; - } + LLViewerWindow::sSnapshotBaseName = gDirUtilp->getBaseFileName(filepath, true); + LLViewerWindow::sSnapshotDir = gDirUtilp->getDirName(filepath); } // Look for an unused file name - LLString filepath; + std::string filepath; S32 i = 1; S32 err = 0; do { filepath = sSnapshotDir; + filepath += gDirUtilp->getDirDelimiter(); filepath += sSnapshotBaseName; filepath += llformat("_%.3d",i); filepath += extension; - struct stat stat_info; - err = gViewerWindow->mWindow->stat( filepath.c_str(), &stat_info ); + 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). - LLPointer<LLImageFormatted> formatted_image = LLImageFormatted::createFromExtension(extension); - LLImageBase::setSizeOverride(TRUE); - BOOL success = formatted_image->encode(raw); - if( success ) - { - success = formatted_image->save(filepath); - } - else - { - llwarns << "Unable to encode bmp snapshot" << llendl; - } - LLImageBase::setSizeOverride(FALSE); - - return success; + return image->save(filepath); } +void LLViewerWindow::resetSnapshotLoc() +{ + sSnapshotDir.clear(); +} static S32 BORDERHEIGHT = 0; static S32 BORDERWIDTH = 0; +// static void LLViewerWindow::movieSize(S32 new_width, S32 new_height) { LLCoordScreen size; @@ -4186,28 +3789,18 @@ void LLViewerWindow::movieSize(S32 new_width, S32 new_height) if ( (size.mX != new_width + BORDERWIDTH) ||(size.mY != new_height + BORDERHEIGHT)) { - S32 x = gViewerWindow->getWindowWidth(); - S32 y = gViewerWindow->getWindowHeight(); + // use actual display dimensions, not virtual UI dimensions + S32 x = gViewerWindow->getWindowWidthRaw(); + S32 y = gViewerWindow->getWindowHeightRaw(); BORDERWIDTH = size.mX - x; BORDERHEIGHT = size.mY- y; LLCoordScreen new_size(new_width + BORDERWIDTH, new_height + BORDERHEIGHT); - BOOL disable_sync = gSavedSettings.getBOOL("DisableVerticalSync"); - if (gViewerWindow->mWindow->getFullscreen()) - { - gViewerWindow->changeDisplaySettings(FALSE, - new_size, - disable_sync, - TRUE); - } - else - { - gViewerWindow->mWindow->setSize(new_size); - } + gViewerWindow->mWindow->setSize(new_size); } } -BOOL LLViewerWindow::saveSnapshot( const LLString& filepath, S32 image_width, S32 image_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) +BOOL LLViewerWindow::saveSnapshot( const std::string& filepath, S32 image_width, S32 image_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) { llinfos << "Saving snapshot to: " << filepath << llendl; @@ -4217,7 +3810,7 @@ BOOL LLViewerWindow::saveSnapshot( const LLString& filepath, S32 image_width, S3 if (success) { LLPointer<LLImageBMP> bmp_image = new LLImageBMP; - success = bmp_image->encode(raw); + success = bmp_image->encode(raw, 0.0f); if( success ) { success = bmp_image->save(filepath); @@ -4238,26 +3831,29 @@ BOOL LLViewerWindow::saveSnapshot( const LLString& filepath, S32 image_width, S3 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::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) +{ + return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, do_rebuild, type); +} // Saves the image from the screen to the specified filename and path. BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL do_rebuild, ESnapshotType type, S32 max_size) { - //F32 image_aspect_ratio = ((F32)image_width) / ((F32)image_height); - //F32 window_aspect_ratio = ((F32)getWindowWidth()) / ((F32)getWindowHeight()); - - if ((!gWorldPointer) || - (!raw)) + if (!raw) { return FALSE; } // PRE SNAPSHOT - render_ui_and_swap_if_needed(); gDisplaySwapBuffers = FALSE; glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); @@ -4280,71 +3876,61 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei // Copy screen to a buffer // crop sides or top and bottom, if taking a snapshot of different aspect ratio // from window - S32 snapshot_width = mWindowRect.getWidth(); - S32 snapshot_height = mWindowRect.getHeight(); + S32 snapshot_width = mWindowRectRaw.getWidth(); + S32 snapshot_height = mWindowRectRaw.getHeight(); + // SNAPSHOT + S32 window_width = mWindowRectRaw.getWidth(); + S32 window_height = mWindowRectRaw.getHeight(); + LLRect window_rect = mWindowRectRaw; + BOOL use_fbo = FALSE; + + LLRenderTarget target; F32 scale_factor = 1.0f ; - if (keep_window_aspect || is_texture) //map the entire window to snapshot - { + if(!keep_window_aspect) //image cropping + { + 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) ; } - else //scale or crop + else //the scene(window) proportion needs to be maintained. { - if(snapshot_width > image_width) //crop - { - snapshot_width = image_width ; - } - if(snapshot_height > image_height)//crop + if(image_width > window_width || image_height > window_height) //need to enlarge the scene { - snapshot_height = image_height ; - } - - //if (image_aspect_ratio > window_aspect_ratio) - //{ - // snapshot_height = llround((F32)snapshot_width / image_aspect_ratio); - //} - //else if (image_aspect_ratio < window_aspect_ratio) - //{ - // snapshot_width = llround((F32)snapshot_height * image_aspect_ratio); - //} - } - - LLRenderTarget target; - - scale_factor = llmax(1.f, (F32)image_width / snapshot_width, (F32)image_height / snapshot_height); - - // SNAPSHOT - S32 window_width = mWindowRect.getWidth(); - S32 window_height = mWindowRect.getHeight(); - - LLRect window_rect = mWindowRect; - - BOOL use_fbo = FALSE; - - if (gGLManager.mHasFramebufferObject && - (image_width > window_width || - image_height > window_height) && - !show_ui && - keep_window_aspect) - { - GLint max_size = 0; - glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &max_size); + if (!LLPipeline::sRenderDeferred && gGLManager.mHasFramebufferObject && !show_ui) + { + GLint max_size = 0; + glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &max_size); - if (image_width <= max_size && image_height <= max_size) - { - use_fbo = TRUE; - - snapshot_width = image_width; - snapshot_height = image_height; - target.allocate(snapshot_width, snapshot_height, GL_RGBA, TRUE, GL_TEXTURE_RECTANGLE_ARB, TRUE); - window_width = snapshot_width; - window_height = snapshot_height; - scale_factor = 1.f; - mWindowRect.set(0, 0, snapshot_width, snapshot_height); - target.bindTarget(); + if (image_width <= max_size && image_height <= max_size) //re-project the scene + { + use_fbo = TRUE; + + snapshot_width = image_width; + snapshot_height = image_height; + target.allocate(snapshot_width, snapshot_height, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, TRUE); + window_width = snapshot_width; + window_height = snapshot_height; + scale_factor = 1.f; + mWindowRectRaw.set(0, snapshot_height, snapshot_width, 0); + target.bindTarget(); + } + } - + if(!use_fbo) //no re-projection, so tiling the scene + { + 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) ; + } } + //else: keep the current scene scale, re-scale it if necessary after reading out. } + // if not showing ui, use full window to render world view + updateWorldViewRect(!show_ui); + 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); @@ -4356,21 +3942,34 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei image_buffer_x = llfloor(snapshot_width*scale_factor) ; image_buffer_y = llfloor(snapshot_height *scale_factor) ; } - raw->resize(image_buffer_x, image_buffer_y, type == SNAPSHOT_TYPE_DEPTH ? 4 : 3); + 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 > 1.f; + BOOL high_res = scale_factor >= 2.f; // Font scaling is slow, only do so if rez is much higher if (high_res) { send_agent_pause(); //rescale fonts initFonts(scale_factor); - LLHUDText::reshape(); + LLHUDObject::reshapeAll(); } S32 output_buffer_offset_y = 0; - F32 depth_conversion_factor_1 = (gCamera->getFar() + gCamera->getNear()) / (2.f * gCamera->getFar() * gCamera->getNear()); - F32 depth_conversion_factor_2 = (gCamera->getFar() - gCamera->getNear()) / (2.f * gCamera->getFar() * gCamera->getNear()); + 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()); + + gObjectList.generatePickList(*LLViewerCamera::getInstance()); for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y) { @@ -4383,22 +3982,30 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei for (int subimage_x = 0; subimage_x < scale_factor; ++subimage_x) { gDisplaySwapBuffers = FALSE; + gDepthDirty = TRUE; if (type == SNAPSHOT_TYPE_OBJECT_ID) { glClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - gCamera->setZoomParameters(scale_factor, subimage_x+(subimage_y*llceil(scale_factor))); + LLViewerCamera::getInstance()->setZoomParameters(scale_factor, subimage_x+(subimage_y*llceil(scale_factor))); setup3DRender(); - setupViewport(); - BOOL first_time_through = (subimage_x + subimage_y == 0); - gPickTransparent = FALSE; - gObjectList.renderObjectsForSelect(*gCamera, FALSE, !first_time_through); + gObjectList.renderPickList(gViewerWindow->getWindowRectScaled(), FALSE, FALSE); } else { - display(do_rebuild, scale_factor, subimage_x+(subimage_y*llceil(scale_factor)), use_fbo); - render_ui_and_swap(); + const U32 subfield = subimage_x+(subimage_y*llceil(scale_factor)); + + if (LLPipeline::sRenderDeferred) + { + display(do_rebuild, scale_factor, subfield, FALSE); + } + else + { + display(do_rebuild, scale_factor, subfield, TRUE); + // Required for showing the GUI in snapshots? See DEV-16350 for details. JC + render_ui(scale_factor, subfield); + } } S32 subimage_x_offset = llclamp(buffer_x_offset - (subimage_x * window_width), 0, window_width); @@ -4407,49 +4014,50 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei llmax(0, (window_width * (subimage_x + 1)) - (buffer_x_offset + raw->getWidth()))); 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 wathdog thread every 100 lines to keep us alive (arbitrary number, feel free to change) + if (out_y % 100 == 0) + { + LLAppViewer::instance()->pingMainloopTimeout("LLViewerWindow::rawSnapshot"); + } + if (type == SNAPSHOT_TYPE_OBJECT_ID || type == SNAPSHOT_TYPE_COLOR) { glReadPixels( subimage_x_offset, out_y + subimage_y_offset, read_width, 1, GL_RGB, GL_UNSIGNED_BYTE, - raw->getData() + // current output pixel is beginning of buffer... - ( - (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... - ) * 3 // times 3 bytes per pixel + raw->getData() + output_buffer_offset ); } else // SNAPSHOT_TYPE_DEPTH { - 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... - ) * 4; // times 4 bytes per pixel - + 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, - raw->getData() + output_buffer_offset// current output pixel is beginning of buffer... + depth_line_buffer->getData()// current output pixel is beginning of buffer... ); - for (S32 i = output_buffer_offset; i < output_buffer_offset + (S32)read_width * 4; i += 4) + for (S32 i = 0; i < (S32)read_width; i++) { - F32 depth_float = *(F32*)(raw->getData() + 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, gCamera->getNear(), gCamera->getFar()); - *(raw->getData() + i + 0) = depth_byte; - *(raw->getData() + i + 1) = depth_byte; - *(raw->getData() + i + 2) = depth_byte; - *(raw->getData() + i + 3) = 255; + 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; + } } } } @@ -4461,11 +4069,12 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei if (use_fbo) { - mWindowRect = window_rect; + mWindowRectRaw = window_rect; target.flush(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } gDisplaySwapBuffers = FALSE; + gDepthDirty = TRUE; // POST SNAPSHOT if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) @@ -4481,21 +4090,22 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei if (high_res) { initFonts(1.f); - LLHUDText::reshape(); + 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 * (type == SNAPSHOT_TYPE_DEPTH ? 4 : 3)) % 4 ; + 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) { - raw->scale( image_width, image_height ); + ret = raw->scale( image_width, image_height ); } else if(image_width != image_buffer_x || image_height != image_buffer_y) { - raw->scale( image_width, image_height, FALSE ); + ret = raw->scale( image_width, image_height, FALSE ); } @@ -4516,7 +4126,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei send_agent_resume(); } - return TRUE; + return ret; } void LLViewerWindow::destroyWindow() @@ -4531,143 +4141,130 @@ void LLViewerWindow::destroyWindow() void LLViewerWindow::drawMouselookInstructions() { - // Draw instructions for mouselook ("Press ESC to leave Mouselook" in a box at the top of the screen.) - const char* instructions = "Press ESC to leave Mouselook."; - const LLFontGL* font = gResMgr->getRes( LLFONT_SANSSERIF ); - - const S32 INSTRUCTIONS_PAD = 5; - LLRect instructions_rect; - instructions_rect.setLeftTopAndSize( - INSTRUCTIONS_PAD, - gViewerWindow->getWindowHeight() - INSTRUCTIONS_PAD, - font->getWidth( instructions ) + 2 * INSTRUCTIONS_PAD, - llround(font->getLineHeight() + 2 * INSTRUCTIONS_PAD)); - - { - LLGLSNoTexture gls_no_texture; - gGL.color4f( 0.9f, 0.9f, 0.9f, 1.0f ); - gl_rect_2d( instructions_rect ); - } + // 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, - instructions_rect.mLeft + INSTRUCTIONS_PAD, - instructions_rect.mTop - INSTRUCTIONS_PAD, - LLColor4( 0.0f, 0.0f, 0.0f, 1.f ), - LLFontGL::LEFT, LLFontGL::TOP); + getWorldViewRectScaled().getCenterX(), + getWorldViewRectScaled().mBottom + INSTRUCTIONS_PAD, + LLColor4( 1.0f, 1.0f, 1.0f, 0.5f ), + LLFontGL::HCENTER, LLFontGL::TOP, + LLFontGL::NORMAL,LLFontGL::DROP_SHADOW); } - -// These functions are here only because LLViewerWindow used to do the work that gFocusMgr does now. -// They let other objects continue to work without change. - -void LLViewerWindow::setKeyboardFocus(LLUICtrl* new_focus) +void* LLViewerWindow::getPlatformWindow() const { - gFocusMgr.setKeyboardFocus( new_focus ); + return mWindow->getPlatformWindow(); } -LLUICtrl* LLViewerWindow::getKeyboardFocus() +void* LLViewerWindow::getMediaWindow() const { - return gFocusMgr.getKeyboardFocus(); + return mWindow->getMediaWindow(); } -BOOL LLViewerWindow::hasKeyboardFocus(const LLUICtrl* possible_focus) const +void LLViewerWindow::focusClient() const { - return possible_focus == gFocusMgr.getKeyboardFocus(); + return mWindow->focusClient(); } -BOOL LLViewerWindow::childHasKeyboardFocus(const LLView* parent) const +LLRootView* LLViewerWindow::getRootView() const { - return gFocusMgr.childHasKeyboardFocus( parent ); + return mRootView; } -void LLViewerWindow::setMouseCapture(LLMouseHandler* new_captor) +LLRect LLViewerWindow::getWorldViewRectScaled() const { - gFocusMgr.setMouseCapture( new_captor ); + return mWorldViewRectScaled; } -LLMouseHandler* LLViewerWindow::getMouseCaptor() const +S32 LLViewerWindow::getWorldViewHeightScaled() const { - return gFocusMgr.getMouseCapture(); + return mWorldViewRectScaled.getHeight(); } -S32 LLViewerWindow::getWindowHeight() const -{ - return mVirtualWindowRect.getHeight(); -} - -S32 LLViewerWindow::getWindowWidth() const -{ - return mVirtualWindowRect.getWidth(); +S32 LLViewerWindow::getWorldViewWidthScaled() const +{ + return mWorldViewRectScaled.getWidth(); } -S32 LLViewerWindow::getWindowDisplayHeight() const -{ - return mWindowRect.getHeight(); -} -S32 LLViewerWindow::getWindowDisplayWidth() const -{ - return mWindowRect.getWidth(); +S32 LLViewerWindow::getWorldViewHeightRaw() const +{ + return mWorldViewRectRaw.getHeight(); } -LLUICtrl* LLViewerWindow::getTopCtrl() const +S32 LLViewerWindow::getWorldViewWidthRaw() const { - return gFocusMgr.getTopCtrl(); + return mWorldViewRectRaw.getWidth(); } -BOOL LLViewerWindow::hasTopCtrl(LLView* view) const -{ - return view == gFocusMgr.getTopCtrl(); +S32 LLViewerWindow::getWindowHeightScaled() const +{ + return mWindowRectScaled.getHeight(); } -void LLViewerWindow::setTopCtrl(LLUICtrl* new_top) -{ - gFocusMgr.setTopCtrl( new_top ); +S32 LLViewerWindow::getWindowWidthScaled() const +{ + return mWindowRectScaled.getWidth(); } -void LLViewerWindow::setupViewport(S32 x_offset, S32 y_offset) -{ - gGLViewport[0] = x_offset; - gGLViewport[1] = y_offset; - gGLViewport[2] = mWindowRect.getWidth(); - gGLViewport[3] = mWindowRect.getHeight(); - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); +S32 LLViewerWindow::getWindowHeightRaw() const +{ + return mWindowRectRaw.getHeight(); } -void LLViewerWindow::setup3DRender() -{ - gCamera->setPerspective(NOT_FOR_SELECTION, 0, 0, mWindowRect.getWidth(), mWindowRect.getHeight(), FALSE, gCamera->getNear(), MAX_FAR_CLIP*2.f); +S32 LLViewerWindow::getWindowWidthRaw() const +{ + return mWindowRectRaw.getWidth(); } void LLViewerWindow::setup2DRender() { - gl_state_for_2d(mWindowRect.getWidth(), mWindowRect.getHeight()); + // setup ortho camera + gl_state_for_2d(mWindowRectRaw.getWidth(), mWindowRectRaw.getHeight()); + setup2DViewport(); } -// Could cache the pointer from the last hitObjectOrLand here. -LLViewerObject *LLViewerWindow::lastObjectHit() +void LLViewerWindow::setup2DViewport(S32 x_offset, S32 y_offset) { - return gObjectList.findObject( gLastHitObjectID ); + 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]); } -const LLVector3d& LLViewerWindow::lastObjectHitOffset() -{ - return gLastHitObjectOffset; -} -// Could cache the pointer from the last hitObjectOrLand here. -LLViewerObject *LLViewerWindow::lastNonFloraObjectHit() +void LLViewerWindow::setup3DRender() { - return gObjectList.findObject( gLastHitNonFloraObjectID ); + // 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(); } -const LLVector3d& LLViewerWindow::lastNonFloraObjectHitOffset() +void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset) { - return gLastHitNonFloraObjectOffset; + if (LLRenderTarget::getCurrentBoundTarget() != NULL) + { + // don't use translation component of mWorldViewRectRaw, as we are already in a properly sized render target + gGLViewport[0] = x_offset; + gGLViewport[1] = y_offset; + } + else + { + 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::setShowProgress(const BOOL show) { if (mProgressView) @@ -4681,17 +4278,7 @@ BOOL LLViewerWindow::getShowProgress() const return (mProgressView && mProgressView->getVisible()); } - -void LLViewerWindow::moveProgressViewToFront() -{ - if( mProgressView && mRootView ) - { - mRootView->removeChild( mProgressView ); - mRootView->addChild( mProgressView ); - } -} - -void LLViewerWindow::setProgressString(const LLString& string) +void LLViewerWindow::setProgressString(const std::string& string) { if (mProgressView) { @@ -4699,7 +4286,7 @@ void LLViewerWindow::setProgressString(const LLString& string) } } -void LLViewerWindow::setProgressMessage(const LLString& msg) +void LLViewerWindow::setProgressMessage(const std::string& msg) { if(mProgressView) { @@ -4715,7 +4302,7 @@ void LLViewerWindow::setProgressPercent(const F32 percent) } } -void LLViewerWindow::setProgressCancelButtonVisible( BOOL b, const LLString& label ) +void LLViewerWindow::setProgressCancelButtonVisible( BOOL b, const std::string& label ) { if (mProgressView) { @@ -4739,6 +4326,10 @@ void LLViewerWindow::dumpState() 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) { llinfos << "Shutting down GL..." << llendl; @@ -4747,23 +4338,23 @@ void LLViewerWindow::stopGL(BOOL save_state) LLAppViewer::getTextureCache()->pause(); LLAppViewer::getImageDecodeThread()->pause(); LLAppViewer::getTextureFetch()->pause(); - + gSky.destroyGL(); - stop_glerror(); - - gImageList.destroyGL(save_state); - stop_glerror(); + stop_glerror(); + + LLManipTranslate::destroyGL() ; + stop_glerror(); gBumpImageList.destroyGL(); stop_glerror(); - LLFontGL::destroyGL(); + LLFontGL::destroyAllGL(); stop_glerror(); LLVOAvatar::destroyGL(); stop_glerror(); - LLDynamicTexture::destroyGL(); + LLViewerDynamicTexture::destroyGL(); stop_glerror(); if (gPipeline.isInit()) @@ -4776,37 +4367,53 @@ void LLViewerWindow::stopGL(BOOL save_state) gSphere.cleanupGL(); gCylinder.cleanupGL(); + if(gPostProcess) + { + gPostProcess->invalidate(); + } + + gTextureList.destroyGL(save_state); + stop_glerror(); + gGLManager.mIsDisabled = TRUE; stop_glerror(); - llinfos << "Remaining allocated texture memory: " << LLImageGL::sGlobalTextureMemory << " bytes" << llendl; + llinfos << "Remaining allocated texture memory: " << LLImageGL::sGlobalTextureMemoryInBytes << " bytes" << llendl; } } -void LLViewerWindow::restoreGL(const LLString& progress_message) +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) { llinfos << "Restoring GL..." << llendl; gGLManager.mIsDisabled = FALSE; - + + initGLDefaults(); + LLGLState::restoreGL(); + + gTextureList.restoreGL(); + // for future support of non-square pixels, and fonts that are properly stretched //LLFontGL::destroyDefaultFonts(); initFonts(); - initGLDefaults(); - LLGLState::restoreGL(); + gSky.restoreGL(); gPipeline.restoreGL(); LLDrawPoolWater::restoreGL(); LLManipTranslate::restoreGL(); - gImageList.restoreGL(); + gBumpImageList.restoreGL(); - LLDynamicTexture::restoreGL(); + LLViewerDynamicTexture::restoreGL(); LLVOAvatar::restoreGL(); - + gResizeScreenTexture = TRUE; - if (gFloaterCustomize && gFloaterCustomize->getVisible()) + if (isAgentAvatarValid() && !gAgentAvatarp->isUsingBakedTextures()) { LLVisualParamHint::requestHintUpdates(); } @@ -4819,104 +4426,47 @@ void LLViewerWindow::restoreGL(const LLString& progress_message) setProgressString(progress_message); } llinfos << "...Restoring GL done" << llendl; -#if LL_WINDOWS - if (SetUnhandledExceptionFilter(LLWinDebug::handleException) != LLWinDebug::handleException) + if(!LLAppViewer::instance()->restoreErrorTrap()) { - llwarns << " Someone took over my exception handler (post restoreGL)!" << llendl; + llwarns << " Someone took over my signal/exception handler (post restoreGL)!" << llendl; } -#endif } } void LLViewerWindow::initFonts(F32 zoom_factor) { - LLFontGL::destroyGL(); - LLFontGL::initDefaultFonts( gSavedSettings.getF32("FontScreenDPI"), + LLFontGL::destroyAllGL(); + // Initialize with possibly different zoom factor + LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"), mDisplayScale.mV[VX] * zoom_factor, mDisplayScale.mV[VY] * zoom_factor, - gSavedSettings.getString("FontMonospace"), - gSavedSettings.getF32("FontSizeMonospace"), - gSavedSettings.getString("FontSansSerif"), - gSavedSettings.getString("FontSansSerifFallback"), - gSavedSettings.getF32("FontSansSerifFallbackScale"), - gSavedSettings.getF32("FontSizeSmall"), - gSavedSettings.getF32("FontSizeMedium"), - gSavedSettings.getF32("FontSizeLarge"), - gSavedSettings.getF32("FontSizeHuge"), - gSavedSettings.getString("FontSansSerifBold"), - gSavedSettings.getF32("FontSizeMedium"), - gDirUtilp->getAppRODataDir() - ); -} -void LLViewerWindow::toggleFullscreen(BOOL show_progress) -{ - if (mWindow) - { - mWantFullscreen = mWindow->getFullscreen() ? FALSE : TRUE; - mShowFullscreenProgress = show_progress; - } + gDirUtilp->getAppRODataDir(), + LLUI::getXUIPaths()); + // Force font reloads, which can be very slow + LLFontGL::loadDefaultFonts(); } -void LLViewerWindow::getTargetWindow(BOOL& fullscreen, S32& width, S32& height) const +void LLViewerWindow::requestResolutionUpdate() { - fullscreen = mWantFullscreen; - - if (gViewerWindow->mWindow - && gViewerWindow->mWindow->getFullscreen() == mWantFullscreen) - { - width = gViewerWindow->getWindowDisplayWidth(); - height = gViewerWindow->getWindowDisplayHeight(); - } - else if (mWantFullscreen) - { - width = gSavedSettings.getS32("FullScreenWidth"); - height = gSavedSettings.getS32("FullScreenHeight"); - } - else - { - width = gSavedSettings.getS32("WindowWidth"); - height = gSavedSettings.getS32("WindowHeight"); - } + mResDirty = true; } - -BOOL LLViewerWindow::checkSettings() +void LLViewerWindow::checkSettings() { - BOOL is_fullscreen = gViewerWindow->mWindow->getFullscreen(); - if (is_fullscreen && !mWantFullscreen) + if (mStatesDirty) { - gViewerWindow->changeDisplaySettings(FALSE, - LLCoordScreen(gSavedSettings.getS32("WindowWidth"), - gSavedSettings.getS32("WindowHeight")), - TRUE, - mShowFullscreenProgress); - return TRUE; + gGL.refreshState(); + LLViewerShaderMgr::instance()->setShaders(); + mStatesDirty = false; } - else if (!is_fullscreen && mWantFullscreen) + + // We want to update the resolution AFTER the states getting refreshed not before. + if (mResDirty) { - if (!LLStartUp::canGoFullscreen()) - { - return FALSE; - } - -#ifndef LL_RELEASE_FOR_DOWNLOAD - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); -#endif - gViewerWindow->changeDisplaySettings(TRUE, - LLCoordScreen(gSavedSettings.getS32("FullScreenWidth"), - gSavedSettings.getS32("FullScreenHeight")), - gSavedSettings.getBOOL("DisableVerticalSync"), - mShowFullscreenProgress); - -#ifndef LL_RELEASE_FOR_DOWNLOAD - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); -#endif - return TRUE; - } - return FALSE; + reshape(getWindowWidthRaw(), getWindowHeightRaw()); + mResDirty = false; + } } void LLViewerWindow::restartDisplay(BOOL show_progress_bar) @@ -4925,7 +4475,7 @@ void LLViewerWindow::restartDisplay(BOOL show_progress_bar) stopGL(); if (show_progress_bar) { - restoreGL("Changing Resolution..."); + restoreGL(LLTrans::getString("ProgressChangingResolution")); } else { @@ -4933,45 +4483,35 @@ void LLViewerWindow::restartDisplay(BOOL show_progress_bar) } } -BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar) +BOOL LLViewerWindow::changeDisplaySettings(LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar) { - BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized"); - mWantFullscreen = fullscreen; - mShowFullscreenProgress = show_progress_bar; - gSavedSettings.setBOOL("FullScreen", mWantFullscreen); + //BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized"); + + //gResizeScreenTexture = TRUE; - gResizeScreenTexture = TRUE; + //U32 fsaa = gSavedSettings.getU32("RenderFSAASamples"); + //U32 old_fsaa = mWindow->getFSAASamples(); - BOOL old_fullscreen = mWindow->getFullscreen(); - if (!old_fullscreen && fullscreen && !LLStartUp::canGoFullscreen()) + // if not maximized, use the request size + if (!mWindow->getMaximized()) { - // we can't do this now, so do it later - - gSavedSettings.setS32("FullScreenWidth", size.mX); - gSavedSettings.setS32("FullScreenHeight", size.mY); - //gSavedSettings.setBOOL("DisableVerticalSync", disable_vsync); - - return TRUE; // a lie..., because we'll get to it later + mWindow->setSize(size); } - // going from windowed to windowed - if (!old_fullscreen && !fullscreen) + //if (fsaa == old_fsaa) { - // if not maximized, use the request size - if (!mWindow->getMaximized()) - { - mWindow->setSize(size); - } return TRUE; } +/* + // Close floaters that don't handle settings change - LLFloaterSnapshot::hide(0); + LLFloaterReg::hideInstance("snapshot"); BOOL result_first_try = FALSE; BOOL result_second_try = FALSE; - LLUICtrl* keyboard_focus = gFocusMgr.getKeyboardFocus(); + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); send_agent_pause(); llinfos << "Stopping GL during changeDisplaySettings" << llendl; stopGL(); @@ -4979,20 +4519,15 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, LLCoordScreen old_size; LLCoordScreen old_pos; mWindow->getSize(&old_size); - BOOL got_position = mWindow->getPosition(&old_pos); - if (!old_fullscreen && fullscreen && got_position) - { - // switching from windowed to fullscreen, so save window position - gSavedSettings.setS32("WindowX", old_pos.mX); - gSavedSettings.setS32("WindowY", old_pos.mY); - } - - result_first_try = mWindow->switchContext(fullscreen, size, disable_vsync); + //mWindow->setFSAASamples(fsaa); + + result_first_try = mWindow->switchContext(false, size, disable_vsync); if (!result_first_try) { // try to switch back - result_second_try = mWindow->switchContext(old_fullscreen, old_size, disable_vsync); + //mWindow->setFSAASamples(old_fsaa); + result_second_try = mWindow->switchContext(false, old_size, disable_vsync); if (!result_second_try) { @@ -5007,7 +4542,7 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, llinfos << "Restoring GL during resolution change" << llendl; if (show_progress_bar) { - restoreGL("Changing Resolution..."); + restoreGL(LLTrans::getString("ProgressChangingResolution")); } else { @@ -5016,27 +4551,16 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, if (!result_first_try) { - LLStringBase<char>::format_map_t args; - args["[RESX]"] = llformat("%d",size.mX); - args["[RESY]"] = llformat("%d",size.mY); - alertXml("ResolutionSwitchFail", args); + 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) - { -#if LL_WINDOWS - // Only trigger a reshape after switching to fullscreen; otherwise rely on the windows callback - // (otherwise size is wrong; this is the entire window size, reshape wants the visible window size) - if (fullscreen) -#endif - { - reshape(size.mX, size.mY); - } - } - if (!mWindow->getFullscreen() && success) + if (success) { // maximize window if was maximized, else reposition if (was_maximized) @@ -5054,75 +4578,16 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, mIgnoreActivate = FALSE; gFocusMgr.setKeyboardFocus(keyboard_focus); - mWantFullscreen = mWindow->getFullscreen(); - mShowFullscreenProgress = FALSE; return success; -} + */ +} -F32 LLViewerWindow::getDisplayAspectRatio() const +F32 LLViewerWindow::getWorldViewAspectRatio() const { - if (mWindow->getFullscreen()) - { - if (gSavedSettings.getBOOL("FullScreenAutoDetectAspectRatio")) - { - return mWindow->getNativeAspectRatio(); - } - else - { - return gSavedSettings.getF32("FullScreenAspectRatio"); - } - } - else - { - return mWindow->getNativeAspectRatio(); - } -} - - -void LLViewerWindow::drawPickBuffer() const -{ - if (mPickBuffer) - { - gGL.start(); - gGL.pushMatrix(); - LLGLDisable no_blend(GL_BLEND); - LLGLDisable no_alpha_test(GL_ALPHA_TEST); - LLGLSNoTexture no_texture; - glPixelZoom(10.f, 10.f); - glRasterPos2f(((F32)mPickPoint.mX * mDisplayScale.mV[VX] + 10.f), - ((F32)mPickPoint.mY * mDisplayScale.mV[VY] + 10.f)); - glDrawPixels(PICK_DIAMETER, PICK_DIAMETER, GL_RGBA, GL_UNSIGNED_BYTE, mPickBuffer); - glPixelZoom(1.f, 1.f); - gGL.color4fv(LLColor4::white.mV); - gl_rect_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] - (F32)(PICK_HALF_WIDTH)), - llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH)), - llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH)), - llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] - (F32)(PICK_HALF_WIDTH)), - FALSE); - gl_line_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] - (F32)(PICK_HALF_WIDTH)), - llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH)), - llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + 10.f), - llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_DIAMETER) * 10.f + 10.f)); - gl_line_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH)), - llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] - (F32)(PICK_HALF_WIDTH)), - llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_DIAMETER) * 10.f + 10.f), - llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + 10.f)); - gGL.translatef(10.f, 10.f, 0.f); - gl_rect_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX]), - llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_DIAMETER) * 10.f), - llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_DIAMETER) * 10.f), - llround((F32)mPickPoint.mY * mDisplayScale.mV[VY]), - FALSE); - gl_rect_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH + mPickOffset.mX)* 10.f), - llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH + mPickOffset.mY + 1) * 10.f), - llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH + mPickOffset.mX + 1) * 10.f), - llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH + mPickOffset.mY) * 10.f), - FALSE); - gGL.popMatrix(); - gGL.stop(); - } + F32 world_aspect = (F32)mWorldViewRectRaw.getWidth() / (F32)mWorldViewRectRaw.getHeight(); + return world_aspect; } void LLViewerWindow::calcDisplayScale() @@ -5130,27 +4595,13 @@ void LLViewerWindow::calcDisplayScale() F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor"); LLVector2 display_scale; display_scale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f)); - F32 height_normalization = gSavedSettings.getBOOL("UIAutoScale") ? ((F32)mWindowRect.getHeight() / display_scale.mV[VY]) / 768.f : 1.f; - if(mWindow->getFullscreen()) - { - display_scale *= (ui_scale_factor * height_normalization); - } - else - { - display_scale *= ui_scale_factor; - } + 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 (mWindow->getFullscreen()) - { - display_scale.mV[0] = llround(display_scale.mV[0], 2.0f/(F32) mWindowRect.getWidth()); - display_scale.mV[1] = llround(display_scale.mV[1], 2.0f/(F32) mWindowRect.getHeight()); - } if (display_scale != mDisplayScale) { @@ -5162,152 +4613,324 @@ void LLViewerWindow::calcDisplayScale() } } -//---------------------------------------------------------------------------- +//static +LLRect LLViewerWindow::calcScaledRect(const LLRect & rect, const LLVector2& display_scale) +{ + LLRect res = rect; + res.mLeft = llround((F32)res.mLeft / display_scale.mV[VX]); + res.mRight = llround((F32)res.mRight / display_scale.mV[VX]); + res.mBottom = llround((F32)res.mBottom / display_scale.mV[VY]); + res.mTop = llround((F32)res.mTop / display_scale.mV[VY]); -// static -bool LLViewerWindow::alertCallback(S32 modal) + return res; +} + +S32 LLViewerWindow::getChatConsoleBottomPad() { - if (gNoRender) + S32 offset = 0; + + if(LLBottomTray::instanceExists()) + offset += LLBottomTray::getInstance()->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) { - return false; + console_rect.mRight -= CONSOLE_PADDING_RIGHT; } else { -// if (modal) // we really always want to take you out of mouselook - { - // If we're in mouselook, the mouse is hidden and so the user can't click - // the dialog buttons. In that case, change to First Person instead. - if( gAgent.cameraMouselook() ) - { - gAgent.changeCameraToDefault(); - } - } - return true; + // Make console rect somewhat narrow so having inventory open is + // less of a problem. + console_rect.mRight = console_rect.mLeft + 2 * getWindowWidthScaled() / 3; } -} -LLAlertDialog* LLViewerWindow::alertXml(const std::string& xml_filename, - LLAlertDialog::alert_callback_t callback, void* user_data) -{ - LLString::format_map_t args; - return alertXml( xml_filename, args, callback, user_data ); + return console_rect; } +//---------------------------------------------------------------------------- + -LLAlertDialog* LLViewerWindow::alertXml(const std::string& xml_filename, const LLString::format_map_t& args, - LLAlertDialog::alert_callback_t callback, void* user_data) +//static +bool LLViewerWindow::onAlert(const LLSD& notify) { + LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); + if (gNoRender) { - llinfos << "Alert: " << xml_filename << llendl; - if (callback) - { - callback(-1, user_data); - } - return NULL; + llinfos << "Alert: " << notification->getName() << llendl; + notification->respond(LLSD::emptyMap()); + LLNotifications::instance().cancel(notification); + return false; } // If we're in mouselook, the mouse is hidden and so the user can't click // the dialog buttons. In that case, change to First Person instead. - if( gAgent.cameraMouselook() ) + if( gAgentCamera.cameraMouselook() ) { - gAgent.changeCameraToDefault(); + gAgentCamera.changeCameraToDefault(); } + return false; +} + +//////////////////////////////////////////////////////////////////////////// +// +// 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(), + mBinormal(), + mHUDIcon(NULL), + mPickTransparent(FALSE) +{ +} - // Note: object adds, removes, and destroys itself. - return LLAlertDialog::showXml( xml_filename, args, callback, user_data ); +LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos, + MASK keyboard_mask, + BOOL pick_transparent, + BOOL pick_uv_coords, + 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(), + mBinormal(), + mHUDIcon(NULL), + mPickTransparent(pick_transparent) +{ } -LLAlertDialog* LLViewerWindow::alertXmlEditText(const std::string& xml_filename, const LLString::format_map_t& args, - LLAlertDialog::alert_callback_t callback, void* user_data, - LLAlertDialog::alert_text_callback_t text_callback, void *text_data, - const LLString::format_map_t& edit_args, BOOL draw_asterixes) +void LLPickInfo::fetchResults() { - if (gNoRender) + + S32 face_hit = -1; + LLVector3 intersection, normal, binormal; + LLVector2 uv; + + LLHUDIcon* hit_icon = gViewerWindow->cursorIntersectIcon(mMousePt.mX, mMousePt.mY, 512.f, &intersection); + + F32 icon_dist = 0.f; + if (hit_icon) { - llinfos << "Alert: " << xml_filename << llendl; - if (callback) - { - callback(-1, user_data); - } - return NULL; + icon_dist = (LLViewerCamera::getInstance()->getOrigin()-intersection).magVec(); } + LLViewerObject* hit_object = gViewerWindow->cursorIntersect(mMousePt.mX, mMousePt.mY, 512.f, + NULL, -1, mPickTransparent, &face_hit, + &intersection, &uv, &normal, &binormal); + + mPickPt = mMousePt; - // If we're in mouselook, the mouse is hidden and so the user can't click - // the dialog buttons. In that case, change to First Person instead. - if( gAgent.cameraMouselook() ) + U32 te_offset = face_hit > -1 ? face_hit : 0; + + //unproject relative clicked coordinate from window coordinate using GL + + LLViewerObject* objectp = hit_object; + + if (hit_icon && + (!objectp || + icon_dist < (LLViewerCamera::getInstance()->getOrigin()-intersection).magVec())) { - gAgent.changeCameraToDefault(); + // was this name referring to a hud icon? + mHUDIcon = hit_icon; + mPickType = PICK_ICON; + mPosGlobal = mHUDIcon->getPositionGlobal(); } - - // Note: object adds, removes, and destroys itself. - LLAlertDialog* alert = LLAlertDialog::createXml( xml_filename, args, callback, user_data ); - if (alert) + else if (objectp) { - if (text_callback) + if( objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH ) { - alert->setEditTextCallback(text_callback, text_data); - } - alert->setEditTextArgs(edit_args); - alert->setDrawAsterixes(draw_asterixes); - alert->show(); - } - return alert; -} + // 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)) + { + // The selected point is beyond the draw distance or is otherwise + // not selectable. Return before calling mPickCallback(). + return; + } -LLBottomPanel::LLBottomPanel(const LLRect &rect) : - LLPanel("", rect, FALSE), - mIndicator(NULL) -{ - // bottom panel is focus root, so Tab moves through the toolbar and button bar, and overlay - setFocusRoot(TRUE); - // flag this panel as chrome so buttons don't grab keyboard focus - setIsChrome(TRUE); + // 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; + } + mObjectOffset = gAgentCamera.calcFocusOffset(objectp, intersection, mPickPt.mX, mPickPt.mY); + mObjectID = objectp->mID; + mObjectFace = (te_offset == NO_FACE) ? -1 : (S32)te_offset; - mFactoryMap["toolbar"] = LLCallbackMap(createToolBar, NULL); - mFactoryMap["overlay"] = LLCallbackMap(createOverlayBar, NULL); - mFactoryMap["hud"] = LLCallbackMap(createHUD, NULL); - gUICtrlFactory->buildPanel(this, "panel_bars.xml", &getFactoryMap()); + mPosGlobal = gAgent.getPosGlobalFromAgent(intersection); + + if (mWantSurfaceInfo) + { + getSurfaceInfo(); + } + } + } - setOrigin(rect.mLeft, rect.mBottom); - reshape(rect.getWidth(), rect.getHeight()); + if (mPickCallback) + { + mPickCallback(*this); + } } -void LLBottomPanel::setFocusIndicator(LLView * indicator) +LLPointer<LLViewerObject> LLPickInfo::getObject() const { - mIndicator = indicator; + return gObjectList.findObject( mObjectID ); } -void LLBottomPanel::draw() +void LLPickInfo::updateXYCoords() { - if(mIndicator) + if (mObjectFace > -1) { - BOOL hasFocus = gFocusMgr.childHasKeyboardFocus(this); - mIndicator->setVisible(hasFocus); - mIndicator->setEnabled(hasFocus); + 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 = llround(mUVCoords.mV[VX] * (F32)imagep->getWidth()); + mXYCoords.mY = llround((1.f - mUVCoords.mV[VY]) * (F32)imagep->getHeight()); + } } - LLPanel::draw(); } -void* LLBottomPanel::createHUD(void* data) +void LLPickInfo::getSurfaceInfo() { - delete gHUDView; - gHUDView = new LLHUDView(); - return gHUDView; + // 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); + + LLViewerObject* objectp = getObject(); + + if (objectp) + { + if (gViewerWindow->cursorIntersect(llround((F32)mMousePt.mX), llround((F32)mMousePt.mY), 1024.f, + objectp, -1, mPickTransparent, + &mObjectFace, + &mIntersection, + &mSTCoords, + &mNormal, + &mBinormal)) + { + // if we succeeded with the intersect above, compute the texture coordinates: + + if (objectp->mDrawable.notNull() && mObjectFace > -1) + { + LLFace* facep = objectp->mDrawable->getFace(mObjectFace); + + mUVCoords = facep->surfaceToTexture(mSTCoords, mIntersection, mNormal); + } + + // and XY coords: + updateXYCoords(); + + } + } } -void* LLBottomPanel::createOverlayBar(void* data) +/* code to get UV via a special UV render - removed in lieu of raycast method +LLVector2 LLPickInfo::pickUV() { - delete gOverlayBar; - gOverlayBar = new LLOverlayBar(); - return gOverlayBar; -} + LLVector2 result(-1.f, -1.f); + + LLViewerObject* objectp = getObject(); + if (!objectp) + { + return result; + } + + if (mObjectFace > -1 && + objectp->mDrawable.notNull() && objectp->getPCode() == LL_PCODE_VOLUME && + mObjectFace < objectp->mDrawable->getNumFaces()) + { + S32 scaled_x = llround((F32)mPickPt.mX * gViewerWindow->getDisplayScale().mV[VX]); + S32 scaled_y = llround((F32)mPickPt.mY * gViewerWindow->getDisplayScale().mV[VY]); + const S32 UV_PICK_WIDTH = 5; + const S32 UV_PICK_HALF_WIDTH = (UV_PICK_WIDTH - 1) / 2; + U8 uv_pick_buffer[UV_PICK_WIDTH * UV_PICK_WIDTH * 4]; + LLFace* facep = objectp->mDrawable->getFace(mObjectFace); + if (facep) + { + LLGLState scissor_state(GL_SCISSOR_TEST); + scissor_state.enable(); + LLViewerCamera::getInstance()->setPerspective(FOR_SELECTION, scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, FALSE); + //glViewport(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH); + glScissor(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH); + + glClear(GL_DEPTH_BUFFER_BIT); -void* LLBottomPanel::createToolBar(void* data) + facep->renderSelectedUV(); + + glReadPixels(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, GL_RGBA, GL_UNSIGNED_BYTE, uv_pick_buffer); + U8* center_pixel = &uv_pick_buffer[4 * ((UV_PICK_WIDTH * UV_PICK_HALF_WIDTH) + UV_PICK_HALF_WIDTH + 1)]; + + result.mV[VX] = (F32)((center_pixel[VGREEN] & 0xf) + (16.f * center_pixel[VRED])) / 4095.f; + result.mV[VY] = (F32)((center_pixel[VGREEN] >> 4) + (16.f * center_pixel[VBLUE])) / 4095.f; + } + } + + return result; +} */ + + +//static +bool LLPickInfo::isFlora(LLViewerObject* object) { - delete gToolBar; - gToolBar = new LLToolBar(); - return gToolBar; + 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; } |