diff options
author | Nyx (Neal Orman) <nyx@lindenlab.com> | 2012-01-27 15:09:20 -0500 |
---|---|---|
committer | Nyx (Neal Orman) <nyx@lindenlab.com> | 2012-01-27 15:09:20 -0500 |
commit | f19a77047d10eca2bff07891375b7859b9e68e99 (patch) | |
tree | e1785f17d278baae42e16047ff9e163af9eba6dd | |
parent | 78e96466cbb7ec054ff11a211dc6734ba317cb0f (diff) |
PATH-192 FIX fixed last issues with convex decomp merge
-rw-r--r-- | autobuild.xml | 8 | ||||
-rw-r--r-- | indra/cmake/LLPhysicsExtensions.cmake | 21 | ||||
-rw-r--r-- | indra/newview/llappviewer.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llfloaterpathfindingconsole.cpp | 1242 | ||||
-rw-r--r-- | indra/newview/llfloaterpathfindingconsole.h | 302 | ||||
-rw-r--r-- | indra/newview/llnavmeshstation.cpp | 2 | ||||
-rw-r--r-- | indra/newview/llviewerdisplay.cpp | 3208 | ||||
-rw-r--r-- | indra/newview/llviewerwindow.cpp | 10572 | ||||
-rw-r--r-- | indra/newview/pipeline.cpp | 19612 |
9 files changed, 17487 insertions, 17484 deletions
diff --git a/autobuild.xml b/autobuild.xml index ac4735ce44..2ff33714b1 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1110,9 +1110,9 @@ <key>archive</key> <map> <key>hash</key> - <string>49f3d038379af818f9fc8f57cc4e313f</string> + <string>e26b6d955394e079a151ad3b0d7d5c90</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/stinson_llpathinglibrary/rev/248427/arch/Linux/installer/llphysicsextensions-0.1-linux-20120126.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/stinson_llpathinglibrary/rev/248566/arch/Linux/installer/llphysicsextensions-0.1-linux-20120127.tar.bz2</string> </map> <key>name</key> <string>linux</string> @@ -1122,9 +1122,9 @@ <key>archive</key> <map> <key>hash</key> - <string>573a0daa04bde79bd7b7b338984dfbf3</string> + <string>0afb3d1e08c56c74db31ae3e78640abc</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/stinson_llpathinglibrary/rev/248427/arch/CYGWIN/installer/llphysicsextensions-0.1-windows-20120125.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/stinson_llpathinglibrary/rev/248567/arch/CYGWIN/installer/llphysicsextensions-0.1-windows-20120127.tar.bz2</string> </map> <key>name</key> <string>windows</string> diff --git a/indra/cmake/LLPhysicsExtensions.cmake b/indra/cmake/LLPhysicsExtensions.cmake index 598ac72849..53972e050a 100644 --- a/indra/cmake/LLPhysicsExtensions.cmake +++ b/indra/cmake/LLPhysicsExtensions.cmake @@ -1,14 +1,21 @@ # -*- cmake -*- include(Prebuilt) -use_prebuilt_binary(llphysicsextensions) +if (INSTALL_PROPRIETARY AND NOT STANDALONE) + use_prebuilt_binary(llphysicsextensions) + set(LLPHYSICS_EXTENSIONS_LIB_NAME llphysicsextensions) +else (INSTALL_PROPRIETARY AND NOT STANDALONE) + use_prebuilt_binary(llphysicsextensionsstub) + set(LLPHYSICS_EXTENSIONS_LIB_NAME llphysicsextensionsstub) +endif (INSTALL_PROPRIETARY AND NOT STANDALONE) + set(LLPHYSICS_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/lib/include) set(LLPHYSICS_DEBUG_LIBRARY_PATH ${LIBS_PREBUILT_DIR}/lib/debug) set(LLPHYSICS_RELEASE_LIBRARY_PATH ${LIBS_PREBUILT_DIR}/lib/release) -find_library(LL_PHYSICS_DEBUG_LIB llphysicsextensions PATHS ${LLPHYSICS_DEBUG_LIBRARY_PATH}) -find_library(LL_PHYSICS_RELEASE_LIB llphysicsextensions PATHS ${LLPHYSICS_RELEASE_LIBRARY_PATH}) +find_library(LL_PHYSICS_DEBUG_LIB ${LLPHYSICS_EXTENSIONS_LIB_NAME} PATHS ${LLPHYSICS_DEBUG_LIBRARY_PATH}) +find_library(LL_PHYSICS_RELEASE_LIB ${LLPHYSICS_EXTENSIONS_LIB_NAME} PATHS ${LLPHYSICS_RELEASE_LIBRARY_PATH}) set(LLPHYSICS_LIBRARIES @@ -21,11 +28,3 @@ if (LINUX) list(APPEND LLPHYSICS_LIBRARIES -Wl,--end-group) endif (LINUX) -# if (INSTALL_PROPRIETARY AND NOT STANDALONE) -# use_prebuilt_binary(llconvexdecomposition) -# set(LLCONVEXDECOMP_LIBRARY llconvexdecomposition) -# else (INSTALL_PROPRIETARY AND NOT STANDALONE) -# use_prebuilt_binary(llconvexdecompositionstub) -# set(LLCONVEXDECOMP_LIBRARY llconvexdecompositionstub) -# endif (INSTALL_PROPRIETARY AND NOT STANDALONE) - diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index a455d359bf..85e6cd3d3f 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -106,6 +106,7 @@ #include "llvfsthread.h" #include "llvolumemgr.h" #include "llxfermanager.h" +#include "llphysicsextensions.h" #include "llnotificationmanager.h" #include "llnotifications.h" @@ -1543,6 +1544,9 @@ bool LLAppViewer::cleanup() // shut down mesh streamer gMeshRepo.shutdown(); + // shut down Havok + LLPhysicsExtensions::quitSystem(); + // Must clean up texture references before viewer window is destroyed. if(LLHUDManager::instanceExists()) { diff --git a/indra/newview/llfloaterpathfindingconsole.cpp b/indra/newview/llfloaterpathfindingconsole.cpp index 772f42860f..fce67c4171 100644 --- a/indra/newview/llfloaterpathfindingconsole.cpp +++ b/indra/newview/llfloaterpathfindingconsole.cpp @@ -1,621 +1,621 @@ -/**
-* @file llfloaterpathfindingconsole.cpp
-* @author William Todd Stinson
-* @brief "Pathfinding console" floater, allowing manipulation of the Havok AI pathfinding settings.
-*
-* $LicenseInfo:firstyear=2002&license=viewerlgpl$
-* Second Life Viewer Source Code
-* Copyright (C) 2010, Linden Research, Inc.
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU Lesser General Public
-* License as published by the Free Software Foundation;
-* version 2.1 of the License only.
-*
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public
-* License along with this library; if not, write to the Free Software
-* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-*
-* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
-* $/LicenseInfo$
-*/
-
-#include "llviewerprecompiledheaders.h"
-#include "llfloaterpathfindingconsole.h"
-#include "llfloaterpathfindinglinksets.h"
-
-#include "llsd.h"
-#include "llagent.h"
-#include "llbutton.h"
-#include "llradiogroup.h"
-#include "llsliderctrl.h"
-#include "lllineeditor.h"
-#include "lltextbase.h"
-#include "lltextvalidate.h"
-#include "llnavmeshstation.h"
-#include "llviewerregion.h"
-
-#include "llphysicsextensions.h"
-
-#define XUI_RENDER_OVERLAY_ON_FIXED_PHYSICS_GEOMETRY 1
-#define XUI_RENDER_OVERLAY_ON_ALL_RENDERABLE_GEOMETRY 2
-
-#define XUI_PATH_SELECT_NONE 0
-#define XUI_PATH_SELECT_START_POINT 1
-#define XUI_PATH_SELECT_END_POINT 2
-
-#define XUI_CHARACTER_TYPE_A 1
-#define XUI_CHARACTER_TYPE_B 2
-#define XUI_CHARACTER_TYPE_C 3
-#define XUI_CHARACTER_TYPE_D 4
-
-const int CURRENT_REGION = 99;
-const int MAX_OBSERVERS = 10;
-//---------------------------------------------------------------------------
-// LLFloaterPathfindingConsole
-//---------------------------------------------------------------------------
-
-BOOL LLFloaterPathfindingConsole::postBuild()
-{
- childSetAction("view_and_edit_linksets", boost::bind(&LLFloaterPathfindingConsole::onViewEditLinksetClicked, this));
- childSetAction("rebuild_navmesh", boost::bind(&LLFloaterPathfindingConsole::onRebuildNavMeshClicked, this));
- childSetAction("refresh_navmesh", boost::bind(&LLFloaterPathfindingConsole::onRefreshNavMeshClicked, this));
-
- mShowNavMeshCheckBox = findChild<LLCheckBoxCtrl>("show_navmesh_overlay");
- llassert(mShowNavMeshCheckBox != NULL);
- mShowNavMeshCheckBox->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onShowNavMeshToggle, this));
-
- mShowExcludeVolumesCheckBox = findChild<LLCheckBoxCtrl>("show_exclusion_volumes");
- llassert(mShowExcludeVolumesCheckBox != NULL);
- mShowExcludeVolumesCheckBox->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onShowExcludeVolumesToggle, this));
-
- mShowPathCheckBox = findChild<LLCheckBoxCtrl>("show_path");
- llassert(mShowPathCheckBox != NULL);
- mShowPathCheckBox->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onShowPathToggle, this));
-
- mShowWaterPlaneCheckBox = findChild<LLCheckBoxCtrl>("show_water_plane");
- llassert(mShowWaterPlaneCheckBox != NULL);
- mShowWaterPlaneCheckBox->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onShowWaterPlaneToggle, this));
-
- mRegionOverlayDisplayRadioGroup = findChild<LLRadioGroup>("region_overlay_display");
- llassert(mRegionOverlayDisplayRadioGroup != NULL);
- mRegionOverlayDisplayRadioGroup->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onRegionOverlayDisplaySwitch, this));
-
- mPathSelectionRadioGroup = findChild<LLRadioGroup>("path_selection");
- llassert(mPathSelectionRadioGroup != NULL);
- mPathSelectionRadioGroup ->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onPathSelectionSwitch, this));
-
- mCharacterWidthSlider = findChild<LLSliderCtrl>("character_width");
- llassert(mCharacterWidthSlider != NULL);
- mCharacterWidthSlider->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onCharacterWidthSet, this));
-
- mCharacterTypeRadioGroup = findChild<LLRadioGroup>("character_type");
- llassert(mCharacterTypeRadioGroup != NULL);
- mCharacterTypeRadioGroup->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onCharacterTypeSwitch, this));
-
- mPathfindingStatus = findChild<LLTextBase>("pathfinding_status");
- llassert(mPathfindingStatus != NULL);
-
- mTerrainMaterialA = findChild<LLLineEditor>("terrain_material_a");
- llassert(mTerrainMaterialA != NULL);
- mTerrainMaterialA->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onTerrainMaterialASet, this));
- mTerrainMaterialA->setPrevalidate(LLTextValidate::validateFloat);
-
- mTerrainMaterialB = findChild<LLLineEditor>("terrain_material_b");
- llassert(mTerrainMaterialB != NULL);
- mTerrainMaterialB->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onTerrainMaterialBSet, this));
- mTerrainMaterialB->setPrevalidate(LLTextValidate::validateFloat);
-
- mTerrainMaterialC = findChild<LLLineEditor>("terrain_material_c");
- llassert(mTerrainMaterialC != NULL);
- mTerrainMaterialC->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onTerrainMaterialCSet, this));
- mTerrainMaterialC->setPrevalidate(LLTextValidate::validateFloat);
-
- mTerrainMaterialD = findChild<LLLineEditor>("terrain_material_d");
- llassert(mTerrainMaterialD != NULL);
- mTerrainMaterialD->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onTerrainMaterialDSet, this));
- mTerrainMaterialD->setPrevalidate(LLTextValidate::validateFloat);
-
- return LLFloater::postBuild();
-}
-
-LLFloaterPathfindingConsole::ERegionOverlayDisplay LLFloaterPathfindingConsole::getRegionOverlayDisplay() const
-{
- ERegionOverlayDisplay regionOverlayDisplay;
- switch (mRegionOverlayDisplayRadioGroup->getValue().asInteger())
- {
- case XUI_RENDER_OVERLAY_ON_FIXED_PHYSICS_GEOMETRY :
- regionOverlayDisplay = kRenderOverlayOnFixedPhysicsGeometry;
- break;
- case XUI_RENDER_OVERLAY_ON_ALL_RENDERABLE_GEOMETRY :
- regionOverlayDisplay = kRenderOverlayOnAllRenderableGeometry;
- break;
- default :
- regionOverlayDisplay = kRenderOverlayOnFixedPhysicsGeometry;
- llassert(0);
- break;
- }
-
- return regionOverlayDisplay;
-}
-
-void LLFloaterPathfindingConsole::setRegionOverlayDisplay(ERegionOverlayDisplay pRegionOverlayDisplay)
-{
- LLSD radioGroupValue;
-
- switch (pRegionOverlayDisplay)
- {
- case kRenderOverlayOnFixedPhysicsGeometry :
- radioGroupValue = XUI_RENDER_OVERLAY_ON_FIXED_PHYSICS_GEOMETRY;
- break;
- case kRenderOverlayOnAllRenderableGeometry :
- radioGroupValue = XUI_RENDER_OVERLAY_ON_ALL_RENDERABLE_GEOMETRY;
- break;
- default :
- radioGroupValue = XUI_RENDER_OVERLAY_ON_FIXED_PHYSICS_GEOMETRY;
- llassert(0);
- break;
- }
-
- mRegionOverlayDisplayRadioGroup->setValue(radioGroupValue);
-}
-
-LLFloaterPathfindingConsole::EPathSelectionState LLFloaterPathfindingConsole::getPathSelectionState() const
-{
- EPathSelectionState pathSelectionState;
-
- switch (mPathSelectionRadioGroup->getValue().asInteger())
- {
- case XUI_PATH_SELECT_START_POINT :
- pathSelectionState = kPathSelectStartPoint;
- break;
- case XUI_PATH_SELECT_END_POINT :
- pathSelectionState = kPathSelectEndPoint;
- break;
- default :
- pathSelectionState = kPathSelectNone;
- break;
- }
-
- return pathSelectionState;
-}
-
-void LLFloaterPathfindingConsole::setPathSelectionState(EPathSelectionState pPathSelectionState)
-{
- LLSD radioGroupValue;
-
- switch (pPathSelectionState)
- {
- case kPathSelectStartPoint :
- radioGroupValue = XUI_PATH_SELECT_START_POINT;
- break;
- case kPathSelectEndPoint :
- radioGroupValue = XUI_PATH_SELECT_END_POINT;
- break;
- default :
- radioGroupValue = XUI_PATH_SELECT_NONE;
- break;
- }
-
- mPathSelectionRadioGroup->setValue(radioGroupValue);
-}
-
-F32 LLFloaterPathfindingConsole::getCharacterWidth() const
-{
- return mCharacterWidthSlider->getValueF32();
-}
-
-void LLFloaterPathfindingConsole::setCharacterWidth(F32 pCharacterWidth)
-{
- mCharacterWidthSlider->setValue(LLSD(pCharacterWidth));
-}
-
-LLFloaterPathfindingConsole::ECharacterType LLFloaterPathfindingConsole::getCharacterType() const
-{
- ECharacterType characterType;
-
- switch (mCharacterTypeRadioGroup->getValue().asInteger())
- {
- case XUI_CHARACTER_TYPE_A :
- characterType = kCharacterTypeA;
- break;
- case XUI_CHARACTER_TYPE_B :
- characterType = kCharacterTypeB;
- break;
- case XUI_CHARACTER_TYPE_C :
- characterType = kCharacterTypeC;
- break;
- case XUI_CHARACTER_TYPE_D :
- characterType = kCharacterTypeD;
- break;
- default :
- characterType = kCharacterTypeA;
- llassert(0);
- break;
- }
-
- return characterType;
-}
-
-void LLFloaterPathfindingConsole::setCharacterType(ECharacterType pCharacterType)
-{
- LLSD radioGroupValue;
-
- switch (pCharacterType)
- {
- case kCharacterTypeA :
- radioGroupValue = XUI_CHARACTER_TYPE_A;
- break;
- case kCharacterTypeB :
- radioGroupValue = XUI_CHARACTER_TYPE_B;
- break;
- case kCharacterTypeC :
- radioGroupValue = XUI_CHARACTER_TYPE_C;
- break;
- case kCharacterTypeD :
- radioGroupValue = XUI_CHARACTER_TYPE_D;
- break;
- default :
- radioGroupValue = XUI_CHARACTER_TYPE_A;
- llassert(0);
- break;
- }
-
- mCharacterTypeRadioGroup->setValue(radioGroupValue);
-}
-
-F32 LLFloaterPathfindingConsole::getTerrainMaterialA() const
-{
- return mTerrainMaterialA->getValue().asReal();
-}
-
-void LLFloaterPathfindingConsole::setTerrainMaterialA(F32 pTerrainMaterial)
-{
- mTerrainMaterialA->setValue(LLSD(pTerrainMaterial));
-}
-
-F32 LLFloaterPathfindingConsole::getTerrainMaterialB() const
-{
- return mTerrainMaterialB->getValue().asReal();
-}
-
-void LLFloaterPathfindingConsole::setTerrainMaterialB(F32 pTerrainMaterial)
-{
- mTerrainMaterialB->setValue(LLSD(pTerrainMaterial));
-}
-
-F32 LLFloaterPathfindingConsole::getTerrainMaterialC() const
-{
- return mTerrainMaterialC->getValue().asReal();
-}
-
-void LLFloaterPathfindingConsole::setTerrainMaterialC(F32 pTerrainMaterial)
-{
- mTerrainMaterialC->setValue(LLSD(pTerrainMaterial));
-}
-
-F32 LLFloaterPathfindingConsole::getTerrainMaterialD() const
-{
- return mTerrainMaterialD->getValue().asReal();
-}
-
-void LLFloaterPathfindingConsole::setTerrainMaterialD(F32 pTerrainMaterial)
-{
- mTerrainMaterialD->setValue(LLSD(pTerrainMaterial));
-}
-
-void LLFloaterPathfindingConsole::setHasNavMeshReceived()
-{
- std::string str = getString("navmesh_fetch_complete_available");
- mPathfindingStatus->setText((LLStringExplicit)str);
-}
-
-void LLFloaterPathfindingConsole::setHasNoNavMesh()
-{
- std::string str = getString("navmesh_fetch_complete_none");
- mPathfindingStatus->setText((LLStringExplicit)str);
-}
-
-LLFloaterPathfindingConsole::LLFloaterPathfindingConsole(const LLSD& pSeed)
- : LLFloater(pSeed),
- mShowNavMeshCheckBox(NULL),
- mShowExcludeVolumesCheckBox(NULL),
- mShowPathCheckBox(NULL),
- mShowWaterPlaneCheckBox(NULL),
- mRegionOverlayDisplayRadioGroup(NULL),
- mPathSelectionRadioGroup(NULL),
- mCharacterWidthSlider(NULL),
- mCharacterTypeRadioGroup(NULL),
- mPathfindingStatus(NULL),
- mTerrainMaterialA(NULL),
- mTerrainMaterialB(NULL),
- mTerrainMaterialC(NULL),
- mTerrainMaterialD(NULL)
-{
- for (int i=0;i<MAX_OBSERVERS;++i)
- {
- mNavMeshDownloadObserver[i].setPathfindingConsole(this);
- }
-}
-
-LLFloaterPathfindingConsole::~LLFloaterPathfindingConsole()
-{
-}
-
-void LLFloaterPathfindingConsole::onOpen(const LLSD& pKey)
-{
- //make sure we have a pathing system
- if ( !LLPathingLib::getInstance() )
- {
- LLPathingLib::initSystem();
- }
- //prep# test remove
- //LLSD content;
- //LLPathingLib::getInstance()->extractNavMeshSrcFromLLSD( content );
- //return true;
- //prep# end test
- if ( LLPathingLib::getInstance() == NULL )
- {
- std::string str = getString("navmesh_library_not_implemented");
- LLStyle::Params styleParams;
- styleParams.color = LLUIColorTable::instance().getColor("DrYellow");
- mPathfindingStatus->setText((LLStringExplicit)str, styleParams);
- llwarns <<"Errror: cannout find pathing library implementation."<<llendl;
- }
- else
- {
- mCurrentMDO = 0;
- //make sure the region is essentially enabled for navmesh support
- std::string capability = "RetrieveNavMeshSrc";
-
- //prep# neighboring navmesh support proto
- LLViewerRegion* pCurrentRegion = gAgent.getRegion();
- std::vector<LLViewerRegion*> regions;
- regions.push_back( pCurrentRegion );
- //pCurrentRegion->getNeighboringRegions( regions );
-
- std::vector<int> shift;
- shift.push_back( CURRENT_REGION );
- //pCurrentRegion->getNeighboringRegionsStatus( shift );
-
- int regionCnt = regions.size();
- for ( int i=0; i<regionCnt; ++i )
- {
- std::string url = regions[i]->getCapability( capability );
-
- if ( !url.empty() )
- {
- std::string str = getString("navmesh_fetch_inprogress");
- mPathfindingStatus->setText((LLStringExplicit)str);
- LLNavMeshStation::getInstance()->setNavMeshDownloadURL( url );
- int dir = shift[i];
- LLNavMeshStation::getInstance()->downloadNavMeshSrc( mNavMeshDownloadObserver[mCurrentMDO].getObserverHandle(), dir );
- ++mCurrentMDO;
- }
- else
- {
- std::string str = getString("navmesh_region_not_enabled");
- LLStyle::Params styleParams;
- styleParams.color = LLUIColorTable::instance().getColor("DrYellow");
- mPathfindingStatus->setText((LLStringExplicit)str, styleParams);
- llinfos<<"Region has does not required caps of type ["<<capability<<"]"<<llendl;
- }
- }
- }
-}
-
-void LLFloaterPathfindingConsole::onShowNavMeshToggle()
-{
- BOOL checkBoxValue = mShowNavMeshCheckBox->get();
-
- LLPathingLib *llPathingLibInstance = LLPathingLib::getInstance();
- if (llPathingLibInstance != NULL)
- {
- llPathingLibInstance->setRenderNavMesh(checkBoxValue);
- }
- else
- {
- mShowNavMeshCheckBox->set(FALSE);
- llwarns << "cannot find LLPathingLib instance" << llendl;
- }
-}
-
-void LLFloaterPathfindingConsole::onShowExcludeVolumesToggle()
-{
- BOOL checkBoxValue = mShowExcludeVolumesCheckBox->get();
-
- LLPathingLib *llPathingLibInstance = LLPathingLib::getInstance();
- if (llPathingLibInstance != NULL)
- {
- llPathingLibInstance->setRenderNavMeshandShapes(checkBoxValue);
- }
- else
- {
- mShowExcludeVolumesCheckBox->set(FALSE);
- llwarns << "cannot find LLPathingLib instance" << llendl;
- }
-}
-
-void LLFloaterPathfindingConsole::onShowPathToggle()
-{
- BOOL checkBoxValue = mShowPathCheckBox->get();
-
- llwarns << "functionality has not yet been implemented to toggle '"
- << mShowPathCheckBox->getLabel() << "' to "
- << (checkBoxValue ? "ON" : "OFF") << llendl;
-}
-
-void LLFloaterPathfindingConsole::onShowWaterPlaneToggle()
-{
- BOOL checkBoxValue = mShowWaterPlaneCheckBox->get();
-
- llwarns << "functionality has not yet been implemented to toggle '"
- << mShowWaterPlaneCheckBox->getLabel() << "' to "
- << (checkBoxValue ? "ON" : "OFF") << llendl;
-}
-
-void LLFloaterPathfindingConsole::onRegionOverlayDisplaySwitch()
-{
- switch (getRegionOverlayDisplay())
- {
- case kRenderOverlayOnFixedPhysicsGeometry :
- llwarns << "functionality has not yet been implemented to toggle '"
- << mRegionOverlayDisplayRadioGroup->getName() << "' to RenderOverlayOnFixedPhysicsGeometry"
- << llendl;
- break;
- case kRenderOverlayOnAllRenderableGeometry :
- llwarns << "functionality has not yet been implemented to toggle '"
- << mRegionOverlayDisplayRadioGroup->getName() << "' to RenderOverlayOnAllRenderableGeometry"
- << llendl;
- break;
- default :
- llassert(0);
- break;
- }
-}
-
-void LLFloaterPathfindingConsole::onPathSelectionSwitch()
-{
- switch (getPathSelectionState())
- {
- case kPathSelectNone :
- llwarns << "functionality has not yet been implemented to toggle '"
- << mPathSelectionRadioGroup->getName() << "' to PathSelectNone"
- << llendl;
- break;
- case kPathSelectStartPoint :
- llwarns << "functionality has not yet been implemented to toggle '"
- << mPathSelectionRadioGroup->getName() << "' to PathSelectStartPoint"
- << llendl;
- break;
- case kPathSelectEndPoint :
- llwarns << "functionality has not yet been implemented to toggle '"
- << mPathSelectionRadioGroup->getName() << "' to PathSelectEndPoint"
- << llendl;
- break;
- default :
- llassert(0);
- break;
- }
-}
-
-void LLFloaterPathfindingConsole::onCharacterWidthSet()
-{
- F32 characterWidth = getCharacterWidth();
- llwarns << "functionality has not yet been implemented to set '" << mCharacterWidthSlider->getName()
- << "' to the value (" << characterWidth << ")" << llendl;
-}
-
-void LLFloaterPathfindingConsole::onCharacterTypeSwitch()
-{
- switch (getCharacterType())
- {
- case kCharacterTypeA :
- llwarns << "functionality has not yet been implemented to toggle '"
- << mCharacterTypeRadioGroup->getName() << "' to CharacterTypeA"
- << llendl;
- break;
- case kCharacterTypeB :
- llwarns << "functionality has not yet been implemented to toggle '"
- << mCharacterTypeRadioGroup->getName() << "' to CharacterTypeB"
- << llendl;
- break;
- case kCharacterTypeC :
- llwarns << "functionality has not yet been implemented to toggle '"
- << mCharacterTypeRadioGroup->getName() << "' to CharacterTypeC"
- << llendl;
- break;
- case kCharacterTypeD :
- llwarns << "functionality has not yet been implemented to toggle '"
- << mCharacterTypeRadioGroup->getName() << "' to CharacterTypeD"
- << llendl;
- break;
- default :
- llassert(0);
- break;
- }
-
-}
-
-void LLFloaterPathfindingConsole::onViewEditLinksetClicked()
-{
- LLFloaterPathfindingLinksets::openLinksetsEditor();
-}
-
-void LLFloaterPathfindingConsole::onRebuildNavMeshClicked()
-{
- llwarns << "functionality has not yet been implemented to handle rebuilding of the navmesh" << llendl;
-}
-
-void LLFloaterPathfindingConsole::onRefreshNavMeshClicked()
-{
- llwarns << "functionality has not yet been implemented to handle refreshing of the navmesh" << llendl;
-}
-
-void LLFloaterPathfindingConsole::onTerrainMaterialASet()
-{
- F32 terrainMaterial = getTerrainMaterialA();
- llwarns << "functionality has not yet been implemented to setting '" << mTerrainMaterialA->getName()
- << "' to value (" << terrainMaterial << ")" << llendl;
-}
-
-void LLFloaterPathfindingConsole::onTerrainMaterialBSet()
-{
- F32 terrainMaterial = getTerrainMaterialB();
- llwarns << "functionality has not yet been implemented to setting '" << mTerrainMaterialB->getName()
- << "' to value (" << terrainMaterial << ")" << llendl;
-}
-
-void LLFloaterPathfindingConsole::onTerrainMaterialCSet()
-{
- F32 terrainMaterial = getTerrainMaterialC();
- llwarns << "functionality has not yet been implemented to setting '" << mTerrainMaterialC->getName()
- << "' to value (" << terrainMaterial << ")" << llendl;
-}
-
-void LLFloaterPathfindingConsole::onTerrainMaterialDSet()
-{
- F32 terrainMaterial = getTerrainMaterialD();
- llwarns << "functionality has not yet been implemented to setting '" << mTerrainMaterialD->getName()
- << "' to value (" << terrainMaterial << ")" << llendl;
-}
-
-
-BOOL LLFloaterPathfindingConsole::allowAllRenderables() const
-{
- return getRegionOverlayDisplay() == kRenderOverlayOnAllRenderableGeometry ? true : false;
-}
-
-void LLFloaterPathfindingConsole::providePathingData( const LLVector3& point1, const LLVector3& point2 )
-{
- switch (getPathSelectionState())
- {
- case kPathSelectNone :
- llwarns << "not yet been implemented to toggle '"
- << mPathSelectionRadioGroup->getName() << "' to PathSelectNone"
- << llendl;
- break;
-
- case kPathSelectStartPoint :
- mPathData.mStartPointA = point1;
- mPathData.mEndPointA = point2;
- break;
-
- case kPathSelectEndPoint :
- mPathData.mStartPointB = point1;
- mPathData.mEndPointB = point2;
- mPathData.mCharacterWidth = getCharacterWidth();
- //prep#TODO# possibly consider an alternate behavior - perhaps add a "path" button to submit the data.
- LLPathingLib::getInstance()->generatePath( mPathData );
- break;
-
- default :
- llassert(0);
- break;
- }
-}
+/** +* @file llfloaterpathfindingconsole.cpp +* @author William Todd Stinson +* @brief "Pathfinding console" floater, allowing manipulation of the Havok AI pathfinding settings. +* +* $LicenseInfo:firstyear=2002&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2010, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" +#include "llfloaterpathfindingconsole.h" +#include "llfloaterpathfindinglinksets.h" + +#include "llsd.h" +#include "llagent.h" +#include "llbutton.h" +#include "llradiogroup.h" +#include "llsliderctrl.h" +#include "lllineeditor.h" +#include "lltextbase.h" +#include "lltextvalidate.h" +#include "llnavmeshstation.h" +#include "llviewerregion.h" + +#include "LLPathingLib.h" + +#define XUI_RENDER_OVERLAY_ON_FIXED_PHYSICS_GEOMETRY 1 +#define XUI_RENDER_OVERLAY_ON_ALL_RENDERABLE_GEOMETRY 2 + +#define XUI_PATH_SELECT_NONE 0 +#define XUI_PATH_SELECT_START_POINT 1 +#define XUI_PATH_SELECT_END_POINT 2 + +#define XUI_CHARACTER_TYPE_A 1 +#define XUI_CHARACTER_TYPE_B 2 +#define XUI_CHARACTER_TYPE_C 3 +#define XUI_CHARACTER_TYPE_D 4 + +const int CURRENT_REGION = 99; +const int MAX_OBSERVERS = 10; +//--------------------------------------------------------------------------- +// LLFloaterPathfindingConsole +//--------------------------------------------------------------------------- + +BOOL LLFloaterPathfindingConsole::postBuild() +{ + childSetAction("view_and_edit_linksets", boost::bind(&LLFloaterPathfindingConsole::onViewEditLinksetClicked, this)); + childSetAction("rebuild_navmesh", boost::bind(&LLFloaterPathfindingConsole::onRebuildNavMeshClicked, this)); + childSetAction("refresh_navmesh", boost::bind(&LLFloaterPathfindingConsole::onRefreshNavMeshClicked, this)); + + mShowNavMeshCheckBox = findChild<LLCheckBoxCtrl>("show_navmesh_overlay"); + llassert(mShowNavMeshCheckBox != NULL); + mShowNavMeshCheckBox->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onShowNavMeshToggle, this)); + + mShowExcludeVolumesCheckBox = findChild<LLCheckBoxCtrl>("show_exclusion_volumes"); + llassert(mShowExcludeVolumesCheckBox != NULL); + mShowExcludeVolumesCheckBox->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onShowExcludeVolumesToggle, this)); + + mShowPathCheckBox = findChild<LLCheckBoxCtrl>("show_path"); + llassert(mShowPathCheckBox != NULL); + mShowPathCheckBox->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onShowPathToggle, this)); + + mShowWaterPlaneCheckBox = findChild<LLCheckBoxCtrl>("show_water_plane"); + llassert(mShowWaterPlaneCheckBox != NULL); + mShowWaterPlaneCheckBox->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onShowWaterPlaneToggle, this)); + + mRegionOverlayDisplayRadioGroup = findChild<LLRadioGroup>("region_overlay_display"); + llassert(mRegionOverlayDisplayRadioGroup != NULL); + mRegionOverlayDisplayRadioGroup->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onRegionOverlayDisplaySwitch, this)); + + mPathSelectionRadioGroup = findChild<LLRadioGroup>("path_selection"); + llassert(mPathSelectionRadioGroup != NULL); + mPathSelectionRadioGroup ->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onPathSelectionSwitch, this)); + + mCharacterWidthSlider = findChild<LLSliderCtrl>("character_width"); + llassert(mCharacterWidthSlider != NULL); + mCharacterWidthSlider->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onCharacterWidthSet, this)); + + mCharacterTypeRadioGroup = findChild<LLRadioGroup>("character_type"); + llassert(mCharacterTypeRadioGroup != NULL); + mCharacterTypeRadioGroup->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onCharacterTypeSwitch, this)); + + mPathfindingStatus = findChild<LLTextBase>("pathfinding_status"); + llassert(mPathfindingStatus != NULL); + + mTerrainMaterialA = findChild<LLLineEditor>("terrain_material_a"); + llassert(mTerrainMaterialA != NULL); + mTerrainMaterialA->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onTerrainMaterialASet, this)); + mTerrainMaterialA->setPrevalidate(LLTextValidate::validateFloat); + + mTerrainMaterialB = findChild<LLLineEditor>("terrain_material_b"); + llassert(mTerrainMaterialB != NULL); + mTerrainMaterialB->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onTerrainMaterialBSet, this)); + mTerrainMaterialB->setPrevalidate(LLTextValidate::validateFloat); + + mTerrainMaterialC = findChild<LLLineEditor>("terrain_material_c"); + llassert(mTerrainMaterialC != NULL); + mTerrainMaterialC->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onTerrainMaterialCSet, this)); + mTerrainMaterialC->setPrevalidate(LLTextValidate::validateFloat); + + mTerrainMaterialD = findChild<LLLineEditor>("terrain_material_d"); + llassert(mTerrainMaterialD != NULL); + mTerrainMaterialD->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onTerrainMaterialDSet, this)); + mTerrainMaterialD->setPrevalidate(LLTextValidate::validateFloat); + + return LLFloater::postBuild(); +} + +LLFloaterPathfindingConsole::ERegionOverlayDisplay LLFloaterPathfindingConsole::getRegionOverlayDisplay() const +{ + ERegionOverlayDisplay regionOverlayDisplay; + switch (mRegionOverlayDisplayRadioGroup->getValue().asInteger()) + { + case XUI_RENDER_OVERLAY_ON_FIXED_PHYSICS_GEOMETRY : + regionOverlayDisplay = kRenderOverlayOnFixedPhysicsGeometry; + break; + case XUI_RENDER_OVERLAY_ON_ALL_RENDERABLE_GEOMETRY : + regionOverlayDisplay = kRenderOverlayOnAllRenderableGeometry; + break; + default : + regionOverlayDisplay = kRenderOverlayOnFixedPhysicsGeometry; + llassert(0); + break; + } + + return regionOverlayDisplay; +} + +void LLFloaterPathfindingConsole::setRegionOverlayDisplay(ERegionOverlayDisplay pRegionOverlayDisplay) +{ + LLSD radioGroupValue; + + switch (pRegionOverlayDisplay) + { + case kRenderOverlayOnFixedPhysicsGeometry : + radioGroupValue = XUI_RENDER_OVERLAY_ON_FIXED_PHYSICS_GEOMETRY; + break; + case kRenderOverlayOnAllRenderableGeometry : + radioGroupValue = XUI_RENDER_OVERLAY_ON_ALL_RENDERABLE_GEOMETRY; + break; + default : + radioGroupValue = XUI_RENDER_OVERLAY_ON_FIXED_PHYSICS_GEOMETRY; + llassert(0); + break; + } + + mRegionOverlayDisplayRadioGroup->setValue(radioGroupValue); +} + +LLFloaterPathfindingConsole::EPathSelectionState LLFloaterPathfindingConsole::getPathSelectionState() const +{ + EPathSelectionState pathSelectionState; + + switch (mPathSelectionRadioGroup->getValue().asInteger()) + { + case XUI_PATH_SELECT_START_POINT : + pathSelectionState = kPathSelectStartPoint; + break; + case XUI_PATH_SELECT_END_POINT : + pathSelectionState = kPathSelectEndPoint; + break; + default : + pathSelectionState = kPathSelectNone; + break; + } + + return pathSelectionState; +} + +void LLFloaterPathfindingConsole::setPathSelectionState(EPathSelectionState pPathSelectionState) +{ + LLSD radioGroupValue; + + switch (pPathSelectionState) + { + case kPathSelectStartPoint : + radioGroupValue = XUI_PATH_SELECT_START_POINT; + break; + case kPathSelectEndPoint : + radioGroupValue = XUI_PATH_SELECT_END_POINT; + break; + default : + radioGroupValue = XUI_PATH_SELECT_NONE; + break; + } + + mPathSelectionRadioGroup->setValue(radioGroupValue); +} + +F32 LLFloaterPathfindingConsole::getCharacterWidth() const +{ + return mCharacterWidthSlider->getValueF32(); +} + +void LLFloaterPathfindingConsole::setCharacterWidth(F32 pCharacterWidth) +{ + mCharacterWidthSlider->setValue(LLSD(pCharacterWidth)); +} + +LLFloaterPathfindingConsole::ECharacterType LLFloaterPathfindingConsole::getCharacterType() const +{ + ECharacterType characterType; + + switch (mCharacterTypeRadioGroup->getValue().asInteger()) + { + case XUI_CHARACTER_TYPE_A : + characterType = kCharacterTypeA; + break; + case XUI_CHARACTER_TYPE_B : + characterType = kCharacterTypeB; + break; + case XUI_CHARACTER_TYPE_C : + characterType = kCharacterTypeC; + break; + case XUI_CHARACTER_TYPE_D : + characterType = kCharacterTypeD; + break; + default : + characterType = kCharacterTypeA; + llassert(0); + break; + } + + return characterType; +} + +void LLFloaterPathfindingConsole::setCharacterType(ECharacterType pCharacterType) +{ + LLSD radioGroupValue; + + switch (pCharacterType) + { + case kCharacterTypeA : + radioGroupValue = XUI_CHARACTER_TYPE_A; + break; + case kCharacterTypeB : + radioGroupValue = XUI_CHARACTER_TYPE_B; + break; + case kCharacterTypeC : + radioGroupValue = XUI_CHARACTER_TYPE_C; + break; + case kCharacterTypeD : + radioGroupValue = XUI_CHARACTER_TYPE_D; + break; + default : + radioGroupValue = XUI_CHARACTER_TYPE_A; + llassert(0); + break; + } + + mCharacterTypeRadioGroup->setValue(radioGroupValue); +} + +F32 LLFloaterPathfindingConsole::getTerrainMaterialA() const +{ + return mTerrainMaterialA->getValue().asReal(); +} + +void LLFloaterPathfindingConsole::setTerrainMaterialA(F32 pTerrainMaterial) +{ + mTerrainMaterialA->setValue(LLSD(pTerrainMaterial)); +} + +F32 LLFloaterPathfindingConsole::getTerrainMaterialB() const +{ + return mTerrainMaterialB->getValue().asReal(); +} + +void LLFloaterPathfindingConsole::setTerrainMaterialB(F32 pTerrainMaterial) +{ + mTerrainMaterialB->setValue(LLSD(pTerrainMaterial)); +} + +F32 LLFloaterPathfindingConsole::getTerrainMaterialC() const +{ + return mTerrainMaterialC->getValue().asReal(); +} + +void LLFloaterPathfindingConsole::setTerrainMaterialC(F32 pTerrainMaterial) +{ + mTerrainMaterialC->setValue(LLSD(pTerrainMaterial)); +} + +F32 LLFloaterPathfindingConsole::getTerrainMaterialD() const +{ + return mTerrainMaterialD->getValue().asReal(); +} + +void LLFloaterPathfindingConsole::setTerrainMaterialD(F32 pTerrainMaterial) +{ + mTerrainMaterialD->setValue(LLSD(pTerrainMaterial)); +} + +void LLFloaterPathfindingConsole::setHasNavMeshReceived() +{ + std::string str = getString("navmesh_fetch_complete_available"); + mPathfindingStatus->setText((LLStringExplicit)str); +} + +void LLFloaterPathfindingConsole::setHasNoNavMesh() +{ + std::string str = getString("navmesh_fetch_complete_none"); + mPathfindingStatus->setText((LLStringExplicit)str); +} + +LLFloaterPathfindingConsole::LLFloaterPathfindingConsole(const LLSD& pSeed) + : LLFloater(pSeed), + mShowNavMeshCheckBox(NULL), + mShowExcludeVolumesCheckBox(NULL), + mShowPathCheckBox(NULL), + mShowWaterPlaneCheckBox(NULL), + mRegionOverlayDisplayRadioGroup(NULL), + mPathSelectionRadioGroup(NULL), + mCharacterWidthSlider(NULL), + mCharacterTypeRadioGroup(NULL), + mPathfindingStatus(NULL), + mTerrainMaterialA(NULL), + mTerrainMaterialB(NULL), + mTerrainMaterialC(NULL), + mTerrainMaterialD(NULL) +{ + for (int i=0;i<MAX_OBSERVERS;++i) + { + mNavMeshDownloadObserver[i].setPathfindingConsole(this); + } +} + +LLFloaterPathfindingConsole::~LLFloaterPathfindingConsole() +{ +} + +void LLFloaterPathfindingConsole::onOpen(const LLSD& pKey) +{ + //make sure we have a pathing system + if ( !LLPathingLib::getInstance() ) + { + LLPathingLib::initSystem(); + } + //prep# test remove + //LLSD content; + //LLPathingLib::getInstance()->extractNavMeshSrcFromLLSD( content ); + //return true; + //prep# end test + if ( LLPathingLib::getInstance() == NULL ) + { + std::string str = getString("navmesh_library_not_implemented"); + LLStyle::Params styleParams; + styleParams.color = LLUIColorTable::instance().getColor("DrYellow"); + mPathfindingStatus->setText((LLStringExplicit)str, styleParams); + llwarns <<"Errror: cannout find pathing library implementation."<<llendl; + } + else + { + mCurrentMDO = 0; + //make sure the region is essentially enabled for navmesh support + std::string capability = "RetrieveNavMeshSrc"; + + //prep# neighboring navmesh support proto + LLViewerRegion* pCurrentRegion = gAgent.getRegion(); + std::vector<LLViewerRegion*> regions; + regions.push_back( pCurrentRegion ); + //pCurrentRegion->getNeighboringRegions( regions ); + + std::vector<int> shift; + shift.push_back( CURRENT_REGION ); + //pCurrentRegion->getNeighboringRegionsStatus( shift ); + + int regionCnt = regions.size(); + for ( int i=0; i<regionCnt; ++i ) + { + std::string url = regions[i]->getCapability( capability ); + + if ( !url.empty() ) + { + std::string str = getString("navmesh_fetch_inprogress"); + mPathfindingStatus->setText((LLStringExplicit)str); + LLNavMeshStation::getInstance()->setNavMeshDownloadURL( url ); + int dir = shift[i]; + LLNavMeshStation::getInstance()->downloadNavMeshSrc( mNavMeshDownloadObserver[mCurrentMDO].getObserverHandle(), dir ); + ++mCurrentMDO; + } + else + { + std::string str = getString("navmesh_region_not_enabled"); + LLStyle::Params styleParams; + styleParams.color = LLUIColorTable::instance().getColor("DrYellow"); + mPathfindingStatus->setText((LLStringExplicit)str, styleParams); + llinfos<<"Region has does not required caps of type ["<<capability<<"]"<<llendl; + } + } + } +} + +void LLFloaterPathfindingConsole::onShowNavMeshToggle() +{ + BOOL checkBoxValue = mShowNavMeshCheckBox->get(); + + LLPathingLib *llPathingLibInstance = LLPathingLib::getInstance(); + if (llPathingLibInstance != NULL) + { + llPathingLibInstance->setRenderNavMesh(checkBoxValue); + } + else + { + mShowNavMeshCheckBox->set(FALSE); + llwarns << "cannot find LLPathingLib instance" << llendl; + } +} + +void LLFloaterPathfindingConsole::onShowExcludeVolumesToggle() +{ + BOOL checkBoxValue = mShowExcludeVolumesCheckBox->get(); + + LLPathingLib *llPathingLibInstance = LLPathingLib::getInstance(); + if (llPathingLibInstance != NULL) + { + llPathingLibInstance->setRenderNavMeshandShapes(checkBoxValue); + } + else + { + mShowExcludeVolumesCheckBox->set(FALSE); + llwarns << "cannot find LLPathingLib instance" << llendl; + } +} + +void LLFloaterPathfindingConsole::onShowPathToggle() +{ + BOOL checkBoxValue = mShowPathCheckBox->get(); + + llwarns << "functionality has not yet been implemented to toggle '" + << mShowPathCheckBox->getLabel() << "' to " + << (checkBoxValue ? "ON" : "OFF") << llendl; +} + +void LLFloaterPathfindingConsole::onShowWaterPlaneToggle() +{ + BOOL checkBoxValue = mShowWaterPlaneCheckBox->get(); + + llwarns << "functionality has not yet been implemented to toggle '" + << mShowWaterPlaneCheckBox->getLabel() << "' to " + << (checkBoxValue ? "ON" : "OFF") << llendl; +} + +void LLFloaterPathfindingConsole::onRegionOverlayDisplaySwitch() +{ + switch (getRegionOverlayDisplay()) + { + case kRenderOverlayOnFixedPhysicsGeometry : + llwarns << "functionality has not yet been implemented to toggle '" + << mRegionOverlayDisplayRadioGroup->getName() << "' to RenderOverlayOnFixedPhysicsGeometry" + << llendl; + break; + case kRenderOverlayOnAllRenderableGeometry : + llwarns << "functionality has not yet been implemented to toggle '" + << mRegionOverlayDisplayRadioGroup->getName() << "' to RenderOverlayOnAllRenderableGeometry" + << llendl; + break; + default : + llassert(0); + break; + } +} + +void LLFloaterPathfindingConsole::onPathSelectionSwitch() +{ + switch (getPathSelectionState()) + { + case kPathSelectNone : + llwarns << "functionality has not yet been implemented to toggle '" + << mPathSelectionRadioGroup->getName() << "' to PathSelectNone" + << llendl; + break; + case kPathSelectStartPoint : + llwarns << "functionality has not yet been implemented to toggle '" + << mPathSelectionRadioGroup->getName() << "' to PathSelectStartPoint" + << llendl; + break; + case kPathSelectEndPoint : + llwarns << "functionality has not yet been implemented to toggle '" + << mPathSelectionRadioGroup->getName() << "' to PathSelectEndPoint" + << llendl; + break; + default : + llassert(0); + break; + } +} + +void LLFloaterPathfindingConsole::onCharacterWidthSet() +{ + F32 characterWidth = getCharacterWidth(); + llwarns << "functionality has not yet been implemented to set '" << mCharacterWidthSlider->getName() + << "' to the value (" << characterWidth << ")" << llendl; +} + +void LLFloaterPathfindingConsole::onCharacterTypeSwitch() +{ + switch (getCharacterType()) + { + case kCharacterTypeA : + llwarns << "functionality has not yet been implemented to toggle '" + << mCharacterTypeRadioGroup->getName() << "' to CharacterTypeA" + << llendl; + break; + case kCharacterTypeB : + llwarns << "functionality has not yet been implemented to toggle '" + << mCharacterTypeRadioGroup->getName() << "' to CharacterTypeB" + << llendl; + break; + case kCharacterTypeC : + llwarns << "functionality has not yet been implemented to toggle '" + << mCharacterTypeRadioGroup->getName() << "' to CharacterTypeC" + << llendl; + break; + case kCharacterTypeD : + llwarns << "functionality has not yet been implemented to toggle '" + << mCharacterTypeRadioGroup->getName() << "' to CharacterTypeD" + << llendl; + break; + default : + llassert(0); + break; + } + +} + +void LLFloaterPathfindingConsole::onViewEditLinksetClicked() +{ + LLFloaterPathfindingLinksets::openLinksetsEditor(); +} + +void LLFloaterPathfindingConsole::onRebuildNavMeshClicked() +{ + llwarns << "functionality has not yet been implemented to handle rebuilding of the navmesh" << llendl; +} + +void LLFloaterPathfindingConsole::onRefreshNavMeshClicked() +{ + llwarns << "functionality has not yet been implemented to handle refreshing of the navmesh" << llendl; +} + +void LLFloaterPathfindingConsole::onTerrainMaterialASet() +{ + F32 terrainMaterial = getTerrainMaterialA(); + llwarns << "functionality has not yet been implemented to setting '" << mTerrainMaterialA->getName() + << "' to value (" << terrainMaterial << ")" << llendl; +} + +void LLFloaterPathfindingConsole::onTerrainMaterialBSet() +{ + F32 terrainMaterial = getTerrainMaterialB(); + llwarns << "functionality has not yet been implemented to setting '" << mTerrainMaterialB->getName() + << "' to value (" << terrainMaterial << ")" << llendl; +} + +void LLFloaterPathfindingConsole::onTerrainMaterialCSet() +{ + F32 terrainMaterial = getTerrainMaterialC(); + llwarns << "functionality has not yet been implemented to setting '" << mTerrainMaterialC->getName() + << "' to value (" << terrainMaterial << ")" << llendl; +} + +void LLFloaterPathfindingConsole::onTerrainMaterialDSet() +{ + F32 terrainMaterial = getTerrainMaterialD(); + llwarns << "functionality has not yet been implemented to setting '" << mTerrainMaterialD->getName() + << "' to value (" << terrainMaterial << ")" << llendl; +} + + +BOOL LLFloaterPathfindingConsole::allowAllRenderables() const +{ + return getRegionOverlayDisplay() == kRenderOverlayOnAllRenderableGeometry ? true : false; +} + +void LLFloaterPathfindingConsole::providePathingData( const LLVector3& point1, const LLVector3& point2 ) +{ + switch (getPathSelectionState()) + { + case kPathSelectNone : + llwarns << "not yet been implemented to toggle '" + << mPathSelectionRadioGroup->getName() << "' to PathSelectNone" + << llendl; + break; + + case kPathSelectStartPoint : + mPathData.mStartPointA = point1; + mPathData.mEndPointA = point2; + break; + + case kPathSelectEndPoint : + mPathData.mStartPointB = point1; + mPathData.mEndPointB = point2; + mPathData.mCharacterWidth = getCharacterWidth(); + //prep#TODO# possibly consider an alternate behavior - perhaps add a "path" button to submit the data. + LLPathingLib::getInstance()->generatePath( mPathData ); + break; + + default : + llassert(0); + break; + } +} diff --git a/indra/newview/llfloaterpathfindingconsole.h b/indra/newview/llfloaterpathfindingconsole.h index c46fead91b..3ae5e25695 100644 --- a/indra/newview/llfloaterpathfindingconsole.h +++ b/indra/newview/llfloaterpathfindingconsole.h @@ -1,151 +1,151 @@ -/**
- * @file llfloaterpathfindingconsole.h
- * @author William Todd Stinson
- * @brief "Pathfinding console" floater, allowing manipulation of the Havok AI pathfinding settings.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLFLOATERPATHFINDINGCONSOLE_H
-#define LL_LLFLOATERPATHFINDINGCONSOLE_H
-
-#include "llfloater.h"
-#include "llnavmeshstation.h"
-#include "llphysicsextensions.h"
-#include "llcheckboxctrl.h"
-
-class LLSD;
-class LLRadioGroup;
-class LLSliderCtrl;
-class LLLineEditor;
-class LLTextBase;
-
-class LLFloaterPathfindingConsole
-: public LLFloater
-{
- friend class LLFloaterReg;
-
-public:
- typedef enum
- {
- kRenderOverlayOnFixedPhysicsGeometry = 0,
- kRenderOverlayOnAllRenderableGeometry = 1
- } ERegionOverlayDisplay;
-
- typedef enum
- {
- kPathSelectNone = 0,
- kPathSelectStartPoint = 1,
- kPathSelectEndPoint = 2
- } EPathSelectionState;
-
- typedef enum
- {
- kCharacterTypeA = 0,
- kCharacterTypeB = 1,
- kCharacterTypeC = 2,
- kCharacterTypeD = 3
- } ECharacterType;
-
- virtual BOOL postBuild();
- //Accessor to determine whether renderables are allowed
- BOOL allowAllRenderables() const;
- //Populates a data packet that is forwarded onto the LLPathingSystem
- void providePathingData( const LLVector3& point1, const LLVector3& point2 );
-
- ERegionOverlayDisplay getRegionOverlayDisplay() const;
- void setRegionOverlayDisplay(ERegionOverlayDisplay pRegionOverlayDisplay);
-
- EPathSelectionState getPathSelectionState() const;
- void setPathSelectionState(EPathSelectionState pPathSelectionState);
-
- F32 getCharacterWidth() const;
- void setCharacterWidth(F32 pCharacterWidth);
-
- ECharacterType getCharacterType() const;
- void setCharacterType(ECharacterType pCharacterType);
-
- F32 getTerrainMaterialA() const;
- void setTerrainMaterialA(F32 pTerrainMaterial);
-
- F32 getTerrainMaterialB() const;
- void setTerrainMaterialB(F32 pTerrainMaterial);
-
- F32 getTerrainMaterialC() const;
- void setTerrainMaterialC(F32 pTerrainMaterial);
-
- F32 getTerrainMaterialD() const;
- void setTerrainMaterialD(F32 pTerrainMaterial);
-
- BOOL getShowPathToggle() const {return mShowPathCheckBox->get(); }
-
- void setHasNavMeshReceived();
- void setHasNoNavMesh();
-
-protected:
-
-private:
- // Does its own instance management, so clients not allowed
- // to allocate or destroy.
- LLFloaterPathfindingConsole(const LLSD& pSeed);
- virtual ~LLFloaterPathfindingConsole();
-
- virtual void onOpen(const LLSD& pKey);
-
- void onShowNavMeshToggle();
- void onShowExcludeVolumesToggle();
- void onShowPathToggle();
- void onShowWaterPlaneToggle();
- void onRegionOverlayDisplaySwitch();
- void onPathSelectionSwitch();
- void onCharacterWidthSet();
- void onCharacterTypeSwitch();
- void onViewEditLinksetClicked();
- void onRebuildNavMeshClicked();
- void onRefreshNavMeshClicked();
- void onTerrainMaterialASet();
- void onTerrainMaterialBSet();
- void onTerrainMaterialCSet();
- void onTerrainMaterialDSet();
-
- LLCheckBoxCtrl *mShowNavMeshCheckBox;
- LLCheckBoxCtrl *mShowExcludeVolumesCheckBox;
- LLCheckBoxCtrl *mShowPathCheckBox;
- LLCheckBoxCtrl *mShowWaterPlaneCheckBox;
- LLRadioGroup *mRegionOverlayDisplayRadioGroup;
- LLRadioGroup *mPathSelectionRadioGroup;
- LLSliderCtrl *mCharacterWidthSlider;
- LLRadioGroup *mCharacterTypeRadioGroup;
- LLTextBase *mPathfindingStatus;
- LLLineEditor *mTerrainMaterialA;
- LLLineEditor *mTerrainMaterialB;
- LLLineEditor *mTerrainMaterialC;
- LLLineEditor *mTerrainMaterialD;
-
- LLNavMeshDownloadObserver mNavMeshDownloadObserver[10];
- int mCurrentMDO;
-
- //Container that is populated and subsequently submitted to the LLPathingSystem for processing
- LLPathingLib::PathingPacket mPathData;
-};
-
-#endif // LL_LLFLOATERPATHFINDINGCONSOLE_H
+/** + * @file llfloaterpathfindingconsole.h + * @author William Todd Stinson + * @brief "Pathfinding console" floater, allowing manipulation of the Havok AI pathfinding settings. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERPATHFINDINGCONSOLE_H +#define LL_LLFLOATERPATHFINDINGCONSOLE_H + +#include "llfloater.h" +#include "llnavmeshstation.h" +#include "LLPathingLib.h" +#include "llcheckboxctrl.h" + +class LLSD; +class LLRadioGroup; +class LLSliderCtrl; +class LLLineEditor; +class LLTextBase; + +class LLFloaterPathfindingConsole +: public LLFloater +{ + friend class LLFloaterReg; + +public: + typedef enum + { + kRenderOverlayOnFixedPhysicsGeometry = 0, + kRenderOverlayOnAllRenderableGeometry = 1 + } ERegionOverlayDisplay; + + typedef enum + { + kPathSelectNone = 0, + kPathSelectStartPoint = 1, + kPathSelectEndPoint = 2 + } EPathSelectionState; + + typedef enum + { + kCharacterTypeA = 0, + kCharacterTypeB = 1, + kCharacterTypeC = 2, + kCharacterTypeD = 3 + } ECharacterType; + + virtual BOOL postBuild(); + //Accessor to determine whether renderables are allowed + BOOL allowAllRenderables() const; + //Populates a data packet that is forwarded onto the LLPathingSystem + void providePathingData( const LLVector3& point1, const LLVector3& point2 ); + + ERegionOverlayDisplay getRegionOverlayDisplay() const; + void setRegionOverlayDisplay(ERegionOverlayDisplay pRegionOverlayDisplay); + + EPathSelectionState getPathSelectionState() const; + void setPathSelectionState(EPathSelectionState pPathSelectionState); + + F32 getCharacterWidth() const; + void setCharacterWidth(F32 pCharacterWidth); + + ECharacterType getCharacterType() const; + void setCharacterType(ECharacterType pCharacterType); + + F32 getTerrainMaterialA() const; + void setTerrainMaterialA(F32 pTerrainMaterial); + + F32 getTerrainMaterialB() const; + void setTerrainMaterialB(F32 pTerrainMaterial); + + F32 getTerrainMaterialC() const; + void setTerrainMaterialC(F32 pTerrainMaterial); + + F32 getTerrainMaterialD() const; + void setTerrainMaterialD(F32 pTerrainMaterial); + + BOOL getShowPathToggle() const {return mShowPathCheckBox->get(); } + + void setHasNavMeshReceived(); + void setHasNoNavMesh(); + +protected: + +private: + // Does its own instance management, so clients not allowed + // to allocate or destroy. + LLFloaterPathfindingConsole(const LLSD& pSeed); + virtual ~LLFloaterPathfindingConsole(); + + virtual void onOpen(const LLSD& pKey); + + void onShowNavMeshToggle(); + void onShowExcludeVolumesToggle(); + void onShowPathToggle(); + void onShowWaterPlaneToggle(); + void onRegionOverlayDisplaySwitch(); + void onPathSelectionSwitch(); + void onCharacterWidthSet(); + void onCharacterTypeSwitch(); + void onViewEditLinksetClicked(); + void onRebuildNavMeshClicked(); + void onRefreshNavMeshClicked(); + void onTerrainMaterialASet(); + void onTerrainMaterialBSet(); + void onTerrainMaterialCSet(); + void onTerrainMaterialDSet(); + + LLCheckBoxCtrl *mShowNavMeshCheckBox; + LLCheckBoxCtrl *mShowExcludeVolumesCheckBox; + LLCheckBoxCtrl *mShowPathCheckBox; + LLCheckBoxCtrl *mShowWaterPlaneCheckBox; + LLRadioGroup *mRegionOverlayDisplayRadioGroup; + LLRadioGroup *mPathSelectionRadioGroup; + LLSliderCtrl *mCharacterWidthSlider; + LLRadioGroup *mCharacterTypeRadioGroup; + LLTextBase *mPathfindingStatus; + LLLineEditor *mTerrainMaterialA; + LLLineEditor *mTerrainMaterialB; + LLLineEditor *mTerrainMaterialC; + LLLineEditor *mTerrainMaterialD; + + LLNavMeshDownloadObserver mNavMeshDownloadObserver[10]; + int mCurrentMDO; + + //Container that is populated and subsequently submitted to the LLPathingSystem for processing + LLPathingLib::PathingPacket mPathData; +}; + +#endif // LL_LLFLOATERPATHFINDINGCONSOLE_H diff --git a/indra/newview/llnavmeshstation.cpp b/indra/newview/llnavmeshstation.cpp index 586ed4715d..87f7e92ddd 100644 --- a/indra/newview/llnavmeshstation.cpp +++ b/indra/newview/llnavmeshstation.cpp @@ -27,7 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "llnavmeshstation.h" #include "llcurl.h" -#include "llphysicsextensions.h"
+#include "LLPathingLib.h" #include "llagent.h" #include "llviewerregion.h" #include "llsdutil.h" diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index d2da940260..e8029293fc 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1,1604 +1,1604 @@ -/**
- * @file llviewerdisplay.cpp
- * @brief LLViewerDisplay class implementation
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llviewerdisplay.h"
-
-#include "llgl.h"
-#include "llrender.h"
-#include "llglheaders.h"
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llviewercontrol.h"
-#include "llcoord.h"
-#include "llcriticaldamp.h"
-#include "lldir.h"
-#include "lldynamictexture.h"
-#include "lldrawpoolalpha.h"
-#include "llfeaturemanager.h"
-//#include "llfirstuse.h"
-#include "llhudmanager.h"
-#include "llimagebmp.h"
-#include "llmemory.h"
-#include "llselectmgr.h"
-#include "llsky.h"
-#include "llstartup.h"
-#include "lltoolfocus.h"
-#include "lltoolmgr.h"
-#include "lltooldraganddrop.h"
-#include "lltoolpie.h"
-#include "lltracker.h"
-#include "lltrans.h"
-#include "llui.h"
-#include "llviewercamera.h"
-#include "llviewerobjectlist.h"
-#include "llviewerparcelmgr.h"
-#include "llviewerwindow.h"
-#include "llvoavatarself.h"
-#include "llvograss.h"
-#include "llworld.h"
-#include "pipeline.h"
-#include "llspatialpartition.h"
-#include "llappviewer.h"
-#include "llstartup.h"
-#include "llviewershadermgr.h"
-#include "llfasttimer.h"
-#include "llfloatertools.h"
-#include "llviewertexturelist.h"
-#include "llfocusmgr.h"
-#include "llcubemap.h"
-#include "llviewerregion.h"
-#include "lldrawpoolwater.h"
-#include "lldrawpoolbump.h"
-#include "llwlparammanager.h"
-#include "llwaterparammanager.h"
-#include "llpostprocess.h"
-#include "llphysicsextensions.h"
-#include "llfloaterpathfindingconsole.h"
-#include "llfloaterreg.h"
-
-extern LLPointer<LLViewerTexture> gStartTexture;
-
-LLPointer<LLViewerTexture> gDisconnectedImagep = NULL;
-
-// used to toggle renderer back on after teleport
-const F32 TELEPORT_RENDER_DELAY = 20.f; // Max time a teleport is allowed to take before we raise the curtain
-const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived.
-const F32 TELEPORT_LOCAL_DELAY = 1.0f; // Delay to prevent teleports after starting an in-sim teleport.
-BOOL gTeleportDisplay = FALSE;
-LLFrameTimer gTeleportDisplayTimer;
-LLFrameTimer gTeleportArrivalTimer;
-const F32 RESTORE_GL_TIME = 5.f; // Wait this long while reloading textures before we raise the curtain
-
-BOOL gForceRenderLandFence = FALSE;
-BOOL gDisplaySwapBuffers = FALSE;
-BOOL gDepthDirty = FALSE;
-BOOL gResizeScreenTexture = FALSE;
-BOOL gWindowResized = FALSE;
-BOOL gSnapshot = FALSE;
-
-U32 gRecentFrameCount = 0; // number of 'recent' frames
-LLFrameTimer gRecentFPSTime;
-LLFrameTimer gRecentMemoryTime;
-
-// Rendering stuff
-void pre_show_depth_buffer();
-void post_show_depth_buffer();
-void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
-void render_hud_attachments();
-void render_ui_3d();
-void render_ui_2d();
-void render_disconnected_background();
-
-void display_startup()
-{
- if ( !gViewerWindow->getActive()
- || !gViewerWindow->getWindow()->getVisible()
- || gViewerWindow->getWindow()->getMinimized() )
- {
- return;
- }
-
- gPipeline.updateGL();
-
- // Update images?
- //gImageList.updateImages(0.01f);
- LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName();
-
- LLGLSDefault gls_default;
-
- // Required for HTML update in login screen
- static S32 frame_count = 0;
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
- if (frame_count++ > 1) // make sure we have rendered a frame first
- {
- LLViewerDynamicTexture::updateAllInstances();
- }
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
- glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
- LLGLSUIDefault gls_ui;
- gPipeline.disableLights();
-
- gViewerWindow->setup2DRender();
- gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
- gGL.color4f(1,1,1,1);
- gViewerWindow->draw();
- gGL.flush();
-
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
- gViewerWindow->getWindow()->swapBuffers();
- glClear(GL_DEPTH_BUFFER_BIT);
-}
-
-void display_update_camera()
-{
- LLMemType mt_uc(LLMemType::MTYPE_DISPLAY_UPDATE_CAMERA);
- // TODO: cut draw distance down if customizing avatar?
- // TODO: cut draw distance on per-parcel basis?
-
- // Cut draw distance in half when customizing avatar,
- // but on the viewer only.
- F32 final_far = gAgentCamera.mDrawDistance;
- if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode())
- {
- final_far *= 0.5f;
- }
- LLViewerCamera::getInstance()->setFar(final_far);
- gViewerWindow->setup3DRender();
-
- // update all the sky/atmospheric/water settings
- LLWLParamManager::getInstance()->update(LLViewerCamera::getInstance());
- LLWaterParamManager::getInstance()->update(LLViewerCamera::getInstance());
-
- // Update land visibility too
- LLWorld::getInstance()->setLandFarClip(final_far);
-}
-
-// Write some stats to llinfos
-void display_stats()
-{
- F32 fps_log_freq = gSavedSettings.getF32("FPSLogFrequency");
- if (fps_log_freq > 0.f && gRecentFPSTime.getElapsedTimeF32() >= fps_log_freq)
- {
- F32 fps = gRecentFrameCount / fps_log_freq;
- llinfos << llformat("FPS: %.02f", fps) << llendl;
- gRecentFrameCount = 0;
- gRecentFPSTime.reset();
- }
- F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency");
- if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq)
- {
- gMemoryAllocated = LLMemory::getCurrentRSS();
- U32 memory = (U32)(gMemoryAllocated / (1024*1024));
- llinfos << llformat("MEMORY: %d MB", memory) << llendl;
- LLMemory::logMemoryInfo(TRUE) ;
- gRecentMemoryTime.reset();
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_PICK("Picking");
-static LLFastTimer::DeclareTimer FTM_RENDER("Render", true);
-static LLFastTimer::DeclareTimer FTM_UPDATE_SKY("Update Sky");
-static LLFastTimer::DeclareTimer FTM_UPDATE_TEXTURES("Update Textures");
-static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE("Update Images");
-static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_CLASS("Class");
-static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_BUMP("Bump");
-static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_LIST("List");
-static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_DELETE("Delete");
-
-// Paint the display!
-void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
-{
- LLMemType mt_render(LLMemType::MTYPE_RENDER);
- LLFastTimer t(FTM_RENDER);
-
- if (gWindowResized)
- { //skip render on frames where window has been resized
- gGL.flush();
- glClear(GL_COLOR_BUFFER_BIT);
- gViewerWindow->getWindow()->swapBuffers();
- LLPipeline::refreshCachedSettings();
- gPipeline.resizeScreenTexture();
- gResizeScreenTexture = FALSE;
- gWindowResized = FALSE;
- return;
- }
-
- if (LLPipeline::sRenderDeferred)
- { //hack to make sky show up in deferred snapshots
- for_snapshot = FALSE;
- }
-
- if (LLPipeline::sRenderFrameTest)
- {
- send_agent_pause();
- }
-
- gSnapshot = for_snapshot;
-
- LLGLSDefault gls_default;
- LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE, GL_LEQUAL);
-
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
- stop_glerror();
-
- gPipeline.disableLights();
-
- stop_glerror();
-
- // Don't draw if the window is hidden or minimized.
- // In fact, must explicitly check the minimized state before drawing.
- // Attempting to draw into a minimized window causes a GL error. JC
- if ( !gViewerWindow->getActive()
- || !gViewerWindow->getWindow()->getVisible()
- || gViewerWindow->getWindow()->getMinimized() )
- {
- // Clean up memory the pools may have allocated
- if (rebuild)
- {
- stop_glerror();
- gPipeline.rebuildPools();
- stop_glerror();
- }
-
- stop_glerror();
- gViewerWindow->returnEmptyPicks();
- stop_glerror();
- return;
- }
-
- gViewerWindow->checkSettings();
-
- {
- LLFastTimer ftm(FTM_PICK);
- LLAppViewer::instance()->pingMainloopTimeout("Display:Pick");
- gViewerWindow->performPick();
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:CheckStates");
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
- //////////////////////////////////////////////////////////
- //
- // Logic for forcing window updates if we're in drone mode.
- //
-
- // *TODO: Investigate running display() during gHeadlessClient. See if this early exit is needed DK 2011-02-18
- if (gHeadlessClient)
- {
-#if LL_WINDOWS
- static F32 last_update_time = 0.f;
- if ((gFrameTimeSeconds - last_update_time) > 1.f)
- {
- InvalidateRect((HWND)gViewerWindow->getPlatformWindow(), NULL, FALSE);
- last_update_time = gFrameTimeSeconds;
- }
-#elif LL_DARWIN
- // MBW -- Do something clever here.
-#endif
- // Not actually rendering, don't bother.
- return;
- }
-
-
- //
- // Bail out if we're in the startup state and don't want to try to
- // render the world.
- //
- if (LLStartUp::getStartupState() < STATE_STARTED)
- {
- LLAppViewer::instance()->pingMainloopTimeout("Display:Startup");
- display_startup();
- return;
- }
-
- //LLGLState::verify(FALSE);
-
- /////////////////////////////////////////////////
- //
- // Update GL Texture statistics (used for discard logic?)
- //
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:TextureStats");
- stop_glerror();
-
- LLImageGL::updateStats(gFrameTimeSeconds);
-
- LLVOAvatar::sRenderName = gSavedSettings.getS32("AvatarNameTagMode");
- LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("NameTagShowGroupTitles") && gSavedSettings.getS32("AvatarNameTagMode"));
-
- gPipeline.mBackfaceCull = TRUE;
- gFrameCount++;
- gRecentFrameCount++;
- if (gFocusMgr.getAppHasFocus())
- {
- gForegroundFrameCount++;
- }
-
- //////////////////////////////////////////////////////////
- //
- // Display start screen if we're teleporting, and skip render
- //
-
- if (gTeleportDisplay)
- {
- LLAppViewer::instance()->pingMainloopTimeout("Display:Teleport");
- const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived.
-
- S32 attach_count = 0;
- if (isAgentAvatarValid())
- {
- attach_count = gAgentAvatarp->getAttachmentCount();
- }
- F32 teleport_save_time = TELEPORT_EXPIRY + TELEPORT_EXPIRY_PER_ATTACHMENT * attach_count;
- F32 teleport_elapsed = gTeleportDisplayTimer.getElapsedTimeF32();
- F32 teleport_percent = teleport_elapsed * (100.f / teleport_save_time);
- if( (gAgent.getTeleportState() != LLAgent::TELEPORT_START) && (teleport_percent > 100.f) )
- {
- // Give up. Don't keep the UI locked forever.
- gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
- gAgent.setTeleportMessage(std::string());
- }
-
- const std::string& message = gAgent.getTeleportMessage();
- switch( gAgent.getTeleportState() )
- {
- case LLAgent::TELEPORT_START:
- // Transition to REQUESTED. Viewer has sent some kind
- // of TeleportRequest to the source simulator
- gTeleportDisplayTimer.reset();
- gViewerWindow->setShowProgress(TRUE);
- gViewerWindow->setProgressPercent(0);
- gAgent.setTeleportState( LLAgent::TELEPORT_REQUESTED );
- gAgent.setTeleportMessage(
- LLAgent::sTeleportProgressMessages["requesting"]);
- break;
-
- case LLAgent::TELEPORT_REQUESTED:
- // Waiting for source simulator to respond
- gViewerWindow->setProgressPercent( llmin(teleport_percent, 37.5f) );
- gViewerWindow->setProgressString(message);
- break;
-
- case LLAgent::TELEPORT_MOVING:
- // Viewer has received destination location from source simulator
- gViewerWindow->setProgressPercent( llmin(teleport_percent, 75.f) );
- gViewerWindow->setProgressString(message);
- break;
-
- case LLAgent::TELEPORT_START_ARRIVAL:
- // Transition to ARRIVING. Viewer has received avatar update, etc., from destination simulator
- gTeleportArrivalTimer.reset();
- gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel"));
- gViewerWindow->setProgressPercent(75.f);
- gAgent.setTeleportState( LLAgent::TELEPORT_ARRIVING );
- gAgent.setTeleportMessage(
- LLAgent::sTeleportProgressMessages["arriving"]);
- gTextureList.mForceResetTextureStats = TRUE;
- gAgentCamera.resetView(TRUE, TRUE);
- break;
-
- case LLAgent::TELEPORT_ARRIVING:
- // Make the user wait while content "pre-caches"
- {
- F32 arrival_fraction = (gTeleportArrivalTimer.getElapsedTimeF32() / TELEPORT_ARRIVAL_DELAY);
- if( arrival_fraction > 1.f )
- {
- arrival_fraction = 1.f;
- //LLFirstUse::useTeleport();
- gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
- }
- gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel"));
- gViewerWindow->setProgressPercent( arrival_fraction * 25.f + 75.f);
- gViewerWindow->setProgressString(message);
- }
- break;
-
- case LLAgent::TELEPORT_LOCAL:
- // Short delay when teleporting in the same sim (progress screen active but not shown - did not
- // fall-through from TELEPORT_START)
- {
- if( gTeleportDisplayTimer.getElapsedTimeF32() > TELEPORT_LOCAL_DELAY )
- {
- //LLFirstUse::useTeleport();
- gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
- }
- }
- break;
-
- case LLAgent::TELEPORT_NONE:
- // No teleport in progress
- gViewerWindow->setShowProgress(FALSE);
- gTeleportDisplay = FALSE;
- break;
- }
- }
- else if(LLAppViewer::instance()->logoutRequestSent())
- {
- LLAppViewer::instance()->pingMainloopTimeout("Display:Logout");
- F32 percent_done = gLogoutTimer.getElapsedTimeF32() * 100.f / gLogoutMaxTime;
- if (percent_done > 100.f)
- {
- percent_done = 100.f;
- }
-
- if( LLApp::isExiting() )
- {
- percent_done = 100.f;
- }
-
- gViewerWindow->setProgressPercent( percent_done );
- }
- else
- if (gRestoreGL)
- {
- LLAppViewer::instance()->pingMainloopTimeout("Display:RestoreGL");
- F32 percent_done = gRestoreGLTimer.getElapsedTimeF32() * 100.f / RESTORE_GL_TIME;
- if( percent_done > 100.f )
- {
- gViewerWindow->setShowProgress(FALSE);
- gRestoreGL = FALSE;
- }
- else
- {
-
- if( LLApp::isExiting() )
- {
- percent_done = 100.f;
- }
-
- gViewerWindow->setProgressPercent( percent_done );
- }
- }
-
- //////////////////////////
- //
- // Prepare for the next frame
- //
-
- /////////////////////////////
- //
- // Update the camera
- //
- //
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:Camera");
- LLViewerCamera::getInstance()->setZoomParameters(zoom_factor, subfield);
- LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE);
-
- //////////////////////////
- //
- // clear the next buffer
- // (must follow dynamic texture writing since that uses the frame buffer)
- //
-
- if (gDisconnected)
- {
- LLAppViewer::instance()->pingMainloopTimeout("Display:Disconnected");
- render_ui();
- }
-
- //////////////////////////
- //
- // Set rendering options
- //
- //
- LLAppViewer::instance()->pingMainloopTimeout("Display:RenderSetup");
- stop_glerror();
-
- ///////////////////////////////////////
- //
- // Slam lighting parameters back to our defaults.
- // Note that these are not the same as GL defaults...
-
- stop_glerror();
- gGL.setAmbientLightColor(LLColor4::white);
- stop_glerror();
-
- /////////////////////////////////////
- //
- // Render
- //
- // Actually push all of our triangles to the screen.
- //
-
- // do render-to-texture stuff here
- if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES))
- {
- LLAppViewer::instance()->pingMainloopTimeout("Display:DynamicTextures");
- LLFastTimer t(FTM_UPDATE_TEXTURES);
- if (LLViewerDynamicTexture::updateAllInstances())
- {
- gGL.setColorMask(true, true);
- glClear(GL_DEPTH_BUFFER_BIT);
- }
- }
-
- gViewerWindow->setup3DViewport();
-
- gPipeline.resetFrameStats(); // Reset per-frame statistics.
-
- if (!gDisconnected)
- {
- LLMemType mt_du(LLMemType::MTYPE_DISPLAY_UPDATE);
- LLAppViewer::instance()->pingMainloopTimeout("Display:Update");
- if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- { //don't draw hud objects in this frame
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
- }
-
- if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES))
- { //don't draw hud particles in this frame
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
- }
-
- //upkeep gl name pools
- LLGLNamePool::upkeepPools();
-
- stop_glerror();
- display_update_camera();
- stop_glerror();
-
- // *TODO: merge these two methods
- {
- LLMemType mt_uh(LLMemType::MTYPE_DISPLAY_UPDATE_HUD);
- LLHUDManager::getInstance()->updateEffects();
- LLHUDObject::updateAll();
- stop_glerror();
- }
-
- {
- LLMemType mt_ug(LLMemType::MTYPE_DISPLAY_UPDATE_GEOM);
- const F32 max_geom_update_time = 0.005f*10.f*gFrameIntervalSeconds; // 50 ms/second update time
- gPipeline.createObjects(max_geom_update_time);
- gPipeline.processPartitionQ();
- gPipeline.updateGeom(max_geom_update_time);
- stop_glerror();
- }
-
- gPipeline.updateGL();
- stop_glerror();
-
- S32 water_clip = 0;
- if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) &&
- (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER) ||
- gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER)))
- {
- if (LLViewerCamera::getInstance()->cameraUnderWater())
- {
- water_clip = -1;
- }
- else
- {
- water_clip = 1;
- }
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:Cull");
-
- //Increment drawable frame counter
- LLDrawable::incrementVisible();
-
- LLSpatialGroup::sNoDelete = TRUE;
- LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName();
-
- /*if (LLPipeline::sUseOcclusion && LLPipeline::sRenderDeferred)
- { //force occlusion on for all render types if doing deferred render (tighter shadow frustum)
- LLPipeline::sUseOcclusion = 3;
- }*/
-
- S32 occlusion = LLPipeline::sUseOcclusion;
- if (gDepthDirty)
- { //depth buffer is invalid, don't overwrite occlusion state
- LLPipeline::sUseOcclusion = llmin(occlusion, 1);
- }
- gDepthDirty = FALSE;
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- static LLCullResult result;
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
- gPipeline.updateCull(*LLViewerCamera::getInstance(), result, water_clip);
- stop_glerror();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- BOOL to_texture = gPipeline.canUseVertexShaders() &&
- LLPipeline::sRenderGlow;
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:Swap");
-
- {
- LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SWAP);
-
- if (gResizeScreenTexture)
- {
- gResizeScreenTexture = FALSE;
- gPipeline.resizeScreenTexture();
- }
-
- gGL.setColorMask(true, true);
- glClearColor(0,0,0,0);
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- if (!for_snapshot)
- {
- if (gFrameCount > 1)
- { //for some reason, ATI 4800 series will error out if you
- //try to generate a shadow before the first frame is through
- gPipeline.generateSunShadow(*LLViewerCamera::getInstance());
- }
-
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- glh::matrix4f proj = glh_get_current_projection();
- glh::matrix4f mod = glh_get_current_modelview();
- glViewport(0,0,512,512);
- LLVOAvatar::updateFreezeCounter() ;
-
- if(!LLPipeline::sMemAllocationThrottled)
- {
- LLVOAvatar::updateImpostors();
- }
-
- glh_set_current_projection(proj);
- glh_set_current_modelview(mod);
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.loadMatrix(proj.m);
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.loadMatrix(mod.m);
- gViewerWindow->setup3DViewport();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- }
- glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
- }
-
- LLGLState::checkStates();
- LLGLState::checkClientArrays();
-
- //if (!for_snapshot)
- {
- LLMemType mt_gw(LLMemType::MTYPE_DISPLAY_GEN_REFLECTION);
- LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery");
- gPipeline.generateWaterReflection(*LLViewerCamera::getInstance());
- gPipeline.generateHighlight(*LLViewerCamera::getInstance());
- gPipeline.renderPhysicsDisplay();
- }
-
- LLGLState::checkStates();
- LLGLState::checkClientArrays();
-
- //////////////////////////////////////
- //
- // Update images, using the image stats generated during object update/culling
- //
- // Can put objects onto the retextured list.
- //
- // Doing this here gives hardware occlusion queries extra time to complete
- LLAppViewer::instance()->pingMainloopTimeout("Display:UpdateImages");
-
- {
- LLMemType mt_iu(LLMemType::MTYPE_DISPLAY_IMAGE_UPDATE);
- LLFastTimer t(FTM_IMAGE_UPDATE);
-
- {
- LLFastTimer t(FTM_IMAGE_UPDATE_CLASS);
- LLViewerTexture::updateClass(LLViewerCamera::getInstance()->getVelocityStat()->getMean(),
- LLViewerCamera::getInstance()->getAngularVelocityStat()->getMean());
- }
-
-
- {
- LLFastTimer t(FTM_IMAGE_UPDATE_BUMP);
- gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first.
- }
-
- {
- LLFastTimer t(FTM_IMAGE_UPDATE_LIST);
- F32 max_image_decode_time = 0.050f*gFrameIntervalSeconds; // 50 ms/second decode time
- max_image_decode_time = llclamp(max_image_decode_time, 0.002f, 0.005f ); // min 2ms/frame, max 5ms/frame)
- gTextureList.updateImages(max_image_decode_time);
- }
-
- {
- LLFastTimer t(FTM_IMAGE_UPDATE_DELETE);
- //remove dead textures from GL
- LLImageGL::deleteDeadTextures();
- stop_glerror();
- }
- }
-
- LLGLState::checkStates();
- LLGLState::checkClientArrays();
-
- ///////////////////////////////////
- //
- // StateSort
- //
- // Responsible for taking visible objects, and adding them to the appropriate draw orders.
- // In the case of alpha objects, z-sorts them first.
- // Also creates special lists for outlines and selected face rendering.
- //
- LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort");
- {
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
- LLMemType mt_ss(LLMemType::MTYPE_DISPLAY_STATE_SORT);
- gPipeline.stateSort(*LLViewerCamera::getInstance(), result);
- stop_glerror();
-
- if (rebuild)
- {
- //////////////////////////////////////
- //
- // rebuildPools
- //
- //
- gPipeline.rebuildPools();
- stop_glerror();
- }
- }
-
- LLGLState::checkStates();
- LLGLState::checkClientArrays();
-
- LLPipeline::sUseOcclusion = occlusion;
-
- {
- LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SKY);
- LLAppViewer::instance()->pingMainloopTimeout("Display:Sky");
- LLFastTimer t(FTM_UPDATE_SKY);
- gSky.updateSky();
- }
-
- if(gUseWireframe)
- {
- glClearColor(0.5f, 0.5f, 0.5f, 0.f);
- glClear(GL_COLOR_BUFFER_BIT);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:RenderStart");
-
- //// render frontmost floater opaque for occlusion culling purposes
- //LLFloater* frontmost_floaterp = gFloaterView->getFrontmost();
- //// assumes frontmost floater with focus is opaque
- //if (frontmost_floaterp && gFocusMgr.childHasKeyboardFocus(frontmost_floaterp))
- //{
- // gGL.matrixMode(LLRender::MM_MODELVIEW);
- // gGL.pushMatrix();
- // {
- // gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- // glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
- // gGL.loadIdentity();
-
- // LLRect floater_rect = frontmost_floaterp->calcScreenRect();
- // // deflate by one pixel so rounding errors don't occlude outside of floater extents
- // floater_rect.stretch(-1);
- // LLRectf floater_3d_rect((F32)floater_rect.mLeft / (F32)gViewerWindow->getWindowWidthScaled(),
- // (F32)floater_rect.mTop / (F32)gViewerWindow->getWindowHeightScaled(),
- // (F32)floater_rect.mRight / (F32)gViewerWindow->getWindowWidthScaled(),
- // (F32)floater_rect.mBottom / (F32)gViewerWindow->getWindowHeightScaled());
- // floater_3d_rect.translate(-0.5f, -0.5f);
- // gGL.translatef(0.f, 0.f, -LLViewerCamera::getInstance()->getNear());
- // gGL.scalef(LLViewerCamera::getInstance()->getNear() * LLViewerCamera::getInstance()->getAspect() / sinf(LLViewerCamera::getInstance()->getView()), LLViewerCamera::getInstance()->getNear() / sinf(LLViewerCamera::getInstance()->getView()), 1.f);
- // gGL.color4fv(LLColor4::white.mV);
- // gGL.begin(LLVertexBuffer::QUADS);
- // {
- // gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mBottom, 0.f);
- // gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mTop, 0.f);
- // gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mTop, 0.f);
- // gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mBottom, 0.f);
- // }
- // gGL.end();
- // glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- // }
- // gGL.popMatrix();
- //}
-
- LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE;
-
- LLGLState::checkStates();
- LLGLState::checkClientArrays();
-
- stop_glerror();
-
- if (to_texture)
- {
- gGL.setColorMask(true, true);
-
- if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
- {
- gPipeline.mDeferredScreen.bindTarget();
- glClearColor(1,0,1,1);
- gPipeline.mDeferredScreen.clear();
- }
- else
- {
- gPipeline.mScreen.bindTarget();
- if (LLPipeline::sUnderWaterRender && !gPipeline.canUseWindLightShaders())
- {
- const LLColor4 &col = LLDrawPoolWater::sWaterFogColor;
- glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
- }
- gPipeline.mScreen.clear();
- }
-
- gGL.setColorMask(true, false);
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:RenderGeom");
- bool exclusiveDraw = false;
- BOOL allowRenderables = false;
- BOOL allowPathToBeDrawn = false;
- if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot())
- && !gRestoreGL)
- {
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
- LLMemType mt_rg(LLMemType::MTYPE_DISPLAY_RENDER_GEOM);
- gGL.setColorMask(true, false);
- if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
- {
- gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance());
- }
- else
- {
- //Render any navmesh geometry
- if ( LLPathingLib::getInstance() )
- {
- //Determine if we can should overlay the navmesh ontop of the scenes typical renderables
- LLFloaterPathfindingConsole* pFloater = LLFloaterReg::getTypedInstance<LLFloaterPathfindingConsole>("pathfinding_console");
- if ( pFloater && pFloater->allowAllRenderables() )
- {
- allowRenderables = true;
- }
- //Determine if we should also draw a user supplied path on top of the scene
- if ( pFloater && pFloater->getShowPathToggle() )
- {
- allowPathToBeDrawn = true;
- }
- //NavMesh
- if ( LLPathingLib::getInstance()->getRenderNavMeshState() )
- {
- glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
- glEnable(GL_DEPTH_TEST);
- gGL.setAmbientLightColor( LLColor4::white );
- LLPathingLib::getInstance()->renderNavMesh( allowRenderables );
- exclusiveDraw = true;
- }
- //physics/exclusion shapes
- if ( LLPathingLib::getInstance()->getRenderShapeState() )
- {
- LLPathingLib::getInstance()->renderNavMeshShapesVBO();
- exclusiveDraw = true;
- }
- //User designated path
- if ( allowPathToBeDrawn )
- {
- LLPathingLib::getInstance()->renderPath();
- }
- }
- }
-
- if ( !exclusiveDraw || allowRenderables )
- {
- gPipeline.renderGeom(*LLViewerCamera::getInstance(), TRUE);
- }
-
- gGL.setColorMask(true, true);
-
- //store this frame's modelview matrix for use
- //when rendering next frame's occlusion queries
- for (U32 i = 0; i < 16; i++)
- {
- gGLLastModelView[i] = gGLModelView[i];
- gGLLastProjection[i] = gGLProjection[i];
- }
- stop_glerror();
- }
-
- for (U32 i = 0; i < gGLManager.mNumTextureImageUnits; i++)
- { //dummy cleanup of any currently bound textures
- if (gGL.getTexUnit(i)->getCurrType() != LLTexUnit::TT_NONE)
- {
- gGL.getTexUnit(i)->unbind(gGL.getTexUnit(i)->getCurrType());
- gGL.getTexUnit(i)->disable();
- }
- }
- LLAppViewer::instance()->pingMainloopTimeout("Display:RenderFlush");
-
- if (to_texture)
- {
- LLMemType mt_rf(LLMemType::MTYPE_DISPLAY_RENDER_FLUSH);
- if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
- {
- gPipeline.mDeferredScreen.flush();
- if(LLRenderTarget::sUseFBO)
- {
- LLRenderTarget::copyContentsToFramebuffer(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(),
- gPipeline.mDeferredScreen.getHeight(), 0, 0,
- gPipeline.mDeferredScreen.getWidth(),
- gPipeline.mDeferredScreen.getHeight(),
- GL_DEPTH_BUFFER_BIT, GL_NEAREST);
- }
- }
- else
- {
- gPipeline.mScreen.flush();
- if(LLRenderTarget::sUseFBO)
- {
- LLRenderTarget::copyContentsToFramebuffer(gPipeline.mScreen, 0, 0, gPipeline.mScreen.getWidth(),
- gPipeline.mScreen.getHeight(), 0, 0,
- gPipeline.mScreen.getWidth(),
- gPipeline.mScreen.getHeight(),
- GL_DEPTH_BUFFER_BIT, GL_NEAREST);
- }
- }
- }
-
- if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
- {
- gPipeline.renderDeferredLighting();
- }
-
- LLPipeline::sUnderWaterRender = FALSE;
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:RenderUI");
- if (!for_snapshot)
- {
- LLFastTimer t(FTM_RENDER_UI);
- render_ui();
- }
-
-
- LLSpatialGroup::sNoDelete = FALSE;
- gPipeline.clearReferences();
-
- gPipeline.rebuildGroups();
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:FrameStats");
-
- stop_glerror();
-
- if (LLPipeline::sRenderFrameTest)
- {
- send_agent_resume();
- LLPipeline::sRenderFrameTest = FALSE;
- }
-
- display_stats();
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:Done");
-}
-
-void render_hud_attachments()
-{
- LLMemType mt_ra(LLMemType::MTYPE_DISPLAY_RENDER_ATTACHMENTS);
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.pushMatrix();
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.pushMatrix();
-
- glh::matrix4f current_proj = glh_get_current_projection();
- glh::matrix4f current_mod = glh_get_current_modelview();
-
- // clamp target zoom level to reasonable values
- gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f);
- // smoothly interpolate current zoom level
- gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.mHUDTargetZoom, LLCriticalDamp::getInterpolant(0.03f));
-
- if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices())
- {
- LLCamera hud_cam = *LLViewerCamera::getInstance();
- LLVector3 origin = hud_cam.getOrigin();
- hud_cam.setOrigin(-1.f,0,0);
- hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1));
- LLViewerCamera::updateFrustumPlanes(hud_cam, TRUE);
-
- bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && gSavedSettings.getBOOL("RenderHUDParticles");
-
- //only render hud objects
- gPipeline.pushRenderTypeMask();
-
- // turn off everything
- gPipeline.andRenderTypeMask(LLPipeline::END_RENDER_TYPES);
- // turn on HUD
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
- // turn on HUD particles
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
-
- // if particles are off, turn off hud-particles as well
- if (!render_particles)
- {
- // turn back off HUD particles
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
- }
-
- bool has_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
- if (has_ui)
- {
- gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI);
- }
-
- S32 use_occlusion = LLPipeline::sUseOcclusion;
- LLPipeline::sUseOcclusion = 0;
-
- //cull, sort, and render hud objects
- static LLCullResult result;
- LLSpatialGroup::sNoDelete = TRUE;
-
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
- gPipeline.updateCull(hud_cam, result);
-
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_BUMP);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_SIMPLE);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_BUMP);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_SHINY);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISIBLE);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY);
-
- gPipeline.stateSort(hud_cam, result);
-
- gPipeline.renderGeom(hud_cam);
-
- LLSpatialGroup::sNoDelete = FALSE;
- //gPipeline.clearReferences();
-
- render_hud_elements();
-
- //restore type mask
- gPipeline.popRenderTypeMask();
-
- if (has_ui)
- {
- gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI);
- }
- LLPipeline::sUseOcclusion = use_occlusion;
- }
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.popMatrix();
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.popMatrix();
-
- glh_set_current_projection(current_proj);
- glh_set_current_modelview(current_mod);
-}
-
-LLRect get_whole_screen_region()
-{
- LLRect whole_screen = gViewerWindow->getWorldViewRectScaled();
-
- // 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)
- {
- S32 num_horizontal_tiles = llceil(zoom_factor);
- S32 tile_width = llround((F32)gViewerWindow->getWorldViewWidthScaled() / zoom_factor);
- S32 tile_height = llround((F32)gViewerWindow->getWorldViewHeightScaled() / zoom_factor);
- int tile_y = sub_region / num_horizontal_tiles;
- int tile_x = sub_region - (tile_y * num_horizontal_tiles);
-
- whole_screen.setLeftTopAndSize(tile_x * tile_width, gViewerWindow->getWorldViewHeightScaled() - (tile_y * tile_height), tile_width, tile_height);
- }
- return whole_screen;
-}
-
-bool get_hud_matrices(const LLRect& screen_region, glh::matrix4f &proj, glh::matrix4f &model)
-{
- if (isAgentAvatarValid() && gAgentAvatarp->hasHUDAttachment())
- {
- F32 zoom_level = gAgentCamera.mHUDCurZoom;
- LLBBox hud_bbox = gAgentAvatarp->getHUDBBox();
-
- F32 hud_depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
- proj = gl_ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, hud_depth);
- proj.element(2,2) = -0.01f;
-
- F32 aspect_ratio = LLViewerCamera::getInstance()->getAspect();
-
- glh::matrix4f mat;
- F32 scale_x = (F32)gViewerWindow->getWorldViewWidthScaled() / (F32)screen_region.getWidth();
- F32 scale_y = (F32)gViewerWindow->getWorldViewHeightScaled() / (F32)screen_region.getHeight();
- mat.set_scale(glh::vec3f(scale_x, scale_y, 1.f));
- mat.set_translate(
- glh::vec3f(clamp_rescale((F32)(screen_region.getCenterX() - screen_region.mLeft), 0.f, (F32)gViewerWindow->getWorldViewWidthScaled(), 0.5f * scale_x * aspect_ratio, -0.5f * scale_x * aspect_ratio),
- clamp_rescale((F32)(screen_region.getCenterY() - screen_region.mBottom), 0.f, (F32)gViewerWindow->getWorldViewHeightScaled(), 0.5f * scale_y, -0.5f * scale_y),
- 0.f));
- proj *= mat;
-
- glh::matrix4f tmp_model((GLfloat*) OGL_TO_CFR_ROTATION);
-
- mat.set_scale(glh::vec3f(zoom_level, zoom_level, zoom_level));
- mat.set_translate(glh::vec3f(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f));
-
- tmp_model *= mat;
- model = tmp_model;
- return TRUE;
- }
- else
- {
- return FALSE;
- }
-}
-
-bool get_hud_matrices(glh::matrix4f &proj, glh::matrix4f &model)
-{
- LLRect whole_screen = get_whole_screen_region();
- return get_hud_matrices(whole_screen, proj, model);
-}
-
-BOOL setup_hud_matrices()
-{
- LLRect whole_screen = get_whole_screen_region();
- return setup_hud_matrices(whole_screen);
-}
-
-BOOL setup_hud_matrices(const LLRect& screen_region)
-{
- glh::matrix4f proj, model;
- bool result = get_hud_matrices(screen_region, proj, model);
- if (!result) return result;
-
- // set up transform to keep HUD objects in front of camera
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.loadMatrix(proj.m);
- glh_set_current_projection(proj);
-
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.loadMatrix(model.m);
- glh_set_current_modelview(model);
- return TRUE;
-}
-
-static LLFastTimer::DeclareTimer FTM_SWAP("Swap");
-
-void render_ui(F32 zoom_factor, int subfield)
-{
- LLMemType mt_ru(LLMemType::MTYPE_DISPLAY_RENDER_UI);
- LLGLState::checkStates();
-
- glh::matrix4f saved_view = glh_get_current_modelview();
-
- if (!gSnapshot)
- {
- gGL.pushMatrix();
- gGL.loadMatrix(gGLLastModelView);
- glh_set_current_modelview(glh_copy_matrix(gGLLastModelView));
- }
-
- {
- BOOL to_texture = gPipeline.canUseVertexShaders() &&
- LLPipeline::sRenderGlow;
-
- if (to_texture)
- {
- gPipeline.renderBloom(gSnapshot, zoom_factor, subfield);
- }
-
- render_hud_elements();
- render_hud_attachments();
- }
-
- LLGLSDefault gls_default;
- LLGLSUIDefault gls_ui;
- {
- gPipeline.disableLights();
- }
-
- {
- gGL.color4f(1,1,1,1);
- if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- LLFastTimer t(FTM_RENDER_UI);
-
- if (!gDisconnected)
- {
- render_ui_3d();
- LLGLState::checkStates();
- }
- else
- {
- render_disconnected_background();
- }
-
- render_ui_2d();
- LLGLState::checkStates();
- }
- gGL.flush();
-
- {
- gViewerWindow->setup2DRender();
- gViewerWindow->updateDebugText();
- gViewerWindow->drawDebugText();
- }
-
- LLVertexBuffer::unbind();
- }
-
- if (!gSnapshot)
- {
- glh_set_current_modelview(saved_view);
- gGL.popMatrix();
- }
-
- if (gDisplaySwapBuffers)
- {
- LLFastTimer t(FTM_SWAP);
- gViewerWindow->getWindow()->swapBuffers();
- }
- gDisplaySwapBuffers = TRUE;
-}
-
-void renderCoordinateAxes()
-{
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.begin(LLRender::LINES);
- gGL.color3f(1.0f, 0.0f, 0.0f); // i direction = X-Axis = red
- gGL.vertex3f(0.0f, 0.0f, 0.0f);
- gGL.vertex3f(2.0f, 0.0f, 0.0f);
- gGL.vertex3f(3.0f, 0.0f, 0.0f);
- gGL.vertex3f(5.0f, 0.0f, 0.0f);
- gGL.vertex3f(6.0f, 0.0f, 0.0f);
- gGL.vertex3f(8.0f, 0.0f, 0.0f);
- // Make an X
- gGL.vertex3f(11.0f, 1.0f, 1.0f);
- gGL.vertex3f(11.0f, -1.0f, -1.0f);
- gGL.vertex3f(11.0f, 1.0f, -1.0f);
- gGL.vertex3f(11.0f, -1.0f, 1.0f);
-
- gGL.color3f(0.0f, 1.0f, 0.0f); // j direction = Y-Axis = green
- gGL.vertex3f(0.0f, 0.0f, 0.0f);
- gGL.vertex3f(0.0f, 2.0f, 0.0f);
- gGL.vertex3f(0.0f, 3.0f, 0.0f);
- gGL.vertex3f(0.0f, 5.0f, 0.0f);
- gGL.vertex3f(0.0f, 6.0f, 0.0f);
- gGL.vertex3f(0.0f, 8.0f, 0.0f);
- // Make a Y
- gGL.vertex3f(1.0f, 11.0f, 1.0f);
- gGL.vertex3f(0.0f, 11.0f, 0.0f);
- gGL.vertex3f(-1.0f, 11.0f, 1.0f);
- gGL.vertex3f(0.0f, 11.0f, 0.0f);
- gGL.vertex3f(0.0f, 11.0f, 0.0f);
- gGL.vertex3f(0.0f, 11.0f, -1.0f);
-
- gGL.color3f(0.0f, 0.0f, 1.0f); // Z-Axis = blue
- gGL.vertex3f(0.0f, 0.0f, 0.0f);
- gGL.vertex3f(0.0f, 0.0f, 2.0f);
- gGL.vertex3f(0.0f, 0.0f, 3.0f);
- gGL.vertex3f(0.0f, 0.0f, 5.0f);
- gGL.vertex3f(0.0f, 0.0f, 6.0f);
- gGL.vertex3f(0.0f, 0.0f, 8.0f);
- // Make a Z
- gGL.vertex3f(-1.0f, 1.0f, 11.0f);
- gGL.vertex3f(1.0f, 1.0f, 11.0f);
- gGL.vertex3f(1.0f, 1.0f, 11.0f);
- gGL.vertex3f(-1.0f, -1.0f, 11.0f);
- gGL.vertex3f(-1.0f, -1.0f, 11.0f);
- gGL.vertex3f(1.0f, -1.0f, 11.0f);
- gGL.end();
-}
-
-
-void draw_axes()
-{
- LLGLSUIDefault gls_ui;
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- // A vertical white line at origin
- LLVector3 v = gAgent.getPositionAgent();
- gGL.begin(LLRender::LINES);
- gGL.color3f(1.0f, 1.0f, 1.0f);
- gGL.vertex3f(0.0f, 0.0f, 0.0f);
- gGL.vertex3f(0.0f, 0.0f, 40.0f);
- gGL.end();
- // Some coordinate axes
- gGL.pushMatrix();
- gGL.translatef( v.mV[VX], v.mV[VY], v.mV[VZ] );
- renderCoordinateAxes();
- gGL.popMatrix();
-}
-
-void render_ui_3d()
-{
- LLGLSPipeline gls_pipeline;
-
- //////////////////////////////////////
- //
- // Render 3D UI elements
- // NOTE: zbuffer is cleared before we get here by LLDrawPoolHUD,
- // so 3d elements requiring Z buffer are moved to LLDrawPoolHUD
- //
-
- /////////////////////////////////////////////////////////////
- //
- // Render 2.5D elements (2D elements in the world)
- // Stuff without z writes
- //
-
- // Debugging stuff goes before the UI.
-
- stop_glerror();
-
- if (LLGLSLShader::sNoFixedFunction)
- {
- gUIProgram.bind();
- }
-
- // Coordinate axes
- if (gSavedSettings.getBOOL("ShowAxes"))
- {
- draw_axes();
- }
-
- gViewerWindow->renderSelections(FALSE, FALSE, TRUE); // Non HUD call in render_hud_elements
- stop_glerror();
-}
-
-void render_ui_2d()
-{
- LLGLSUIDefault gls_ui;
-
- /////////////////////////////////////////////////////////////
- //
- // Render 2D UI elements that overlay the world (no z compare)
-
- // Disable wireframe mode below here, as this is HUD/menus
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-
- // Menu overlays, HUD, etc
- gViewerWindow->setup2DRender();
-
- F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
- S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
-
- if (zoom_factor > 1.f)
- {
- //decompose subregion number to x and y values
- int pos_y = sub_region / llceil(zoom_factor);
- int pos_x = sub_region - (pos_y*llceil(zoom_factor));
- // offset for this tile
- LLFontGL::sCurOrigin.mX -= llround((F32)gViewerWindow->getWindowWidthScaled() * (F32)pos_x / zoom_factor);
- LLFontGL::sCurOrigin.mY -= llround((F32)gViewerWindow->getWindowHeightScaled() * (F32)pos_y / zoom_factor);
- }
-
- stop_glerror();
- //gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
- // render outline for HUD
- if (isAgentAvatarValid() && gAgentCamera.mHUDCurZoom < 0.98f)
- {
- gGL.pushMatrix();
- S32 half_width = (gViewerWindow->getWorldViewWidthScaled() / 2);
- S32 half_height = (gViewerWindow->getWorldViewHeightScaled() / 2);
- gGL.scalef(LLUI::sGLScaleFactor.mV[0], LLUI::sGLScaleFactor.mV[1], 1.f);
- gGL.translatef((F32)half_width, (F32)half_height, 0.f);
- F32 zoom = gAgentCamera.mHUDCurZoom;
- gGL.scalef(zoom,zoom,1.f);
- gGL.color4fv(LLColor4::white.mV);
- gl_rect_2d(-half_width, half_height, half_width, -half_height, FALSE);
- gGL.popMatrix();
- stop_glerror();
- }
-
-
- if (gSavedSettings.getBOOL("RenderUIBuffer"))
- {
- if (LLUI::sDirty)
- {
- LLUI::sDirty = FALSE;
- LLRect t_rect;
-
- gPipeline.mUIScreen.bindTarget();
- gGL.setColorMask(true, true);
- {
- static const S32 pad = 8;
-
- LLUI::sDirtyRect.mLeft -= pad;
- LLUI::sDirtyRect.mRight += pad;
- LLUI::sDirtyRect.mBottom -= pad;
- LLUI::sDirtyRect.mTop += pad;
-
- LLGLEnable scissor(GL_SCISSOR_TEST);
- static LLRect last_rect = LLUI::sDirtyRect;
-
- //union with last rect to avoid mouse poop
- last_rect.unionWith(LLUI::sDirtyRect);
-
- t_rect = LLUI::sDirtyRect;
- LLUI::sDirtyRect = last_rect;
- last_rect = t_rect;
-
- last_rect.mLeft = LLRect::tCoordType(last_rect.mLeft / LLUI::sGLScaleFactor.mV[0]);
- last_rect.mRight = LLRect::tCoordType(last_rect.mRight / LLUI::sGLScaleFactor.mV[0]);
- last_rect.mTop = LLRect::tCoordType(last_rect.mTop / LLUI::sGLScaleFactor.mV[1]);
- last_rect.mBottom = LLRect::tCoordType(last_rect.mBottom / LLUI::sGLScaleFactor.mV[1]);
-
- LLRect clip_rect(last_rect);
-
- glClear(GL_COLOR_BUFFER_BIT);
-
- gViewerWindow->draw();
- }
-
- gPipeline.mUIScreen.flush();
- gGL.setColorMask(true, false);
-
- LLUI::sDirtyRect = t_rect;
- }
-
- LLGLDisable cull(GL_CULL_FACE);
- LLGLDisable blend(GL_BLEND);
- S32 width = gViewerWindow->getWindowWidthScaled();
- S32 height = gViewerWindow->getWindowHeightScaled();
- gGL.getTexUnit(0)->bind(&gPipeline.mUIScreen);
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.color4f(1,1,1,1);
- gGL.texCoord2f(0, 0); gGL.vertex2i(0, 0);
- gGL.texCoord2f(width, 0); gGL.vertex2i(width, 0);
- gGL.texCoord2f(0, height); gGL.vertex2i(0, height);
- gGL.texCoord2f(width, height); gGL.vertex2i(width, height);
- gGL.end();
- }
- else
- {
- gViewerWindow->draw();
- }
-
-
-
- // reset current origin for font rendering, in case of tiling render
- LLFontGL::sCurOrigin.set(0, 0);
-}
-
-void render_disconnected_background()
-{
- if (LLGLSLShader::sNoFixedFunction)
- {
- gUIProgram.bind();
- }
-
- gGL.color4f(1,1,1,1);
- if (!gDisconnectedImagep && gDisconnected)
- {
- llinfos << "Loading last bitmap..." << llendl;
-
- std::string temp_str;
- temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + SCREEN_LAST_FILENAME;
-
- LLPointer<LLImageBMP> image_bmp = new LLImageBMP;
- if( !image_bmp->load(temp_str) )
- {
- //llinfos << "Bitmap load failed" << llendl;
- return;
- }
-
- LLPointer<LLImageRaw> raw = new LLImageRaw;
- if (!image_bmp->decode(raw, 0.0f))
- {
- llinfos << "Bitmap decode failed" << llendl;
- gDisconnectedImagep = NULL;
- return;
- }
-
- U8 *rawp = raw->getData();
- S32 npixels = (S32)image_bmp->getWidth()*(S32)image_bmp->getHeight();
- for (S32 i = 0; i < npixels; i++)
- {
- S32 sum = 0;
- sum = *rawp + *(rawp+1) + *(rawp+2);
- sum /= 3;
- *rawp = ((S32)sum*6 + *rawp)/7;
- rawp++;
- *rawp = ((S32)sum*6 + *rawp)/7;
- rawp++;
- *rawp = ((S32)sum*6 + *rawp)/7;
- rawp++;
- }
-
-
- raw->expandToPowerOfTwo();
- gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE );
- gStartTexture = gDisconnectedImagep;
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- }
-
- // Make sure the progress view always fills the entire window.
- S32 width = gViewerWindow->getWindowWidthScaled();
- S32 height = gViewerWindow->getWindowHeightScaled();
-
- if (gDisconnectedImagep)
- {
- LLGLSUIDefault gls_ui;
- gViewerWindow->setup2DRender();
- gGL.pushMatrix();
- {
- // scale ui to reflect UIScaleFactor
- // this can't be done in setup2DRender because it requires a
- // pushMatrix/popMatrix pair
- const LLVector2& display_scale = gViewerWindow->getDisplayScale();
- gGL.scalef(display_scale.mV[VX], display_scale.mV[VY], 1.f);
-
- gGL.getTexUnit(0)->bind(gDisconnectedImagep);
- gGL.color4f(1.f, 1.f, 1.f, 1.f);
- gl_rect_2d_simple_tex(width, height);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- }
- gGL.popMatrix();
- }
- gGL.flush();
-
- if (LLGLSLShader::sNoFixedFunction)
- {
- gUIProgram.unbind();
- }
-
-}
-
-void display_cleanup()
-{
- gDisconnectedImagep = NULL;
-}
+/** + * @file llviewerdisplay.cpp + * @brief LLViewerDisplay class implementation + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llviewerdisplay.h" + +#include "llgl.h" +#include "llrender.h" +#include "llglheaders.h" +#include "llagent.h" +#include "llagentcamera.h" +#include "llviewercontrol.h" +#include "llcoord.h" +#include "llcriticaldamp.h" +#include "lldir.h" +#include "lldynamictexture.h" +#include "lldrawpoolalpha.h" +#include "llfeaturemanager.h" +//#include "llfirstuse.h" +#include "llhudmanager.h" +#include "llimagebmp.h" +#include "llmemory.h" +#include "llselectmgr.h" +#include "llsky.h" +#include "llstartup.h" +#include "lltoolfocus.h" +#include "lltoolmgr.h" +#include "lltooldraganddrop.h" +#include "lltoolpie.h" +#include "lltracker.h" +#include "lltrans.h" +#include "llui.h" +#include "llviewercamera.h" +#include "llviewerobjectlist.h" +#include "llviewerparcelmgr.h" +#include "llviewerwindow.h" +#include "llvoavatarself.h" +#include "llvograss.h" +#include "llworld.h" +#include "pipeline.h" +#include "llspatialpartition.h" +#include "llappviewer.h" +#include "llstartup.h" +#include "llviewershadermgr.h" +#include "llfasttimer.h" +#include "llfloatertools.h" +#include "llviewertexturelist.h" +#include "llfocusmgr.h" +#include "llcubemap.h" +#include "llviewerregion.h" +#include "lldrawpoolwater.h" +#include "lldrawpoolbump.h" +#include "llwlparammanager.h" +#include "llwaterparammanager.h" +#include "llpostprocess.h" +#include "LLPathingLib.h" +#include "llfloaterpathfindingconsole.h" +#include "llfloaterreg.h" + +extern LLPointer<LLViewerTexture> gStartTexture; + +LLPointer<LLViewerTexture> gDisconnectedImagep = NULL; + +// used to toggle renderer back on after teleport +const F32 TELEPORT_RENDER_DELAY = 20.f; // Max time a teleport is allowed to take before we raise the curtain +const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived. +const F32 TELEPORT_LOCAL_DELAY = 1.0f; // Delay to prevent teleports after starting an in-sim teleport. +BOOL gTeleportDisplay = FALSE; +LLFrameTimer gTeleportDisplayTimer; +LLFrameTimer gTeleportArrivalTimer; +const F32 RESTORE_GL_TIME = 5.f; // Wait this long while reloading textures before we raise the curtain + +BOOL gForceRenderLandFence = FALSE; +BOOL gDisplaySwapBuffers = FALSE; +BOOL gDepthDirty = FALSE; +BOOL gResizeScreenTexture = FALSE; +BOOL gWindowResized = FALSE; +BOOL gSnapshot = FALSE; + +U32 gRecentFrameCount = 0; // number of 'recent' frames +LLFrameTimer gRecentFPSTime; +LLFrameTimer gRecentMemoryTime; + +// Rendering stuff +void pre_show_depth_buffer(); +void post_show_depth_buffer(); +void render_ui(F32 zoom_factor = 1.f, int subfield = 0); +void render_hud_attachments(); +void render_ui_3d(); +void render_ui_2d(); +void render_disconnected_background(); + +void display_startup() +{ + if ( !gViewerWindow->getActive() + || !gViewerWindow->getWindow()->getVisible() + || gViewerWindow->getWindow()->getMinimized() ) + { + return; + } + + gPipeline.updateGL(); + + // Update images? + //gImageList.updateImages(0.01f); + LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName(); + + LLGLSDefault gls_default; + + // Required for HTML update in login screen + static S32 frame_count = 0; + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + + if (frame_count++ > 1) // make sure we have rendered a frame first + { + LLViewerDynamicTexture::updateAllInstances(); + } + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + LLGLSUIDefault gls_ui; + gPipeline.disableLights(); + + gViewerWindow->setup2DRender(); + gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); + + gGL.color4f(1,1,1,1); + gViewerWindow->draw(); + gGL.flush(); + + LLVertexBuffer::unbind(); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + + gViewerWindow->getWindow()->swapBuffers(); + glClear(GL_DEPTH_BUFFER_BIT); +} + +void display_update_camera() +{ + LLMemType mt_uc(LLMemType::MTYPE_DISPLAY_UPDATE_CAMERA); + // TODO: cut draw distance down if customizing avatar? + // TODO: cut draw distance on per-parcel basis? + + // Cut draw distance in half when customizing avatar, + // but on the viewer only. + F32 final_far = gAgentCamera.mDrawDistance; + if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode()) + { + final_far *= 0.5f; + } + LLViewerCamera::getInstance()->setFar(final_far); + gViewerWindow->setup3DRender(); + + // update all the sky/atmospheric/water settings + LLWLParamManager::getInstance()->update(LLViewerCamera::getInstance()); + LLWaterParamManager::getInstance()->update(LLViewerCamera::getInstance()); + + // Update land visibility too + LLWorld::getInstance()->setLandFarClip(final_far); +} + +// Write some stats to llinfos +void display_stats() +{ + F32 fps_log_freq = gSavedSettings.getF32("FPSLogFrequency"); + if (fps_log_freq > 0.f && gRecentFPSTime.getElapsedTimeF32() >= fps_log_freq) + { + F32 fps = gRecentFrameCount / fps_log_freq; + llinfos << llformat("FPS: %.02f", fps) << llendl; + gRecentFrameCount = 0; + gRecentFPSTime.reset(); + } + F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency"); + if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq) + { + gMemoryAllocated = LLMemory::getCurrentRSS(); + U32 memory = (U32)(gMemoryAllocated / (1024*1024)); + llinfos << llformat("MEMORY: %d MB", memory) << llendl; + LLMemory::logMemoryInfo(TRUE) ; + gRecentMemoryTime.reset(); + } +} + +static LLFastTimer::DeclareTimer FTM_PICK("Picking"); +static LLFastTimer::DeclareTimer FTM_RENDER("Render", true); +static LLFastTimer::DeclareTimer FTM_UPDATE_SKY("Update Sky"); +static LLFastTimer::DeclareTimer FTM_UPDATE_TEXTURES("Update Textures"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE("Update Images"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_CLASS("Class"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_BUMP("Bump"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_LIST("List"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_DELETE("Delete"); + +// Paint the display! +void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) +{ + LLMemType mt_render(LLMemType::MTYPE_RENDER); + LLFastTimer t(FTM_RENDER); + + if (gWindowResized) + { //skip render on frames where window has been resized + gGL.flush(); + glClear(GL_COLOR_BUFFER_BIT); + gViewerWindow->getWindow()->swapBuffers(); + LLPipeline::refreshCachedSettings(); + gPipeline.resizeScreenTexture(); + gResizeScreenTexture = FALSE; + gWindowResized = FALSE; + return; + } + + if (LLPipeline::sRenderDeferred) + { //hack to make sky show up in deferred snapshots + for_snapshot = FALSE; + } + + if (LLPipeline::sRenderFrameTest) + { + send_agent_pause(); + } + + gSnapshot = for_snapshot; + + LLGLSDefault gls_default; + LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE, GL_LEQUAL); + + LLVertexBuffer::unbind(); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + + stop_glerror(); + + gPipeline.disableLights(); + + stop_glerror(); + + // Don't draw if the window is hidden or minimized. + // In fact, must explicitly check the minimized state before drawing. + // Attempting to draw into a minimized window causes a GL error. JC + if ( !gViewerWindow->getActive() + || !gViewerWindow->getWindow()->getVisible() + || gViewerWindow->getWindow()->getMinimized() ) + { + // Clean up memory the pools may have allocated + if (rebuild) + { + stop_glerror(); + gPipeline.rebuildPools(); + stop_glerror(); + } + + stop_glerror(); + gViewerWindow->returnEmptyPicks(); + stop_glerror(); + return; + } + + gViewerWindow->checkSettings(); + + { + LLFastTimer ftm(FTM_PICK); + LLAppViewer::instance()->pingMainloopTimeout("Display:Pick"); + gViewerWindow->performPick(); + } + + LLAppViewer::instance()->pingMainloopTimeout("Display:CheckStates"); + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + + ////////////////////////////////////////////////////////// + // + // Logic for forcing window updates if we're in drone mode. + // + + // *TODO: Investigate running display() during gHeadlessClient. See if this early exit is needed DK 2011-02-18 + if (gHeadlessClient) + { +#if LL_WINDOWS + static F32 last_update_time = 0.f; + if ((gFrameTimeSeconds - last_update_time) > 1.f) + { + InvalidateRect((HWND)gViewerWindow->getPlatformWindow(), NULL, FALSE); + last_update_time = gFrameTimeSeconds; + } +#elif LL_DARWIN + // MBW -- Do something clever here. +#endif + // Not actually rendering, don't bother. + return; + } + + + // + // Bail out if we're in the startup state and don't want to try to + // render the world. + // + if (LLStartUp::getStartupState() < STATE_STARTED) + { + LLAppViewer::instance()->pingMainloopTimeout("Display:Startup"); + display_startup(); + return; + } + + //LLGLState::verify(FALSE); + + ///////////////////////////////////////////////// + // + // Update GL Texture statistics (used for discard logic?) + // + + LLAppViewer::instance()->pingMainloopTimeout("Display:TextureStats"); + stop_glerror(); + + LLImageGL::updateStats(gFrameTimeSeconds); + + LLVOAvatar::sRenderName = gSavedSettings.getS32("AvatarNameTagMode"); + LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("NameTagShowGroupTitles") && gSavedSettings.getS32("AvatarNameTagMode")); + + gPipeline.mBackfaceCull = TRUE; + gFrameCount++; + gRecentFrameCount++; + if (gFocusMgr.getAppHasFocus()) + { + gForegroundFrameCount++; + } + + ////////////////////////////////////////////////////////// + // + // Display start screen if we're teleporting, and skip render + // + + if (gTeleportDisplay) + { + LLAppViewer::instance()->pingMainloopTimeout("Display:Teleport"); + const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived. + + S32 attach_count = 0; + if (isAgentAvatarValid()) + { + attach_count = gAgentAvatarp->getAttachmentCount(); + } + F32 teleport_save_time = TELEPORT_EXPIRY + TELEPORT_EXPIRY_PER_ATTACHMENT * attach_count; + F32 teleport_elapsed = gTeleportDisplayTimer.getElapsedTimeF32(); + F32 teleport_percent = teleport_elapsed * (100.f / teleport_save_time); + if( (gAgent.getTeleportState() != LLAgent::TELEPORT_START) && (teleport_percent > 100.f) ) + { + // Give up. Don't keep the UI locked forever. + gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + gAgent.setTeleportMessage(std::string()); + } + + const std::string& message = gAgent.getTeleportMessage(); + switch( gAgent.getTeleportState() ) + { + case LLAgent::TELEPORT_START: + // Transition to REQUESTED. Viewer has sent some kind + // of TeleportRequest to the source simulator + gTeleportDisplayTimer.reset(); + gViewerWindow->setShowProgress(TRUE); + gViewerWindow->setProgressPercent(0); + gAgent.setTeleportState( LLAgent::TELEPORT_REQUESTED ); + gAgent.setTeleportMessage( + LLAgent::sTeleportProgressMessages["requesting"]); + break; + + case LLAgent::TELEPORT_REQUESTED: + // Waiting for source simulator to respond + gViewerWindow->setProgressPercent( llmin(teleport_percent, 37.5f) ); + gViewerWindow->setProgressString(message); + break; + + case LLAgent::TELEPORT_MOVING: + // Viewer has received destination location from source simulator + gViewerWindow->setProgressPercent( llmin(teleport_percent, 75.f) ); + gViewerWindow->setProgressString(message); + break; + + case LLAgent::TELEPORT_START_ARRIVAL: + // Transition to ARRIVING. Viewer has received avatar update, etc., from destination simulator + gTeleportArrivalTimer.reset(); + gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel")); + gViewerWindow->setProgressPercent(75.f); + gAgent.setTeleportState( LLAgent::TELEPORT_ARRIVING ); + gAgent.setTeleportMessage( + LLAgent::sTeleportProgressMessages["arriving"]); + gTextureList.mForceResetTextureStats = TRUE; + gAgentCamera.resetView(TRUE, TRUE); + break; + + case LLAgent::TELEPORT_ARRIVING: + // Make the user wait while content "pre-caches" + { + F32 arrival_fraction = (gTeleportArrivalTimer.getElapsedTimeF32() / TELEPORT_ARRIVAL_DELAY); + if( arrival_fraction > 1.f ) + { + arrival_fraction = 1.f; + //LLFirstUse::useTeleport(); + gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + } + gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel")); + gViewerWindow->setProgressPercent( arrival_fraction * 25.f + 75.f); + gViewerWindow->setProgressString(message); + } + break; + + case LLAgent::TELEPORT_LOCAL: + // Short delay when teleporting in the same sim (progress screen active but not shown - did not + // fall-through from TELEPORT_START) + { + if( gTeleportDisplayTimer.getElapsedTimeF32() > TELEPORT_LOCAL_DELAY ) + { + //LLFirstUse::useTeleport(); + gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + } + } + break; + + case LLAgent::TELEPORT_NONE: + // No teleport in progress + gViewerWindow->setShowProgress(FALSE); + gTeleportDisplay = FALSE; + break; + } + } + else if(LLAppViewer::instance()->logoutRequestSent()) + { + LLAppViewer::instance()->pingMainloopTimeout("Display:Logout"); + F32 percent_done = gLogoutTimer.getElapsedTimeF32() * 100.f / gLogoutMaxTime; + if (percent_done > 100.f) + { + percent_done = 100.f; + } + + if( LLApp::isExiting() ) + { + percent_done = 100.f; + } + + gViewerWindow->setProgressPercent( percent_done ); + } + else + if (gRestoreGL) + { + LLAppViewer::instance()->pingMainloopTimeout("Display:RestoreGL"); + F32 percent_done = gRestoreGLTimer.getElapsedTimeF32() * 100.f / RESTORE_GL_TIME; + if( percent_done > 100.f ) + { + gViewerWindow->setShowProgress(FALSE); + gRestoreGL = FALSE; + } + else + { + + if( LLApp::isExiting() ) + { + percent_done = 100.f; + } + + gViewerWindow->setProgressPercent( percent_done ); + } + } + + ////////////////////////// + // + // Prepare for the next frame + // + + ///////////////////////////// + // + // Update the camera + // + // + + LLAppViewer::instance()->pingMainloopTimeout("Display:Camera"); + LLViewerCamera::getInstance()->setZoomParameters(zoom_factor, subfield); + LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE); + + ////////////////////////// + // + // clear the next buffer + // (must follow dynamic texture writing since that uses the frame buffer) + // + + if (gDisconnected) + { + LLAppViewer::instance()->pingMainloopTimeout("Display:Disconnected"); + render_ui(); + } + + ////////////////////////// + // + // Set rendering options + // + // + LLAppViewer::instance()->pingMainloopTimeout("Display:RenderSetup"); + stop_glerror(); + + /////////////////////////////////////// + // + // Slam lighting parameters back to our defaults. + // Note that these are not the same as GL defaults... + + stop_glerror(); + gGL.setAmbientLightColor(LLColor4::white); + stop_glerror(); + + ///////////////////////////////////// + // + // Render + // + // Actually push all of our triangles to the screen. + // + + // do render-to-texture stuff here + if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES)) + { + LLAppViewer::instance()->pingMainloopTimeout("Display:DynamicTextures"); + LLFastTimer t(FTM_UPDATE_TEXTURES); + if (LLViewerDynamicTexture::updateAllInstances()) + { + gGL.setColorMask(true, true); + glClear(GL_DEPTH_BUFFER_BIT); + } + } + + gViewerWindow->setup3DViewport(); + + gPipeline.resetFrameStats(); // Reset per-frame statistics. + + if (!gDisconnected) + { + LLMemType mt_du(LLMemType::MTYPE_DISPLAY_UPDATE); + LLAppViewer::instance()->pingMainloopTimeout("Display:Update"); + if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { //don't draw hud objects in this frame + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); + } + + if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES)) + { //don't draw hud particles in this frame + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES); + } + + //upkeep gl name pools + LLGLNamePool::upkeepPools(); + + stop_glerror(); + display_update_camera(); + stop_glerror(); + + // *TODO: merge these two methods + { + LLMemType mt_uh(LLMemType::MTYPE_DISPLAY_UPDATE_HUD); + LLHUDManager::getInstance()->updateEffects(); + LLHUDObject::updateAll(); + stop_glerror(); + } + + { + LLMemType mt_ug(LLMemType::MTYPE_DISPLAY_UPDATE_GEOM); + const F32 max_geom_update_time = 0.005f*10.f*gFrameIntervalSeconds; // 50 ms/second update time + gPipeline.createObjects(max_geom_update_time); + gPipeline.processPartitionQ(); + gPipeline.updateGeom(max_geom_update_time); + stop_glerror(); + } + + gPipeline.updateGL(); + stop_glerror(); + + S32 water_clip = 0; + if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) && + (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER) || + gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER))) + { + if (LLViewerCamera::getInstance()->cameraUnderWater()) + { + water_clip = -1; + } + else + { + water_clip = 1; + } + } + + LLAppViewer::instance()->pingMainloopTimeout("Display:Cull"); + + //Increment drawable frame counter + LLDrawable::incrementVisible(); + + LLSpatialGroup::sNoDelete = TRUE; + LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName(); + + /*if (LLPipeline::sUseOcclusion && LLPipeline::sRenderDeferred) + { //force occlusion on for all render types if doing deferred render (tighter shadow frustum) + LLPipeline::sUseOcclusion = 3; + }*/ + + S32 occlusion = LLPipeline::sUseOcclusion; + if (gDepthDirty) + { //depth buffer is invalid, don't overwrite occlusion state + LLPipeline::sUseOcclusion = llmin(occlusion, 1); + } + gDepthDirty = FALSE; + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + + static LLCullResult result; + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + gPipeline.updateCull(*LLViewerCamera::getInstance(), result, water_clip); + stop_glerror(); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + + BOOL to_texture = gPipeline.canUseVertexShaders() && + LLPipeline::sRenderGlow; + + LLAppViewer::instance()->pingMainloopTimeout("Display:Swap"); + + { + LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SWAP); + + if (gResizeScreenTexture) + { + gResizeScreenTexture = FALSE; + gPipeline.resizeScreenTexture(); + } + + gGL.setColorMask(true, true); + glClearColor(0,0,0,0); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + + if (!for_snapshot) + { + if (gFrameCount > 1) + { //for some reason, ATI 4800 series will error out if you + //try to generate a shadow before the first frame is through + gPipeline.generateSunShadow(*LLViewerCamera::getInstance()); + } + + LLVertexBuffer::unbind(); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + + glh::matrix4f proj = glh_get_current_projection(); + glh::matrix4f mod = glh_get_current_modelview(); + glViewport(0,0,512,512); + LLVOAvatar::updateFreezeCounter() ; + + if(!LLPipeline::sMemAllocationThrottled) + { + LLVOAvatar::updateImpostors(); + } + + glh_set_current_projection(proj); + glh_set_current_modelview(mod); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.loadMatrix(proj.m); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.loadMatrix(mod.m); + gViewerWindow->setup3DViewport(); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + + } + glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + } + + LLGLState::checkStates(); + LLGLState::checkClientArrays(); + + //if (!for_snapshot) + { + LLMemType mt_gw(LLMemType::MTYPE_DISPLAY_GEN_REFLECTION); + LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery"); + gPipeline.generateWaterReflection(*LLViewerCamera::getInstance()); + gPipeline.generateHighlight(*LLViewerCamera::getInstance()); + gPipeline.renderPhysicsDisplay(); + } + + LLGLState::checkStates(); + LLGLState::checkClientArrays(); + + ////////////////////////////////////// + // + // Update images, using the image stats generated during object update/culling + // + // Can put objects onto the retextured list. + // + // Doing this here gives hardware occlusion queries extra time to complete + LLAppViewer::instance()->pingMainloopTimeout("Display:UpdateImages"); + + { + LLMemType mt_iu(LLMemType::MTYPE_DISPLAY_IMAGE_UPDATE); + LLFastTimer t(FTM_IMAGE_UPDATE); + + { + LLFastTimer t(FTM_IMAGE_UPDATE_CLASS); + LLViewerTexture::updateClass(LLViewerCamera::getInstance()->getVelocityStat()->getMean(), + LLViewerCamera::getInstance()->getAngularVelocityStat()->getMean()); + } + + + { + LLFastTimer t(FTM_IMAGE_UPDATE_BUMP); + gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first. + } + + { + LLFastTimer t(FTM_IMAGE_UPDATE_LIST); + F32 max_image_decode_time = 0.050f*gFrameIntervalSeconds; // 50 ms/second decode time + max_image_decode_time = llclamp(max_image_decode_time, 0.002f, 0.005f ); // min 2ms/frame, max 5ms/frame) + gTextureList.updateImages(max_image_decode_time); + } + + { + LLFastTimer t(FTM_IMAGE_UPDATE_DELETE); + //remove dead textures from GL + LLImageGL::deleteDeadTextures(); + stop_glerror(); + } + } + + LLGLState::checkStates(); + LLGLState::checkClientArrays(); + + /////////////////////////////////// + // + // StateSort + // + // Responsible for taking visible objects, and adding them to the appropriate draw orders. + // In the case of alpha objects, z-sorts them first. + // Also creates special lists for outlines and selected face rendering. + // + LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort"); + { + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + LLMemType mt_ss(LLMemType::MTYPE_DISPLAY_STATE_SORT); + gPipeline.stateSort(*LLViewerCamera::getInstance(), result); + stop_glerror(); + + if (rebuild) + { + ////////////////////////////////////// + // + // rebuildPools + // + // + gPipeline.rebuildPools(); + stop_glerror(); + } + } + + LLGLState::checkStates(); + LLGLState::checkClientArrays(); + + LLPipeline::sUseOcclusion = occlusion; + + { + LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SKY); + LLAppViewer::instance()->pingMainloopTimeout("Display:Sky"); + LLFastTimer t(FTM_UPDATE_SKY); + gSky.updateSky(); + } + + if(gUseWireframe) + { + glClearColor(0.5f, 0.5f, 0.5f, 0.f); + glClear(GL_COLOR_BUFFER_BIT); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } + + LLAppViewer::instance()->pingMainloopTimeout("Display:RenderStart"); + + //// render frontmost floater opaque for occlusion culling purposes + //LLFloater* frontmost_floaterp = gFloaterView->getFrontmost(); + //// assumes frontmost floater with focus is opaque + //if (frontmost_floaterp && gFocusMgr.childHasKeyboardFocus(frontmost_floaterp)) + //{ + // gGL.matrixMode(LLRender::MM_MODELVIEW); + // gGL.pushMatrix(); + // { + // gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + // glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); + // gGL.loadIdentity(); + + // LLRect floater_rect = frontmost_floaterp->calcScreenRect(); + // // deflate by one pixel so rounding errors don't occlude outside of floater extents + // floater_rect.stretch(-1); + // LLRectf floater_3d_rect((F32)floater_rect.mLeft / (F32)gViewerWindow->getWindowWidthScaled(), + // (F32)floater_rect.mTop / (F32)gViewerWindow->getWindowHeightScaled(), + // (F32)floater_rect.mRight / (F32)gViewerWindow->getWindowWidthScaled(), + // (F32)floater_rect.mBottom / (F32)gViewerWindow->getWindowHeightScaled()); + // floater_3d_rect.translate(-0.5f, -0.5f); + // gGL.translatef(0.f, 0.f, -LLViewerCamera::getInstance()->getNear()); + // gGL.scalef(LLViewerCamera::getInstance()->getNear() * LLViewerCamera::getInstance()->getAspect() / sinf(LLViewerCamera::getInstance()->getView()), LLViewerCamera::getInstance()->getNear() / sinf(LLViewerCamera::getInstance()->getView()), 1.f); + // gGL.color4fv(LLColor4::white.mV); + // gGL.begin(LLVertexBuffer::QUADS); + // { + // gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mBottom, 0.f); + // gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mTop, 0.f); + // gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mTop, 0.f); + // gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mBottom, 0.f); + // } + // gGL.end(); + // glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + // } + // gGL.popMatrix(); + //} + + LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE; + + LLGLState::checkStates(); + LLGLState::checkClientArrays(); + + stop_glerror(); + + if (to_texture) + { + gGL.setColorMask(true, true); + + if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) + { + gPipeline.mDeferredScreen.bindTarget(); + glClearColor(1,0,1,1); + gPipeline.mDeferredScreen.clear(); + } + else + { + gPipeline.mScreen.bindTarget(); + if (LLPipeline::sUnderWaterRender && !gPipeline.canUseWindLightShaders()) + { + const LLColor4 &col = LLDrawPoolWater::sWaterFogColor; + glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f); + } + gPipeline.mScreen.clear(); + } + + gGL.setColorMask(true, false); + } + + LLAppViewer::instance()->pingMainloopTimeout("Display:RenderGeom"); + bool exclusiveDraw = false; + BOOL allowRenderables = false; + BOOL allowPathToBeDrawn = false; + if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot()) + && !gRestoreGL) + { + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + LLMemType mt_rg(LLMemType::MTYPE_DISPLAY_RENDER_GEOM); + gGL.setColorMask(true, false); + if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) + { + gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance()); + } + else + { + //Render any navmesh geometry + if ( LLPathingLib::getInstance() ) + { + //Determine if we can should overlay the navmesh ontop of the scenes typical renderables + LLFloaterPathfindingConsole* pFloater = LLFloaterReg::getTypedInstance<LLFloaterPathfindingConsole>("pathfinding_console"); + if ( pFloater && pFloater->allowAllRenderables() ) + { + allowRenderables = true; + } + //Determine if we should also draw a user supplied path on top of the scene + if ( pFloater && pFloater->getShowPathToggle() ) + { + allowPathToBeDrawn = true; + } + //NavMesh + if ( LLPathingLib::getInstance()->getRenderNavMeshState() ) + { + glClearColor(0.0f, 0.0f, 0.0f, 0.5f); + glEnable(GL_DEPTH_TEST); + gGL.setAmbientLightColor( LLColor4::white ); + LLPathingLib::getInstance()->renderNavMesh( allowRenderables ); + exclusiveDraw = true; + } + //physics/exclusion shapes + if ( LLPathingLib::getInstance()->getRenderShapeState() ) + { + LLPathingLib::getInstance()->renderNavMeshShapesVBO(); + exclusiveDraw = true; + } + //User designated path + if ( allowPathToBeDrawn ) + { + LLPathingLib::getInstance()->renderPath(); + } + } + } + + if ( !exclusiveDraw || allowRenderables ) + { + gPipeline.renderGeom(*LLViewerCamera::getInstance(), TRUE); + } + + gGL.setColorMask(true, true); + + //store this frame's modelview matrix for use + //when rendering next frame's occlusion queries + for (U32 i = 0; i < 16; i++) + { + gGLLastModelView[i] = gGLModelView[i]; + gGLLastProjection[i] = gGLProjection[i]; + } + stop_glerror(); + } + + for (U32 i = 0; i < gGLManager.mNumTextureImageUnits; i++) + { //dummy cleanup of any currently bound textures + if (gGL.getTexUnit(i)->getCurrType() != LLTexUnit::TT_NONE) + { + gGL.getTexUnit(i)->unbind(gGL.getTexUnit(i)->getCurrType()); + gGL.getTexUnit(i)->disable(); + } + } + LLAppViewer::instance()->pingMainloopTimeout("Display:RenderFlush"); + + if (to_texture) + { + LLMemType mt_rf(LLMemType::MTYPE_DISPLAY_RENDER_FLUSH); + if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) + { + gPipeline.mDeferredScreen.flush(); + if(LLRenderTarget::sUseFBO) + { + LLRenderTarget::copyContentsToFramebuffer(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), + gPipeline.mDeferredScreen.getHeight(), 0, 0, + gPipeline.mDeferredScreen.getWidth(), + gPipeline.mDeferredScreen.getHeight(), + GL_DEPTH_BUFFER_BIT, GL_NEAREST); + } + } + else + { + gPipeline.mScreen.flush(); + if(LLRenderTarget::sUseFBO) + { + LLRenderTarget::copyContentsToFramebuffer(gPipeline.mScreen, 0, 0, gPipeline.mScreen.getWidth(), + gPipeline.mScreen.getHeight(), 0, 0, + gPipeline.mScreen.getWidth(), + gPipeline.mScreen.getHeight(), + GL_DEPTH_BUFFER_BIT, GL_NEAREST); + } + } + } + + if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) + { + gPipeline.renderDeferredLighting(); + } + + LLPipeline::sUnderWaterRender = FALSE; + + LLAppViewer::instance()->pingMainloopTimeout("Display:RenderUI"); + if (!for_snapshot) + { + LLFastTimer t(FTM_RENDER_UI); + render_ui(); + } + + + LLSpatialGroup::sNoDelete = FALSE; + gPipeline.clearReferences(); + + gPipeline.rebuildGroups(); + } + + LLAppViewer::instance()->pingMainloopTimeout("Display:FrameStats"); + + stop_glerror(); + + if (LLPipeline::sRenderFrameTest) + { + send_agent_resume(); + LLPipeline::sRenderFrameTest = FALSE; + } + + display_stats(); + + LLAppViewer::instance()->pingMainloopTimeout("Display:Done"); +} + +void render_hud_attachments() +{ + LLMemType mt_ra(LLMemType::MTYPE_DISPLAY_RENDER_ATTACHMENTS); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + + glh::matrix4f current_proj = glh_get_current_projection(); + glh::matrix4f current_mod = glh_get_current_modelview(); + + // clamp target zoom level to reasonable values + gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f); + // smoothly interpolate current zoom level + gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.mHUDTargetZoom, LLCriticalDamp::getInterpolant(0.03f)); + + if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices()) + { + LLCamera hud_cam = *LLViewerCamera::getInstance(); + LLVector3 origin = hud_cam.getOrigin(); + hud_cam.setOrigin(-1.f,0,0); + hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1)); + LLViewerCamera::updateFrustumPlanes(hud_cam, TRUE); + + bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && gSavedSettings.getBOOL("RenderHUDParticles"); + + //only render hud objects + gPipeline.pushRenderTypeMask(); + + // turn off everything + gPipeline.andRenderTypeMask(LLPipeline::END_RENDER_TYPES); + // turn on HUD + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); + // turn on HUD particles + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES); + + // if particles are off, turn off hud-particles as well + if (!render_particles) + { + // turn back off HUD particles + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES); + } + + bool has_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI); + if (has_ui) + { + gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI); + } + + S32 use_occlusion = LLPipeline::sUseOcclusion; + LLPipeline::sUseOcclusion = 0; + + //cull, sort, and render hud objects + static LLCullResult result; + LLSpatialGroup::sNoDelete = TRUE; + + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + gPipeline.updateCull(hud_cam, result); + + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_BUMP); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_SIMPLE); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_BUMP); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_SHINY); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISIBLE); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY); + + gPipeline.stateSort(hud_cam, result); + + gPipeline.renderGeom(hud_cam); + + LLSpatialGroup::sNoDelete = FALSE; + //gPipeline.clearReferences(); + + render_hud_elements(); + + //restore type mask + gPipeline.popRenderTypeMask(); + + if (has_ui) + { + gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI); + } + LLPipeline::sUseOcclusion = use_occlusion; + } + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + + glh_set_current_projection(current_proj); + glh_set_current_modelview(current_mod); +} + +LLRect get_whole_screen_region() +{ + LLRect whole_screen = gViewerWindow->getWorldViewRectScaled(); + + // 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) + { + S32 num_horizontal_tiles = llceil(zoom_factor); + S32 tile_width = llround((F32)gViewerWindow->getWorldViewWidthScaled() / zoom_factor); + S32 tile_height = llround((F32)gViewerWindow->getWorldViewHeightScaled() / zoom_factor); + int tile_y = sub_region / num_horizontal_tiles; + int tile_x = sub_region - (tile_y * num_horizontal_tiles); + + whole_screen.setLeftTopAndSize(tile_x * tile_width, gViewerWindow->getWorldViewHeightScaled() - (tile_y * tile_height), tile_width, tile_height); + } + return whole_screen; +} + +bool get_hud_matrices(const LLRect& screen_region, glh::matrix4f &proj, glh::matrix4f &model) +{ + if (isAgentAvatarValid() && gAgentAvatarp->hasHUDAttachment()) + { + F32 zoom_level = gAgentCamera.mHUDCurZoom; + LLBBox hud_bbox = gAgentAvatarp->getHUDBBox(); + + F32 hud_depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f); + proj = gl_ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, hud_depth); + proj.element(2,2) = -0.01f; + + F32 aspect_ratio = LLViewerCamera::getInstance()->getAspect(); + + glh::matrix4f mat; + F32 scale_x = (F32)gViewerWindow->getWorldViewWidthScaled() / (F32)screen_region.getWidth(); + F32 scale_y = (F32)gViewerWindow->getWorldViewHeightScaled() / (F32)screen_region.getHeight(); + mat.set_scale(glh::vec3f(scale_x, scale_y, 1.f)); + mat.set_translate( + glh::vec3f(clamp_rescale((F32)(screen_region.getCenterX() - screen_region.mLeft), 0.f, (F32)gViewerWindow->getWorldViewWidthScaled(), 0.5f * scale_x * aspect_ratio, -0.5f * scale_x * aspect_ratio), + clamp_rescale((F32)(screen_region.getCenterY() - screen_region.mBottom), 0.f, (F32)gViewerWindow->getWorldViewHeightScaled(), 0.5f * scale_y, -0.5f * scale_y), + 0.f)); + proj *= mat; + + glh::matrix4f tmp_model((GLfloat*) OGL_TO_CFR_ROTATION); + + mat.set_scale(glh::vec3f(zoom_level, zoom_level, zoom_level)); + mat.set_translate(glh::vec3f(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f)); + + tmp_model *= mat; + model = tmp_model; + return TRUE; + } + else + { + return FALSE; + } +} + +bool get_hud_matrices(glh::matrix4f &proj, glh::matrix4f &model) +{ + LLRect whole_screen = get_whole_screen_region(); + return get_hud_matrices(whole_screen, proj, model); +} + +BOOL setup_hud_matrices() +{ + LLRect whole_screen = get_whole_screen_region(); + return setup_hud_matrices(whole_screen); +} + +BOOL setup_hud_matrices(const LLRect& screen_region) +{ + glh::matrix4f proj, model; + bool result = get_hud_matrices(screen_region, proj, model); + if (!result) return result; + + // set up transform to keep HUD objects in front of camera + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.loadMatrix(proj.m); + glh_set_current_projection(proj); + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.loadMatrix(model.m); + glh_set_current_modelview(model); + return TRUE; +} + +static LLFastTimer::DeclareTimer FTM_SWAP("Swap"); + +void render_ui(F32 zoom_factor, int subfield) +{ + LLMemType mt_ru(LLMemType::MTYPE_DISPLAY_RENDER_UI); + LLGLState::checkStates(); + + glh::matrix4f saved_view = glh_get_current_modelview(); + + if (!gSnapshot) + { + gGL.pushMatrix(); + gGL.loadMatrix(gGLLastModelView); + glh_set_current_modelview(glh_copy_matrix(gGLLastModelView)); + } + + { + BOOL to_texture = gPipeline.canUseVertexShaders() && + LLPipeline::sRenderGlow; + + if (to_texture) + { + gPipeline.renderBloom(gSnapshot, zoom_factor, subfield); + } + + render_hud_elements(); + render_hud_attachments(); + } + + LLGLSDefault gls_default; + LLGLSUIDefault gls_ui; + { + gPipeline.disableLights(); + } + + { + gGL.color4f(1,1,1,1); + if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { + LLFastTimer t(FTM_RENDER_UI); + + if (!gDisconnected) + { + render_ui_3d(); + LLGLState::checkStates(); + } + else + { + render_disconnected_background(); + } + + render_ui_2d(); + LLGLState::checkStates(); + } + gGL.flush(); + + { + gViewerWindow->setup2DRender(); + gViewerWindow->updateDebugText(); + gViewerWindow->drawDebugText(); + } + + LLVertexBuffer::unbind(); + } + + if (!gSnapshot) + { + glh_set_current_modelview(saved_view); + gGL.popMatrix(); + } + + if (gDisplaySwapBuffers) + { + LLFastTimer t(FTM_SWAP); + gViewerWindow->getWindow()->swapBuffers(); + } + gDisplaySwapBuffers = TRUE; +} + +void renderCoordinateAxes() +{ + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.begin(LLRender::LINES); + gGL.color3f(1.0f, 0.0f, 0.0f); // i direction = X-Axis = red + gGL.vertex3f(0.0f, 0.0f, 0.0f); + gGL.vertex3f(2.0f, 0.0f, 0.0f); + gGL.vertex3f(3.0f, 0.0f, 0.0f); + gGL.vertex3f(5.0f, 0.0f, 0.0f); + gGL.vertex3f(6.0f, 0.0f, 0.0f); + gGL.vertex3f(8.0f, 0.0f, 0.0f); + // Make an X + gGL.vertex3f(11.0f, 1.0f, 1.0f); + gGL.vertex3f(11.0f, -1.0f, -1.0f); + gGL.vertex3f(11.0f, 1.0f, -1.0f); + gGL.vertex3f(11.0f, -1.0f, 1.0f); + + gGL.color3f(0.0f, 1.0f, 0.0f); // j direction = Y-Axis = green + gGL.vertex3f(0.0f, 0.0f, 0.0f); + gGL.vertex3f(0.0f, 2.0f, 0.0f); + gGL.vertex3f(0.0f, 3.0f, 0.0f); + gGL.vertex3f(0.0f, 5.0f, 0.0f); + gGL.vertex3f(0.0f, 6.0f, 0.0f); + gGL.vertex3f(0.0f, 8.0f, 0.0f); + // Make a Y + gGL.vertex3f(1.0f, 11.0f, 1.0f); + gGL.vertex3f(0.0f, 11.0f, 0.0f); + gGL.vertex3f(-1.0f, 11.0f, 1.0f); + gGL.vertex3f(0.0f, 11.0f, 0.0f); + gGL.vertex3f(0.0f, 11.0f, 0.0f); + gGL.vertex3f(0.0f, 11.0f, -1.0f); + + gGL.color3f(0.0f, 0.0f, 1.0f); // Z-Axis = blue + gGL.vertex3f(0.0f, 0.0f, 0.0f); + gGL.vertex3f(0.0f, 0.0f, 2.0f); + gGL.vertex3f(0.0f, 0.0f, 3.0f); + gGL.vertex3f(0.0f, 0.0f, 5.0f); + gGL.vertex3f(0.0f, 0.0f, 6.0f); + gGL.vertex3f(0.0f, 0.0f, 8.0f); + // Make a Z + gGL.vertex3f(-1.0f, 1.0f, 11.0f); + gGL.vertex3f(1.0f, 1.0f, 11.0f); + gGL.vertex3f(1.0f, 1.0f, 11.0f); + gGL.vertex3f(-1.0f, -1.0f, 11.0f); + gGL.vertex3f(-1.0f, -1.0f, 11.0f); + gGL.vertex3f(1.0f, -1.0f, 11.0f); + gGL.end(); +} + + +void draw_axes() +{ + LLGLSUIDefault gls_ui; + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + // A vertical white line at origin + LLVector3 v = gAgent.getPositionAgent(); + gGL.begin(LLRender::LINES); + gGL.color3f(1.0f, 1.0f, 1.0f); + gGL.vertex3f(0.0f, 0.0f, 0.0f); + gGL.vertex3f(0.0f, 0.0f, 40.0f); + gGL.end(); + // Some coordinate axes + gGL.pushMatrix(); + gGL.translatef( v.mV[VX], v.mV[VY], v.mV[VZ] ); + renderCoordinateAxes(); + gGL.popMatrix(); +} + +void render_ui_3d() +{ + LLGLSPipeline gls_pipeline; + + ////////////////////////////////////// + // + // Render 3D UI elements + // NOTE: zbuffer is cleared before we get here by LLDrawPoolHUD, + // so 3d elements requiring Z buffer are moved to LLDrawPoolHUD + // + + ///////////////////////////////////////////////////////////// + // + // Render 2.5D elements (2D elements in the world) + // Stuff without z writes + // + + // Debugging stuff goes before the UI. + + stop_glerror(); + + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.bind(); + } + + // Coordinate axes + if (gSavedSettings.getBOOL("ShowAxes")) + { + draw_axes(); + } + + gViewerWindow->renderSelections(FALSE, FALSE, TRUE); // Non HUD call in render_hud_elements + stop_glerror(); +} + +void render_ui_2d() +{ + LLGLSUIDefault gls_ui; + + ///////////////////////////////////////////////////////////// + // + // Render 2D UI elements that overlay the world (no z compare) + + // Disable wireframe mode below here, as this is HUD/menus + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + // Menu overlays, HUD, etc + gViewerWindow->setup2DRender(); + + F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor(); + S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion(); + + if (zoom_factor > 1.f) + { + //decompose subregion number to x and y values + int pos_y = sub_region / llceil(zoom_factor); + int pos_x = sub_region - (pos_y*llceil(zoom_factor)); + // offset for this tile + LLFontGL::sCurOrigin.mX -= llround((F32)gViewerWindow->getWindowWidthScaled() * (F32)pos_x / zoom_factor); + LLFontGL::sCurOrigin.mY -= llround((F32)gViewerWindow->getWindowHeightScaled() * (F32)pos_y / zoom_factor); + } + + stop_glerror(); + //gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); + + // render outline for HUD + if (isAgentAvatarValid() && gAgentCamera.mHUDCurZoom < 0.98f) + { + gGL.pushMatrix(); + S32 half_width = (gViewerWindow->getWorldViewWidthScaled() / 2); + S32 half_height = (gViewerWindow->getWorldViewHeightScaled() / 2); + gGL.scalef(LLUI::sGLScaleFactor.mV[0], LLUI::sGLScaleFactor.mV[1], 1.f); + gGL.translatef((F32)half_width, (F32)half_height, 0.f); + F32 zoom = gAgentCamera.mHUDCurZoom; + gGL.scalef(zoom,zoom,1.f); + gGL.color4fv(LLColor4::white.mV); + gl_rect_2d(-half_width, half_height, half_width, -half_height, FALSE); + gGL.popMatrix(); + stop_glerror(); + } + + + if (gSavedSettings.getBOOL("RenderUIBuffer")) + { + if (LLUI::sDirty) + { + LLUI::sDirty = FALSE; + LLRect t_rect; + + gPipeline.mUIScreen.bindTarget(); + gGL.setColorMask(true, true); + { + static const S32 pad = 8; + + LLUI::sDirtyRect.mLeft -= pad; + LLUI::sDirtyRect.mRight += pad; + LLUI::sDirtyRect.mBottom -= pad; + LLUI::sDirtyRect.mTop += pad; + + LLGLEnable scissor(GL_SCISSOR_TEST); + static LLRect last_rect = LLUI::sDirtyRect; + + //union with last rect to avoid mouse poop + last_rect.unionWith(LLUI::sDirtyRect); + + t_rect = LLUI::sDirtyRect; + LLUI::sDirtyRect = last_rect; + last_rect = t_rect; + + last_rect.mLeft = LLRect::tCoordType(last_rect.mLeft / LLUI::sGLScaleFactor.mV[0]); + last_rect.mRight = LLRect::tCoordType(last_rect.mRight / LLUI::sGLScaleFactor.mV[0]); + last_rect.mTop = LLRect::tCoordType(last_rect.mTop / LLUI::sGLScaleFactor.mV[1]); + last_rect.mBottom = LLRect::tCoordType(last_rect.mBottom / LLUI::sGLScaleFactor.mV[1]); + + LLRect clip_rect(last_rect); + + glClear(GL_COLOR_BUFFER_BIT); + + gViewerWindow->draw(); + } + + gPipeline.mUIScreen.flush(); + gGL.setColorMask(true, false); + + LLUI::sDirtyRect = t_rect; + } + + LLGLDisable cull(GL_CULL_FACE); + LLGLDisable blend(GL_BLEND); + S32 width = gViewerWindow->getWindowWidthScaled(); + S32 height = gViewerWindow->getWindowHeightScaled(); + gGL.getTexUnit(0)->bind(&gPipeline.mUIScreen); + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.color4f(1,1,1,1); + gGL.texCoord2f(0, 0); gGL.vertex2i(0, 0); + gGL.texCoord2f(width, 0); gGL.vertex2i(width, 0); + gGL.texCoord2f(0, height); gGL.vertex2i(0, height); + gGL.texCoord2f(width, height); gGL.vertex2i(width, height); + gGL.end(); + } + else + { + gViewerWindow->draw(); + } + + + + // reset current origin for font rendering, in case of tiling render + LLFontGL::sCurOrigin.set(0, 0); +} + +void render_disconnected_background() +{ + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.bind(); + } + + gGL.color4f(1,1,1,1); + if (!gDisconnectedImagep && gDisconnected) + { + llinfos << "Loading last bitmap..." << llendl; + + std::string temp_str; + temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + SCREEN_LAST_FILENAME; + + LLPointer<LLImageBMP> image_bmp = new LLImageBMP; + if( !image_bmp->load(temp_str) ) + { + //llinfos << "Bitmap load failed" << llendl; + return; + } + + LLPointer<LLImageRaw> raw = new LLImageRaw; + if (!image_bmp->decode(raw, 0.0f)) + { + llinfos << "Bitmap decode failed" << llendl; + gDisconnectedImagep = NULL; + return; + } + + U8 *rawp = raw->getData(); + S32 npixels = (S32)image_bmp->getWidth()*(S32)image_bmp->getHeight(); + for (S32 i = 0; i < npixels; i++) + { + S32 sum = 0; + sum = *rawp + *(rawp+1) + *(rawp+2); + sum /= 3; + *rawp = ((S32)sum*6 + *rawp)/7; + rawp++; + *rawp = ((S32)sum*6 + *rawp)/7; + rawp++; + *rawp = ((S32)sum*6 + *rawp)/7; + rawp++; + } + + + raw->expandToPowerOfTwo(); + gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE ); + gStartTexture = gDisconnectedImagep; + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + + // Make sure the progress view always fills the entire window. + S32 width = gViewerWindow->getWindowWidthScaled(); + S32 height = gViewerWindow->getWindowHeightScaled(); + + if (gDisconnectedImagep) + { + LLGLSUIDefault gls_ui; + gViewerWindow->setup2DRender(); + gGL.pushMatrix(); + { + // scale ui to reflect UIScaleFactor + // this can't be done in setup2DRender because it requires a + // pushMatrix/popMatrix pair + const LLVector2& display_scale = gViewerWindow->getDisplayScale(); + gGL.scalef(display_scale.mV[VX], display_scale.mV[VY], 1.f); + + gGL.getTexUnit(0)->bind(gDisconnectedImagep); + gGL.color4f(1.f, 1.f, 1.f, 1.f); + gl_rect_2d_simple_tex(width, height); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + gGL.popMatrix(); + } + gGL.flush(); + + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.unbind(); + } + +} + +void display_cleanup() +{ + gDisconnectedImagep = NULL; +} diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 4f34520924..7f2aefcc2b 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1,5286 +1,5286 @@ -/**
- * @file llviewerwindow.cpp
- * @brief Implementation of the LLViewerWindow class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-#include "llviewerwindow.h"
-
-#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 <boost/lambda/core.hpp>
-
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llfloaterreg.h"
-#include "llmeshrepository.h"
-#include "llpanellogin.h"
-#include "llviewerkeyboard.h"
-#include "llviewermenu.h"
-
-#include "llviewquery.h"
-#include "llxmltree.h"
-#include "llslurl.h"
-//#include "llviewercamera.h"
-#include "llrender.h"
-
-#include "llvoiceclient.h" // for push-to-talk button handling
-
-//
-// TODO: Many of these includes are unnecessary. Remove them.
-//
-
-// linden library includes
-#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"
-#include "llui.h"
-#include "lluuid.h"
-#include "llview.h"
-#include "llxfermanager.h"
-#include "message.h"
-#include "object_flags.h"
-#include "lltimer.h"
-#include "timing.h"
-#include "llviewermenu.h"
-#include "lltooltip.h"
-#include "llmediaentry.h"
-#include "llurldispatcher.h"
-#include "raytrace.h"
-
-// newview includes
-#include "llagent.h"
-#include "llbox.h"
-#include "llchicletbar.h"
-#include "llconsole.h"
-#include "llviewercontrol.h"
-#include "llcylinder.h"
-#include "lldebugview.h"
-#include "lldir.h"
-#include "lldrawable.h"
-#include "lldrawpoolalpha.h"
-#include "lldrawpoolbump.h"
-#include "lldrawpoolwater.h"
-#include "llmaniptranslate.h"
-#include "llface.h"
-#include "llfeaturemanager.h"
-#include "llfilepicker.h"
-#include "llfirstuse.h"
-#include "llfloater.h"
-#include "llfloaterbuildoptions.h"
-#include "llfloaterbuyland.h"
-#include "llfloatercamera.h"
-#include "llfloaterland.h"
-#include "llfloaterinspect.h"
-#include "llfloatermap.h"
-#include "llfloaternamedesc.h"
-#include "llfloaterpreference.h"
-#include "llfloatersnapshot.h"
-#include "llfloatertools.h"
-#include "llfloaterworldmap.h"
-#include "llfocusmgr.h"
-#include "llfontfreetype.h"
-#include "llgesturemgr.h"
-#include "llglheaders.h"
-#include "lltooltip.h"
-#include "llhudmanager.h"
-#include "llhudobject.h"
-#include "llhudview.h"
-#include "llimagebmp.h"
-#include "llimagej2c.h"
-#include "llimageworker.h"
-#include "llkeyboard.h"
-#include "lllineeditor.h"
-#include "llmenugl.h"
-#include "llmodaldialog.h"
-#include "llmorphview.h"
-#include "llmoveview.h"
-#include "llnavigationbar.h"
-#include "llpaneltopinfobar.h"
-#include "llpopupview.h"
-#include "llpreviewtexture.h"
-#include "llprogressview.h"
-#include "llresmgr.h"
-#include "llselectmgr.h"
-#include "llrootview.h"
-#include "llrendersphere.h"
-#include "llstartup.h"
-#include "llstatusbar.h"
-#include "llstatview.h"
-#include "llsurface.h"
-#include "llsurfacepatch.h"
-#include "lltexlayer.h"
-#include "lltextbox.h"
-#include "lltexturecache.h"
-#include "lltexturefetch.h"
-#include "lltextureview.h"
-#include "lltool.h"
-#include "lltoolbarview.h"
-#include "lltoolcomp.h"
-#include "lltooldraganddrop.h"
-#include "lltoolface.h"
-#include "lltoolfocus.h"
-#include "lltoolgrab.h"
-#include "lltoolmgr.h"
-#include "lltoolmorph.h"
-#include "lltoolpie.h"
-#include "lltoolselectland.h"
-#include "lltrans.h"
-#include "lluictrlfactory.h"
-#include "llurldispatcher.h" // SLURL from other app instance
-#include "llversioninfo.h"
-#include "llvieweraudio.h"
-#include "llviewercamera.h"
-#include "llviewergesture.h"
-#include "llviewertexturelist.h"
-#include "llviewerinventory.h"
-#include "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 "llvoavatarself.h"
-#include "llvovolume.h"
-#include "llworld.h"
-#include "llworldmapview.h"
-#include "pipeline.h"
-#include "llappviewer.h"
-#include "llviewerdisplay.h"
-#include "llspatialpartition.h"
-#include "llviewerjoystick.h"
-#include "llviewernetwork.h"
-#include "llpostprocess.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 "llwindowlistener.h"
-#include "llviewerwindowlistener.h"
-#include "llpaneltopinfobar.h"
-#include "llphysicsextensions.h"
-#include "llfloaterpathfindingconsole.h"
-
-#if LL_WINDOWS
-#include <tchar.h> // For Unicode conversion methods
-#endif
-
-//
-// Globals
-//
-void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
-
-extern BOOL gDebugClicks;
-extern BOOL gDisplaySwapBuffers;
-extern BOOL gDepthDirty;
-extern BOOL gResizeScreenTexture;
-
-LLViewerWindow *gViewerWindow = NULL;
-
-LLFrameTimer gAwayTimer;
-LLFrameTimer gAwayTriggerTimer;
-
-BOOL gShowOverlayTitle = FALSE;
-
-LLViewerObject* gDebugRaycastObject = NULL;
-LLVector3 gDebugRaycastIntersection;
-LLVector2 gDebugRaycastTexCoord;
-LLVector3 gDebugRaycastNormal;
-LLVector3 gDebugRaycastBinormal;
-S32 gDebugRaycastFaceHit;
-LLVector3 gDebugRaycastStart;
-LLVector3 gDebugRaycastEnd;
-
-// HUD display lines in lower right
-BOOL gDisplayWindInfo = FALSE;
-BOOL gDisplayCameraPos = FALSE;
-BOOL gDisplayFOV = FALSE;
-BOOL gDisplayBadge = FALSE;
-
-static const U8 NO_FACE = 255;
-BOOL gQuietSnapshot = FALSE;
-
-static const F32 MIN_DISPLAY_SCALE = 0.75f;
-
-std::string LLViewerWindow::sSnapshotBaseName;
-std::string LLViewerWindow::sSnapshotDir;
-
-std::string LLViewerWindow::sMovieBaseName;
-
-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
-
- // 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);
- //}
- //}
- }
-};
-
-////////////////////////////////////////////////////////////////////////////
-//
-// LLDebugText
-//
-
-class LLDebugText
-{
-private:
- struct Line
- {
- Line(const std::string& in_text, S32 in_x, S32 in_y) : text(in_text), x(in_x), y(in_y) {}
- std::string text;
- S32 x,y;
- };
-
- LLViewerWindow *mWindow;
-
- typedef std::vector<Line> line_list_t;
- line_list_t mLineList;
- LLColor4 mTextColor;
-
- void addText(S32 x, S32 y, const std::string &text)
- {
- mLineList.push_back(Line(text, x, y));
- }
-
- void clearText() { mLineList.clear(); }
-
-public:
- LLDebugText(LLViewerWindow* window) : mWindow(window) {}
-
- void update()
- {
- static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ;
-
- std::string wind_vel_text;
- std::string wind_vector_text;
- std::string rwind_vel_text;
- std::string rwind_vector_text;
- std::string audio_text;
-
- static const std::string beacon_particle = LLTrans::getString("BeaconParticle");
- static const std::string beacon_physical = LLTrans::getString("BeaconPhysical");
- static const std::string beacon_scripted = LLTrans::getString("BeaconScripted");
- static const std::string beacon_scripted_touch = LLTrans::getString("BeaconScriptedTouch");
- static const std::string beacon_sound = LLTrans::getString("BeaconSound");
- static const std::string beacon_media = LLTrans::getString("BeaconMedia");
- static const std::string particle_hiding = LLTrans::getString("ParticleHiding");
-
- // Draw the statistics in a light gray
- // and in a thin font
- mTextColor = LLColor4( 0.86f, 0.86f, 0.86f, 1.f );
-
- // Draw stuff growing up from right lower corner of screen
- U32 xpos = mWindow->getWorldViewWidthScaled() - 350;
- U32 ypos = 64;
- const U32 y_inc = 20;
-
- clearText();
-
- if (gSavedSettings.getBOOL("DebugShowTime"))
- {
- const U32 y_inc2 = 15;
- for (std::map<S32,LLFrameTimer>::reverse_iterator iter = gDebugTimers.rbegin();
- iter != gDebugTimers.rend(); ++iter)
- {
- S32 idx = iter->first;
- LLFrameTimer& timer = iter->second;
- F32 time = timer.getElapsedTimeF32();
- S32 hours = (S32)(time / (60*60));
- S32 mins = (S32)((time - hours*(60*60)) / 60);
- S32 secs = (S32)((time - hours*(60*60) - mins*60));
- 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;
- S32 hours = (S32)(time / (60*60));
- S32 mins = (S32)((time - hours*(60*60)) / 60);
- S32 secs = (S32)((time - hours*(60*60) - mins*60));
- addText(xpos, ypos, llformat("Time: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc;
- }
-
-#if LL_WINDOWS
- if (gSavedSettings.getBOOL("DebugShowMemory"))
- {
- addText(xpos, ypos, llformat("Memory: %d (KB)", LLMemory::getWorkingSetSize() / 1024));
- ypos += y_inc;
- }
-#endif
-
- if (gDisplayCameraPos)
- {
- std::string camera_view_text;
- std::string camera_center_text;
- std::string agent_view_text;
- std::string agent_left_text;
- std::string agent_center_text;
- std::string agent_root_center_text;
-
- LLVector3d tvector; // Temporary vector to hold data for printing.
-
- // Update camera center, camera view, wind info every other frame
- tvector = gAgent.getPositionGlobal();
- agent_center_text = llformat("AgentCenter %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
-
- if (isAgentAvatarValid())
- {
- tvector = gAgent.getPosGlobalFromAgent(gAgentAvatarp->mRoot.getWorldPosition());
- agent_root_center_text = llformat("AgentRootCenter %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
- }
- else
- {
- agent_root_center_text = "---";
- }
-
-
- tvector = LLVector4(gAgent.getFrameAgent().getAtAxis());
- agent_view_text = llformat("AgentAtAxis %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
-
- tvector = LLVector4(gAgent.getFrameAgent().getLeftAxis());
- agent_left_text = llformat("AgentLeftAxis %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
-
- tvector = gAgentCamera.getCameraPositionGlobal();
- camera_center_text = llformat("CameraCenter %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
-
- tvector = LLVector4(LLViewerCamera::getInstance()->getAtAxis());
- camera_view_text = llformat("CameraAtAxis %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
-
- addText(xpos, ypos, agent_center_text); ypos += y_inc;
- addText(xpos, ypos, agent_root_center_text); ypos += y_inc;
- addText(xpos, ypos, agent_view_text); ypos += y_inc;
- addText(xpos, ypos, agent_left_text); ypos += y_inc;
- addText(xpos, ypos, camera_center_text); ypos += y_inc;
- addText(xpos, ypos, camera_view_text); ypos += y_inc;
- }
-
- if (gDisplayWindInfo)
- {
- wind_vel_text = llformat("Wind velocity %.2f m/s", gWindVec.magVec());
- wind_vector_text = llformat("Wind vector %.2f %.2f %.2f", gWindVec.mV[0], gWindVec.mV[1], gWindVec.mV[2]);
- rwind_vel_text = llformat("RWind vel %.2f m/s", gRelativeWindVec.magVec());
- rwind_vector_text = llformat("RWind vec %.2f %.2f %.2f", gRelativeWindVec.mV[0], gRelativeWindVec.mV[1], gRelativeWindVec.mV[2]);
-
- addText(xpos, ypos, wind_vel_text); ypos += y_inc;
- addText(xpos, ypos, wind_vector_text); ypos += y_inc;
- addText(xpos, ypos, rwind_vel_text); ypos += y_inc;
- addText(xpos, ypos, rwind_vector_text); ypos += y_inc;
- }
- if (gDisplayWindInfo)
- {
- if (gAudiop)
- {
- audio_text= llformat("Audio for wind: %d", gAudiop->isWindEnabled());
- }
- addText(xpos, ypos, audio_text); ypos += y_inc;
- }
- if (gDisplayFOV)
- {
- addText(xpos, ypos, llformat("FOV: %2.1f deg", RAD_TO_DEG * LLViewerCamera::getInstance()->getView()));
- ypos += y_inc;
- }
- if (gDisplayBadge)
- {
- addText(xpos, ypos+(y_inc/2), llformat("Hippos!", RAD_TO_DEG * LLViewerCamera::getInstance()->getView()));
- ypos += y_inc * 2;
- }
-
- /*if (LLViewerJoystick::getInstance()->getOverrideCamera())
- {
- addText(xpos + 200, ypos, llformat("Flycam"));
- ypos += y_inc;
- }*/
-
- if (gSavedSettings.getBOOL("DebugShowRenderInfo"))
- {
- if (gPipeline.getUseVertexShaders() == 0)
- {
- addText(xpos, ypos, "Shaders Disabled");
- ypos += y_inc;
- }
-
- if (gGLManager.mHasATIMemInfo)
- {
- S32 meminfo[4];
- glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo);
-
- addText(xpos, ypos, llformat("%.2f MB Texture Memory Free", meminfo[0]/1024.f));
- ypos += y_inc;
-
- if (gGLManager.mHasVertexBufferObject)
- {
- glGetIntegerv(GL_VBO_FREE_MEMORY_ATI, meminfo);
- addText(xpos, ypos, llformat("%.2f MB VBO Memory Free", meminfo[0]/1024.f));
- ypos += y_inc;
- }
- }
- else if (gGLManager.mHasNVXMemInfo)
- {
- S32 free_memory;
- glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory);
- addText(xpos, ypos, llformat("%.2f MB Video Memory Free", free_memory/1024.f));
- ypos += y_inc;
- }
-
- //show streaming cost/triangle count of known prims in current region OR selection
- {
- F32 cost = 0.f;
- S32 count = 0;
- S32 vcount = 0;
- S32 object_count = 0;
- S32 total_bytes = 0;
- S32 visible_bytes = 0;
-
- const char* label = "Region";
- if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 0)
- { //region
- LLViewerRegion* region = gAgent.getRegion();
- if (region)
- {
- for (U32 i = 0; i < gObjectList.getNumObjects(); ++i)
- {
- LLViewerObject* object = gObjectList.getObject(i);
- if (object &&
- object->getRegion() == region &&
- object->getVolume())
- {
- object_count++;
- S32 bytes = 0;
- S32 visible = 0;
- cost += object->getStreamingCost(&bytes, &visible);
- S32 vt = 0;
- count += object->getTriangleCount(&vt);
- vcount += vt;
- total_bytes += bytes;
- visible_bytes += visible;
- }
- }
- }
- }
- else
- {
- label = "Selection";
- cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectStreamingCost(&total_bytes, &visible_bytes);
- count = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectTriangleCount(&vcount);
- object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
- }
-
- addText(xpos,ypos, llformat("%s streaming cost: %.1f", label, cost));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat(" %.3f KTris, %.3f KVerts, %.1f/%.1f KB, %d objects",
- count/1000.f, vcount/1000.f, visible_bytes/1024.f, total_bytes/1024.f, object_count));
- ypos += y_inc;
-
- }
-
- addText(xpos, ypos, llformat("%d MB Vertex Data (%d MB Pooled)", LLVertexBuffer::sAllocatedBytes/(1024*1024), LLVBOPool::sBytesPooled/(1024*1024)));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Vertex Buffers", LLVertexBuffer::sGLCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Mapped Buffers", LLVertexBuffer::sMappedCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Vertex Buffer Binds", LLVertexBuffer::sBindCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Vertex Buffer Sets", LLVertexBuffer::sSetCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Texture Binds", LLImageGL::sBindCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Unique Textures", LLImageGL::sUniqueCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Render Calls", gPipeline.mBatchCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Matrix Ops", gPipeline.mMatrixOpCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Texture Matrix Ops", gPipeline.mTextureMatrixOps));
- ypos += y_inc;
-
- gPipeline.mTextureMatrixOps = 0;
- gPipeline.mMatrixOpCount = 0;
-
- if (gPipeline.mBatchCount > 0)
- {
- addText(xpos, ypos, llformat("Batch min/max/mean: %d/%d/%d", gPipeline.mMinBatchSize, gPipeline.mMaxBatchSize,
- gPipeline.mTrianglesDrawn/gPipeline.mBatchCount));
-
- gPipeline.mMinBatchSize = gPipeline.mMaxBatchSize;
- gPipeline.mMaxBatchSize = 0;
- gPipeline.mBatchCount = 0;
- }
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("UI Verts/Calls: %d/%d", LLRender::sUIVerts, LLRender::sUICalls));
- LLRender::sUICalls = LLRender::sUIVerts = 0;
- ypos += y_inc;
-
- addText(xpos,ypos, llformat("%d/%d Nodes visible", gPipeline.mNumVisibleNodes, LLSpatialGroup::sNodeCount));
-
- ypos += y_inc;
-
- if (!LLSpatialGroup::sPendingQueries.empty())
- {
- addText(xpos,ypos, llformat("%d Queries pending", LLSpatialGroup::sPendingQueries.size()));
- ypos += y_inc;
- }
-
-
- addText(xpos,ypos, llformat("%d Avatars visible", LLVOAvatar::sNumVisibleAvatars));
-
- ypos += y_inc;
-
- addText(xpos,ypos, llformat("%d Lights visible", LLPipeline::sVisibleLightCount));
-
- ypos += y_inc;
-
- if (gMeshRepo.meshRezEnabled())
- {
- addText(xpos, ypos, llformat("%.3f MB Mesh Data Received", LLMeshRepository::sBytesReceived/(1024.f*1024.f)));
-
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d/%d Mesh HTTP Requests/Retries", LLMeshRepository::sHTTPRequestCount,
- LLMeshRepository::sHTTPRetryCount));
-
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%.3f/%.3f MB Mesh Cache Read/Write ", LLMeshRepository::sCacheBytesRead/(1024.f*1024.f), LLMeshRepository::sCacheBytesWritten/(1024.f*1024.f)));
-
- ypos += y_inc;
- }
-
- LLVertexBuffer::sBindCount = LLImageGL::sBindCount =
- LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount =
- 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"))
- {
- U8 color[4];
- LLCoordGL coord = gViewerWindow->getCurrentMouse();
- glReadPixels(coord.mX, coord.mY, 1,1,GL_RGBA, GL_UNSIGNED_BYTE, color);
- addText(xpos, ypos, llformat("%d %d %d %d", color[0], color[1], color[2], color[3]));
- ypos += y_inc;
- }
-
- if (gSavedSettings.getBOOL("DebugShowPrivateMem"))
- {
- LLPrivateMemoryPoolManager::getInstance()->updateStatistics() ;
- addText(xpos, ypos, llformat("Total Reserved(KB): %d", LLPrivateMemoryPoolManager::getInstance()->mTotalReservedSize / 1024));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("Total Allocated(KB): %d", LLPrivateMemoryPoolManager::getInstance()->mTotalAllocatedSize / 1024));
- ypos += y_inc;
- }
-
- // only display these messages if we are actually rendering beacons at this moment
- if (LLPipeline::getRenderBeacons(NULL) && LLFloaterReg::instanceVisible("beacons"))
- {
- if (LLPipeline::getRenderMOAPBeacons(NULL))
- {
- addText(xpos, ypos, "Viewing media beacons (white)");
- ypos += y_inc;
- }
-
- if (LLPipeline::toggleRenderTypeControlNegated((void*)LLPipeline::RENDER_TYPE_PARTICLES))
- {
- addText(xpos, ypos, particle_hiding);
- ypos += y_inc;
- }
-
- if (LLPipeline::getRenderParticleBeacons(NULL))
- {
- addText(xpos, ypos, "Viewing particle beacons (blue)");
- ypos += y_inc;
- }
-
- if (LLPipeline::getRenderSoundBeacons(NULL))
- {
- addText(xpos, ypos, "Viewing sound beacons (yellow)");
- ypos += y_inc;
- }
-
- if (LLPipeline::getRenderScriptedBeacons(NULL))
- {
- addText(xpos, ypos, beacon_scripted);
- ypos += y_inc;
- }
- else
- if (LLPipeline::getRenderScriptedTouchBeacons(NULL))
- {
- addText(xpos, ypos, beacon_scripted_touch);
- ypos += y_inc;
- }
-
- if (LLPipeline::getRenderPhysicalBeacons(NULL))
- {
- addText(xpos, ypos, "Viewing physical object beacons (green)");
- ypos += y_inc;
- }
- }
-
- if(log_texture_traffic)
- {
- U32 old_y = ypos ;
- for(S32 i = LLViewerTexture::BOOST_NONE; i < LLViewerTexture::MAX_GL_IMAGE_CATEGORY; i++)
- {
- if(gTotalTextureBytesPerBoostLevel[i] > 0)
- {
- addText(xpos, ypos, llformat("Boost_Level %d: %.3f MB", i, (F32)gTotalTextureBytesPerBoostLevel[i] / (1024 * 1024)));
- ypos += y_inc;
- }
- }
- if(ypos != old_y)
- {
- addText(xpos, ypos, "Network traffic for textures:");
- ypos += y_inc;
- }
- }
-
- if (gSavedSettings.getBOOL("DebugShowTextureInfo"))
- {
- LLViewerObject* objectp = NULL ;
- //objectp = = gAgentCamera.getFocusObject();
-
- LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode();
- if (nodep)
- {
- objectp = nodep->getObject();
- }
- if (objectp && !objectp->isDead())
- {
- S32 num_faces = objectp->mDrawable->getNumFaces() ;
-
- for(S32 i = 0 ; i < num_faces; i++)
- {
- LLFace* facep = objectp->mDrawable->getFace(i) ;
- if(facep)
- {
- //addText(xpos, ypos, llformat("ts_min: %.3f ts_max: %.3f tt_min: %.3f tt_max: %.3f", facep->mTexExtents[0].mV[0], facep->mTexExtents[1].mV[0],
- // facep->mTexExtents[0].mV[1], facep->mTexExtents[1].mV[1]));
- //ypos += y_inc;
-
- addText(xpos, ypos, llformat("v_size: %.3f: p_size: %.3f", facep->getVirtualSize(), facep->getPixelArea()));
- ypos += y_inc;
-
- //const LLTextureEntry *tep = facep->getTextureEntry();
- //if(tep)
- //{
- // addText(xpos, ypos, llformat("scale_s: %.3f: scale_t: %.3f", tep->mScaleS, tep->mScaleT)) ;
- // ypos += y_inc;
- //}
-
- LLViewerTexture* tex = facep->getTexture() ;
- if(tex)
- {
- addText(xpos, ypos, llformat("ID: %s v_size: %.3f", tex->getID().asString().c_str(), tex->getMaxVirtualSize()));
- ypos += y_inc;
- }
- }
- }
- }
- }
- }
-
- void draw()
- {
- for (line_list_t::iterator iter = mLineList.begin();
- iter != mLineList.end(); ++iter)
- {
- const Line& line = *iter;
- LLFontGL::getFontMonospace()->renderUTF8(line.text, 0, (F32)line.x, (F32)line.y, mTextColor,
- LLFontGL::LEFT, LLFontGL::TOP,
- LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
- }
- mLineList.clear();
- }
-
-};
-
-void LLViewerWindow::updateDebugText()
-{
- mDebugText->update();
-}
-
-////////////////////////////////////////////////////////////////////////////
-//
-// LLViewerWindow
-//
-
-LLViewerWindow::Params::Params()
-: title("title"),
- name("name"),
- x("x"),
- y("y"),
- width("width"),
- height("height"),
- min_width("min_width"),
- min_height("min_height"),
- fullscreen("fullscreen", false),
- ignore_pixel_depth("ignore_pixel_depth", false)
-{}
-
-
-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]);
-
-
- // only send mouse clicks to UI if UI is visible
- if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
-
- if (down)
- {
- buttonstatestr = "down" ;
- }
- else
- {
- buttonstatestr = "up" ;
- }
-
- switch (clicktype)
- {
- case 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;
- }
-
- LLView::sMouseHandlerMessage.clear();
-
- if (gMenuBarView)
- {
- // stop ALT-key access to menu
- gMenuBarView->resetMenuTrigger();
- }
-
- if (gDebugClicks)
- {
- llinfos << "ViewerWindow " << buttonname << " mouse " << buttonstatestr << " 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();
-
- // Indicate mouse was active
- LLUI::resetMouseIdleTimer();
-
- // Don't let the user move the mouse out of the window until mouse up.
- if( LLToolMgr::getInstance()->getCurrentTool()->clipMouseWhenDown() )
- {
- mWindow->setMouseClipping(down);
- }
-
- LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
- if( mouse_captor )
- {
- S32 local_x;
- S32 local_y;
- mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
- if (LLView::sDebugMouseHandling)
- {
- llinfos << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << llendl;
- }
- return mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down);
- }
-
- // 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);
- // }
- // }
- //}
-
- // Mark the click as handled and return if we aren't within the root view to avoid spurious bugs
- if( !mRootView->pointInView(x, y) )
- {
- return TRUE;
- }
- // Give the UI views a chance to process the click
- if( mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) )
- {
- if (LLView::sDebugMouseHandling)
- {
- llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLView::sMouseHandlerMessage << llendl;
- }
- return TRUE;
- }
- else if (LLView::sDebugMouseHandling)
- {
- llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl;
- }
- }
-
-
- //Determine if we have a pathing system and subsequently provide any mouse input
- if ( LLPathingLib::getInstance() && mLeftMouseDown == down )
- {
- LLVector3 dv = mouseDirectionGlobal(x,y);
- LLVector3 mousePos = LLViewerCamera::getInstance()->getOrigin();
- LLVector3 rayStart = mousePos;
- LLVector3 rayEnd = mousePos + dv * 150;
-
- //Determine if alt is being held in conjunction with a lmb click, if alt is being held
- //then do not provide any input to the pathingLib console
- MASK currentKeyMask = gKeyboard->currentMask(TRUE);
- if ( !(currentKeyMask & MASK_ALT) )
- {
- LLFloaterPathfindingConsole* pFloater = LLFloaterReg::getTypedInstance<LLFloaterPathfindingConsole>("pathfinding_console");
- if ( pFloater )
- {
- //The floater takes care of determining what stage - essentially where the data goes into the pathing packet(start or end)
- pFloater->providePathingData( rayStart, rayEnd );
- }
- }
- }
-
- // Do not allow tool manager to handle mouseclicks if we have disconnected
- if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) )
- {
- 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);
-}
-
-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))
- {
- return TRUE;
- }
- return handleMouseDown(window, pos, mask);
-}
-
-BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- BOOL down = FALSE;
- return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down);
-}
-
-
-BOOL LLViewerWindow::handleRightMouseDown(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]);
-
- 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 (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.
- LLToolPie::getInstance()->handleRightMouseDown(x, y, mask);
- // show_context_menu( x, y, mask );
- }
-
- return TRUE;
-}
-
-BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- BOOL down = FALSE;
- return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down);
-}
-
-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;
-}
-
-LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, LLWindowCallbacks::DragNDropAction action, std::string data)
-{
- LLWindowCallbacks::DragNDropResult result = LLWindowCallbacks::DND_NONE;
-
- const bool prim_media_dnd_enabled = gSavedSettings.getBOOL("PrimMediaDragNDrop");
- const bool slurl_dnd_enabled = gSavedSettings.getBOOL("SLURLDragNDrop");
-
- if ( prim_media_dnd_enabled || slurl_dnd_enabled )
- {
- switch(action)
- {
- // Much of the handling for these two cases is the same.
- case LLWindowCallbacks::DNDA_TRACK:
- case LLWindowCallbacks::DNDA_DROPPED:
- case LLWindowCallbacks::DNDA_START_TRACKING:
- {
- bool drop = (LLWindowCallbacks::DNDA_DROPPED == action);
-
- if (slurl_dnd_enabled)
- {
- LLSLURL dropped_slurl(data);
- if(dropped_slurl.isSpatial())
- {
- if (drop)
- {
- LLURLDispatcher::dispatch( dropped_slurl.getSLURLString(), "clicked", NULL, true );
- return LLWindowCallbacks::DND_MOVE;
- }
- return LLWindowCallbacks::DND_COPY;
- }
- }
-
- if (prim_media_dnd_enabled)
- {
- LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ );
-
- LLUUID object_id = pick_info.getObjectID();
- S32 object_face = pick_info.mObjectFace;
- std::string url = data;
-
- lldebugs << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl;
-
- LLVOVolume *obj = dynamic_cast<LLVOVolume*>(static_cast<LLViewerObject*>(pick_info.getObject()));
-
- if (obj && !obj->getRegion()->getCapability("ObjectMedia").empty())
- {
- LLTextureEntry *te = obj->getTE(object_face);
-
- // can modify URL if we can modify the object or we have navigate permissions
- bool allow_modify_url = obj->permModify() || obj->hasMediaPermission( te->getMediaData(), LLVOVolume::MEDIA_PERM_INTERACT );
-
- if (te && allow_modify_url )
- {
- if (drop)
- {
- // object does NOT have media already
- if ( ! te->hasMedia() )
- {
- // we are allowed to modify the object
- if ( obj->permModify() )
- {
- // Create new media entry
- LLSD media_data;
- // XXX Should we really do Home URL too?
- media_data[LLMediaEntry::HOME_URL_KEY] = url;
- media_data[LLMediaEntry::CURRENT_URL_KEY] = url;
- media_data[LLMediaEntry::AUTO_PLAY_KEY] = true;
- obj->syncMediaData(object_face, media_data, true, true);
- // XXX This shouldn't be necessary, should it ?!?
- if (obj->getMediaImpl(object_face))
- obj->getMediaImpl(object_face)->navigateReload();
- obj->sendMediaDataUpdate();
-
- result = LLWindowCallbacks::DND_COPY;
- }
- }
- else
- // object HAS media already
- {
- // URL passes the whitelist
- if (te->getMediaData()->checkCandidateUrl( url ) )
- {
- // just navigate to the URL
- if (obj->getMediaImpl(object_face))
- {
- obj->getMediaImpl(object_face)->navigateTo(url);
- }
- else
- {
- // This is very strange. Navigation should
- // happen via the Impl, but we don't have one.
- // This sends it to the server, which /should/
- // trigger us getting it. Hopefully.
- LLSD media_data;
- media_data[LLMediaEntry::CURRENT_URL_KEY] = url;
- obj->syncMediaData(object_face, media_data, true, true);
- obj->sendMediaDataUpdate();
- }
- result = LLWindowCallbacks::DND_LINK;
-
- }
- }
- LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
- mDragHoveredObject = NULL;
-
- }
- else
- {
- // Check the whitelist, if there's media (otherwise just show it)
- if (te->getMediaData() == NULL || te->getMediaData()->checkCandidateUrl(url))
- {
- if ( obj != mDragHoveredObject)
- {
- // Highlight the dragged object
- LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
- mDragHoveredObject = obj;
- LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject);
- }
- result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK;
-
- }
- }
- }
- }
- }
- }
- break;
-
- case LLWindowCallbacks::DNDA_STOP_TRACKING:
- // The cleanup case below will make sure things are unhilighted if necessary.
- break;
- }
-
- if (prim_media_dnd_enabled &&
- result == LLWindowCallbacks::DND_NONE && !mDragHoveredObject.isNull())
- {
- LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
- mDragHoveredObject = NULL;
- }
- }
-
- return result;
-}
-
-BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- BOOL down = FALSE;
- 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;
- S32 y = pos.mY;
-
- x = llround((F32)x / mDisplayScale.mV[VX]);
- y = llround((F32)y / mDisplayScale.mV[VY]);
-
- mMouseInWindow = TRUE;
-
- // Save mouse point for access during idle() and display()
-
- LLCoordGL mouse_point(x, y);
-
- if (mouse_point != mCurrentMousePoint)
- {
- LLUI::resetMouseIdleTimer();
- }
-
- saveLastMouse(mouse_point);
-
- mWindow->showCursorFromMouseMove();
-
- if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME
- && !gDisconnected)
- {
- gAgent.clearAFK();
- }
-}
-
-void LLViewerWindow::handleMouseLeave(LLWindow *window)
-{
- // Note: we won't get this if we have captured the mouse.
- llassert( gFocusMgr.getMouseCapture() == NULL );
- mMouseInWindow = FALSE;
- LLToolTipMgr::instance().blockToolTips();
-}
-
-BOOL LLViewerWindow::handleCloseRequest(LLWindow *window)
-{
- // User has indicated they want to close, but we may need to ask
- // about modified documents.
- LLAppViewer::instance()->userQuit();
- // Don't quit immediately
- return FALSE;
-}
-
-void LLViewerWindow::handleQuit(LLWindow *window)
-{
- LLAppViewer::instance()->forceQuit();
-}
-
-void LLViewerWindow::handleResize(LLWindow *window, S32 width, S32 height)
-{
- reshape(width, height);
- mResDirty = true;
-}
-
-// The top-level window has gained focus (e.g. via ALT-TAB)
-void LLViewerWindow::handleFocus(LLWindow *window)
-{
- gFocusMgr.setAppHasFocus(TRUE);
- LLModalDialog::onAppFocusGained();
-
- gAgent.onAppFocusGained();
- LLToolMgr::getInstance()->onAppFocusGained();
-
- // See if we're coming in with modifier keys held down
- if (gKeyboard)
- {
- gKeyboard->resetMaskKeys();
- }
-
- // resume foreground running timer
- // since we artifically limit framerate when not frontmost
- gForegroundTime.unpause();
-}
-
-// The top-level window has lost focus (e.g. via ALT-TAB)
-void LLViewerWindow::handleFocusLost(LLWindow *window)
-{
- gFocusMgr.setAppHasFocus(FALSE);
- //LLModalDialog::onAppFocusLost();
- LLToolMgr::getInstance()->onAppFocusLost();
- gFocusMgr.setMouseCapture( NULL );
-
- if (gMenuBarView)
- {
- // stop ALT-key access to menu
- gMenuBarView->resetMenuTrigger();
- }
-
- // restore mouse cursor
- showCursor();
- getWindow()->setMouseClipping(FALSE);
-
- // If losing focus while keys are down, reset them.
- if (gKeyboard)
- {
- gKeyboard->resetKeys();
- }
-
- // pause timer that tracks total foreground running time
- gForegroundTime.pause();
-}
-
-
-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.
- LLVoiceClient::getInstance()->keyDown(key, mask);
-
- if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME)
- {
- gAgent.clearAFK();
- }
-
- // *NOTE: We want to interpret KEY_RETURN later when it arrives as
- // a Unicode char, not as a keydown. Otherwise when client frame
- // rate is really low, hitting return sends your chat text before
- // it's all entered/processed.
- if (key == KEY_RETURN && mask == MASK_NONE)
- {
- return FALSE;
- }
-
- return gViewerKeyboard.handleKey(key, mask, 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.
- LLVoiceClient::getInstance()->keyUp(key, mask);
-
- return FALSE;
-}
-
-
-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);
-}
-
-
-
-
-BOOL LLViewerWindow::handleActivate(LLWindow *window, BOOL activated)
-{
- if (activated)
- {
- mActive = true;
- send_agent_resume();
- gAgent.clearAFK();
-
- // Unmute audio
- audio_update_volume();
- }
- else
- {
- mActive = false;
-
- // if the user has chosen to go Away automatically after some time, then go Away when minimizing
- if (gSavedSettings.getS32("AFKTimeout"))
- {
- gAgent.setAFK();
- }
-
- // SL-53351: Make sure we're not in mouselook when minimised, to prevent control issues
- if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
- {
- gAgentCamera.changeCameraToDefault();
- }
-
- send_agent_pause();
-
- // Mute audio
- audio_update_volume();
- }
- return TRUE;
-}
-
-BOOL LLViewerWindow::handleActivateApp(LLWindow *window, BOOL activating)
-{
- //if (!activating) gAgentCamera.changeCameraToDefault();
-
- LLViewerJoystick::getInstance()->setNeedsReset(true);
- return FALSE;
-}
-
-
-void LLViewerWindow::handleMenuSelect(LLWindow *window, S32 menu_item)
-{
-}
-
-
-BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height)
-{
- // *TODO: Enable similar information output for other platforms? DK 2011-02-18
-#if LL_WINDOWS
- if (gHeadlessClient)
- {
- HWND window_handle = (HWND)window->getPlatformWindow();
- PAINTSTRUCT ps;
- HDC hdc;
-
- RECT wnd_rect;
- wnd_rect.left = 0;
- wnd_rect.top = 0;
- wnd_rect.bottom = 200;
- wnd_rect.right = 500;
-
- hdc = BeginPaint(window_handle, &ps);
- //SetBKColor(hdc, RGB(255, 255, 255));
- FillRect(hdc, &wnd_rect, CreateSolidBrush(RGB(255, 255, 255)));
-
- std::string temp_str;
- 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();
- temp_str = llformat( "Avatar pos %6.1lf %6.1lf %6.1lf", pos_global.mdV[0], pos_global.mdV[1], pos_global.mdV[2]);
- len = temp_str.length();
- TextOutA(hdc, 0, 25, temp_str.c_str(), len);
-
- TextOutA(hdc, 0, 50, "Set \"HeadlessClient FALSE\" in settings.ini file to reenable", 61);
- EndPaint(window_handle, &ps);
- return TRUE;
- }
-#endif
- return FALSE;
-}
-
-
-void LLViewerWindow::handleScrollWheel(LLWindow *window, S32 clicks)
-{
- handleScrollWheel( clicks );
-}
-
-void LLViewerWindow::handleWindowBlock(LLWindow *window)
-{
- send_agent_pause();
-}
-
-void LLViewerWindow::handleWindowUnblock(LLWindow *window)
-{
- send_agent_resume();
-}
-
-void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data)
-{
- const S32 SLURL_MESSAGE_TYPE = 0;
- switch (data_type)
- {
- case SLURL_MESSAGE_TYPE:
- // received URL
- std::string url = (const char*)data;
- LLMediaCtrl* web = NULL;
- const bool trusted_browser = false;
- // don't treat slapps coming from external browsers as "clicks" as this would bypass throttling
- if (LLURLDispatcher::dispatch(url, "", web, trusted_browser))
- {
- // bring window to foreground, as it has just been "launched" from a URL
- mWindow->bringToFront();
- }
- break;
- }
-}
-
-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(const Params& p)
-: mWindow(NULL),
- mActive(true),
- mUIVisible(true),
- mWindowRectRaw(0, p.height, p.width, 0),
- mWindowRectScaled(0, p.height, p.width, 0),
- mWorldViewRectRaw(0, p.height, p.width, 0),
- mLeftMouseDown(FALSE),
- mMiddleMouseDown(FALSE),
- mRightMouseDown(FALSE),
- mMouseInWindow( FALSE ),
- mLastMask( MASK_NONE ),
- mToolStored( NULL ),
- mHideCursorPermanent( FALSE ),
- mCursorHidden(FALSE),
- mIgnoreActivate( FALSE ),
- mResDirty(false),
- mStatesDirty(false),
- mCurrResolutionIndex(0),
- // gKeyboard is still NULL, so it doesn't do LLWindowListener any good to
- // pass its value right now. Instead, pass it a nullary function that
- // will, when we later need it, return the value of gKeyboard.
- // boost::lambda::var() constructs such a functor on the fly.
- mWindowListener(new LLWindowListener(this, boost::lambda::var(gKeyboard))),
- mViewerWindowListener(new LLViewerWindowListener(this)),
- mProgressView(NULL)
-{
- 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(this,
- p.title, p.name, p.x, p.y, p.width, p.height, 0,
- p.fullscreen,
- gHeadlessClient,
- gSavedSettings.getBOOL("DisableVerticalSync"),
- !gHeadlessClient,
- p.ignore_pixel_depth,
- gSavedSettings.getBOOL("RenderDeferred") ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled
-
- if (!LLViewerShaderMgr::sInitialized)
- { //immediately initialize shaders
- LLViewerShaderMgr::sInitialized = TRUE;
- LLViewerShaderMgr::instance()->setShaders();
- }
-
- if (NULL == mWindow)
- {
- LLSplashScreen::update(LLTrans::getString("StartupRequireDriverUpdate"));
-
- LL_WARNS("Window") << "Failed to create window, to be shutting Down, be sure your graphics driver is updated." << llendl ;
-
- ms_sleep(5000) ; //wait for 5 seconds.
-
- 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
- LL_WARNS("Window") << "Unable to create window, be sure screen is set at 32-bit color in Control Panels->Display->Settings"
- << LL_ENDL;
-#endif
- LLAppViewer::instance()->fastQuit(1);
- }
-
- if (!LLAppViewer::instance()->restoreErrorTrap())
- {
- LL_WARNS("Window") << " Someone took over my signal/exception handler (post createWindow)!" << LL_ENDL;
- }
-
- const bool do_not_enforce = false;
- mWindow->setMinSize(p.min_width, p.min_height, do_not_enforce); // root view not set
- LLCoordScreen scr;
- mWindow->getSize(&scr);
-
- if(p.fullscreen && ( scr.mX!=p.width || scr.mY!=p.height))
- {
- llwarns << "Fullscreen has forced us in to a different resolution now using "<<scr.mX<<" x "<<scr.mY<<llendl;
- gSavedSettings.setS32("FullScreenWidth",scr.mX);
- gSavedSettings.setS32("FullScreenHeight",scr.mY);
- }
-
- // Get the real window rect the window was created with (since there are various OS-dependent reasons why
- // the size of a window or fullscreen context may have been adjusted slightly...)
- F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor");
-
- mDisplayScale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
- mDisplayScale *= ui_scale_factor;
- LLUI::setScaleFactor(mDisplayScale);
-
- {
- LLCoordWindow size;
- mWindow->getSize(&size);
- mWindowRectRaw.set(0, size.mY, size.mX, 0);
- mWindowRectScaled.set(0, llround((F32)size.mY / mDisplayScale.mV[VY]), llround((F32)size.mX / mDisplayScale.mV[VX]), 0);
- }
-
- LLFontManager::initClass();
-
- //
- // We want to set this stuff up BEFORE we initialize the pipeline, so we can turn off
- // stuff like AGP if we think that it'll crash the viewer.
- //
- LL_DEBUGS("Window") << "Loading feature tables." << LL_ENDL;
-
- LLFeatureManager::getInstance()->init();
-
- // Initialize OpenGL Renderer
- if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderVBOEnable") ||
- !gGLManager.mHasVertexBufferObject)
- {
- gSavedSettings.setBOOL("RenderVBOEnable", FALSE);
- }
- LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"), gSavedSettings.getBOOL("RenderVBOMappingDisable"));
- LL_INFOS("RenderInit") << "LLVertexBuffer initialization done." << LL_ENDL ;
- gGL.init() ;
-
- if (LLFeatureManager::getInstance()->isSafe()
- || (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion())
- || (gSavedSettings.getString("LastGPUString") != LLFeatureManager::getInstance()->getGPUString())
- || (gSavedSettings.getBOOL("ProbeHardwareOnStartup")))
- {
- LLFeatureManager::getInstance()->applyRecommendedSettings();
- gSavedSettings.setBOOL("ProbeHardwareOnStartup", FALSE);
- }
-
- if (!gGLManager.mHasDepthClamp)
- {
- LL_INFOS("RenderInit") << "Missing feature GL_ARB_depth_clamp. Void water might disappear in rare cases." << LL_ENDL;
- }
-
- // If we crashed while initializng GL stuff last time, disable certain features
- if (gSavedSettings.getBOOL("RenderInitError"))
- {
- mInitAlert = "DisplaySettingsNoShaders";
- LLFeatureManager::getInstance()->setGraphicsLevel(0, false);
- gSavedSettings.setU32("RenderQualityPerformance", 0);
- }
-
- // Init the image list. Must happen after GL is initialized and before the images that
- // LLViewerWindow needs are requested.
- 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
- 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 = getWindowWidthScaled() / 2;
- mCurrentMousePoint.mY = getWindowHeightScaled() / 2;
-
- gShowOverlayTitle = gSavedSettings.getBOOL("ShowOverlayTitle");
- mOverlayTitle = gSavedSettings.getString("OverlayTitle");
- // Can't have spaces in settings.ini strings, so use underscores instead and convert them.
- LLStringUtil::replaceChar(mOverlayTitle, '_', ' ');
-
- // 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.setSceneBlendType(LLRender::BT_ALPHA);
-
- if (!LLGLSLShader::sNoFixedFunction)
- { //initialize fixed function state
- glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
-
- glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,LLColor4::black.mV);
- glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,LLColor4::white.mV);
-
- // lights for objects
- glShadeModel( GL_SMOOTH );
-
- gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
- gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
- }
-
- glPixelStorei(GL_PACK_ALIGNMENT,1);
- glPixelStorei(GL_UNPACK_ALIGNMENT,1);
-
- gGL.setAmbientLightColor(LLColor4::black);
-
- glCullFace(GL_BACK);
-
- // RN: Need this for translation and stretch manip.
- gBox.prerender();
-}
-
-struct MainPanel : public LLPanel
-{
-};
-
-void LLViewerWindow::initBase()
-{
- S32 height = getWindowHeightScaled();
- S32 width = getWindowWidthScaled();
-
- LLRect full_window(0, height, width, 0);
-
- ////////////////////
- //
- // Set the gamma
- //
-
- F32 gamma = gSavedSettings.getF32("RenderGamma");
- if (gamma != 0.0f)
- {
- getWindow()->setGamma(gamma);
- }
-
- // Create global views
-
- // 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();
- mPopupView = main_view->getChild<LLPopupView>("popup_holder");
- mHintHolder = main_view->getChild<LLView>("hint_holder")->getHandle();
- mLoginPanelHolder = main_view->getChild<LLView>("login_panel_holder")->getHandle();
-
- // Create the toolbar view
- // Get a pointer to the toolbar view holder
- LLPanel* panel_holder = main_view->getChild<LLPanel>("toolbar_view_holder");
- // Load the toolbar view from file
- gToolBarView = LLUICtrlFactory::getInstance()->createFromFile<LLToolBarView>("panel_toolbar_view.xml", panel_holder, LLDefaultChildRegistry::instance());
- gToolBarView->setShape(panel_holder->getLocalRect());
- // Hide the toolbars for the moment: we'll make them visible after logging in world (see LLViewerWindow::initWorldUI())
- gToolBarView->setVisible(FALSE);
-
- // Constrain floaters to inside the menu and status bar regions.
- gFloaterView = main_view->getChild<LLFloaterView>("Floater View");
- gFloaterView->setFloaterSnapView(main_view->getChild<LLView>("floater_snap_region")->getHandle());
- gSnapshotFloaterView = main_view->getChild<LLSnapshotFloaterView>("Snapshot Floater View");
-
-
- // Console
- llassert( !gConsole );
- LLConsole::Params cp;
- cp.name("console");
- cp.max_lines(gSavedSettings.getS32("ConsoleBufferSize"));
- cp.rect(getChatConsoleRect());
- cp.persist_time(gSavedSettings.getF32("ChatPersistTime"));
- cp.font_size_index(gSavedSettings.getS32("ChatFontSize"));
- cp.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
- gConsole = LLUICtrlFactory::create<LLConsole>(cp);
- getRootView()->addChild(gConsole);
-
- // optionally forward warnings to chat console/chat floater
- // for qa runs and dev builds
-#if !LL_RELEASE_FOR_DOWNLOAD
- LLError::addRecorder(RecordToChatConsole::getInstance());
-#else
- if(gSavedSettings.getBOOL("QAMode"))
- {
- LLError::addRecorder(RecordToChatConsole::getInstance());
- }
-#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 = getRootView()->findChild<LLProgressView>("progress_view");
- setShowProgress(FALSE);
- setProgressCancelButtonVisible(FALSE);
-
- gMenuHolder = getRootView()->getChild<LLViewerMenuHolderGL>("Menu Holder");
-
- LLMenuGL::sMenuContainer = gMenuHolder;
-
-}
-
-void LLViewerWindow::initWorldUI()
-{
- S32 height = mRootView->getRect().getHeight();
- S32 width = mRootView->getRect().getWidth();
- LLRect full_window(0, height, width, 0);
-
-
- gIMMgr = LLIMMgr::getInstance();
-
- //getRootView()->sendChildToFront(gFloaterView);
- //getRootView()->sendChildToFront(gSnapshotFloaterView);
-
- LLPanel* chiclet_container = getRootView()->getChild<LLPanel>("chiclet_container");
- LLChicletBar* chiclet_bar = LLChicletBar::getInstance();
- chiclet_bar->setShape(chiclet_container->getLocalRect());
- chiclet_bar->setFollowsAll();
- chiclet_container->addChild(chiclet_bar);
- chiclet_container->setVisible(TRUE);
-
- LLRect morph_view_rect = full_window;
- morph_view_rect.stretch( -STATUS_BAR_HEIGHT );
- morph_view_rect.mTop = full_window.mTop - 32;
- LLMorphView::Params mvp;
- mvp.name("MorphView");
- mvp.rect(morph_view_rect);
- mvp.visible(false);
- gMorphView = LLUICtrlFactory::create<LLMorphView>(mvp);
- getRootView()->addChild(gMorphView);
-
- LLWorldMapView::initClass();
-
- // Force gFloaterWorldMap to initialize
- LLFloaterReg::getInstance("world_map");
-
- // Force gFloaterTools to initialize
- LLFloaterReg::getInstance("build");
- 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->addChildInBack(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->setVisible(FALSE);
- }
-
- // Top Info bar
- LLPanel* topinfo_bar_container = getRootView()->getChild<LLPanel>("topinfo_bar_container");
- LLPanelTopInfoBar* topinfo_bar = LLPanelTopInfoBar::getInstance();
-
- topinfo_bar->setShape(topinfo_bar_container->getLocalRect());
-
- topinfo_bar_container->addChild(topinfo_bar);
- topinfo_bar_container->setVisible(TRUE);
-
- if (!gSavedSettings.getBOOL("ShowMiniLocationPanel"))
- {
- topinfo_bar->setVisible(FALSE);
- }
-
- if ( gHUDView == NULL )
- {
- LLRect hud_rect = full_window;
- hud_rect.mBottom += 50;
- if (gMenuBarView && gMenuBarView->isInVisibleChain())
- {
- hud_rect.mTop -= gMenuBarView->getRect().getHeight();
- }
- gHUDView = new LLHUDView(hud_rect);
- getRootView()->addChild(gHUDView);
- }
-
- 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);
-
- // Load and make the toolbars visible
- // Note: we need to load the toolbars only *after* the user is logged in and IW
- if (gToolBarView)
- {
- gToolBarView->loadToolbars();
- gToolBarView->setVisible(TRUE);
- }
-
- LLMediaCtrl* destinations = LLFloaterReg::getInstance("destinations")->getChild<LLMediaCtrl>("destination_guide_contents");
- if (destinations)
- {
- destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
- std::string url = gSavedSettings.getString("DestinationGuideURL");
- url = LLWeb::expandURLSubstitutions(url, LLSD());
- destinations->navigateTo(url, "text/html");
- }
- LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents");
- if (avatar_picker)
- {
- avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
- std::string url = gSavedSettings.getString("AvatarPickerURL");
- url = LLWeb::expandURLSubstitutions(url, LLSD());
- avatar_picker->navigateTo(url, "text/html");
- }
-}
-
-// Destroy the UI
-void LLViewerWindow::shutdownViews()
-{
- // clean up warning logger
- LLError::removeRecorder(RecordToChatConsole::getInstance());
-
- delete mDebugText;
- mDebugText = NULL;
-
- // 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
- if (LLNavigationBar::instanceExists())
- {
- 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.
- gStatusBar = NULL;
- gIMMgr = NULL;
- gToolTipView = NULL;
-
- gToolBarView = NULL;
- gFloaterView = NULL;
- gMorphView = NULL;
-
- gHUDView = NULL;
-}
-
-void LLViewerWindow::shutdownGL()
-{
- //--------------------------------------------------------
- // Shutdown GL cleanly. Order is very important here.
- //--------------------------------------------------------
- LLFontGL::destroyDefaultFonts();
- LLFontManager::cleanupClass();
- stop_glerror();
-
- gSky.cleanup();
- stop_glerror();
-
- LLWearableList::instance().cleanup() ;
-
- gTextureList.shutdown();
- stop_glerror();
-
- gBumpImageList.shutdown();
- stop_glerror();
-
- LLWorldMapView::cleanupTextures();
-
- llinfos << "Cleaning up pipeline" << llendl;
- gPipeline.cleanup();
- stop_glerror();
-
- LLViewerTextureManager::cleanup() ;
- LLImageGL::cleanupClass() ;
-
- llinfos << "All textures and llimagegl images are destroyed!" << llendl ;
-
- llinfos << "Cleaning up select manager" << llendl;
- LLSelectMgr::getInstance()->cleanup();
-
- llinfos << "Stopping GL during shutdown" << llendl;
- stopGL(FALSE);
- stop_glerror();
-
- gGL.shutdown();
-
- LLVertexBuffer::cleanupClass();
-
- llinfos << "LLVertexBuffer cleaned." << llendl ;
-}
-
-// shutdownViews() and shutdownGL() need to be called first
-LLViewerWindow::~LLViewerWindow()
-{
- llinfos << "Destroying Window" << llendl;
- destroyWindow();
-
- delete mDebugText;
- mDebugText = NULL;
-}
-
-
-void LLViewerWindow::setCursor( ECursorType c )
-{
- mWindow->setCursor( c );
-}
-
-void LLViewerWindow::showCursor()
-{
- mWindow->showCursor();
-
- mCursorHidden = FALSE;
-}
-
-void LLViewerWindow::hideCursor()
-{
- // And hide the cursor
- mWindow->hideCursor();
-
- mCursorHidden = TRUE;
-}
-
-void LLViewerWindow::sendShapeToSim()
-{
- LLMessageSystem* msg = gMessageSystem;
- if(!msg) return;
- msg->newMessageFast(_PREHASH_AgentHeightWidth);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addU32Fast(_PREHASH_CircuitCode, gMessageSystem->mOurCircuitCode);
- msg->nextBlockFast(_PREHASH_HeightWidthBlock);
- msg->addU32Fast(_PREHASH_GenCounter, 0);
- U16 height16 = (U16) mWorldViewRectRaw.getHeight();
- U16 width16 = (U16) mWorldViewRectRaw.getWidth();
- msg->addU16Fast(_PREHASH_Height, height16);
- msg->addU16Fast(_PREHASH_Width, width16);
- gAgent.sendReliableMessage();
-}
-
-// Must be called after window is created to set up agent
-// camera variables and UI variables.
-void LLViewerWindow::reshape(S32 width, S32 height)
-{
- // Destroying the window at quit time generates spurious
- // reshape messages. We don't care about these, and we
- // don't want to send messages because the message system
- // may have been destructed.
- if (!LLApp::isExiting())
- {
- gWindowResized = TRUE;
-
- // update our window rectangle
- mWindowRectRaw.mRight = mWindowRectRaw.mLeft + width;
- mWindowRectRaw.mTop = mWindowRectRaw.mBottom + height;
-
- //glViewport(0, 0, width, height );
-
- if (height > 0)
- {
- LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
- LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() );
- }
-
- calcDisplayScale();
-
- BOOL display_scale_changed = mDisplayScale != LLUI::sGLScaleFactor;
- LLUI::setScaleFactor(mDisplayScale);
-
- // update our window rectangle
- mWindowRectScaled.mRight = mWindowRectScaled.mLeft + llround((F32)width / mDisplayScale.mV[VX]);
- mWindowRectScaled.mTop = mWindowRectScaled.mBottom + llround((F32)height / mDisplayScale.mV[VY]);
-
- setup2DViewport();
-
- // Inform lower views of the change
- // round up when converting coordinates to make sure there are no gaps at edge of window
- LLView::sForceReshape = display_scale_changed;
- mRootView->reshape(llceil((F32)width / mDisplayScale.mV[VX]), llceil((F32)height / mDisplayScale.mV[VY]));
- LLView::sForceReshape = FALSE;
-
- // clear font width caches
- if (display_scale_changed)
- {
- LLHUDObject::reshapeAll();
- }
-
- sendShapeToSim();
-
- // store new settings for the mode we are in, regardless
- BOOL maximized = mWindow->getMaximized();
- gSavedSettings.setBOOL("WindowMaximized", maximized);
-
- if (!maximized)
- {
- U32 min_window_width=gSavedSettings.getU32("MinWindowWidth");
- U32 min_window_height=gSavedSettings.getU32("MinWindowHeight");
- // tell the OS specific window code about min window size
- mWindow->setMinSize(min_window_width, min_window_height);
-
- // Only save size if not maximized
- gSavedSettings.setU32("WindowWidth", mWindowRectRaw.getWidth());
- gSavedSettings.setU32("WindowHeight", mWindowRectRaw.getHeight());
- }
-
- LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width);
- LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height);
- }
-}
-
-
-// Hide normal UI when a logon fails
-void LLViewerWindow::setNormalControlsVisible( BOOL visible )
-{
- if(LLChicletBar::instanceExists())
- {
- LLChicletBar::getInstance()->setVisible(visible);
- LLChicletBar::getInstance()->setEnabled(visible);
- }
-
- if ( gMenuBarView )
- {
- gMenuBarView->setVisible( visible );
- gMenuBarView->setEnabled( visible );
-
- // ...and set the menu color appropriately.
- setMenuBackgroundColor(gAgent.getGodLevel() > GOD_NOT,
- LLGridManager::getInstance()->isInProductionGrid());
- }
-
- if ( gStatusBar )
- {
- gStatusBar->setVisible( visible );
- gStatusBar->setEnabled( visible );
- }
-
- LLNavigationBar* navbarp = LLUI::getRootView()->findChild<LLNavigationBar>("navigation_bar");
- if (navbarp)
- {
- // when it's time to show navigation bar we need to ensure that the user wants to see it
- // i.e. ShowNavbarNavigationPanel option is true
- navbarp->setVisible( visible && gSavedSettings.getBOOL("ShowNavbarNavigationPanel") );
- }
-}
-
-void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid)
-{
- LLSD args;
- LLColor4 new_bg_color;
-
- // 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 = LLUIColorTable::instance().getColor( "MenuBarGodBgColor" );
- }
- else if(god_mode && !LLGridManager::getInstance()->isInProductionGrid())
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionGodBgColor" );
- }
- else if (!god_mode && isProject)
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuBarProjectBgColor" );
- }
- else if(!god_mode && !LLGridManager::getInstance()->isInProductionGrid())
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" );
- }
- else
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuBarBgColor" );
- }
-
- if(gMenuBarView)
- {
- gMenuBarView->setBackgroundColor( new_bg_color );
- }
-
- if(gStatusBar)
- {
- gStatusBar->setBackgroundColor( new_bg_color );
- }
-}
-
-void LLViewerWindow::drawDebugText()
-{
- gGL.color4f(1,1,1,1);
- gGL.pushMatrix();
- gGL.pushUIMatrix();
- if (LLGLSLShader::sNoFixedFunction)
- {
- gUIProgram.bind();
- }
- {
- // scale view by UI global scale factor and aspect ratio correction factor
- gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
- mDebugText->draw();
- }
- gGL.popUIMatrix();
- gGL.popMatrix();
-
- gGL.flush();
- if (LLGLSLShader::sNoFixedFunction)
- {
- gUIProgram.unbind();
- }
-}
-
-void LLViewerWindow::draw()
-{
-
-//#if LL_DEBUG
- LLView::sIsDrawing = TRUE;
-//#endif
- stop_glerror();
-
- LLUI::setLineWidth(1.f);
-
- LLUI::setLineWidth(1.f);
- // Reset any left-over transforms
- gGL.matrixMode(LLRender::MM_MODELVIEW);
-
- gGL.loadIdentity();
-
- //S32 screen_x, screen_y;
-
- if (!gSavedSettings.getBOOL("RenderUIBuffer"))
- {
- LLUI::sDirtyRect = getWindowRectScaled();
- }
-
- // HACK for timecode debugging
- if (gSavedSettings.getBOOL("DisplayTimecode"))
- {
- // draw timecode block
- std::string text;
-
- gGL.loadIdentity();
-
- microsecondsToTimecodeString(gFrameTime,text);
- const LLFontGL* font = LLFontGL::getFontSansSerif();
- font->renderUTF8(text, 0,
- llround((getWindowWidthScaled()/2)-100.f),
- llround((getWindowHeightScaled()-60.f)),
- LLColor4( 1.f, 1.f, 1.f, 1.f ),
- LLFontGL::LEFT, LLFontGL::TOP);
- }
-
- // Draw all nested UI views.
- // No translation needed, this view is glued to 0,0
-
- if (LLGLSLShader::sNoFixedFunction)
- {
- gUIProgram.bind();
- }
-
- gGL.pushMatrix();
- LLUI::pushMatrix();
- {
-
- // scale view by UI global scale factor and aspect ratio correction factor
- gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
-
- LLVector2 old_scale_factor = LLUI::sGLScaleFactor;
- // apply camera zoom transform (for high res screenshots)
- F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
- S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
- if (zoom_factor > 1.f)
- {
- //decompose subregion number to x and y values
- int pos_y = sub_region / llceil(zoom_factor);
- int pos_x = sub_region - (pos_y*llceil(zoom_factor));
- // offset for this tile
- gGL.translatef((F32)getWindowWidthScaled() * -(F32)pos_x,
- (F32)getWindowHeightScaled() * -(F32)pos_y,
- 0.f);
- gGL.scalef(zoom_factor, zoom_factor, 1.f);
- LLUI::sGLScaleFactor *= zoom_factor;
- }
-
- // Draw tool specific overlay on world
- LLToolMgr::getInstance()->getCurrentTool()->draw();
-
- if( gAgentCamera.cameraMouselook() || LLFloaterCamera::inFreeCameraMode() )
- {
- drawMouselookInstructions();
- stop_glerror();
- }
-
- // Draw all nested UI views.
- // No translation needed, this view is glued to 0,0
- mRootView->draw();
-
- if (LLView::sDebugRects)
- {
- gToolTipView->drawStickyRect();
- }
-
- // Draw optional on-top-of-everyone view
- LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- if (top_ctrl && top_ctrl->getVisible())
- {
- S32 screen_x, screen_y;
- top_ctrl->localPointToScreen(0, 0, &screen_x, &screen_y);
-
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- LLUI::pushMatrix();
- LLUI::translate( (F32) screen_x, (F32) screen_y, 0.f);
- top_ctrl->draw();
- LLUI::popMatrix();
- }
-
-
- if( gShowOverlayTitle && !mOverlayTitle.empty() )
- {
- // Used for special titles such as "Second Life - Special E3 2003 Beta"
- const S32 DIST_FROM_TOP = 20;
- LLFontGL::getFontSansSerifBig()->renderUTF8(
- mOverlayTitle, 0,
- 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 (LLGLSLShader::sNoFixedFunction)
- {
- gUIProgram.unbind();
- }
-
-//#if LL_DEBUG
- LLView::sIsDrawing = FALSE;
-//#endif
-}
-
-// Takes a single keydown event, usually when UI is visible
-BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
-{
- // 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.getKeyboardFocus() != NULL);
- }
- }
-
- // 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)))
- {
- return TRUE;
- }
-
- LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
-
- // give menus a chance to handle modified (Ctrl, Alt) shortcut keys before current focus
- // as long as focus isn't locked
- if (mask & (MASK_CONTROL | MASK_ALT) && !gFocusMgr.focusLocked())
- {
- // Check the current floater's menu first, if it has one.
- if (gFocusMgr.keyboardFocusHasAccelerators()
- && keyboard_focus
- && keyboard_focus->handleKey(key,mask,FALSE))
- {
- return TRUE;
- }
-
- if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
- ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask)))
- {
- return TRUE;
- }
- }
-
- // give floaters first chance to handle TAB key
- // so frontmost floater gets focus
- // if nothing has focus, go to first or last UI element as appropriate
- if (key == KEY_TAB && (mask & MASK_CONTROL || 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;
- }
- // hidden edit menu for cut/copy/paste
- if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask))
- {
- return TRUE;
- }
-
- // Traverses up the hierarchy
- if( keyboard_focus )
- {
- LLNearbyChatBar* nearby_chat = LLFloaterReg::findTypedInstance<LLNearbyChatBar>("chat_bar");
-
- if (nearby_chat)
- {
- LLLineEditor* chat_editor = nearby_chat->getChatBox();
-
- // arrow keys move avatar while chatting hack
- if (chat_editor && chat_editor->hasFocus())
- {
- // 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"))
- {
- // let Control-Up and Control-Down through for chat line history,
- if (!(key == KEY_UP && mask == MASK_CONTROL)
- && !(key == KEY_DOWN && mask == MASK_CONTROL))
- {
- 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;
- }
- }
- }
- }
- }
- if (keyboard_focus->handleKey(key, mask, FALSE))
- {
- return TRUE;
- }
- }
-
- if( LLToolMgr::getInstance()->getCurrentTool()->handleKey(key, mask) )
- {
- return TRUE;
- }
-
- // Try for a new-format gesture
- if (LLGestureMgr::instance().triggerGesture(key, mask))
- {
- return TRUE;
- }
-
- // See if this is a gesture trigger. If so, eat the key and
- // don't pass it down to the menus.
- if (gGestureList.trigger(key, mask))
- {
- return TRUE;
- }
-
- // If "Pressing letter keys starts local chat" option is selected, we are not in mouselook,
- // no view has keyboard focus, this is a printable character key (and no modifier key is
- // pressed except shift), then give focus to nearby chat (STORM-560)
- if ( gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() &&
- !keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) )
- {
- LLLineEditor* chat_editor = LLFloaterReg::getTypedInstance<LLNearbyChatBar>("chat_bar")->getChatBox();
- if (chat_editor)
- {
- // passing NULL here, character will be added later when it is handled by character handler.
- LLNearbyChatBar::getInstance()->startChat(NULL);
- return TRUE;
- }
- }
-
- // give menus a chance to handle unmodified accelerator keys
- if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
- ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask)))
- {
- return TRUE;
- }
-
- // don't pass keys on to world when something in ui has focus
- return gFocusMgr.childHasKeyboardFocus(mRootView)
- || LLMenuGL::getKeyboardMode()
- || (gMenuBarView && gMenuBarView->getHighlightedItem() && gMenuBarView->getHighlightedItem()->isActive());
-}
-
-
-BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
-{
- // HACK: We delay processing of return keys until they arrive as a Unicode char,
- // so that if you're typing chat text at low frame rate, we don't send the chat
- // until all keystrokes have been entered. JC
- // HACK: Numeric keypad <enter> on Mac is Unicode 3
- // HACK: Control-M on Windows is Unicode 13
- if ((uni_char == 13 && mask != MASK_CONTROL)
- || (uni_char == 3 && mask == MASK_NONE))
- {
- return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
- }
-
- // let menus handle navigation (jump) keys
- if (gMenuBarView && gMenuBarView->handleUnicodeChar(uni_char, TRUE))
- {
- return TRUE;
- }
-
- // Traverses up the hierarchy
- LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
- if( keyboard_focus )
- {
- if (keyboard_focus->handleUnicodeChar(uni_char, FALSE))
- {
- return TRUE;
- }
-
- //// 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;
- }
-
- return FALSE;
-}
-
-
-void LLViewerWindow::handleScrollWheel(S32 clicks)
-{
- LLView::sMouseHandlerMessage.clear();
-
- LLUI::resetMouseIdleTimer();
-
- LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
- if( mouse_captor )
- {
- S32 local_x;
- S32 local_y;
- mouse_captor->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
- mouse_captor->handleScrollWheel(local_x, local_y, clicks);
- if (LLView::sDebugMouseHandling)
- {
- llinfos << "Scroll Wheel handled by captor " << mouse_captor->getName() << llendl;
- }
- return;
- }
-
- LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- if (top_ctrl)
- {
- S32 local_x;
- S32 local_y;
- top_ctrl->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
- if (top_ctrl->handleScrollWheel(local_x, local_y, clicks)) return;
- }
-
- if (mRootView->handleScrollWheel(mCurrentMousePoint.mX, mCurrentMousePoint.mY, clicks) )
- {
- if (LLView::sDebugMouseHandling)
- {
- llinfos << "Scroll Wheel" << LLView::sMouseHandlerMessage << llendl;
- }
- return;
- }
- else if (LLView::sDebugMouseHandling)
- {
- llinfos << "Scroll Wheel not handled by view" << llendl;
- }
-
- // 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)
- {
- mPopupView->addPopup(popup);
- }
-}
-
-void LLViewerWindow::removePopup(LLView* popup)
-{
- if (mPopupView)
- {
- mPopupView->removePopup(popup);
- }
-}
-
-void LLViewerWindow::clearPopups()
-{
- if (mPopupView)
- {
- mPopupView->clearPopups();
- }
-}
-
-void LLViewerWindow::moveCursorToCenter()
-{
- if (! gSavedSettings.getBOOL("DisableMouseWarp"))
- {
- S32 x = getWorldViewWidthScaled() / 2;
- S32 y = getWorldViewHeightScaled() / 2;
-
- //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::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.
-void LLViewerWindow::updateUI()
-{
- static LLFastTimer::DeclareTimer ftm("Update UI");
- LLFastTimer t(ftm);
-
- static std::string last_handle_msg;
-
- if (gLoggedInTime.getStarted())
- {
- if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("DestinationGuideHintTimeout"))
- {
- LLFirstUse::notUsingDestinationGuide();
- }
- if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("SidePanelHintTimeout"))
- {
- LLFirstUse::notUsingSidePanel();
- }
- }
-
- LLConsole::updateClass();
-
- // animate layout stacks so we have up to date rect for world view
- LLLayoutStack::updateClass();
-
- // use full window for world view when not rendering UI
- bool world_view_uses_full_window = gAgentCamera.cameraMouselook() || !gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
- updateWorldViewRect(world_view_uses_full_window);
-
- LLView::sMouseHandlerMessage.clear();
-
- S32 x = mCurrentMousePoint.mX;
- S32 y = mCurrentMousePoint.mY;
-
- MASK mask = gKeyboard->currentMask(TRUE);
-
- if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
- {
- gDebugRaycastFaceHit = -1;
- gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE,
- &gDebugRaycastFaceHit,
- &gDebugRaycastIntersection,
- &gDebugRaycastTexCoord,
- &gDebugRaycastNormal,
- &gDebugRaycastBinormal,
- &gDebugRaycastStart,
- &gDebugRaycastEnd);
- }
-
- updateMouseDelta();
- updateKeyboardFocus();
-
- 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)
- {
- 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)
- {
- LLView* captor_parent_view = captor_view->getParent();
- while(captor_parent_view)
- {
- mouse_hover_set.insert(captor_parent_view->getHandle());
- captor_parent_view = captor_parent_view->getParent();
- }
- }
-
- // aggregate visible views that contain mouse cursor in display order
- LLPopupView::popup_list_t popups = mPopupView->getCurrentPopups();
-
- for(LLPopupView::popup_list_t::iterator popup_it = popups.begin(); popup_it != popups.end(); ++popup_it)
- {
- LLView* popup = popup_it->get();
- if (popup && popup->calcScreenBoundingRect().pointInRect(x, y))
- {
- // iterator over contents of top_ctrl, and throw into mouse_hover_set
- for (LLView::tree_iterator_t it = popup->beginTreeDFS();
- it != popup->endTreeDFS();
- ++it)
- {
- LLView* viewp = *it;
- if (viewp->getVisible()
- && viewp->calcScreenBoundingRect().pointInRect(x, y))
- {
- // we have a view that contains the mouse, add it to the set
- mouse_hover_set.insert(viewp->getHandle());
- }
- else
- {
- // skip this view and all of its children
- it.skipDescendants();
- }
- }
- }
- }
-
- // while the top_ctrl contains the mouse cursor, only it and its descendants will receive onMouseEnter events
- if (top_ctrl && top_ctrl->calcScreenBoundingRect().pointInRect(x, y))
- {
- // iterator over contents of top_ctrl, and throw into mouse_hover_set
- for (LLView::tree_iterator_t it = top_ctrl->beginTreeDFS();
- it != top_ctrl->endTreeDFS();
- ++it)
- {
- LLView* viewp = *it;
- if (viewp->getVisible()
- && viewp->calcScreenBoundingRect().pointInRect(x, y))
- {
- // we have a view that contains the mouse, add it to the set
- mouse_hover_set.insert(viewp->getHandle());
- }
- else
- {
- // skip this view and all of its children
- it.skipDescendants();
- }
- }
- }
- else
- {
- // walk UI tree in depth-first order
- for (LLView::tree_iterator_t it = root_view->beginTreeDFS();
- it != root_view->endTreeDFS();
- ++it)
- {
- LLView* viewp = *it;
- // calculating the screen rect involves traversing the parent, so this is less than optimal
- if (viewp->getVisible()
- && viewp->calcScreenBoundingRect().pointInRect(x, y))
- {
-
- // if this view is mouse opaque, nothing behind it should be in mouse_hover_set
- if (viewp->getMouseOpaque())
- {
- // constrain further iteration to children of this widget
- it = viewp->beginTreeDFS();
- }
-
- // we have a view that contains the mouse, add it to the set
- mouse_hover_set.insert(viewp->getHandle());
- }
- else
- {
- // skip this view and all of its children
- it.skipDescendants();
- }
- }
- }
- }
-
- typedef std::vector<LLHandle<LLView> > view_handle_list_t;
-
- // call onMouseEnter() on all views which contain the mouse cursor but did not before
- view_handle_list_t mouse_enter_views;
- std::set_difference(mouse_hover_set.begin(), mouse_hover_set.end(),
- mMouseHoverViews.begin(), mMouseHoverViews.end(),
- std::back_inserter(mouse_enter_views));
- for (view_handle_list_t::iterator it = mouse_enter_views.begin();
- it != mouse_enter_views.end();
- ++it)
- {
- LLView* viewp = it->get();
- if (viewp)
- {
- LLRect view_screen_rect = viewp->calcScreenRect();
- viewp->onMouseEnter(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask);
- }
- }
-
- // call onMouseLeave() on all views which no longer contain the mouse cursor
- view_handle_list_t mouse_leave_views;
- std::set_difference(mMouseHoverViews.begin(), mMouseHoverViews.end(),
- mouse_hover_set.begin(), mouse_hover_set.end(),
- std::back_inserter(mouse_leave_views));
- for (view_handle_list_t::iterator it = mouse_leave_views.begin();
- it != mouse_leave_views.end();
- ++it)
- {
- LLView* viewp = it->get();
- if (viewp)
- {
- LLRect view_screen_rect = viewp->calcScreenRect();
- viewp->onMouseLeave(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask);
- }
- }
-
- // store resulting hover set for next frame
- swap(mMouseHoverViews, mouse_hover_set);
-
- // only handle hover events when UI is enabled
- if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
-
- if( mouse_captor )
- {
- // Pass hover events to object capturing mouse events.
- S32 local_x;
- S32 local_y;
- mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
- handled = mouse_captor->handleHover(local_x, local_y, mask);
- if (LLView::sDebugMouseHandling)
- {
- llinfos << "Hover handled by captor " << mouse_captor->getName() << llendl;
- }
-
- if( !handled )
- {
- lldebugst(LLERR_USER_INPUT) << "hover not handled by mouse captor" << llendl;
- }
- }
- else
- {
- if (top_ctrl)
- {
- S32 local_x, local_y;
- top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
- handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleHover(local_x, local_y, mask);
- 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)
- {
- if (last_handle_msg != LLStringUtil::null)
- {
- last_handle_msg.clear();
- llinfos << "Hover not handled by view" << llendl;
- }
- }
- }
-
- if (!handled)
- {
- LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
-
- if(mMouseInWindow && tool)
- {
- handled = tool->handleHover(x, y, mask);
- }
- }
- }
-
- // Show a new tool tip (or update one that is already shown)
- BOOL tool_tip_handled = FALSE;
- std::string tool_tip_msg;
- if( handled
- && !mWindow->isCursorHidden())
- {
- LLRect screen_sticky_rect = mRootView->getLocalRect();
- S32 local_x, local_y;
-
- if (gSavedSettings.getBOOL("DebugShowXUINames"))
- {
- LLToolTip::Params params;
-
- LLView* tooltip_view = mRootView;
- LLView::tree_iterator_t end_it = mRootView->endTreeDFS();
- for (LLView::tree_iterator_t it = mRootView->beginTreeDFS(); it != end_it; ++it)
- {
- LLView* viewp = *it;
- LLRect screen_rect;
- viewp->localRectToScreen(viewp->getLocalRect(), &screen_rect);
- if (!(viewp->getVisible()
- && screen_rect.pointInRect(x, y)))
- {
- it.skipDescendants();
- }
- // only report xui names for LLUICtrls,
- // and blacklist the various containers we don't care about
- else if (dynamic_cast<LLUICtrl*>(viewp)
- && viewp != gMenuHolder
- && viewp != gFloaterView
- && viewp != gConsole)
- {
- if (dynamic_cast<LLFloater*>(viewp))
- {
- // constrain search to descendants of this (frontmost) floater
- // by resetting iterator
- it = viewp->beginTreeDFS();
- }
-
- // if we are in a new part of the tree (not a descendent of current tooltip_view)
- // then push the results for tooltip_view and start with a new potential view
- // NOTE: this emulates visiting only the leaf nodes that meet our criteria
- if (!viewp->hasAncestor(tooltip_view))
- {
- append_xui_tooltip(tooltip_view, params);
- screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
- }
- tooltip_view = viewp;
- }
- }
-
- append_xui_tooltip(tooltip_view, params);
- screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
-
- params.sticky_rect = screen_sticky_rect;
- params.max_width = 400;
-
- LLToolTipMgr::instance().show(params);
- }
- // if there is a mouse captor, nothing else gets a tooltip
- else if (mouse_captor)
- {
- mouse_captor->screenPointToLocal(x, y, &local_x, &local_y);
- tool_tip_handled = mouse_captor->handleToolTip(local_x, local_y, mask);
- }
- else
- {
- // next is top_ctrl
- if (!tool_tip_handled && top_ctrl)
- {
- top_ctrl->screenPointToLocal(x, y, &local_x, &local_y);
- tool_tip_handled = top_ctrl->handleToolTip(local_x, local_y, mask );
- }
-
- if (!tool_tip_handled)
- {
- local_x = x; local_y = y;
- tool_tip_handled = mRootView->handleToolTip(local_x, local_y, mask );
- }
-
- LLTool* current_tool = LLToolMgr::getInstance()->getCurrentTool();
- if (!tool_tip_handled && current_tool)
- {
- current_tool->screenPointToLocal(x, y, &local_x, &local_y);
- tool_tip_handled = current_tool->handleToolTip(local_x, local_y, mask );
- }
- }
- }
- }
- else
- { // just have tools handle hover when UI is turned off
- LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
-
- if(mMouseInWindow && tool)
- {
- handled = tool->handleHover(x, y, mask);
- }
- }
-
- updateLayout();
-
- mLastMousePoint = mCurrentMousePoint;
-
- // cleanup unused selections when no modal dialogs are open
- if (LLModalDialog::activeCount() == 0)
- {
- LLViewerParcelMgr::getInstance()->deselectUnused();
- }
-
- if (LLModalDialog::activeCount() == 0)
- {
- LLSelectMgr::getInstance()->deselectUnused();
- }
-}
-
-
-void LLViewerWindow::updateLayout()
-{
- LLTool* tool = LLToolMgr::getInstance()->getCurrentTool();
- if (gFloaterTools != NULL
- && tool != NULL
- && tool != gToolNull
- && tool != LLToolCompInspect::getInstance()
- && tool != LLToolDragAndDrop::getInstance()
- && !gSavedSettings.getBOOL("FreezeTime"))
- {
- // Suppress the toolbox view if our source tool was the pie tool,
- // and we've overridden to something else.
- bool suppress_toolbox =
- (LLToolMgr::getInstance()->getBaseTool() == LLToolPie::getInstance()) &&
- (LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance());
-
- LLMouseHandler *captor = gFocusMgr.getMouseCapture();
- // With the null, inspect, or drag and drop tool, don't muck
- // with visibility.
-
- if (gFloaterTools->isMinimized()
- || (tool != LLToolPie::getInstance() // not default tool
- && tool != LLToolCompGun::getInstance() // not coming out of mouselook
- && !suppress_toolbox // not override in third person
- && LLToolMgr::getInstance()->getCurrentToolset() != 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->openFloater();
- }
- // Update the location of the blue box tool popup
- LLCoordGL select_center_screen;
- MASK mask = gKeyboard->currentMask(TRUE);
- gFloaterTools->updatePopup( select_center_screen, mask );
- }
- else
- {
- gFloaterTools->setVisible(FALSE);
- }
- //gMenuBarView->setItemVisible("BuildTools", gFloaterTools->getVisible());
- }
-
- LLFloaterBuildOptions* build_options_floater = LLFloaterReg::findTypedInstance<LLFloaterBuildOptions>("build_options");
- if (build_options_floater && build_options_floater->getVisible())
- {
- build_options_floater->updateGridMode();
- }
-
- // Always update console
- if(gConsole)
- {
- 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]);
-
- //RN: fix for asynchronous notification of mouse leaving window not working
- LLCoordWindow mouse_pos;
- mWindow->getCursorPosition(&mouse_pos);
- if (mouse_pos.mX < 0 ||
- mouse_pos.mY < 0 ||
- mouse_pos.mX > mWindowRectRaw.getWidth() ||
- mouse_pos.mY > mWindowRectRaw.getHeight())
- {
- mMouseInWindow = FALSE;
- }
- else
- {
- mMouseInWindow = TRUE;
- }
-
- LLVector2 mouse_vel;
-
- if (gSavedSettings.getBOOL("MouseSmooth"))
- {
- static F32 fdx = 0.f;
- static F32 fdy = 0.f;
-
- F32 amount = 16.f;
- fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f);
- fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f);
-
- 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());
-}
-
-void LLViewerWindow::updateKeyboardFocus()
-{
- if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- gFocusMgr.setKeyboardFocus(NULL);
- }
-
- // clean up current focus
- LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
- if (cur_focus)
- {
- if (!cur_focus->isInVisibleChain() || !cur_focus->isInEnabledChain())
- {
- // don't release focus, just reassign so that if being given
- // to a sibling won't call onFocusLost on all the ancestors
- // gFocusMgr.releaseFocusIfNeeded(cur_focus);
-
- LLUICtrl* parent = cur_focus->getParentUICtrl();
- const LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot();
- bool new_focus_found = false;
- while(parent)
- {
- if (parent->isCtrl()
- && (parent->hasTabStop() || parent == focus_root)
- && !parent->getIsChrome()
- && parent->isInVisibleChain()
- && parent->isInEnabledChain())
- {
- if (!parent->focusFirstItem())
- {
- parent->setFocus(TRUE);
- }
- new_focus_found = true;
- break;
- }
- parent = parent->getParentUICtrl();
- }
-
- // if we didn't find a better place to put focus, just release it
- // hasFocus() will return true if and only if we didn't touch focus since we
- // are only moving focus higher in the hierarchy
- if (!new_focus_found)
- {
- cur_focus->setFocus(FALSE);
- }
- }
- else if (cur_focus->isFocusRoot())
- {
- // focus roots keep trying to delegate focus to their first valid descendant
- // this assumes that focus roots are not valid focus holders on their own
- cur_focus->focusFirstItem();
- }
- }
-
- // last ditch force of edit menu to selection manager
- if (LLEditMenuHandler::gEditMenuHandler == NULL && LLSelectMgr::getInstance()->getSelection()->getObjectCount())
- {
- LLEditMenuHandler::gEditMenuHandler = LLSelectMgr::getInstance();
- }
-
- if (gFloaterView->getCycleMode())
- {
- // sync all floaters with their focus state
- gFloaterView->highlightFocusedFloater();
- gSnapshotFloaterView->highlightFocusedFloater();
- MASK mask = gKeyboard->currentMask(TRUE);
- if ((mask & MASK_CONTROL) == 0)
- {
- // control key no longer held down, finish cycle mode
- gFloaterView->setCycleMode(FALSE);
-
- gFloaterView->syncFloaterTabOrder();
- }
- else
- {
- // user holding down CTRL, don't update tab order of floaters
- }
- }
- else
- {
- // update focused floater
- gFloaterView->highlightFocusedFloater();
- gSnapshotFloaterView->highlightFocusedFloater();
- // make sure floater visible order is in sync with tab order
- gFloaterView->syncFloaterTabOrder();
- }
-}
-
-static 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())
- {
- 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]);
- }
-
- if (mWorldViewRectRaw != new_world_rect)
- {
- mWorldViewRectRaw = new_world_rect;
- gResizeScreenTexture = TRUE;
- LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
- LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() );
-
- LLRect old_world_rect_scaled = mWorldViewRectScaled;
- mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale);
-
- // sending a signal with a new WorldView rect
- mOnWorldViewRectUpdated(old_world_rect_scaled, mWorldViewRectScaled);
- }
-}
-
-void LLViewerWindow::saveLastMouse(const LLCoordGL &point)
-{
- // Store last mouse location.
- // If mouse leaves window, pretend last point was on edge of window
- if (point.mX < 0)
- {
- mCurrentMousePoint.mX = 0;
- }
- else if (point.mX > getWindowWidthScaled())
- {
- mCurrentMousePoint.mX = getWindowWidthScaled();
- }
- else
- {
- mCurrentMousePoint.mX = point.mX;
- }
-
- if (point.mY < 0)
- {
- mCurrentMousePoint.mY = 0;
- }
- else if (point.mY > getWindowHeightScaled() )
- {
- mCurrentMousePoint.mY = getWindowHeightScaled();
- }
- else
- {
- mCurrentMousePoint.mY = point.mY;
- }
-}
-
-
-// Draws the selection outlines for the currently selected objects
-// Must be called after displayObjects is called, which sets the mGLName parameter
-// NOTE: This function gets called 3 times:
-// render_ui_3d: FALSE, FALSE, TRUE
-// render_hud_elements: FALSE, FALSE, FALSE
-void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, BOOL for_hud )
-{
- LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
-
- if (!for_hud && !for_gl_pick)
- {
- // Call this once and only once
- LLSelectMgr::getInstance()->updateSilhouettes();
- }
-
- // Draw fence around land selections
- if (for_gl_pick)
- {
- if (pick_parcel_walls)
- {
- LLViewerParcelMgr::getInstance()->renderParcelCollision();
- }
- }
- else if (( for_hud && selection->getSelectType() == SELECT_TYPE_HUD) ||
- (!for_hud && selection->getSelectType() != SELECT_TYPE_HUD))
- {
- LLSelectMgr::getInstance()->renderSilhouettes(for_hud);
-
- stop_glerror();
-
- // setup HUD render
- if (selection->getSelectType() == SELECT_TYPE_HUD && LLSelectMgr::getInstance()->getSelection()->getObjectCount())
- {
- LLBBox hud_bbox = gAgentAvatarp->getHUDBBox();
-
- // set up transform to encompass bounding box of HUD
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.pushMatrix();
- gGL.loadIdentity();
- F32 depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
- gGL.ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, depth);
-
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.pushMatrix();
- gGL.loadIdentity();
- gGL.loadMatrix(OGL_TO_CFR_ROTATION); // Load Cory's favorite reference frame
- gGL.translatef(-hud_bbox.getCenterLocal().mV[VX] + (depth *0.5f), 0.f, 0.f);
- }
-
- // Render light for editing
- if (LLSelectMgr::sRenderLightRadius && LLToolMgr::getInstance()->inEdit())
- {
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLGLEnable gls_blend(GL_BLEND);
- LLGLEnable gls_cull(GL_CULL_FACE);
- LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.pushMatrix();
- if (selection->getSelectType() == SELECT_TYPE_HUD)
- {
- F32 zoom = gAgentCamera.mHUDCurZoom;
- gGL.scalef(zoom, zoom, zoom);
- }
-
- struct f : public LLSelectedObjectFunctor
- {
- virtual bool apply(LLViewerObject* object)
- {
- LLDrawable* drawable = object->mDrawable;
- if (drawable && drawable->isLight())
- {
- LLVOVolume* vovolume = drawable->getVOVolume();
- gGL.pushMatrix();
-
- LLVector3 center = drawable->getPositionAgent();
- gGL.translatef(center[0], center[1], center[2]);
- F32 scale = vovolume->getLightRadius();
- gGL.scalef(scale, scale, scale);
-
- LLColor4 color(vovolume->getLightColor(), .5f);
- gGL.color4fv(color.mV);
-
- //F32 pixel_area = 100000.f;
- // Render Outside
- gSphere.render();
-
- // Render Inside
- glCullFace(GL_FRONT);
- gSphere.render();
- glCullFace(GL_BACK);
-
- gGL.popMatrix();
- }
- return true;
- }
- } func;
- LLSelectMgr::getInstance()->getSelection()->applyToObjects(&func);
-
- gGL.popMatrix();
- }
-
- // NOTE: The average position for the axis arrows of the selected objects should
- // not be recalculated at this time. If they are, then group rotations will break.
-
- // Draw arrows at average center of all selected objects
- LLTool* tool = LLToolMgr::getInstance()->getCurrentTool();
- if (tool)
- {
- if(tool->isAlwaysRendered())
- {
- tool->render();
- }
- else
- {
- if( !LLSelectMgr::getInstance()->getSelection()->isEmpty() )
- {
- BOOL 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 = LLSelectMgr::getInstance()->getSelection()->begin();
- iter != LLSelectMgr::getInstance()->getSelection()->end(); iter++)
- {
- LLSelectNode* nodep = *iter;
- LLViewerObject* object = nodep->getObject();
- BOOL this_object_movable = FALSE;
- if (object->permMove() && (object->permModify() || selecting_linked_set))
- {
- moveable_object_selected = TRUE;
- this_object_movable = TRUE;
- }
- all_selected_objects_move = all_selected_objects_move && this_object_movable;
- all_selected_objects_modify = all_selected_objects_modify && object->permModify();
- }
-
- BOOL draw_handles = TRUE;
-
- if (tool == LLToolCompTranslate::getInstance() && (!moveable_object_selected || !all_selected_objects_move))
- {
- draw_handles = FALSE;
- }
-
- if (tool == LLToolCompRotate::getInstance() && (!moveable_object_selected || !all_selected_objects_move))
- {
- draw_handles = FALSE;
- }
-
- if ( !all_selected_objects_modify && tool == LLToolCompScale::getInstance() )
- {
- draw_handles = FALSE;
- }
-
- if( draw_handles )
- {
- tool->render();
- }
- }
- }
- if (selection->getSelectType() == SELECT_TYPE_HUD && selection->getObjectCount())
- {
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.popMatrix();
-
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.popMatrix();
- stop_glerror();
- }
- }
- }
-}
-
-// Return a point near the clicked object representative of the place the object was clicked.
-LLVector3d LLViewerWindow::clickPointInWorldGlobal(S32 x, S32 y_from_bot, LLViewerObject* clicked_object) const
-{
- // create a normalized vector pointing from the camera center into the
- // world at the location of the mouse click
- LLVector3 mouse_direction_global = mouseDirectionGlobal( x, y_from_bot );
-
- LLVector3d relative_object = clicked_object->getPositionGlobal() - gAgentCamera.getCameraPositionGlobal();
-
- // make mouse vector as long as object vector, so it touchs a point near
- // where the user clicked on the object
- mouse_direction_global *= (F32) relative_object.magVec();
-
- LLVector3d new_pos;
- new_pos.setVec(mouse_direction_global);
- // transform mouse vector back to world coords
- new_pos += gAgentCamera.getCameraPositionGlobal();
-
- return new_pos;
-}
-
-
-BOOL LLViewerWindow::clickPointOnSurfaceGlobal(const S32 x, const S32 y, LLViewerObject *objectp, LLVector3d &point_global) const
-{
- BOOL intersect = FALSE;
-
-// U8 shape = objectp->mPrimitiveCode & LL_PCODE_BASE_MASK;
- if (!intersect)
- {
- point_global = clickPointInWorldGlobal(x, y, objectp);
- llinfos << "approx intersection at " << (objectp->getPositionGlobal() - point_global) << llendl;
- }
- else
- {
- llinfos << "good intersection at " << (objectp->getPositionGlobal() - point_global) << llendl;
- }
-
- return intersect;
-}
-
-void LLViewerWindow::pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(const LLPickInfo& info), BOOL pick_transparent)
-{
- 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;
- }
-
- LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, TRUE, callback);
- schedulePick(pick_info);
-}
-
-void LLViewerWindow::schedulePick(LLPickInfo& pick_info)
-{
- if (mPicks.size() >= 1024 || mWindow->getMinimized())
- { //something went wrong, picks are being scheduled but not processed
-
- if (pick_info.mPickCallback)
- {
- pick_info.mPickCallback(pick_info);
- }
-
- return;
- }
- mPicks.push_back(pick_info);
-
- // delay further event processing until we receive results of pick
- // only do this for async picks so that handleMouseUp won't be called
- // until the pick triggered in handleMouseDown has been processed, for example
- mWindow->delayInputProcessing();
-}
-
-
-void LLViewerWindow::performPick()
-{
- if (!mPicks.empty())
- {
- std::vector<LLPickInfo>::iterator pick_it;
- for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it)
- {
- pick_it->fetchResults();
- }
-
- mLastPick = mPicks.back();
- mPicks.clear();
- }
-}
-
-void LLViewerWindow::returnEmptyPicks()
-{
- std::vector<LLPickInfo>::iterator pick_it;
- for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it)
- {
- mLastPick = *pick_it;
- // just trigger callback with empty results
- if (pick_it->mPickCallback)
- {
- pick_it->mPickCallback(*pick_it);
- }
- }
- mPicks.clear();
-}
-
-// Performs the GL object/land pick.
-LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_transparent)
-{
- BOOL 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;
- }
-
- // shortcut queueing in mPicks and just update mLastPick in place
- MASK key_mask = gKeyboard->currentMask(TRUE);
- mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), key_mask, pick_transparent, TRUE, NULL);
- mLastPick.fetchResults();
-
- return mLastPick;
-}
-
-LLHUDIcon* LLViewerWindow::cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 depth,
- LLVector3* intersection)
-{
- S32 x = mouse_x;
- S32 y = mouse_y;
-
- if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position
- {
- x = getCurrentMouseX();
- y = getCurrentMouseY();
- }
-
- // world coordinates of mouse
- 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;
-
- return LLHUDIcon::lineSegmentIntersectAll(mouse_world_start, mouse_world_end, intersection);
-
-
-}
-
-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,
- LLVector3* start,
- LLVector3* end)
-{
- S32 x = mouse_x;
- S32 y = mouse_y;
-
- if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position
- {
- x = getCurrentMouseX();
- y = getCurrentMouseY();
- }
-
- // HUD coordinates of mouse
- LLVector3 mouse_point_hud = mousePointHUD(x, y);
- LLVector3 mouse_hud_start = mouse_point_hud - LLVector3(depth, 0, 0);
- LLVector3 mouse_hud_end = mouse_point_hud + LLVector3(depth, 0, 0);
-
- // world coordinates of mouse
- LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
- LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin();
-
- //get near clip plane
- LLVector3 n = LLViewerCamera::getInstance()->getAtAxis();
- LLVector3 p = mouse_point_global + n * LLViewerCamera::getInstance()->getNear();
-
- //project mouse point onto plane
- LLVector3 pos;
- line_plane(mouse_point_global, mouse_direction_global, p, n, pos);
- mouse_point_global = pos;
-
- LLVector3 mouse_world_start = mouse_point_global;
- LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth;
-
- if (!LLViewerJoystick::getInstance()->getOverrideCamera())
- { //always set raycast intersection to mouse_world_end unless
- //flycam is on (for DoF effect)
- gDebugRaycastIntersection = mouse_world_end;
- }
-
- if (start)
- {
- *start = mouse_world_start;
- }
-
- if (end)
- {
- *end = mouse_world_end;
- }
-
- LLViewerObject* found = NULL;
-
- if (this_object) // check only this object
- {
- if (this_object->isHUDAttachment()) // is a HUD object?
- {
- if (this_object->lineSegmentIntersect(mouse_hud_start, mouse_hud_end, this_face, pick_transparent,
- face_hit, intersection, uv, normal, binormal))
- {
- found = this_object;
- }
- }
- else // is a world object
- {
- if (this_object->lineSegmentIntersect(mouse_world_start, mouse_world_end, this_face, pick_transparent,
- face_hit, intersection, uv, normal, binormal))
- {
- found = this_object;
- }
- }
- }
- else // check ALL objects
- {
- 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:
- {
- found = gPipeline.lineSegmentIntersectInWorld(mouse_world_start, mouse_world_end, pick_transparent,
- face_hit, intersection, uv, normal, binormal);
- if (found && !pick_transparent)
- {
- gDebugRaycastIntersection = *intersection;
- }
- }
- }
-
- return found;
-}
-
-// Returns unit vector relative to camera
-// indicating direction of point on screen x,y
-LLVector3 LLViewerWindow::mouseDirectionGlobal(const S32 x, const S32 y) const
-{
- // find vertical field of view
- F32 fov = LLViewerCamera::getInstance()->getView();
-
- // find world view center in scaled ui coordinates
- F32 center_x = getWorldViewRectScaled().getCenterX();
- F32 center_y = getWorldViewRectScaled().getCenterY();
-
- // calculate pixel distance to screen
- F32 distance = ((F32)getWorldViewHeightScaled() * 0.5f) / (tan(fov / 2.f));
-
- // calculate click point relative to middle of screen
- F32 click_x = x - center_x;
- F32 click_y = y - center_y;
-
- // compute mouse vector
- LLVector3 mouse_vector = distance * LLViewerCamera::getInstance()->getAtAxis()
- - click_x * LLViewerCamera::getInstance()->getLeftAxis()
- + click_y * LLViewerCamera::getInstance()->getUpAxis();
-
- mouse_vector.normVec();
-
- return mouse_vector;
-}
-
-LLVector3 LLViewerWindow::mousePointHUD(const S32 x, const S32 y) const
-{
- // find screen resolution
- S32 height = getWorldViewHeightScaled();
-
- // find world view center
- F32 center_x = getWorldViewRectScaled().getCenterX();
- F32 center_y = getWorldViewRectScaled().getCenterY();
-
- // remap with uniform scale (1/height) so that top is -0.5, bottom is +0.5
- F32 hud_x = -((F32)x - center_x) / height;
- F32 hud_y = ((F32)y - center_y) / height;
-
- return LLVector3(0.f, hud_x/gAgentCamera.mHUDCurZoom, hud_y/gAgentCamera.mHUDCurZoom);
-}
-
-// Returns unit vector relative to camera in camera space
-// indicating direction of point on screen x,y
-LLVector3 LLViewerWindow::mouseDirectionCamera(const S32 x, const S32 y) const
-{
- // find vertical field of view
- F32 fov_height = LLViewerCamera::getInstance()->getView();
- F32 fov_width = fov_height * LLViewerCamera::getInstance()->getAspect();
-
- // find screen resolution
- S32 height = getWorldViewHeightScaled();
- S32 width = getWorldViewWidthScaled();
-
- // find world view center
- F32 center_x = getWorldViewRectScaled().getCenterX();
- F32 center_y = getWorldViewRectScaled().getCenterY();
-
- // calculate click point relative to middle of screen
- F32 click_x = (((F32)x - center_x) / (F32)width) * fov_width * -1.f;
- F32 click_y = (((F32)y - center_y) / (F32)height) * fov_height;
-
- // compute mouse vector
- LLVector3 mouse_vector = LLVector3(0.f, 0.f, -1.f);
- LLQuaternion mouse_rotate;
- mouse_rotate.setQuat(click_y, click_x, 0.f);
-
- mouse_vector = mouse_vector * mouse_rotate;
- // project to z = -1 plane;
- mouse_vector = mouse_vector * (-1.f / mouse_vector.mV[VZ]);
-
- return mouse_vector;
-}
-
-
-
-BOOL LLViewerWindow::mousePointOnPlaneGlobal(LLVector3d& point, const S32 x, const S32 y,
- const LLVector3d &plane_point_global,
- const LLVector3 &plane_normal_global)
-{
- LLVector3d mouse_direction_global_d;
-
- mouse_direction_global_d.setVec(mouseDirectionGlobal(x,y));
- LLVector3d plane_normal_global_d;
- plane_normal_global_d.setVec(plane_normal_global);
- F64 plane_mouse_dot = (plane_normal_global_d * mouse_direction_global_d);
- LLVector3d plane_origin_camera_rel = plane_point_global - gAgentCamera.getCameraPositionGlobal();
- F64 mouse_look_at_scale = (plane_normal_global_d * plane_origin_camera_rel)
- / plane_mouse_dot;
- if (llabs(plane_mouse_dot) < 0.00001)
- {
- // if mouse is parallel to plane, return closest point on line through plane origin
- // that is parallel to camera plane by scaling mouse direction vector
- // by distance to plane origin, modulated by deviation of mouse direction from plane origin
- LLVector3d plane_origin_dir = plane_origin_camera_rel;
- plane_origin_dir.normVec();
-
- mouse_look_at_scale = plane_origin_camera_rel.magVec() / (plane_origin_dir * mouse_direction_global_d);
- }
-
- point = gAgentCamera.getCameraPositionGlobal() + mouse_look_at_scale * mouse_direction_global_d;
-
- return mouse_look_at_scale > 0.0;
-}
-
-
-// Returns global position
-BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d *land_position_global)
-{
- LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
- F32 mouse_dir_scale;
- BOOL hit_land = FALSE;
- LLViewerRegion *regionp;
- F32 land_z;
- const F32 FIRST_PASS_STEP = 1.0f; // meters
- const F32 SECOND_PASS_STEP = 0.1f; // meters
- LLVector3d camera_pos_global;
-
- camera_pos_global = gAgentCamera.getCameraPositionGlobal();
- LLVector3d probe_point_global;
- LLVector3 probe_point_region;
-
- // walk forwards to find the point
- for (mouse_dir_scale = FIRST_PASS_STEP; mouse_dir_scale < 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 = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global);
-
- if (!regionp)
- {
- // ...we're outside the world somehow
- continue;
- }
-
- S32 i = (S32) (probe_point_region.mV[VX]/regionp->getLand().getMetersPerGrid());
- S32 j = (S32) (probe_point_region.mV[VY]/regionp->getLand().getMetersPerGrid());
- S32 grids_per_edge = (S32) regionp->getLand().mGridsPerEdge;
- if ((i >= grids_per_edge) || (j >= grids_per_edge))
- {
- //llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl;
- continue;
- }
-
- land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
-
- //llinfos << "mousePointOnLand initial z " << land_z << llendl;
-
- if (probe_point_region.mV[VZ] < land_z)
- {
- // ...just went under land
-
- // cout << "under land at " << probe_point << " scale " << mouse_vec_scale << endl;
-
- hit_land = TRUE;
- break;
- }
- }
-
-
- if (hit_land)
- {
- // Don't go more than one step beyond where we stopped above.
- // This can't just be "mouse_vec_scale" because floating point error
- // will stop the loop before the last increment.... X - 1.0 + 0.1 + 0.1 + ... + 0.1 != X
- F32 stop_mouse_dir_scale = mouse_dir_scale + FIRST_PASS_STEP;
-
- // take a step backwards, then walk forwards again to refine position
- for ( mouse_dir_scale -= FIRST_PASS_STEP; mouse_dir_scale <= stop_mouse_dir_scale; mouse_dir_scale += SECOND_PASS_STEP)
- {
- LLVector3d mouse_direction_global_d;
- mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale);
- probe_point_global = camera_pos_global + mouse_direction_global_d;
-
- regionp = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global);
-
- if (!regionp)
- {
- // ...we're outside the world somehow
- continue;
- }
-
- /*
- i = (S32) (local_probe_point.mV[VX]/regionp->getLand().getMetersPerGrid());
- j = (S32) (local_probe_point.mV[VY]/regionp->getLand().getMetersPerGrid());
- if ((i >= regionp->getLand().mGridsPerEdge) || (j >= regionp->getLand().mGridsPerEdge))
- {
- // llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl;
- continue;
- }
- land_z = regionp->getLand().mSurfaceZ[ i + j * (regionp->getLand().mGridsPerEdge) ];
- */
-
- land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
-
- //llinfos << "mousePointOnLand refine z " << land_z << llendl;
-
- if (probe_point_region.mV[VZ] < land_z)
- {
- // ...just went under land again
-
- *land_position_global = probe_point_global;
- return TRUE;
- }
- }
- }
-
- return FALSE;
-}
-
-// Saves an image to the harddrive as "SnapshotX" where X >= 1.
-BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image, bool force_picker)
-{
- if (!image)
- {
- llwarns << "No image to save" << llendl;
- return FALSE;
- }
-
- 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 base file location if needed.
- if (force_picker || !isSnapshotLocSet())
- {
- std::string proposed_name( sSnapshotBaseName );
-
- // getSaveFile will append an appropriate extension to the proposed name, based on the ESaveFilter constant passed in.
-
- // pick a directory in which to save
- LLFilePicker& picker = LLFilePicker::instance();
- if (!picker.getSaveFile(pick_type, proposed_name))
- {
- // Clicked cancel
- return FALSE;
- }
-
- // Copy the directory + file name
- std::string filepath = picker.getFirstFile();
-
- LLViewerWindow::sSnapshotBaseName = gDirUtilp->getBaseFileName(filepath, true);
- LLViewerWindow::sSnapshotDir = gDirUtilp->getDirName(filepath);
- }
-
- // Look for an unused file name
- std::string filepath;
- S32 i = 1;
- S32 err = 0;
-
- do
- {
- filepath = sSnapshotDir;
- filepath += gDirUtilp->getDirDelimiter();
- filepath += sSnapshotBaseName;
- filepath += llformat("_%.3d",i);
- filepath += extension;
-
- llstat stat_info;
- err = LLFile::stat( filepath, &stat_info );
- i++;
- }
- while( -1 != err ); // search until the file is not found (i.e., stat() gives an error).
-
- llinfos << "Saving snapshot to " << filepath << llendl;
- return image->save(filepath);
-}
-
-void LLViewerWindow::resetSnapshotLoc()
-{
- sSnapshotDir.clear();
-}
-
-// static
-void LLViewerWindow::movieSize(S32 new_width, S32 new_height)
-{
- LLCoordWindow size;
- gViewerWindow->getWindow()->getSize(&size);
- if ( size.mX != new_width
- || size.mY != new_height)
- {
- LLCoordWindow new_size(new_width, new_height);
- LLCoordScreen screen_size;
- gViewerWindow->getWindow()->convertCoords(new_size, &screen_size);
- gViewerWindow->getWindow()->setSize(screen_size);
- }
-}
-
-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;
-
- LLPointer<LLImageRaw> raw = new LLImageRaw;
- BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, do_rebuild);
-
- if (success)
- {
- LLPointer<LLImageBMP> bmp_image = new LLImageBMP;
- success = bmp_image->encode(raw, 0.0f);
- if( success )
- {
- success = bmp_image->save(filepath);
- }
- else
- {
- llwarns << "Unable to encode bmp snapshot" << llendl;
- }
- }
- else
- {
- llwarns << "Unable to capture raw snapshot" << llendl;
- }
-
- return success;
-}
-
-
-void LLViewerWindow::playSnapshotAnimAndSound()
-{
- if (gSavedSettings.getBOOL("QuietSnapshotsToDisk"))
- {
- return;
- }
- gAgent.sendAnimationRequest(ANIM_AGENT_SNAPSHOT, ANIM_REQUEST_START);
- send_sound_trigger(LLUUID(gSavedSettings.getString("UISndSnapshot")), 1.0f);
-}
-
-BOOL LLViewerWindow::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 a raw image
-// Since the required size might be bigger than the available screen, this method rerenders the scene in parts (called subimages) and copy
-// the results over to the final raw image.
-BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height,
- BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL do_rebuild, ESnapshotType type, S32 max_size)
-{
- if (!raw)
- {
- return FALSE;
- }
- //check if there is enough memory for the snapshot image
- if(LLPipeline::sMemAllocationThrottled)
- {
- return FALSE ; //snapshot taking is disabled due to memory restriction.
- }
- if(image_width * image_height > (1 << 22)) //if snapshot image is larger than 2K by 2K
- {
- if(!LLMemory::tryToAlloc(NULL, image_width * image_height * 3))
- {
- llwarns << "No enough memory to take the snapshot with size (w : h): " << image_width << " : " << image_height << llendl ;
- return FALSE ; //there is no enough memory for taking this snapshot.
- }
- }
-
- // PRE SNAPSHOT
- gDisplaySwapBuffers = FALSE;
-
- glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
- setCursor(UI_CURSOR_WAIT);
-
- // Hide all the UI widgets first and draw a frame
- BOOL prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI) ? TRUE : FALSE;
-
- if ( prev_draw_ui != show_ui)
- {
- LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
- }
-
- BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && LLPipeline::sShowHUDAttachments;
- if (hide_hud)
- {
- LLPipeline::sShowHUDAttachments = FALSE;
- }
-
- // if not showing ui, use full window to render world view
- updateWorldViewRect(!show_ui);
-
- // Copy screen to a buffer
- // crop sides or top and bottom, if taking a snapshot of different aspect ratio
- // from window
- LLRect window_rect = show_ui ? getWindowRectRaw() : getWorldViewRectRaw();
-
- S32 snapshot_width = window_rect.getWidth();
- S32 snapshot_height = window_rect.getHeight();
- // SNAPSHOT
- S32 window_width = snapshot_width;
- S32 window_height = snapshot_height;
-
- // Note: Scaling of the UI is currently *not* supported so we limit the output size if UI is requested
- if (show_ui)
- {
- // If the user wants the UI, limit the output size to the available screen size
- image_width = llmin(image_width, window_width);
- image_height = llmin(image_height, window_height);
- }
-
- F32 scale_factor = 1.0f ;
- if (!keep_window_aspect || (image_width > window_width) || (image_height > window_height))
- {
- // if image cropping or need to enlarge the scene, compute a scale_factor
- F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ;
- snapshot_width = (S32)(ratio * image_width) ;
- snapshot_height = (S32)(ratio * image_height) ;
- scale_factor = llmax(1.0f, 1.0f / ratio) ;
- }
-
- if (show_ui && scale_factor > 1.f)
- {
- // Note: we should never get there...
- llwarns << "over scaling UI not supported." << llendl;
- }
-
- S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f);
- S32 buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f);
-
- S32 image_buffer_x = llfloor(snapshot_width * scale_factor) ;
- S32 image_buffer_y = llfloor(snapshot_height * scale_factor) ;
-
- if ((image_buffer_x > max_size) || (image_buffer_y > max_size)) // boundary check to avoid memory overflow
- {
- scale_factor *= llmin((F32)max_size / image_buffer_x, (F32)max_size / image_buffer_y) ;
- image_buffer_x = llfloor(snapshot_width * scale_factor) ;
- image_buffer_y = llfloor(snapshot_height * scale_factor) ;
- }
- if ((image_buffer_x > 0) && (image_buffer_y > 0))
- {
- raw->resize(image_buffer_x, image_buffer_y, 3);
- }
- else
- {
- return FALSE ;
- }
- if (raw->isBufferInvalid())
- {
- return FALSE ;
- }
-
- BOOL high_res = scale_factor >= 2.f; // Font scaling is slow, only do so if rez is much higher
- if (high_res && show_ui)
- {
- // Note: we should never get there...
- llwarns << "High res UI snapshot not supported. " << llendl;
- /*send_agent_pause();
- //rescale fonts
- initFonts(scale_factor);
- LLHUDObject::reshapeAll();*/
- }
-
- S32 output_buffer_offset_y = 0;
-
- F32 depth_conversion_factor_1 = (LLViewerCamera::getInstance()->getFar() + LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear());
- F32 depth_conversion_factor_2 = (LLViewerCamera::getInstance()->getFar() - LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear());
-
- gObjectList.generatePickList(*LLViewerCamera::getInstance());
-
- // Subimages are in fact partial rendering of the final view. This happens when the final view is bigger than the screen.
- // In most common cases, scale_factor is 1 and there's no more than 1 iteration on x and y
- for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y)
- {
- S32 subimage_y_offset = llclamp(buffer_y_offset - (subimage_y * window_height), 0, window_height);;
- // handle fractional columns
- U32 read_height = llmax(0, (window_height - subimage_y_offset) -
- llmax(0, (window_height * (subimage_y + 1)) - (buffer_y_offset + raw->getHeight())));
-
- S32 output_buffer_offset_x = 0;
- for (int subimage_x = 0; subimage_x < scale_factor; ++subimage_x)
- {
- gDisplaySwapBuffers = FALSE;
- gDepthDirty = TRUE;
-
- S32 subimage_x_offset = llclamp(buffer_x_offset - (subimage_x * window_width), 0, window_width);
- // handle fractional rows
- U32 read_width = llmax(0, (window_width - subimage_x_offset) -
- llmax(0, (window_width * (subimage_x + 1)) - (buffer_x_offset + raw->getWidth())));
-
- // Skip rendering and sampling altogether if either width or height is degenerated to 0 (common in cropping cases)
- if (read_width && read_height)
- {
- const U32 subfield = subimage_x+(subimage_y*llceil(scale_factor));
- display(do_rebuild, scale_factor, subfield, TRUE);
-
- if (!LLPipeline::sRenderDeferred)
- {
- // Required for showing the GUI in snapshots and performing bloom composite overlay
- // Call even if show_ui is FALSE
- render_ui(scale_factor, subfield);
- }
-
- for (U32 out_y = 0; out_y < read_height ; out_y++)
- {
- S32 output_buffer_offset = (
- (out_y * (raw->getWidth())) // ...plus iterated y...
- + (window_width * subimage_x) // ...plus subimage start in x...
- + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y...
- - output_buffer_offset_x // ...minus buffer padding x...
- - (output_buffer_offset_y * (raw->getWidth())) // ...minus buffer padding y...
- ) * raw->getComponents();
-
- // Ping the watchdog thread every 100 lines to keep us alive (arbitrary number, feel free to change)
- if (out_y % 100 == 0)
- {
- LLAppViewer::instance()->pingMainloopTimeout("LLViewerWindow::rawSnapshot");
- }
-
- if (type == SNAPSHOT_TYPE_COLOR)
- {
- glReadPixels(
- subimage_x_offset, out_y + subimage_y_offset,
- read_width, 1,
- GL_RGB, GL_UNSIGNED_BYTE,
- raw->getData() + output_buffer_offset
- );
- }
- else // SNAPSHOT_TYPE_DEPTH
- {
- LLPointer<LLImageRaw> depth_line_buffer = new LLImageRaw(read_width, 1, sizeof(GL_FLOAT)); // need to store floating point values
- glReadPixels(
- subimage_x_offset, out_y + subimage_y_offset,
- read_width, 1,
- GL_DEPTH_COMPONENT, GL_FLOAT,
- depth_line_buffer->getData()// current output pixel is beginning of buffer...
- );
-
- for (S32 i = 0; i < (S32)read_width; i++)
- {
- F32 depth_float = *(F32*)(depth_line_buffer->getData() + (i * sizeof(F32)));
-
- F32 linear_depth_float = 1.f / (depth_conversion_factor_1 - (depth_float * depth_conversion_factor_2));
- U8 depth_byte = F32_to_U8(linear_depth_float, LLViewerCamera::getInstance()->getNear(), LLViewerCamera::getInstance()->getFar());
- // write converted scanline out to result image
- for (S32 j = 0; j < raw->getComponents(); j++)
- {
- *(raw->getData() + output_buffer_offset + (i * raw->getComponents()) + j) = depth_byte;
- }
- }
- }
- }
- }
- output_buffer_offset_x += subimage_x_offset;
- stop_glerror();
- }
- output_buffer_offset_y += subimage_y_offset;
- }
-
- gDisplaySwapBuffers = FALSE;
- gDepthDirty = TRUE;
-
- // POST SNAPSHOT
- if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
- }
-
- if (hide_hud)
- {
- LLPipeline::sShowHUDAttachments = TRUE;
- }
-
- /*if (high_res)
- {
- initFonts(1.f);
- LLHUDObject::reshapeAll();
- }*/
-
- // Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding)
- // Note: this formula depends on the number of components being 3. Not obvious, but it's correct.
- image_width += (image_width * 3) % 4;
-
- BOOL ret = TRUE ;
- // Resize image
- if(llabs(image_width - image_buffer_x) > 4 || llabs(image_height - image_buffer_y) > 4)
- {
- ret = raw->scale( image_width, image_height );
- }
- else if(image_width != image_buffer_x || image_height != image_buffer_y)
- {
- ret = raw->scale( image_width, image_height, FALSE );
- }
-
-
- setCursor(UI_CURSOR_ARROW);
-
- if (do_rebuild)
- {
- // If we had to do a rebuild, that means that the lists of drawables to be rendered
- // was empty before we started.
- // Need to reset these, otherwise we call state sort on it again when render gets called the next time
- // and we stand a good chance of crashing on rebuild because the render drawable arrays have multiple copies of
- // objects on them.
- gPipeline.resetDrawOrders();
- }
-
- if (high_res)
- {
- send_agent_resume();
- }
-
- return ret;
-}
-
-void LLViewerWindow::destroyWindow()
-{
- if (mWindow)
- {
- LLWindowManager::destroyWindow(mWindow);
- }
- mWindow = NULL;
-}
-
-
-void LLViewerWindow::drawMouselookInstructions()
-{
- // Draw instructions for mouselook ("Press ESC to return to World View" partially transparent at the bottom of the screen.)
- const std::string instructions = LLTrans::getString("LeaveMouselook");
- const LLFontGL* font = LLFontGL::getFont(LLFontDescriptor("SansSerif", "Large", LLFontGL::BOLD));
-
- //to be on top of Bottom bar when it is opened
- const S32 INSTRUCTIONS_PAD = 50;
-
- font->renderUTF8(
- instructions, 0,
- getWorldViewRectScaled().getCenterX(),
- getWorldViewRectScaled().mBottom + INSTRUCTIONS_PAD,
- LLColor4( 1.0f, 1.0f, 1.0f, 0.5f ),
- LLFontGL::HCENTER, LLFontGL::TOP,
- LLFontGL::NORMAL,LLFontGL::DROP_SHADOW);
-}
-
-void* LLViewerWindow::getPlatformWindow() const
-{
- return mWindow->getPlatformWindow();
-}
-
-void* LLViewerWindow::getMediaWindow() const
-{
- return mWindow->getMediaWindow();
-}
-
-void LLViewerWindow::focusClient() const
-{
- return mWindow->focusClient();
-}
-
-LLRootView* LLViewerWindow::getRootView() const
-{
- return mRootView;
-}
-
-LLRect LLViewerWindow::getWorldViewRectScaled() const
-{
- return mWorldViewRectScaled;
-}
-
-S32 LLViewerWindow::getWorldViewHeightScaled() const
-{
- return mWorldViewRectScaled.getHeight();
-}
-
-S32 LLViewerWindow::getWorldViewWidthScaled() const
-{
- return mWorldViewRectScaled.getWidth();
-}
-
-
-S32 LLViewerWindow::getWorldViewHeightRaw() const
-{
- return mWorldViewRectRaw.getHeight();
-}
-
-S32 LLViewerWindow::getWorldViewWidthRaw() const
-{
- return mWorldViewRectRaw.getWidth();
-}
-
-S32 LLViewerWindow::getWindowHeightScaled() const
-{
- return mWindowRectScaled.getHeight();
-}
-
-S32 LLViewerWindow::getWindowWidthScaled() const
-{
- return mWindowRectScaled.getWidth();
-}
-
-S32 LLViewerWindow::getWindowHeightRaw() const
-{
- return mWindowRectRaw.getHeight();
-}
-
-S32 LLViewerWindow::getWindowWidthRaw() const
-{
- return mWindowRectRaw.getWidth();
-}
-
-void LLViewerWindow::setup2DRender()
-{
- // setup ortho camera
- gl_state_for_2d(mWindowRectRaw.getWidth(), mWindowRectRaw.getHeight());
- setup2DViewport();
-}
-
-void LLViewerWindow::setup2DViewport(S32 x_offset, S32 y_offset)
-{
- gGLViewport[0] = mWindowRectRaw.mLeft + x_offset;
- gGLViewport[1] = mWindowRectRaw.mBottom + y_offset;
- gGLViewport[2] = mWindowRectRaw.getWidth();
- gGLViewport[3] = mWindowRectRaw.getHeight();
- glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
-}
-
-
-void LLViewerWindow::setup3DRender()
-{
- // setup perspective camera
- LLViewerCamera::getInstance()->setPerspective(NOT_FOR_SELECTION, mWorldViewRectRaw.mLeft, mWorldViewRectRaw.mBottom, mWorldViewRectRaw.getWidth(), mWorldViewRectRaw.getHeight(), FALSE, LLViewerCamera::getInstance()->getNear(), MAX_FAR_CLIP*2.f);
- setup3DViewport();
-}
-
-void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset)
-{
- gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset;
- gGLViewport[1] = mWorldViewRectRaw.mBottom + y_offset;
- gGLViewport[2] = mWorldViewRectRaw.getWidth();
- gGLViewport[3] = mWorldViewRectRaw.getHeight();
- glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
-}
-
-void LLViewerWindow::revealIntroPanel()
-{
- if (mProgressView)
- {
- mProgressView->revealIntroPanel();
- }
-}
-
-void LLViewerWindow::setShowProgress(const BOOL show)
-{
- if (mProgressView)
- {
- mProgressView->setVisible(show);
- }
-}
-
-void LLViewerWindow::setStartupComplete()
-{
- if (mProgressView)
- {
- mProgressView->setStartupComplete();
- }
-}
-
-BOOL LLViewerWindow::getShowProgress() const
-{
- return (mProgressView && mProgressView->getVisible());
-}
-
-void LLViewerWindow::setProgressString(const std::string& string)
-{
- if (mProgressView)
- {
- mProgressView->setText(string);
- }
-}
-
-void LLViewerWindow::setProgressMessage(const std::string& msg)
-{
- if(mProgressView)
- {
- mProgressView->setMessage(msg);
- }
-}
-
-void LLViewerWindow::setProgressPercent(const F32 percent)
-{
- if (mProgressView)
- {
- mProgressView->setPercent(percent);
- }
-}
-
-void LLViewerWindow::setProgressCancelButtonVisible( BOOL b, const std::string& label )
-{
- if (mProgressView)
- {
- mProgressView->setCancelButtonVisible( b, label );
- }
-}
-
-
-LLProgressView *LLViewerWindow::getProgressView() const
-{
- return mProgressView;
-}
-
-void LLViewerWindow::dumpState()
-{
- llinfos << "LLViewerWindow Active " << S32(mActive) << llendl;
- llinfos << "mWindow visible " << S32(mWindow->getVisible())
- << " minimized " << S32(mWindow->getMinimized())
- << llendl;
-}
-
-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;
-
- // Pause texture decode threads (will get unpaused during main loop)
- LLAppViewer::getTextureCache()->pause();
- LLAppViewer::getImageDecodeThread()->pause();
- LLAppViewer::getTextureFetch()->pause();
-
- gSky.destroyGL();
- stop_glerror();
-
- LLManipTranslate::destroyGL() ;
- stop_glerror();
-
- gBumpImageList.destroyGL();
- stop_glerror();
-
- LLFontGL::destroyAllGL();
- stop_glerror();
-
- LLVOAvatar::destroyGL();
- stop_glerror();
-
- LLViewerDynamicTexture::destroyGL();
- stop_glerror();
-
- if (gPipeline.isInit())
- {
- gPipeline.destroyGL();
- }
-
- gBox.cleanupGL();
-
- if(gPostProcess)
- {
- gPostProcess->invalidate();
- }
-
- gTextureList.destroyGL(save_state);
- stop_glerror();
-
- gGLManager.mIsDisabled = TRUE;
- stop_glerror();
-
- llinfos << "Remaining allocated texture memory: " << LLImageGL::sGlobalTextureMemoryInBytes << " bytes" << llendl;
- }
-}
-
-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();
-
- gSky.restoreGL();
- gPipeline.restoreGL();
- LLDrawPoolWater::restoreGL();
- LLManipTranslate::restoreGL();
-
- gBumpImageList.restoreGL();
- LLViewerDynamicTexture::restoreGL();
- LLVOAvatar::restoreGL();
-
- gResizeScreenTexture = TRUE;
- gWindowResized = TRUE;
-
- if (isAgentAvatarValid() && !gAgentAvatarp->isUsingBakedTextures())
- {
- LLVisualParamHint::requestHintUpdates();
- }
-
- if (!progress_message.empty())
- {
- gRestoreGLTimer.reset();
- gRestoreGL = TRUE;
- setShowProgress(TRUE);
- setProgressString(progress_message);
- }
- llinfos << "...Restoring GL done" << llendl;
- if(!LLAppViewer::instance()->restoreErrorTrap())
- {
- llwarns << " Someone took over my signal/exception handler (post restoreGL)!" << llendl;
- }
-
- }
-}
-
-void LLViewerWindow::initFonts(F32 zoom_factor)
-{
- LLFontGL::destroyAllGL();
- // Initialize with possibly different zoom factor
-
- LLFontManager::initClass();
-
- LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"),
- mDisplayScale.mV[VX] * zoom_factor,
- mDisplayScale.mV[VY] * zoom_factor,
- gDirUtilp->getAppRODataDir(),
- LLUI::getXUIPaths());
- // Force font reloads, which can be very slow
- LLFontGL::loadDefaultFonts();
-}
-
-void LLViewerWindow::requestResolutionUpdate()
-{
- mResDirty = true;
-}
-
-void LLViewerWindow::checkSettings()
-{
- if (mStatesDirty)
- {
- gGL.refreshState();
- LLViewerShaderMgr::instance()->setShaders();
- mStatesDirty = false;
- }
-
- // We want to update the resolution AFTER the states getting refreshed not before.
- if (mResDirty)
- {
- reshape(getWindowWidthRaw(), getWindowHeightRaw());
- mResDirty = false;
- }
-}
-
-void LLViewerWindow::restartDisplay(BOOL show_progress_bar)
-{
- llinfos << "Restaring GL" << llendl;
- stopGL();
- if (show_progress_bar)
- {
- restoreGL(LLTrans::getString("ProgressChangingResolution"));
- }
- else
- {
- restoreGL();
- }
-}
-
-BOOL LLViewerWindow::changeDisplaySettings(LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar)
-{
- //BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized");
-
- //gResizeScreenTexture = TRUE;
-
-
- //U32 fsaa = gSavedSettings.getU32("RenderFSAASamples");
- //U32 old_fsaa = mWindow->getFSAASamples();
-
- // if not maximized, use the request size
- if (!mWindow->getMaximized())
- {
- mWindow->setSize(size);
- }
-
- //if (fsaa == old_fsaa)
- {
- return TRUE;
- }
-
-/*
-
- // Close floaters that don't handle settings change
- LLFloaterReg::hideInstance("snapshot");
-
- BOOL result_first_try = FALSE;
- BOOL result_second_try = FALSE;
-
- LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
- send_agent_pause();
- llinfos << "Stopping GL during changeDisplaySettings" << llendl;
- stopGL();
- mIgnoreActivate = TRUE;
- LLCoordScreen old_size;
- LLCoordScreen old_pos;
- mWindow->getSize(&old_size);
-
- //mWindow->setFSAASamples(fsaa);
-
- result_first_try = mWindow->switchContext(false, size, disable_vsync);
- if (!result_first_try)
- {
- // try to switch back
- //mWindow->setFSAASamples(old_fsaa);
- result_second_try = mWindow->switchContext(false, old_size, disable_vsync);
-
- if (!result_second_try)
- {
- // we are stuck...try once again with a minimal resolution?
- send_agent_resume();
- mIgnoreActivate = FALSE;
- return FALSE;
- }
- }
- send_agent_resume();
-
- llinfos << "Restoring GL during resolution change" << llendl;
- if (show_progress_bar)
- {
- restoreGL(LLTrans::getString("ProgressChangingResolution"));
- }
- else
- {
- restoreGL();
- }
-
- if (!result_first_try)
- {
- LLSD args;
- args["RESX"] = llformat("%d",size.mX);
- args["RESY"] = llformat("%d",size.mY);
- LLNotificationsUtil::add("ResolutionSwitchFail", args);
- size = old_size; // for reshape below
- }
-
- BOOL success = result_first_try || result_second_try;
-
- if (success)
- {
- // maximize window if was maximized, else reposition
- if (was_maximized)
- {
- mWindow->maximize();
- }
- else
- {
- S32 windowX = gSavedSettings.getS32("WindowX");
- S32 windowY = gSavedSettings.getS32("WindowY");
-
- mWindow->setPosition(LLCoordScreen ( windowX, windowY ) );
- }
- }
-
- mIgnoreActivate = FALSE;
- gFocusMgr.setKeyboardFocus(keyboard_focus);
-
- return success;
-
- */
-}
-
-F32 LLViewerWindow::getWorldViewAspectRatio() const
-{
- F32 world_aspect = (F32)mWorldViewRectRaw.getWidth() / (F32)mWorldViewRectRaw.getHeight();
- return world_aspect;
-}
-
-void LLViewerWindow::calcDisplayScale()
-{
- F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor");
- LLVector2 display_scale;
- display_scale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
- display_scale *= ui_scale_factor;
-
- // limit minimum display scale
- if (display_scale.mV[VX] < MIN_DISPLAY_SCALE || display_scale.mV[VY] < MIN_DISPLAY_SCALE)
- {
- display_scale *= MIN_DISPLAY_SCALE / llmin(display_scale.mV[VX], display_scale.mV[VY]);
- }
-
- if (display_scale != mDisplayScale)
- {
- llinfos << "Setting display scale to " << display_scale << llendl;
-
- mDisplayScale = display_scale;
- // Init default fonts
- initFonts();
- }
-}
-
-//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]);
-
- return res;
-}
-
-S32 LLViewerWindow::getChatConsoleBottomPad()
-{
- S32 offset = 0;
-
- if(gToolBarView)
- offset += gToolBarView->getChild<LLView>("bottom_toolbar_panel")->getRect().getHeight();
-
- return offset;
-}
-
-LLRect LLViewerWindow::getChatConsoleRect()
-{
- LLRect full_window(0, getWindowHeightScaled(), getWindowWidthScaled(), 0);
- LLRect console_rect = full_window;
-
- const S32 CONSOLE_PADDING_TOP = 24;
- const S32 CONSOLE_PADDING_LEFT = 24;
- const S32 CONSOLE_PADDING_RIGHT = 10;
-
- console_rect.mTop -= CONSOLE_PADDING_TOP;
- console_rect.mBottom += getChatConsoleBottomPad();
-
- console_rect.mLeft += CONSOLE_PADDING_LEFT;
-
- static const BOOL CHAT_FULL_WIDTH = gSavedSettings.getBOOL("ChatFullWidth");
-
- if (CHAT_FULL_WIDTH)
- {
- console_rect.mRight -= CONSOLE_PADDING_RIGHT;
- }
- else
- {
- // Make console rect somewhat narrow so having inventory open is
- // less of a problem.
- console_rect.mRight = console_rect.mLeft + 2 * getWindowWidthScaled() / 3;
- }
-
- return console_rect;
-}
-//----------------------------------------------------------------------------
-
-
-//static
-bool LLViewerWindow::onAlert(const LLSD& notify)
-{
- LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID());
-
- if (gHeadlessClient)
- {
- llinfos << "Alert: " << notification->getName() << llendl;
- }
-
- // 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( gAgentCamera.cameraMouselook() )
- {
- gAgentCamera.changeCameraToDefault();
- }
- return false;
-}
-
-void LLViewerWindow::setUIVisibility(bool visible)
-{
- mUIVisible = visible;
-
- if (!visible)
- {
- gAgentCamera.changeCameraToThirdPerson(FALSE);
- gFloaterView->hideAllFloaters();
- }
- else
- {
- gFloaterView->showHiddenFloaters();
- }
-
- if (gToolBarView)
- {
- gToolBarView->setToolBarsVisible(visible);
- }
-
- LLNavigationBar::getInstance()->setVisible(visible ? gSavedSettings.getBOOL("ShowNavbarNavigationPanel") : FALSE);
- LLPanelTopInfoBar::getInstance()->setVisible(visible? gSavedSettings.getBOOL("ShowMiniLocationPanel") : FALSE);
- mRootView->getChildView("status_bar_container")->setVisible(visible);
-}
-
-bool LLViewerWindow::getUIVisibility()
-{
- return mUIVisible;
-}
-
-////////////////////////////////////////////////////////////////////////////
-//
-// LLPickInfo
-//
-LLPickInfo::LLPickInfo()
- : mKeyMask(MASK_NONE),
- mPickCallback(NULL),
- mPickType(PICK_INVALID),
- mWantSurfaceInfo(FALSE),
- mObjectFace(-1),
- mUVCoords(-1.f, -1.f),
- mSTCoords(-1.f, -1.f),
- mXYCoords(-1, -1),
- mIntersection(),
- mNormal(),
- mBinormal(),
- mHUDIcon(NULL),
- mPickTransparent(FALSE)
-{
-}
-
-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)
-{
-}
-
-void LLPickInfo::fetchResults()
-{
-
- 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)
- {
- 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;
-
- 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()))
- {
- // was this name referring to a hud icon?
- mHUDIcon = hit_icon;
- mPickType = PICK_ICON;
- mPosGlobal = mHUDIcon->getPositionGlobal();
- }
- else if (objectp)
- {
- if( objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH )
- {
- // Hit land
- mPickType = PICK_LAND;
- mObjectID.setNull(); // land has no id
-
- // put global position into land_pos
- LLVector3d land_pos;
- if (!gViewerWindow->mousePointOnLandGlobal(mPickPt.mX, mPickPt.mY, &land_pos))
- {
- // The selected point is beyond the draw distance or is otherwise
- // not selectable. Return before calling mPickCallback().
- return;
- }
-
- // Fudge the land focus a little bit above ground.
- mPosGlobal = land_pos + LLVector3d::z_axis * 0.1f;
- }
- else
- {
- if(isFlora(objectp))
- {
- mPickType = PICK_FLORA;
- }
- else
- {
- mPickType = PICK_OBJECT;
- }
- mObjectOffset = gAgentCamera.calcFocusOffset(objectp, intersection, mPickPt.mX, mPickPt.mY);
- mObjectID = objectp->mID;
- mObjectFace = (te_offset == NO_FACE) ? -1 : (S32)te_offset;
-
- mPosGlobal = gAgent.getPosGlobalFromAgent(intersection);
-
- if (mWantSurfaceInfo)
- {
- getSurfaceInfo();
- }
- }
- }
-
- if (mPickCallback)
- {
- mPickCallback(*this);
- }
-}
-
-LLPointer<LLViewerObject> LLPickInfo::getObject() const
-{
- return gObjectList.findObject( mObjectID );
-}
-
-void LLPickInfo::updateXYCoords()
-{
- if (mObjectFace > -1)
- {
- const LLTextureEntry* tep = getObject()->getTE(mObjectFace);
- LLPointer<LLViewerTexture> imagep = LLViewerTextureManager::getFetchedTexture(tep->getID());
- if(mUVCoords.mV[VX] >= 0.f && mUVCoords.mV[VY] >= 0.f && imagep.notNull())
- {
- mXYCoords.mX = llround(mUVCoords.mV[VX] * (F32)imagep->getWidth());
- mXYCoords.mY = llround((1.f - mUVCoords.mV[VY]) * (F32)imagep->getHeight());
- }
- }
-}
-
-void LLPickInfo::getSurfaceInfo()
-{
- // set values to uninitialized - this is what we return if no intersection is found
- mObjectFace = -1;
- mUVCoords = LLVector2(-1, -1);
- mSTCoords = LLVector2(-1, -1);
- mXYCoords = LLCoordScreen(-1, -1);
- mIntersection = LLVector3(0,0,0);
- mNormal = LLVector3(0,0,0);
- mBinormal = LLVector3(0,0,0);
-
- 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();
-
- }
- }
-}
-
-
-/* code to get UV via a special UV render - removed in lieu of raycast method
-LLVector2 LLPickInfo::pickUV()
-{
- 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);
-
- 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)
-{
- if (!object) return false;
-
- LLPCode pcode = object->getPCode();
-
- if( (LL_PCODE_LEGACY_GRASS == pcode)
- || (LL_PCODE_LEGACY_TREE == pcode)
- || (LL_PCODE_TREE_NEW == pcode))
- {
- return true;
- }
- return false;
-}
+/** + * @file llviewerwindow.cpp + * @brief Implementation of the LLViewerWindow class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llviewerwindow.h" + +#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 <boost/lambda/core.hpp> + +#include "llagent.h" +#include "llagentcamera.h" +#include "llfloaterreg.h" +#include "llmeshrepository.h" +#include "llpanellogin.h" +#include "llviewerkeyboard.h" +#include "llviewermenu.h" + +#include "llviewquery.h" +#include "llxmltree.h" +#include "llslurl.h" +//#include "llviewercamera.h" +#include "llrender.h" + +#include "llvoiceclient.h" // for push-to-talk button handling + +// +// TODO: Many of these includes are unnecessary. Remove them. +// + +// linden library includes +#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" +#include "llui.h" +#include "lluuid.h" +#include "llview.h" +#include "llxfermanager.h" +#include "message.h" +#include "object_flags.h" +#include "lltimer.h" +#include "timing.h" +#include "llviewermenu.h" +#include "lltooltip.h" +#include "llmediaentry.h" +#include "llurldispatcher.h" +#include "raytrace.h" + +// newview includes +#include "llagent.h" +#include "llbox.h" +#include "llchicletbar.h" +#include "llconsole.h" +#include "llviewercontrol.h" +#include "llcylinder.h" +#include "lldebugview.h" +#include "lldir.h" +#include "lldrawable.h" +#include "lldrawpoolalpha.h" +#include "lldrawpoolbump.h" +#include "lldrawpoolwater.h" +#include "llmaniptranslate.h" +#include "llface.h" +#include "llfeaturemanager.h" +#include "llfilepicker.h" +#include "llfirstuse.h" +#include "llfloater.h" +#include "llfloaterbuildoptions.h" +#include "llfloaterbuyland.h" +#include "llfloatercamera.h" +#include "llfloaterland.h" +#include "llfloaterinspect.h" +#include "llfloatermap.h" +#include "llfloaternamedesc.h" +#include "llfloaterpreference.h" +#include "llfloatersnapshot.h" +#include "llfloatertools.h" +#include "llfloaterworldmap.h" +#include "llfocusmgr.h" +#include "llfontfreetype.h" +#include "llgesturemgr.h" +#include "llglheaders.h" +#include "lltooltip.h" +#include "llhudmanager.h" +#include "llhudobject.h" +#include "llhudview.h" +#include "llimagebmp.h" +#include "llimagej2c.h" +#include "llimageworker.h" +#include "llkeyboard.h" +#include "lllineeditor.h" +#include "llmenugl.h" +#include "llmodaldialog.h" +#include "llmorphview.h" +#include "llmoveview.h" +#include "llnavigationbar.h" +#include "llpaneltopinfobar.h" +#include "llpopupview.h" +#include "llpreviewtexture.h" +#include "llprogressview.h" +#include "llresmgr.h" +#include "llselectmgr.h" +#include "llrootview.h" +#include "llrendersphere.h" +#include "llstartup.h" +#include "llstatusbar.h" +#include "llstatview.h" +#include "llsurface.h" +#include "llsurfacepatch.h" +#include "lltexlayer.h" +#include "lltextbox.h" +#include "lltexturecache.h" +#include "lltexturefetch.h" +#include "lltextureview.h" +#include "lltool.h" +#include "lltoolbarview.h" +#include "lltoolcomp.h" +#include "lltooldraganddrop.h" +#include "lltoolface.h" +#include "lltoolfocus.h" +#include "lltoolgrab.h" +#include "lltoolmgr.h" +#include "lltoolmorph.h" +#include "lltoolpie.h" +#include "lltoolselectland.h" +#include "lltrans.h" +#include "lluictrlfactory.h" +#include "llurldispatcher.h" // SLURL from other app instance +#include "llversioninfo.h" +#include "llvieweraudio.h" +#include "llviewercamera.h" +#include "llviewergesture.h" +#include "llviewertexturelist.h" +#include "llviewerinventory.h" +#include "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 "llvoavatarself.h" +#include "llvovolume.h" +#include "llworld.h" +#include "llworldmapview.h" +#include "pipeline.h" +#include "llappviewer.h" +#include "llviewerdisplay.h" +#include "llspatialpartition.h" +#include "llviewerjoystick.h" +#include "llviewernetwork.h" +#include "llpostprocess.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 "llwindowlistener.h" +#include "llviewerwindowlistener.h" +#include "llpaneltopinfobar.h" +#include "LLPathingLib.h" +#include "llfloaterpathfindingconsole.h" + +#if LL_WINDOWS +#include <tchar.h> // For Unicode conversion methods +#endif + +// +// Globals +// +void render_ui(F32 zoom_factor = 1.f, int subfield = 0); + +extern BOOL gDebugClicks; +extern BOOL gDisplaySwapBuffers; +extern BOOL gDepthDirty; +extern BOOL gResizeScreenTexture; + +LLViewerWindow *gViewerWindow = NULL; + +LLFrameTimer gAwayTimer; +LLFrameTimer gAwayTriggerTimer; + +BOOL gShowOverlayTitle = FALSE; + +LLViewerObject* gDebugRaycastObject = NULL; +LLVector3 gDebugRaycastIntersection; +LLVector2 gDebugRaycastTexCoord; +LLVector3 gDebugRaycastNormal; +LLVector3 gDebugRaycastBinormal; +S32 gDebugRaycastFaceHit; +LLVector3 gDebugRaycastStart; +LLVector3 gDebugRaycastEnd; + +// HUD display lines in lower right +BOOL gDisplayWindInfo = FALSE; +BOOL gDisplayCameraPos = FALSE; +BOOL gDisplayFOV = FALSE; +BOOL gDisplayBadge = FALSE; + +static const U8 NO_FACE = 255; +BOOL gQuietSnapshot = FALSE; + +static const F32 MIN_DISPLAY_SCALE = 0.75f; + +std::string LLViewerWindow::sSnapshotBaseName; +std::string LLViewerWindow::sSnapshotDir; + +std::string LLViewerWindow::sMovieBaseName; + +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 + + // 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); + //} + //} + } +}; + +//////////////////////////////////////////////////////////////////////////// +// +// LLDebugText +// + +class LLDebugText +{ +private: + struct Line + { + Line(const std::string& in_text, S32 in_x, S32 in_y) : text(in_text), x(in_x), y(in_y) {} + std::string text; + S32 x,y; + }; + + LLViewerWindow *mWindow; + + typedef std::vector<Line> line_list_t; + line_list_t mLineList; + LLColor4 mTextColor; + + void addText(S32 x, S32 y, const std::string &text) + { + mLineList.push_back(Line(text, x, y)); + } + + void clearText() { mLineList.clear(); } + +public: + LLDebugText(LLViewerWindow* window) : mWindow(window) {} + + void update() + { + static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ; + + std::string wind_vel_text; + std::string wind_vector_text; + std::string rwind_vel_text; + std::string rwind_vector_text; + std::string audio_text; + + static const std::string beacon_particle = LLTrans::getString("BeaconParticle"); + static const std::string beacon_physical = LLTrans::getString("BeaconPhysical"); + static const std::string beacon_scripted = LLTrans::getString("BeaconScripted"); + static const std::string beacon_scripted_touch = LLTrans::getString("BeaconScriptedTouch"); + static const std::string beacon_sound = LLTrans::getString("BeaconSound"); + static const std::string beacon_media = LLTrans::getString("BeaconMedia"); + static const std::string particle_hiding = LLTrans::getString("ParticleHiding"); + + // Draw the statistics in a light gray + // and in a thin font + mTextColor = LLColor4( 0.86f, 0.86f, 0.86f, 1.f ); + + // Draw stuff growing up from right lower corner of screen + U32 xpos = mWindow->getWorldViewWidthScaled() - 350; + U32 ypos = 64; + const U32 y_inc = 20; + + clearText(); + + if (gSavedSettings.getBOOL("DebugShowTime")) + { + const U32 y_inc2 = 15; + for (std::map<S32,LLFrameTimer>::reverse_iterator iter = gDebugTimers.rbegin(); + iter != gDebugTimers.rend(); ++iter) + { + S32 idx = iter->first; + LLFrameTimer& timer = iter->second; + F32 time = timer.getElapsedTimeF32(); + S32 hours = (S32)(time / (60*60)); + S32 mins = (S32)((time - hours*(60*60)) / 60); + S32 secs = (S32)((time - hours*(60*60) - mins*60)); + 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; + S32 hours = (S32)(time / (60*60)); + S32 mins = (S32)((time - hours*(60*60)) / 60); + S32 secs = (S32)((time - hours*(60*60) - mins*60)); + addText(xpos, ypos, llformat("Time: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc; + } + +#if LL_WINDOWS + if (gSavedSettings.getBOOL("DebugShowMemory")) + { + addText(xpos, ypos, llformat("Memory: %d (KB)", LLMemory::getWorkingSetSize() / 1024)); + ypos += y_inc; + } +#endif + + if (gDisplayCameraPos) + { + std::string camera_view_text; + std::string camera_center_text; + std::string agent_view_text; + std::string agent_left_text; + std::string agent_center_text; + std::string agent_root_center_text; + + LLVector3d tvector; // Temporary vector to hold data for printing. + + // Update camera center, camera view, wind info every other frame + tvector = gAgent.getPositionGlobal(); + agent_center_text = llformat("AgentCenter %f %f %f", + (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ])); + + if (isAgentAvatarValid()) + { + tvector = gAgent.getPosGlobalFromAgent(gAgentAvatarp->mRoot.getWorldPosition()); + agent_root_center_text = llformat("AgentRootCenter %f %f %f", + (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ])); + } + else + { + agent_root_center_text = "---"; + } + + + tvector = LLVector4(gAgent.getFrameAgent().getAtAxis()); + agent_view_text = llformat("AgentAtAxis %f %f %f", + (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ])); + + tvector = LLVector4(gAgent.getFrameAgent().getLeftAxis()); + agent_left_text = llformat("AgentLeftAxis %f %f %f", + (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ])); + + tvector = gAgentCamera.getCameraPositionGlobal(); + camera_center_text = llformat("CameraCenter %f %f %f", + (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ])); + + tvector = LLVector4(LLViewerCamera::getInstance()->getAtAxis()); + camera_view_text = llformat("CameraAtAxis %f %f %f", + (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ])); + + addText(xpos, ypos, agent_center_text); ypos += y_inc; + addText(xpos, ypos, agent_root_center_text); ypos += y_inc; + addText(xpos, ypos, agent_view_text); ypos += y_inc; + addText(xpos, ypos, agent_left_text); ypos += y_inc; + addText(xpos, ypos, camera_center_text); ypos += y_inc; + addText(xpos, ypos, camera_view_text); ypos += y_inc; + } + + if (gDisplayWindInfo) + { + wind_vel_text = llformat("Wind velocity %.2f m/s", gWindVec.magVec()); + wind_vector_text = llformat("Wind vector %.2f %.2f %.2f", gWindVec.mV[0], gWindVec.mV[1], gWindVec.mV[2]); + rwind_vel_text = llformat("RWind vel %.2f m/s", gRelativeWindVec.magVec()); + rwind_vector_text = llformat("RWind vec %.2f %.2f %.2f", gRelativeWindVec.mV[0], gRelativeWindVec.mV[1], gRelativeWindVec.mV[2]); + + addText(xpos, ypos, wind_vel_text); ypos += y_inc; + addText(xpos, ypos, wind_vector_text); ypos += y_inc; + addText(xpos, ypos, rwind_vel_text); ypos += y_inc; + addText(xpos, ypos, rwind_vector_text); ypos += y_inc; + } + if (gDisplayWindInfo) + { + if (gAudiop) + { + audio_text= llformat("Audio for wind: %d", gAudiop->isWindEnabled()); + } + addText(xpos, ypos, audio_text); ypos += y_inc; + } + if (gDisplayFOV) + { + addText(xpos, ypos, llformat("FOV: %2.1f deg", RAD_TO_DEG * LLViewerCamera::getInstance()->getView())); + ypos += y_inc; + } + if (gDisplayBadge) + { + addText(xpos, ypos+(y_inc/2), llformat("Hippos!", RAD_TO_DEG * LLViewerCamera::getInstance()->getView())); + ypos += y_inc * 2; + } + + /*if (LLViewerJoystick::getInstance()->getOverrideCamera()) + { + addText(xpos + 200, ypos, llformat("Flycam")); + ypos += y_inc; + }*/ + + if (gSavedSettings.getBOOL("DebugShowRenderInfo")) + { + if (gPipeline.getUseVertexShaders() == 0) + { + addText(xpos, ypos, "Shaders Disabled"); + ypos += y_inc; + } + + if (gGLManager.mHasATIMemInfo) + { + S32 meminfo[4]; + glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo); + + addText(xpos, ypos, llformat("%.2f MB Texture Memory Free", meminfo[0]/1024.f)); + ypos += y_inc; + + if (gGLManager.mHasVertexBufferObject) + { + glGetIntegerv(GL_VBO_FREE_MEMORY_ATI, meminfo); + addText(xpos, ypos, llformat("%.2f MB VBO Memory Free", meminfo[0]/1024.f)); + ypos += y_inc; + } + } + else if (gGLManager.mHasNVXMemInfo) + { + S32 free_memory; + glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory); + addText(xpos, ypos, llformat("%.2f MB Video Memory Free", free_memory/1024.f)); + ypos += y_inc; + } + + //show streaming cost/triangle count of known prims in current region OR selection + { + F32 cost = 0.f; + S32 count = 0; + S32 vcount = 0; + S32 object_count = 0; + S32 total_bytes = 0; + S32 visible_bytes = 0; + + const char* label = "Region"; + if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 0) + { //region + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + for (U32 i = 0; i < gObjectList.getNumObjects(); ++i) + { + LLViewerObject* object = gObjectList.getObject(i); + if (object && + object->getRegion() == region && + object->getVolume()) + { + object_count++; + S32 bytes = 0; + S32 visible = 0; + cost += object->getStreamingCost(&bytes, &visible); + S32 vt = 0; + count += object->getTriangleCount(&vt); + vcount += vt; + total_bytes += bytes; + visible_bytes += visible; + } + } + } + } + else + { + label = "Selection"; + cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectStreamingCost(&total_bytes, &visible_bytes); + count = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectTriangleCount(&vcount); + object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + } + + addText(xpos,ypos, llformat("%s streaming cost: %.1f", label, cost)); + ypos += y_inc; + + addText(xpos, ypos, llformat(" %.3f KTris, %.3f KVerts, %.1f/%.1f KB, %d objects", + count/1000.f, vcount/1000.f, visible_bytes/1024.f, total_bytes/1024.f, object_count)); + ypos += y_inc; + + } + + addText(xpos, ypos, llformat("%d MB Vertex Data (%d MB Pooled)", LLVertexBuffer::sAllocatedBytes/(1024*1024), LLVBOPool::sBytesPooled/(1024*1024))); + ypos += y_inc; + + addText(xpos, ypos, llformat("%d Vertex Buffers", LLVertexBuffer::sGLCount)); + ypos += y_inc; + + addText(xpos, ypos, llformat("%d Mapped Buffers", LLVertexBuffer::sMappedCount)); + ypos += y_inc; + + addText(xpos, ypos, llformat("%d Vertex Buffer Binds", LLVertexBuffer::sBindCount)); + ypos += y_inc; + + addText(xpos, ypos, llformat("%d Vertex Buffer Sets", LLVertexBuffer::sSetCount)); + ypos += y_inc; + + addText(xpos, ypos, llformat("%d Texture Binds", LLImageGL::sBindCount)); + ypos += y_inc; + + addText(xpos, ypos, llformat("%d Unique Textures", LLImageGL::sUniqueCount)); + ypos += y_inc; + + addText(xpos, ypos, llformat("%d Render Calls", gPipeline.mBatchCount)); + ypos += y_inc; + + addText(xpos, ypos, llformat("%d Matrix Ops", gPipeline.mMatrixOpCount)); + ypos += y_inc; + + addText(xpos, ypos, llformat("%d Texture Matrix Ops", gPipeline.mTextureMatrixOps)); + ypos += y_inc; + + gPipeline.mTextureMatrixOps = 0; + gPipeline.mMatrixOpCount = 0; + + if (gPipeline.mBatchCount > 0) + { + addText(xpos, ypos, llformat("Batch min/max/mean: %d/%d/%d", gPipeline.mMinBatchSize, gPipeline.mMaxBatchSize, + gPipeline.mTrianglesDrawn/gPipeline.mBatchCount)); + + gPipeline.mMinBatchSize = gPipeline.mMaxBatchSize; + gPipeline.mMaxBatchSize = 0; + gPipeline.mBatchCount = 0; + } + ypos += y_inc; + + addText(xpos, ypos, llformat("UI Verts/Calls: %d/%d", LLRender::sUIVerts, LLRender::sUICalls)); + LLRender::sUICalls = LLRender::sUIVerts = 0; + ypos += y_inc; + + addText(xpos,ypos, llformat("%d/%d Nodes visible", gPipeline.mNumVisibleNodes, LLSpatialGroup::sNodeCount)); + + ypos += y_inc; + + if (!LLSpatialGroup::sPendingQueries.empty()) + { + addText(xpos,ypos, llformat("%d Queries pending", LLSpatialGroup::sPendingQueries.size())); + ypos += y_inc; + } + + + addText(xpos,ypos, llformat("%d Avatars visible", LLVOAvatar::sNumVisibleAvatars)); + + ypos += y_inc; + + addText(xpos,ypos, llformat("%d Lights visible", LLPipeline::sVisibleLightCount)); + + ypos += y_inc; + + if (gMeshRepo.meshRezEnabled()) + { + addText(xpos, ypos, llformat("%.3f MB Mesh Data Received", LLMeshRepository::sBytesReceived/(1024.f*1024.f))); + + ypos += y_inc; + + addText(xpos, ypos, llformat("%d/%d Mesh HTTP Requests/Retries", LLMeshRepository::sHTTPRequestCount, + LLMeshRepository::sHTTPRetryCount)); + + ypos += y_inc; + + addText(xpos, ypos, llformat("%.3f/%.3f MB Mesh Cache Read/Write ", LLMeshRepository::sCacheBytesRead/(1024.f*1024.f), LLMeshRepository::sCacheBytesWritten/(1024.f*1024.f))); + + ypos += y_inc; + } + + LLVertexBuffer::sBindCount = LLImageGL::sBindCount = + LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount = + 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")) + { + U8 color[4]; + LLCoordGL coord = gViewerWindow->getCurrentMouse(); + glReadPixels(coord.mX, coord.mY, 1,1,GL_RGBA, GL_UNSIGNED_BYTE, color); + addText(xpos, ypos, llformat("%d %d %d %d", color[0], color[1], color[2], color[3])); + ypos += y_inc; + } + + if (gSavedSettings.getBOOL("DebugShowPrivateMem")) + { + LLPrivateMemoryPoolManager::getInstance()->updateStatistics() ; + addText(xpos, ypos, llformat("Total Reserved(KB): %d", LLPrivateMemoryPoolManager::getInstance()->mTotalReservedSize / 1024)); + ypos += y_inc; + + addText(xpos, ypos, llformat("Total Allocated(KB): %d", LLPrivateMemoryPoolManager::getInstance()->mTotalAllocatedSize / 1024)); + ypos += y_inc; + } + + // only display these messages if we are actually rendering beacons at this moment + if (LLPipeline::getRenderBeacons(NULL) && LLFloaterReg::instanceVisible("beacons")) + { + if (LLPipeline::getRenderMOAPBeacons(NULL)) + { + addText(xpos, ypos, "Viewing media beacons (white)"); + ypos += y_inc; + } + + if (LLPipeline::toggleRenderTypeControlNegated((void*)LLPipeline::RENDER_TYPE_PARTICLES)) + { + addText(xpos, ypos, particle_hiding); + ypos += y_inc; + } + + if (LLPipeline::getRenderParticleBeacons(NULL)) + { + addText(xpos, ypos, "Viewing particle beacons (blue)"); + ypos += y_inc; + } + + if (LLPipeline::getRenderSoundBeacons(NULL)) + { + addText(xpos, ypos, "Viewing sound beacons (yellow)"); + ypos += y_inc; + } + + if (LLPipeline::getRenderScriptedBeacons(NULL)) + { + addText(xpos, ypos, beacon_scripted); + ypos += y_inc; + } + else + if (LLPipeline::getRenderScriptedTouchBeacons(NULL)) + { + addText(xpos, ypos, beacon_scripted_touch); + ypos += y_inc; + } + + if (LLPipeline::getRenderPhysicalBeacons(NULL)) + { + addText(xpos, ypos, "Viewing physical object beacons (green)"); + ypos += y_inc; + } + } + + if(log_texture_traffic) + { + U32 old_y = ypos ; + for(S32 i = LLViewerTexture::BOOST_NONE; i < LLViewerTexture::MAX_GL_IMAGE_CATEGORY; i++) + { + if(gTotalTextureBytesPerBoostLevel[i] > 0) + { + addText(xpos, ypos, llformat("Boost_Level %d: %.3f MB", i, (F32)gTotalTextureBytesPerBoostLevel[i] / (1024 * 1024))); + ypos += y_inc; + } + } + if(ypos != old_y) + { + addText(xpos, ypos, "Network traffic for textures:"); + ypos += y_inc; + } + } + + if (gSavedSettings.getBOOL("DebugShowTextureInfo")) + { + LLViewerObject* objectp = NULL ; + //objectp = = gAgentCamera.getFocusObject(); + + LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode(); + if (nodep) + { + objectp = nodep->getObject(); + } + if (objectp && !objectp->isDead()) + { + S32 num_faces = objectp->mDrawable->getNumFaces() ; + + for(S32 i = 0 ; i < num_faces; i++) + { + LLFace* facep = objectp->mDrawable->getFace(i) ; + if(facep) + { + //addText(xpos, ypos, llformat("ts_min: %.3f ts_max: %.3f tt_min: %.3f tt_max: %.3f", facep->mTexExtents[0].mV[0], facep->mTexExtents[1].mV[0], + // facep->mTexExtents[0].mV[1], facep->mTexExtents[1].mV[1])); + //ypos += y_inc; + + addText(xpos, ypos, llformat("v_size: %.3f: p_size: %.3f", facep->getVirtualSize(), facep->getPixelArea())); + ypos += y_inc; + + //const LLTextureEntry *tep = facep->getTextureEntry(); + //if(tep) + //{ + // addText(xpos, ypos, llformat("scale_s: %.3f: scale_t: %.3f", tep->mScaleS, tep->mScaleT)) ; + // ypos += y_inc; + //} + + LLViewerTexture* tex = facep->getTexture() ; + if(tex) + { + addText(xpos, ypos, llformat("ID: %s v_size: %.3f", tex->getID().asString().c_str(), tex->getMaxVirtualSize())); + ypos += y_inc; + } + } + } + } + } + } + + void draw() + { + for (line_list_t::iterator iter = mLineList.begin(); + iter != mLineList.end(); ++iter) + { + const Line& line = *iter; + LLFontGL::getFontMonospace()->renderUTF8(line.text, 0, (F32)line.x, (F32)line.y, mTextColor, + LLFontGL::LEFT, LLFontGL::TOP, + LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); + } + mLineList.clear(); + } + +}; + +void LLViewerWindow::updateDebugText() +{ + mDebugText->update(); +} + +//////////////////////////////////////////////////////////////////////////// +// +// LLViewerWindow +// + +LLViewerWindow::Params::Params() +: title("title"), + name("name"), + x("x"), + y("y"), + width("width"), + height("height"), + min_width("min_width"), + min_height("min_height"), + fullscreen("fullscreen", false), + ignore_pixel_depth("ignore_pixel_depth", false) +{} + + +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]); + + + // only send mouse clicks to UI if UI is visible + if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { + + if (down) + { + buttonstatestr = "down" ; + } + else + { + buttonstatestr = "up" ; + } + + switch (clicktype) + { + case 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; + } + + LLView::sMouseHandlerMessage.clear(); + + if (gMenuBarView) + { + // stop ALT-key access to menu + gMenuBarView->resetMenuTrigger(); + } + + if (gDebugClicks) + { + llinfos << "ViewerWindow " << buttonname << " mouse " << buttonstatestr << " 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(); + + // Indicate mouse was active + LLUI::resetMouseIdleTimer(); + + // Don't let the user move the mouse out of the window until mouse up. + if( LLToolMgr::getInstance()->getCurrentTool()->clipMouseWhenDown() ) + { + mWindow->setMouseClipping(down); + } + + LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); + if( mouse_captor ) + { + S32 local_x; + S32 local_y; + mouse_captor->screenPointToLocal( x, y, &local_x, &local_y ); + if (LLView::sDebugMouseHandling) + { + llinfos << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << llendl; + } + return mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down); + } + + // 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); + // } + // } + //} + + // Mark the click as handled and return if we aren't within the root view to avoid spurious bugs + if( !mRootView->pointInView(x, y) ) + { + return TRUE; + } + // Give the UI views a chance to process the click + if( mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) ) + { + if (LLView::sDebugMouseHandling) + { + llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLView::sMouseHandlerMessage << llendl; + } + return TRUE; + } + else if (LLView::sDebugMouseHandling) + { + llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl; + } + } + + + //Determine if we have a pathing system and subsequently provide any mouse input + if ( LLPathingLib::getInstance() && mLeftMouseDown == down ) + { + LLVector3 dv = mouseDirectionGlobal(x,y); + LLVector3 mousePos = LLViewerCamera::getInstance()->getOrigin(); + LLVector3 rayStart = mousePos; + LLVector3 rayEnd = mousePos + dv * 150; + + //Determine if alt is being held in conjunction with a lmb click, if alt is being held + //then do not provide any input to the pathingLib console + MASK currentKeyMask = gKeyboard->currentMask(TRUE); + if ( !(currentKeyMask & MASK_ALT) ) + { + LLFloaterPathfindingConsole* pFloater = LLFloaterReg::getTypedInstance<LLFloaterPathfindingConsole>("pathfinding_console"); + if ( pFloater ) + { + //The floater takes care of determining what stage - essentially where the data goes into the pathing packet(start or end) + pFloater->providePathingData( rayStart, rayEnd ); + } + } + } + + // Do not allow tool manager to handle mouseclicks if we have disconnected + if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) ) + { + 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); +} + +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)) + { + return TRUE; + } + return handleMouseDown(window, pos, mask); +} + +BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) +{ + BOOL down = FALSE; + return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); +} + + +BOOL LLViewerWindow::handleRightMouseDown(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]); + + 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 (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. + LLToolPie::getInstance()->handleRightMouseDown(x, y, mask); + // show_context_menu( x, y, mask ); + } + + return TRUE; +} + +BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) +{ + BOOL down = FALSE; + return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down); +} + +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; +} + +LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, LLWindowCallbacks::DragNDropAction action, std::string data) +{ + LLWindowCallbacks::DragNDropResult result = LLWindowCallbacks::DND_NONE; + + const bool prim_media_dnd_enabled = gSavedSettings.getBOOL("PrimMediaDragNDrop"); + const bool slurl_dnd_enabled = gSavedSettings.getBOOL("SLURLDragNDrop"); + + if ( prim_media_dnd_enabled || slurl_dnd_enabled ) + { + switch(action) + { + // Much of the handling for these two cases is the same. + case LLWindowCallbacks::DNDA_TRACK: + case LLWindowCallbacks::DNDA_DROPPED: + case LLWindowCallbacks::DNDA_START_TRACKING: + { + bool drop = (LLWindowCallbacks::DNDA_DROPPED == action); + + if (slurl_dnd_enabled) + { + LLSLURL dropped_slurl(data); + if(dropped_slurl.isSpatial()) + { + if (drop) + { + LLURLDispatcher::dispatch( dropped_slurl.getSLURLString(), "clicked", NULL, true ); + return LLWindowCallbacks::DND_MOVE; + } + return LLWindowCallbacks::DND_COPY; + } + } + + if (prim_media_dnd_enabled) + { + LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ ); + + LLUUID object_id = pick_info.getObjectID(); + S32 object_face = pick_info.mObjectFace; + std::string url = data; + + lldebugs << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl; + + LLVOVolume *obj = dynamic_cast<LLVOVolume*>(static_cast<LLViewerObject*>(pick_info.getObject())); + + if (obj && !obj->getRegion()->getCapability("ObjectMedia").empty()) + { + LLTextureEntry *te = obj->getTE(object_face); + + // can modify URL if we can modify the object or we have navigate permissions + bool allow_modify_url = obj->permModify() || obj->hasMediaPermission( te->getMediaData(), LLVOVolume::MEDIA_PERM_INTERACT ); + + if (te && allow_modify_url ) + { + if (drop) + { + // object does NOT have media already + if ( ! te->hasMedia() ) + { + // we are allowed to modify the object + if ( obj->permModify() ) + { + // Create new media entry + LLSD media_data; + // XXX Should we really do Home URL too? + media_data[LLMediaEntry::HOME_URL_KEY] = url; + media_data[LLMediaEntry::CURRENT_URL_KEY] = url; + media_data[LLMediaEntry::AUTO_PLAY_KEY] = true; + obj->syncMediaData(object_face, media_data, true, true); + // XXX This shouldn't be necessary, should it ?!? + if (obj->getMediaImpl(object_face)) + obj->getMediaImpl(object_face)->navigateReload(); + obj->sendMediaDataUpdate(); + + result = LLWindowCallbacks::DND_COPY; + } + } + else + // object HAS media already + { + // URL passes the whitelist + if (te->getMediaData()->checkCandidateUrl( url ) ) + { + // just navigate to the URL + if (obj->getMediaImpl(object_face)) + { + obj->getMediaImpl(object_face)->navigateTo(url); + } + else + { + // This is very strange. Navigation should + // happen via the Impl, but we don't have one. + // This sends it to the server, which /should/ + // trigger us getting it. Hopefully. + LLSD media_data; + media_data[LLMediaEntry::CURRENT_URL_KEY] = url; + obj->syncMediaData(object_face, media_data, true, true); + obj->sendMediaDataUpdate(); + } + result = LLWindowCallbacks::DND_LINK; + + } + } + LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); + mDragHoveredObject = NULL; + + } + else + { + // Check the whitelist, if there's media (otherwise just show it) + if (te->getMediaData() == NULL || te->getMediaData()->checkCandidateUrl(url)) + { + if ( obj != mDragHoveredObject) + { + // Highlight the dragged object + LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); + mDragHoveredObject = obj; + LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject); + } + result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK; + + } + } + } + } + } + } + break; + + case LLWindowCallbacks::DNDA_STOP_TRACKING: + // The cleanup case below will make sure things are unhilighted if necessary. + break; + } + + if (prim_media_dnd_enabled && + result == LLWindowCallbacks::DND_NONE && !mDragHoveredObject.isNull()) + { + LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); + mDragHoveredObject = NULL; + } + } + + return result; +} + +BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) +{ + BOOL down = FALSE; + 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; + S32 y = pos.mY; + + x = llround((F32)x / mDisplayScale.mV[VX]); + y = llround((F32)y / mDisplayScale.mV[VY]); + + mMouseInWindow = TRUE; + + // Save mouse point for access during idle() and display() + + LLCoordGL mouse_point(x, y); + + if (mouse_point != mCurrentMousePoint) + { + LLUI::resetMouseIdleTimer(); + } + + saveLastMouse(mouse_point); + + mWindow->showCursorFromMouseMove(); + + if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME + && !gDisconnected) + { + gAgent.clearAFK(); + } +} + +void LLViewerWindow::handleMouseLeave(LLWindow *window) +{ + // Note: we won't get this if we have captured the mouse. + llassert( gFocusMgr.getMouseCapture() == NULL ); + mMouseInWindow = FALSE; + LLToolTipMgr::instance().blockToolTips(); +} + +BOOL LLViewerWindow::handleCloseRequest(LLWindow *window) +{ + // User has indicated they want to close, but we may need to ask + // about modified documents. + LLAppViewer::instance()->userQuit(); + // Don't quit immediately + return FALSE; +} + +void LLViewerWindow::handleQuit(LLWindow *window) +{ + LLAppViewer::instance()->forceQuit(); +} + +void LLViewerWindow::handleResize(LLWindow *window, S32 width, S32 height) +{ + reshape(width, height); + mResDirty = true; +} + +// The top-level window has gained focus (e.g. via ALT-TAB) +void LLViewerWindow::handleFocus(LLWindow *window) +{ + gFocusMgr.setAppHasFocus(TRUE); + LLModalDialog::onAppFocusGained(); + + gAgent.onAppFocusGained(); + LLToolMgr::getInstance()->onAppFocusGained(); + + // See if we're coming in with modifier keys held down + if (gKeyboard) + { + gKeyboard->resetMaskKeys(); + } + + // resume foreground running timer + // since we artifically limit framerate when not frontmost + gForegroundTime.unpause(); +} + +// The top-level window has lost focus (e.g. via ALT-TAB) +void LLViewerWindow::handleFocusLost(LLWindow *window) +{ + gFocusMgr.setAppHasFocus(FALSE); + //LLModalDialog::onAppFocusLost(); + LLToolMgr::getInstance()->onAppFocusLost(); + gFocusMgr.setMouseCapture( NULL ); + + if (gMenuBarView) + { + // stop ALT-key access to menu + gMenuBarView->resetMenuTrigger(); + } + + // restore mouse cursor + showCursor(); + getWindow()->setMouseClipping(FALSE); + + // If losing focus while keys are down, reset them. + if (gKeyboard) + { + gKeyboard->resetKeys(); + } + + // pause timer that tracks total foreground running time + gForegroundTime.pause(); +} + + +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. + LLVoiceClient::getInstance()->keyDown(key, mask); + + if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME) + { + gAgent.clearAFK(); + } + + // *NOTE: We want to interpret KEY_RETURN later when it arrives as + // a Unicode char, not as a keydown. Otherwise when client frame + // rate is really low, hitting return sends your chat text before + // it's all entered/processed. + if (key == KEY_RETURN && mask == MASK_NONE) + { + return FALSE; + } + + return gViewerKeyboard.handleKey(key, mask, 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. + LLVoiceClient::getInstance()->keyUp(key, mask); + + return FALSE; +} + + +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); +} + + + + +BOOL LLViewerWindow::handleActivate(LLWindow *window, BOOL activated) +{ + if (activated) + { + mActive = true; + send_agent_resume(); + gAgent.clearAFK(); + + // Unmute audio + audio_update_volume(); + } + else + { + mActive = false; + + // if the user has chosen to go Away automatically after some time, then go Away when minimizing + if (gSavedSettings.getS32("AFKTimeout")) + { + gAgent.setAFK(); + } + + // SL-53351: Make sure we're not in mouselook when minimised, to prevent control issues + if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK) + { + gAgentCamera.changeCameraToDefault(); + } + + send_agent_pause(); + + // Mute audio + audio_update_volume(); + } + return TRUE; +} + +BOOL LLViewerWindow::handleActivateApp(LLWindow *window, BOOL activating) +{ + //if (!activating) gAgentCamera.changeCameraToDefault(); + + LLViewerJoystick::getInstance()->setNeedsReset(true); + return FALSE; +} + + +void LLViewerWindow::handleMenuSelect(LLWindow *window, S32 menu_item) +{ +} + + +BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height) +{ + // *TODO: Enable similar information output for other platforms? DK 2011-02-18 +#if LL_WINDOWS + if (gHeadlessClient) + { + HWND window_handle = (HWND)window->getPlatformWindow(); + PAINTSTRUCT ps; + HDC hdc; + + RECT wnd_rect; + wnd_rect.left = 0; + wnd_rect.top = 0; + wnd_rect.bottom = 200; + wnd_rect.right = 500; + + hdc = BeginPaint(window_handle, &ps); + //SetBKColor(hdc, RGB(255, 255, 255)); + FillRect(hdc, &wnd_rect, CreateSolidBrush(RGB(255, 255, 255))); + + std::string temp_str; + 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(); + temp_str = llformat( "Avatar pos %6.1lf %6.1lf %6.1lf", pos_global.mdV[0], pos_global.mdV[1], pos_global.mdV[2]); + len = temp_str.length(); + TextOutA(hdc, 0, 25, temp_str.c_str(), len); + + TextOutA(hdc, 0, 50, "Set \"HeadlessClient FALSE\" in settings.ini file to reenable", 61); + EndPaint(window_handle, &ps); + return TRUE; + } +#endif + return FALSE; +} + + +void LLViewerWindow::handleScrollWheel(LLWindow *window, S32 clicks) +{ + handleScrollWheel( clicks ); +} + +void LLViewerWindow::handleWindowBlock(LLWindow *window) +{ + send_agent_pause(); +} + +void LLViewerWindow::handleWindowUnblock(LLWindow *window) +{ + send_agent_resume(); +} + +void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data) +{ + const S32 SLURL_MESSAGE_TYPE = 0; + switch (data_type) + { + case SLURL_MESSAGE_TYPE: + // received URL + std::string url = (const char*)data; + LLMediaCtrl* web = NULL; + const bool trusted_browser = false; + // don't treat slapps coming from external browsers as "clicks" as this would bypass throttling + if (LLURLDispatcher::dispatch(url, "", web, trusted_browser)) + { + // bring window to foreground, as it has just been "launched" from a URL + mWindow->bringToFront(); + } + break; + } +} + +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(const Params& p) +: mWindow(NULL), + mActive(true), + mUIVisible(true), + mWindowRectRaw(0, p.height, p.width, 0), + mWindowRectScaled(0, p.height, p.width, 0), + mWorldViewRectRaw(0, p.height, p.width, 0), + mLeftMouseDown(FALSE), + mMiddleMouseDown(FALSE), + mRightMouseDown(FALSE), + mMouseInWindow( FALSE ), + mLastMask( MASK_NONE ), + mToolStored( NULL ), + mHideCursorPermanent( FALSE ), + mCursorHidden(FALSE), + mIgnoreActivate( FALSE ), + mResDirty(false), + mStatesDirty(false), + mCurrResolutionIndex(0), + // gKeyboard is still NULL, so it doesn't do LLWindowListener any good to + // pass its value right now. Instead, pass it a nullary function that + // will, when we later need it, return the value of gKeyboard. + // boost::lambda::var() constructs such a functor on the fly. + mWindowListener(new LLWindowListener(this, boost::lambda::var(gKeyboard))), + mViewerWindowListener(new LLViewerWindowListener(this)), + mProgressView(NULL) +{ + 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(this, + p.title, p.name, p.x, p.y, p.width, p.height, 0, + p.fullscreen, + gHeadlessClient, + gSavedSettings.getBOOL("DisableVerticalSync"), + !gHeadlessClient, + p.ignore_pixel_depth, + gSavedSettings.getBOOL("RenderDeferred") ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled + + if (!LLViewerShaderMgr::sInitialized) + { //immediately initialize shaders + LLViewerShaderMgr::sInitialized = TRUE; + LLViewerShaderMgr::instance()->setShaders(); + } + + if (NULL == mWindow) + { + LLSplashScreen::update(LLTrans::getString("StartupRequireDriverUpdate")); + + LL_WARNS("Window") << "Failed to create window, to be shutting Down, be sure your graphics driver is updated." << llendl ; + + ms_sleep(5000) ; //wait for 5 seconds. + + 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 + LL_WARNS("Window") << "Unable to create window, be sure screen is set at 32-bit color in Control Panels->Display->Settings" + << LL_ENDL; +#endif + LLAppViewer::instance()->fastQuit(1); + } + + if (!LLAppViewer::instance()->restoreErrorTrap()) + { + LL_WARNS("Window") << " Someone took over my signal/exception handler (post createWindow)!" << LL_ENDL; + } + + const bool do_not_enforce = false; + mWindow->setMinSize(p.min_width, p.min_height, do_not_enforce); // root view not set + LLCoordScreen scr; + mWindow->getSize(&scr); + + if(p.fullscreen && ( scr.mX!=p.width || scr.mY!=p.height)) + { + llwarns << "Fullscreen has forced us in to a different resolution now using "<<scr.mX<<" x "<<scr.mY<<llendl; + gSavedSettings.setS32("FullScreenWidth",scr.mX); + gSavedSettings.setS32("FullScreenHeight",scr.mY); + } + + // Get the real window rect the window was created with (since there are various OS-dependent reasons why + // the size of a window or fullscreen context may have been adjusted slightly...) + F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor"); + + mDisplayScale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f)); + mDisplayScale *= ui_scale_factor; + LLUI::setScaleFactor(mDisplayScale); + + { + LLCoordWindow size; + mWindow->getSize(&size); + mWindowRectRaw.set(0, size.mY, size.mX, 0); + mWindowRectScaled.set(0, llround((F32)size.mY / mDisplayScale.mV[VY]), llround((F32)size.mX / mDisplayScale.mV[VX]), 0); + } + + LLFontManager::initClass(); + + // + // We want to set this stuff up BEFORE we initialize the pipeline, so we can turn off + // stuff like AGP if we think that it'll crash the viewer. + // + LL_DEBUGS("Window") << "Loading feature tables." << LL_ENDL; + + LLFeatureManager::getInstance()->init(); + + // Initialize OpenGL Renderer + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderVBOEnable") || + !gGLManager.mHasVertexBufferObject) + { + gSavedSettings.setBOOL("RenderVBOEnable", FALSE); + } + LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"), gSavedSettings.getBOOL("RenderVBOMappingDisable")); + LL_INFOS("RenderInit") << "LLVertexBuffer initialization done." << LL_ENDL ; + gGL.init() ; + + if (LLFeatureManager::getInstance()->isSafe() + || (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion()) + || (gSavedSettings.getString("LastGPUString") != LLFeatureManager::getInstance()->getGPUString()) + || (gSavedSettings.getBOOL("ProbeHardwareOnStartup"))) + { + LLFeatureManager::getInstance()->applyRecommendedSettings(); + gSavedSettings.setBOOL("ProbeHardwareOnStartup", FALSE); + } + + if (!gGLManager.mHasDepthClamp) + { + LL_INFOS("RenderInit") << "Missing feature GL_ARB_depth_clamp. Void water might disappear in rare cases." << LL_ENDL; + } + + // If we crashed while initializng GL stuff last time, disable certain features + if (gSavedSettings.getBOOL("RenderInitError")) + { + mInitAlert = "DisplaySettingsNoShaders"; + LLFeatureManager::getInstance()->setGraphicsLevel(0, false); + gSavedSettings.setU32("RenderQualityPerformance", 0); + } + + // Init the image list. Must happen after GL is initialized and before the images that + // LLViewerWindow needs are requested. + 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 + 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 = getWindowWidthScaled() / 2; + mCurrentMousePoint.mY = getWindowHeightScaled() / 2; + + gShowOverlayTitle = gSavedSettings.getBOOL("ShowOverlayTitle"); + mOverlayTitle = gSavedSettings.getString("OverlayTitle"); + // Can't have spaces in settings.ini strings, so use underscores instead and convert them. + LLStringUtil::replaceChar(mOverlayTitle, '_', ' '); + + // 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.setSceneBlendType(LLRender::BT_ALPHA); + + if (!LLGLSLShader::sNoFixedFunction) + { //initialize fixed function state + glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ); + + glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,LLColor4::black.mV); + glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,LLColor4::white.mV); + + // lights for objects + glShadeModel( GL_SMOOTH ); + + gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); + } + + glPixelStorei(GL_PACK_ALIGNMENT,1); + glPixelStorei(GL_UNPACK_ALIGNMENT,1); + + gGL.setAmbientLightColor(LLColor4::black); + + glCullFace(GL_BACK); + + // RN: Need this for translation and stretch manip. + gBox.prerender(); +} + +struct MainPanel : public LLPanel +{ +}; + +void LLViewerWindow::initBase() +{ + S32 height = getWindowHeightScaled(); + S32 width = getWindowWidthScaled(); + + LLRect full_window(0, height, width, 0); + + //////////////////// + // + // Set the gamma + // + + F32 gamma = gSavedSettings.getF32("RenderGamma"); + if (gamma != 0.0f) + { + getWindow()->setGamma(gamma); + } + + // Create global views + + // 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(); + mPopupView = main_view->getChild<LLPopupView>("popup_holder"); + mHintHolder = main_view->getChild<LLView>("hint_holder")->getHandle(); + mLoginPanelHolder = main_view->getChild<LLView>("login_panel_holder")->getHandle(); + + // Create the toolbar view + // Get a pointer to the toolbar view holder + LLPanel* panel_holder = main_view->getChild<LLPanel>("toolbar_view_holder"); + // Load the toolbar view from file + gToolBarView = LLUICtrlFactory::getInstance()->createFromFile<LLToolBarView>("panel_toolbar_view.xml", panel_holder, LLDefaultChildRegistry::instance()); + gToolBarView->setShape(panel_holder->getLocalRect()); + // Hide the toolbars for the moment: we'll make them visible after logging in world (see LLViewerWindow::initWorldUI()) + gToolBarView->setVisible(FALSE); + + // Constrain floaters to inside the menu and status bar regions. + gFloaterView = main_view->getChild<LLFloaterView>("Floater View"); + gFloaterView->setFloaterSnapView(main_view->getChild<LLView>("floater_snap_region")->getHandle()); + gSnapshotFloaterView = main_view->getChild<LLSnapshotFloaterView>("Snapshot Floater View"); + + + // Console + llassert( !gConsole ); + LLConsole::Params cp; + cp.name("console"); + cp.max_lines(gSavedSettings.getS32("ConsoleBufferSize")); + cp.rect(getChatConsoleRect()); + cp.persist_time(gSavedSettings.getF32("ChatPersistTime")); + cp.font_size_index(gSavedSettings.getS32("ChatFontSize")); + cp.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM); + gConsole = LLUICtrlFactory::create<LLConsole>(cp); + getRootView()->addChild(gConsole); + + // optionally forward warnings to chat console/chat floater + // for qa runs and dev builds +#if !LL_RELEASE_FOR_DOWNLOAD + LLError::addRecorder(RecordToChatConsole::getInstance()); +#else + if(gSavedSettings.getBOOL("QAMode")) + { + LLError::addRecorder(RecordToChatConsole::getInstance()); + } +#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 = getRootView()->findChild<LLProgressView>("progress_view"); + setShowProgress(FALSE); + setProgressCancelButtonVisible(FALSE); + + gMenuHolder = getRootView()->getChild<LLViewerMenuHolderGL>("Menu Holder"); + + LLMenuGL::sMenuContainer = gMenuHolder; + +} + +void LLViewerWindow::initWorldUI() +{ + S32 height = mRootView->getRect().getHeight(); + S32 width = mRootView->getRect().getWidth(); + LLRect full_window(0, height, width, 0); + + + gIMMgr = LLIMMgr::getInstance(); + + //getRootView()->sendChildToFront(gFloaterView); + //getRootView()->sendChildToFront(gSnapshotFloaterView); + + LLPanel* chiclet_container = getRootView()->getChild<LLPanel>("chiclet_container"); + LLChicletBar* chiclet_bar = LLChicletBar::getInstance(); + chiclet_bar->setShape(chiclet_container->getLocalRect()); + chiclet_bar->setFollowsAll(); + chiclet_container->addChild(chiclet_bar); + chiclet_container->setVisible(TRUE); + + LLRect morph_view_rect = full_window; + morph_view_rect.stretch( -STATUS_BAR_HEIGHT ); + morph_view_rect.mTop = full_window.mTop - 32; + LLMorphView::Params mvp; + mvp.name("MorphView"); + mvp.rect(morph_view_rect); + mvp.visible(false); + gMorphView = LLUICtrlFactory::create<LLMorphView>(mvp); + getRootView()->addChild(gMorphView); + + LLWorldMapView::initClass(); + + // Force gFloaterWorldMap to initialize + LLFloaterReg::getInstance("world_map"); + + // Force gFloaterTools to initialize + LLFloaterReg::getInstance("build"); + 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->addChildInBack(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->setVisible(FALSE); + } + + // Top Info bar + LLPanel* topinfo_bar_container = getRootView()->getChild<LLPanel>("topinfo_bar_container"); + LLPanelTopInfoBar* topinfo_bar = LLPanelTopInfoBar::getInstance(); + + topinfo_bar->setShape(topinfo_bar_container->getLocalRect()); + + topinfo_bar_container->addChild(topinfo_bar); + topinfo_bar_container->setVisible(TRUE); + + if (!gSavedSettings.getBOOL("ShowMiniLocationPanel")) + { + topinfo_bar->setVisible(FALSE); + } + + if ( gHUDView == NULL ) + { + LLRect hud_rect = full_window; + hud_rect.mBottom += 50; + if (gMenuBarView && gMenuBarView->isInVisibleChain()) + { + hud_rect.mTop -= gMenuBarView->getRect().getHeight(); + } + gHUDView = new LLHUDView(hud_rect); + getRootView()->addChild(gHUDView); + } + + 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); + + // Load and make the toolbars visible + // Note: we need to load the toolbars only *after* the user is logged in and IW + if (gToolBarView) + { + gToolBarView->loadToolbars(); + gToolBarView->setVisible(TRUE); + } + + LLMediaCtrl* destinations = LLFloaterReg::getInstance("destinations")->getChild<LLMediaCtrl>("destination_guide_contents"); + if (destinations) + { + destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL")); + std::string url = gSavedSettings.getString("DestinationGuideURL"); + url = LLWeb::expandURLSubstitutions(url, LLSD()); + destinations->navigateTo(url, "text/html"); + } + LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents"); + if (avatar_picker) + { + avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL")); + std::string url = gSavedSettings.getString("AvatarPickerURL"); + url = LLWeb::expandURLSubstitutions(url, LLSD()); + avatar_picker->navigateTo(url, "text/html"); + } +} + +// Destroy the UI +void LLViewerWindow::shutdownViews() +{ + // clean up warning logger + LLError::removeRecorder(RecordToChatConsole::getInstance()); + + delete mDebugText; + mDebugText = NULL; + + // 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 + if (LLNavigationBar::instanceExists()) + { + 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. + gStatusBar = NULL; + gIMMgr = NULL; + gToolTipView = NULL; + + gToolBarView = NULL; + gFloaterView = NULL; + gMorphView = NULL; + + gHUDView = NULL; +} + +void LLViewerWindow::shutdownGL() +{ + //-------------------------------------------------------- + // Shutdown GL cleanly. Order is very important here. + //-------------------------------------------------------- + LLFontGL::destroyDefaultFonts(); + LLFontManager::cleanupClass(); + stop_glerror(); + + gSky.cleanup(); + stop_glerror(); + + LLWearableList::instance().cleanup() ; + + gTextureList.shutdown(); + stop_glerror(); + + gBumpImageList.shutdown(); + stop_glerror(); + + LLWorldMapView::cleanupTextures(); + + llinfos << "Cleaning up pipeline" << llendl; + gPipeline.cleanup(); + stop_glerror(); + + LLViewerTextureManager::cleanup() ; + LLImageGL::cleanupClass() ; + + llinfos << "All textures and llimagegl images are destroyed!" << llendl ; + + llinfos << "Cleaning up select manager" << llendl; + LLSelectMgr::getInstance()->cleanup(); + + llinfos << "Stopping GL during shutdown" << llendl; + stopGL(FALSE); + stop_glerror(); + + gGL.shutdown(); + + LLVertexBuffer::cleanupClass(); + + llinfos << "LLVertexBuffer cleaned." << llendl ; +} + +// shutdownViews() and shutdownGL() need to be called first +LLViewerWindow::~LLViewerWindow() +{ + llinfos << "Destroying Window" << llendl; + destroyWindow(); + + delete mDebugText; + mDebugText = NULL; +} + + +void LLViewerWindow::setCursor( ECursorType c ) +{ + mWindow->setCursor( c ); +} + +void LLViewerWindow::showCursor() +{ + mWindow->showCursor(); + + mCursorHidden = FALSE; +} + +void LLViewerWindow::hideCursor() +{ + // And hide the cursor + mWindow->hideCursor(); + + mCursorHidden = TRUE; +} + +void LLViewerWindow::sendShapeToSim() +{ + LLMessageSystem* msg = gMessageSystem; + if(!msg) return; + msg->newMessageFast(_PREHASH_AgentHeightWidth); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addU32Fast(_PREHASH_CircuitCode, gMessageSystem->mOurCircuitCode); + msg->nextBlockFast(_PREHASH_HeightWidthBlock); + msg->addU32Fast(_PREHASH_GenCounter, 0); + U16 height16 = (U16) mWorldViewRectRaw.getHeight(); + U16 width16 = (U16) mWorldViewRectRaw.getWidth(); + msg->addU16Fast(_PREHASH_Height, height16); + msg->addU16Fast(_PREHASH_Width, width16); + gAgent.sendReliableMessage(); +} + +// Must be called after window is created to set up agent +// camera variables and UI variables. +void LLViewerWindow::reshape(S32 width, S32 height) +{ + // Destroying the window at quit time generates spurious + // reshape messages. We don't care about these, and we + // don't want to send messages because the message system + // may have been destructed. + if (!LLApp::isExiting()) + { + gWindowResized = TRUE; + + // update our window rectangle + mWindowRectRaw.mRight = mWindowRectRaw.mLeft + width; + mWindowRectRaw.mTop = mWindowRectRaw.mBottom + height; + + //glViewport(0, 0, width, height ); + + if (height > 0) + { + LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() ); + LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() ); + } + + calcDisplayScale(); + + BOOL display_scale_changed = mDisplayScale != LLUI::sGLScaleFactor; + LLUI::setScaleFactor(mDisplayScale); + + // update our window rectangle + mWindowRectScaled.mRight = mWindowRectScaled.mLeft + llround((F32)width / mDisplayScale.mV[VX]); + mWindowRectScaled.mTop = mWindowRectScaled.mBottom + llround((F32)height / mDisplayScale.mV[VY]); + + setup2DViewport(); + + // Inform lower views of the change + // round up when converting coordinates to make sure there are no gaps at edge of window + LLView::sForceReshape = display_scale_changed; + mRootView->reshape(llceil((F32)width / mDisplayScale.mV[VX]), llceil((F32)height / mDisplayScale.mV[VY])); + LLView::sForceReshape = FALSE; + + // clear font width caches + if (display_scale_changed) + { + LLHUDObject::reshapeAll(); + } + + sendShapeToSim(); + + // store new settings for the mode we are in, regardless + BOOL maximized = mWindow->getMaximized(); + gSavedSettings.setBOOL("WindowMaximized", maximized); + + if (!maximized) + { + U32 min_window_width=gSavedSettings.getU32("MinWindowWidth"); + U32 min_window_height=gSavedSettings.getU32("MinWindowHeight"); + // tell the OS specific window code about min window size + mWindow->setMinSize(min_window_width, min_window_height); + + // Only save size if not maximized + gSavedSettings.setU32("WindowWidth", mWindowRectRaw.getWidth()); + gSavedSettings.setU32("WindowHeight", mWindowRectRaw.getHeight()); + } + + LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width); + LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height); + } +} + + +// Hide normal UI when a logon fails +void LLViewerWindow::setNormalControlsVisible( BOOL visible ) +{ + if(LLChicletBar::instanceExists()) + { + LLChicletBar::getInstance()->setVisible(visible); + LLChicletBar::getInstance()->setEnabled(visible); + } + + if ( gMenuBarView ) + { + gMenuBarView->setVisible( visible ); + gMenuBarView->setEnabled( visible ); + + // ...and set the menu color appropriately. + setMenuBackgroundColor(gAgent.getGodLevel() > GOD_NOT, + LLGridManager::getInstance()->isInProductionGrid()); + } + + if ( gStatusBar ) + { + gStatusBar->setVisible( visible ); + gStatusBar->setEnabled( visible ); + } + + LLNavigationBar* navbarp = LLUI::getRootView()->findChild<LLNavigationBar>("navigation_bar"); + if (navbarp) + { + // when it's time to show navigation bar we need to ensure that the user wants to see it + // i.e. ShowNavbarNavigationPanel option is true + navbarp->setVisible( visible && gSavedSettings.getBOOL("ShowNavbarNavigationPanel") ); + } +} + +void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid) +{ + LLSD args; + LLColor4 new_bg_color; + + // 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 = LLUIColorTable::instance().getColor( "MenuBarGodBgColor" ); + } + else if(god_mode && !LLGridManager::getInstance()->isInProductionGrid()) + { + new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionGodBgColor" ); + } + else if (!god_mode && isProject) + { + new_bg_color = LLUIColorTable::instance().getColor( "MenuBarProjectBgColor" ); + } + else if(!god_mode && !LLGridManager::getInstance()->isInProductionGrid()) + { + new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" ); + } + else + { + new_bg_color = LLUIColorTable::instance().getColor( "MenuBarBgColor" ); + } + + if(gMenuBarView) + { + gMenuBarView->setBackgroundColor( new_bg_color ); + } + + if(gStatusBar) + { + gStatusBar->setBackgroundColor( new_bg_color ); + } +} + +void LLViewerWindow::drawDebugText() +{ + gGL.color4f(1,1,1,1); + gGL.pushMatrix(); + gGL.pushUIMatrix(); + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.bind(); + } + { + // scale view by UI global scale factor and aspect ratio correction factor + gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f); + mDebugText->draw(); + } + gGL.popUIMatrix(); + gGL.popMatrix(); + + gGL.flush(); + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.unbind(); + } +} + +void LLViewerWindow::draw() +{ + +//#if LL_DEBUG + LLView::sIsDrawing = TRUE; +//#endif + stop_glerror(); + + LLUI::setLineWidth(1.f); + + LLUI::setLineWidth(1.f); + // Reset any left-over transforms + gGL.matrixMode(LLRender::MM_MODELVIEW); + + gGL.loadIdentity(); + + //S32 screen_x, screen_y; + + if (!gSavedSettings.getBOOL("RenderUIBuffer")) + { + LLUI::sDirtyRect = getWindowRectScaled(); + } + + // HACK for timecode debugging + if (gSavedSettings.getBOOL("DisplayTimecode")) + { + // draw timecode block + std::string text; + + gGL.loadIdentity(); + + microsecondsToTimecodeString(gFrameTime,text); + const LLFontGL* font = LLFontGL::getFontSansSerif(); + font->renderUTF8(text, 0, + llround((getWindowWidthScaled()/2)-100.f), + llround((getWindowHeightScaled()-60.f)), + LLColor4( 1.f, 1.f, 1.f, 1.f ), + LLFontGL::LEFT, LLFontGL::TOP); + } + + // Draw all nested UI views. + // No translation needed, this view is glued to 0,0 + + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.bind(); + } + + gGL.pushMatrix(); + LLUI::pushMatrix(); + { + + // scale view by UI global scale factor and aspect ratio correction factor + gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f); + + LLVector2 old_scale_factor = LLUI::sGLScaleFactor; + // apply camera zoom transform (for high res screenshots) + F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor(); + S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion(); + if (zoom_factor > 1.f) + { + //decompose subregion number to x and y values + int pos_y = sub_region / llceil(zoom_factor); + int pos_x = sub_region - (pos_y*llceil(zoom_factor)); + // offset for this tile + gGL.translatef((F32)getWindowWidthScaled() * -(F32)pos_x, + (F32)getWindowHeightScaled() * -(F32)pos_y, + 0.f); + gGL.scalef(zoom_factor, zoom_factor, 1.f); + LLUI::sGLScaleFactor *= zoom_factor; + } + + // Draw tool specific overlay on world + LLToolMgr::getInstance()->getCurrentTool()->draw(); + + if( gAgentCamera.cameraMouselook() || LLFloaterCamera::inFreeCameraMode() ) + { + drawMouselookInstructions(); + stop_glerror(); + } + + // Draw all nested UI views. + // No translation needed, this view is glued to 0,0 + mRootView->draw(); + + if (LLView::sDebugRects) + { + gToolTipView->drawStickyRect(); + } + + // Draw optional on-top-of-everyone view + LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); + if (top_ctrl && top_ctrl->getVisible()) + { + S32 screen_x, screen_y; + top_ctrl->localPointToScreen(0, 0, &screen_x, &screen_y); + + gGL.matrixMode(LLRender::MM_MODELVIEW); + LLUI::pushMatrix(); + LLUI::translate( (F32) screen_x, (F32) screen_y, 0.f); + top_ctrl->draw(); + LLUI::popMatrix(); + } + + + if( gShowOverlayTitle && !mOverlayTitle.empty() ) + { + // Used for special titles such as "Second Life - Special E3 2003 Beta" + const S32 DIST_FROM_TOP = 20; + LLFontGL::getFontSansSerifBig()->renderUTF8( + mOverlayTitle, 0, + 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 (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.unbind(); + } + +//#if LL_DEBUG + LLView::sIsDrawing = FALSE; +//#endif +} + +// Takes a single keydown event, usually when UI is visible +BOOL LLViewerWindow::handleKey(KEY key, MASK mask) +{ + // 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.getKeyboardFocus() != NULL); + } + } + + // 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))) + { + return TRUE; + } + + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); + + // give menus a chance to handle modified (Ctrl, Alt) shortcut keys before current focus + // as long as focus isn't locked + if (mask & (MASK_CONTROL | MASK_ALT) && !gFocusMgr.focusLocked()) + { + // Check the current floater's menu first, if it has one. + if (gFocusMgr.keyboardFocusHasAccelerators() + && keyboard_focus + && keyboard_focus->handleKey(key,mask,FALSE)) + { + return TRUE; + } + + if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask)) + ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask))) + { + return TRUE; + } + } + + // give floaters first chance to handle TAB key + // so frontmost floater gets focus + // if nothing has focus, go to first or last UI element as appropriate + if (key == KEY_TAB && (mask & MASK_CONTROL || 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; + } + // hidden edit menu for cut/copy/paste + if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask)) + { + return TRUE; + } + + // Traverses up the hierarchy + if( keyboard_focus ) + { + LLNearbyChatBar* nearby_chat = LLFloaterReg::findTypedInstance<LLNearbyChatBar>("chat_bar"); + + if (nearby_chat) + { + LLLineEditor* chat_editor = nearby_chat->getChatBox(); + + // arrow keys move avatar while chatting hack + if (chat_editor && chat_editor->hasFocus()) + { + // 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")) + { + // let Control-Up and Control-Down through for chat line history, + if (!(key == KEY_UP && mask == MASK_CONTROL) + && !(key == KEY_DOWN && mask == MASK_CONTROL)) + { + 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; + } + } + } + } + } + if (keyboard_focus->handleKey(key, mask, FALSE)) + { + return TRUE; + } + } + + if( LLToolMgr::getInstance()->getCurrentTool()->handleKey(key, mask) ) + { + return TRUE; + } + + // Try for a new-format gesture + if (LLGestureMgr::instance().triggerGesture(key, mask)) + { + return TRUE; + } + + // See if this is a gesture trigger. If so, eat the key and + // don't pass it down to the menus. + if (gGestureList.trigger(key, mask)) + { + return TRUE; + } + + // If "Pressing letter keys starts local chat" option is selected, we are not in mouselook, + // no view has keyboard focus, this is a printable character key (and no modifier key is + // pressed except shift), then give focus to nearby chat (STORM-560) + if ( gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() && + !keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) ) + { + LLLineEditor* chat_editor = LLFloaterReg::getTypedInstance<LLNearbyChatBar>("chat_bar")->getChatBox(); + if (chat_editor) + { + // passing NULL here, character will be added later when it is handled by character handler. + LLNearbyChatBar::getInstance()->startChat(NULL); + return TRUE; + } + } + + // give menus a chance to handle unmodified accelerator keys + if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask)) + ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask))) + { + return TRUE; + } + + // don't pass keys on to world when something in ui has focus + return gFocusMgr.childHasKeyboardFocus(mRootView) + || LLMenuGL::getKeyboardMode() + || (gMenuBarView && gMenuBarView->getHighlightedItem() && gMenuBarView->getHighlightedItem()->isActive()); +} + + +BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask) +{ + // HACK: We delay processing of return keys until they arrive as a Unicode char, + // so that if you're typing chat text at low frame rate, we don't send the chat + // until all keystrokes have been entered. JC + // HACK: Numeric keypad <enter> on Mac is Unicode 3 + // HACK: Control-M on Windows is Unicode 13 + if ((uni_char == 13 && mask != MASK_CONTROL) + || (uni_char == 3 && mask == MASK_NONE)) + { + return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN)); + } + + // let menus handle navigation (jump) keys + if (gMenuBarView && gMenuBarView->handleUnicodeChar(uni_char, TRUE)) + { + return TRUE; + } + + // Traverses up the hierarchy + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); + if( keyboard_focus ) + { + if (keyboard_focus->handleUnicodeChar(uni_char, FALSE)) + { + return TRUE; + } + + //// 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; + } + + return FALSE; +} + + +void LLViewerWindow::handleScrollWheel(S32 clicks) +{ + LLView::sMouseHandlerMessage.clear(); + + LLUI::resetMouseIdleTimer(); + + LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); + if( mouse_captor ) + { + S32 local_x; + S32 local_y; + mouse_captor->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y ); + mouse_captor->handleScrollWheel(local_x, local_y, clicks); + if (LLView::sDebugMouseHandling) + { + llinfos << "Scroll Wheel handled by captor " << mouse_captor->getName() << llendl; + } + return; + } + + LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); + if (top_ctrl) + { + S32 local_x; + S32 local_y; + top_ctrl->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y ); + if (top_ctrl->handleScrollWheel(local_x, local_y, clicks)) return; + } + + if (mRootView->handleScrollWheel(mCurrentMousePoint.mX, mCurrentMousePoint.mY, clicks) ) + { + if (LLView::sDebugMouseHandling) + { + llinfos << "Scroll Wheel" << LLView::sMouseHandlerMessage << llendl; + } + return; + } + else if (LLView::sDebugMouseHandling) + { + llinfos << "Scroll Wheel not handled by view" << llendl; + } + + // 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) + { + mPopupView->addPopup(popup); + } +} + +void LLViewerWindow::removePopup(LLView* popup) +{ + if (mPopupView) + { + mPopupView->removePopup(popup); + } +} + +void LLViewerWindow::clearPopups() +{ + if (mPopupView) + { + mPopupView->clearPopups(); + } +} + +void LLViewerWindow::moveCursorToCenter() +{ + if (! gSavedSettings.getBOOL("DisableMouseWarp")) + { + S32 x = getWorldViewWidthScaled() / 2; + S32 y = getWorldViewHeightScaled() / 2; + + //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::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. +void LLViewerWindow::updateUI() +{ + static LLFastTimer::DeclareTimer ftm("Update UI"); + LLFastTimer t(ftm); + + static std::string last_handle_msg; + + if (gLoggedInTime.getStarted()) + { + if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("DestinationGuideHintTimeout")) + { + LLFirstUse::notUsingDestinationGuide(); + } + if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("SidePanelHintTimeout")) + { + LLFirstUse::notUsingSidePanel(); + } + } + + LLConsole::updateClass(); + + // animate layout stacks so we have up to date rect for world view + LLLayoutStack::updateClass(); + + // use full window for world view when not rendering UI + bool world_view_uses_full_window = gAgentCamera.cameraMouselook() || !gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI); + updateWorldViewRect(world_view_uses_full_window); + + LLView::sMouseHandlerMessage.clear(); + + S32 x = mCurrentMousePoint.mX; + S32 y = mCurrentMousePoint.mY; + + MASK mask = gKeyboard->currentMask(TRUE); + + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) + { + gDebugRaycastFaceHit = -1; + gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, + &gDebugRaycastFaceHit, + &gDebugRaycastIntersection, + &gDebugRaycastTexCoord, + &gDebugRaycastNormal, + &gDebugRaycastBinormal, + &gDebugRaycastStart, + &gDebugRaycastEnd); + } + + updateMouseDelta(); + updateKeyboardFocus(); + + 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) + { + 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) + { + LLView* captor_parent_view = captor_view->getParent(); + while(captor_parent_view) + { + mouse_hover_set.insert(captor_parent_view->getHandle()); + captor_parent_view = captor_parent_view->getParent(); + } + } + + // aggregate visible views that contain mouse cursor in display order + LLPopupView::popup_list_t popups = mPopupView->getCurrentPopups(); + + for(LLPopupView::popup_list_t::iterator popup_it = popups.begin(); popup_it != popups.end(); ++popup_it) + { + LLView* popup = popup_it->get(); + if (popup && popup->calcScreenBoundingRect().pointInRect(x, y)) + { + // iterator over contents of top_ctrl, and throw into mouse_hover_set + for (LLView::tree_iterator_t it = popup->beginTreeDFS(); + it != popup->endTreeDFS(); + ++it) + { + LLView* viewp = *it; + if (viewp->getVisible() + && viewp->calcScreenBoundingRect().pointInRect(x, y)) + { + // we have a view that contains the mouse, add it to the set + mouse_hover_set.insert(viewp->getHandle()); + } + else + { + // skip this view and all of its children + it.skipDescendants(); + } + } + } + } + + // while the top_ctrl contains the mouse cursor, only it and its descendants will receive onMouseEnter events + if (top_ctrl && top_ctrl->calcScreenBoundingRect().pointInRect(x, y)) + { + // iterator over contents of top_ctrl, and throw into mouse_hover_set + for (LLView::tree_iterator_t it = top_ctrl->beginTreeDFS(); + it != top_ctrl->endTreeDFS(); + ++it) + { + LLView* viewp = *it; + if (viewp->getVisible() + && viewp->calcScreenBoundingRect().pointInRect(x, y)) + { + // we have a view that contains the mouse, add it to the set + mouse_hover_set.insert(viewp->getHandle()); + } + else + { + // skip this view and all of its children + it.skipDescendants(); + } + } + } + else + { + // walk UI tree in depth-first order + for (LLView::tree_iterator_t it = root_view->beginTreeDFS(); + it != root_view->endTreeDFS(); + ++it) + { + LLView* viewp = *it; + // calculating the screen rect involves traversing the parent, so this is less than optimal + if (viewp->getVisible() + && viewp->calcScreenBoundingRect().pointInRect(x, y)) + { + + // if this view is mouse opaque, nothing behind it should be in mouse_hover_set + if (viewp->getMouseOpaque()) + { + // constrain further iteration to children of this widget + it = viewp->beginTreeDFS(); + } + + // we have a view that contains the mouse, add it to the set + mouse_hover_set.insert(viewp->getHandle()); + } + else + { + // skip this view and all of its children + it.skipDescendants(); + } + } + } + } + + typedef std::vector<LLHandle<LLView> > view_handle_list_t; + + // call onMouseEnter() on all views which contain the mouse cursor but did not before + view_handle_list_t mouse_enter_views; + std::set_difference(mouse_hover_set.begin(), mouse_hover_set.end(), + mMouseHoverViews.begin(), mMouseHoverViews.end(), + std::back_inserter(mouse_enter_views)); + for (view_handle_list_t::iterator it = mouse_enter_views.begin(); + it != mouse_enter_views.end(); + ++it) + { + LLView* viewp = it->get(); + if (viewp) + { + LLRect view_screen_rect = viewp->calcScreenRect(); + viewp->onMouseEnter(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask); + } + } + + // call onMouseLeave() on all views which no longer contain the mouse cursor + view_handle_list_t mouse_leave_views; + std::set_difference(mMouseHoverViews.begin(), mMouseHoverViews.end(), + mouse_hover_set.begin(), mouse_hover_set.end(), + std::back_inserter(mouse_leave_views)); + for (view_handle_list_t::iterator it = mouse_leave_views.begin(); + it != mouse_leave_views.end(); + ++it) + { + LLView* viewp = it->get(); + if (viewp) + { + LLRect view_screen_rect = viewp->calcScreenRect(); + viewp->onMouseLeave(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask); + } + } + + // store resulting hover set for next frame + swap(mMouseHoverViews, mouse_hover_set); + + // only handle hover events when UI is enabled + if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { + + if( mouse_captor ) + { + // Pass hover events to object capturing mouse events. + S32 local_x; + S32 local_y; + mouse_captor->screenPointToLocal( x, y, &local_x, &local_y ); + handled = mouse_captor->handleHover(local_x, local_y, mask); + if (LLView::sDebugMouseHandling) + { + llinfos << "Hover handled by captor " << mouse_captor->getName() << llendl; + } + + if( !handled ) + { + lldebugst(LLERR_USER_INPUT) << "hover not handled by mouse captor" << llendl; + } + } + else + { + if (top_ctrl) + { + S32 local_x, local_y; + top_ctrl->screenPointToLocal( x, y, &local_x, &local_y ); + handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleHover(local_x, local_y, mask); + 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) + { + if (last_handle_msg != LLStringUtil::null) + { + last_handle_msg.clear(); + llinfos << "Hover not handled by view" << llendl; + } + } + } + + if (!handled) + { + LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); + + if(mMouseInWindow && tool) + { + handled = tool->handleHover(x, y, mask); + } + } + } + + // Show a new tool tip (or update one that is already shown) + BOOL tool_tip_handled = FALSE; + std::string tool_tip_msg; + if( handled + && !mWindow->isCursorHidden()) + { + LLRect screen_sticky_rect = mRootView->getLocalRect(); + S32 local_x, local_y; + + if (gSavedSettings.getBOOL("DebugShowXUINames")) + { + LLToolTip::Params params; + + LLView* tooltip_view = mRootView; + LLView::tree_iterator_t end_it = mRootView->endTreeDFS(); + for (LLView::tree_iterator_t it = mRootView->beginTreeDFS(); it != end_it; ++it) + { + LLView* viewp = *it; + LLRect screen_rect; + viewp->localRectToScreen(viewp->getLocalRect(), &screen_rect); + if (!(viewp->getVisible() + && screen_rect.pointInRect(x, y))) + { + it.skipDescendants(); + } + // only report xui names for LLUICtrls, + // and blacklist the various containers we don't care about + else if (dynamic_cast<LLUICtrl*>(viewp) + && viewp != gMenuHolder + && viewp != gFloaterView + && viewp != gConsole) + { + if (dynamic_cast<LLFloater*>(viewp)) + { + // constrain search to descendants of this (frontmost) floater + // by resetting iterator + it = viewp->beginTreeDFS(); + } + + // if we are in a new part of the tree (not a descendent of current tooltip_view) + // then push the results for tooltip_view and start with a new potential view + // NOTE: this emulates visiting only the leaf nodes that meet our criteria + if (!viewp->hasAncestor(tooltip_view)) + { + append_xui_tooltip(tooltip_view, params); + screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect()); + } + tooltip_view = viewp; + } + } + + append_xui_tooltip(tooltip_view, params); + screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect()); + + params.sticky_rect = screen_sticky_rect; + params.max_width = 400; + + LLToolTipMgr::instance().show(params); + } + // if there is a mouse captor, nothing else gets a tooltip + else if (mouse_captor) + { + mouse_captor->screenPointToLocal(x, y, &local_x, &local_y); + tool_tip_handled = mouse_captor->handleToolTip(local_x, local_y, mask); + } + else + { + // next is top_ctrl + if (!tool_tip_handled && top_ctrl) + { + top_ctrl->screenPointToLocal(x, y, &local_x, &local_y); + tool_tip_handled = top_ctrl->handleToolTip(local_x, local_y, mask ); + } + + if (!tool_tip_handled) + { + local_x = x; local_y = y; + tool_tip_handled = mRootView->handleToolTip(local_x, local_y, mask ); + } + + LLTool* current_tool = LLToolMgr::getInstance()->getCurrentTool(); + if (!tool_tip_handled && current_tool) + { + current_tool->screenPointToLocal(x, y, &local_x, &local_y); + tool_tip_handled = current_tool->handleToolTip(local_x, local_y, mask ); + } + } + } + } + else + { // just have tools handle hover when UI is turned off + LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); + + if(mMouseInWindow && tool) + { + handled = tool->handleHover(x, y, mask); + } + } + + updateLayout(); + + mLastMousePoint = mCurrentMousePoint; + + // cleanup unused selections when no modal dialogs are open + if (LLModalDialog::activeCount() == 0) + { + LLViewerParcelMgr::getInstance()->deselectUnused(); + } + + if (LLModalDialog::activeCount() == 0) + { + LLSelectMgr::getInstance()->deselectUnused(); + } +} + + +void LLViewerWindow::updateLayout() +{ + LLTool* tool = LLToolMgr::getInstance()->getCurrentTool(); + if (gFloaterTools != NULL + && tool != NULL + && tool != gToolNull + && tool != LLToolCompInspect::getInstance() + && tool != LLToolDragAndDrop::getInstance() + && !gSavedSettings.getBOOL("FreezeTime")) + { + // Suppress the toolbox view if our source tool was the pie tool, + // and we've overridden to something else. + bool suppress_toolbox = + (LLToolMgr::getInstance()->getBaseTool() == LLToolPie::getInstance()) && + (LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance()); + + LLMouseHandler *captor = gFocusMgr.getMouseCapture(); + // With the null, inspect, or drag and drop tool, don't muck + // with visibility. + + if (gFloaterTools->isMinimized() + || (tool != LLToolPie::getInstance() // not default tool + && tool != LLToolCompGun::getInstance() // not coming out of mouselook + && !suppress_toolbox // not override in third person + && LLToolMgr::getInstance()->getCurrentToolset() != 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->openFloater(); + } + // Update the location of the blue box tool popup + LLCoordGL select_center_screen; + MASK mask = gKeyboard->currentMask(TRUE); + gFloaterTools->updatePopup( select_center_screen, mask ); + } + else + { + gFloaterTools->setVisible(FALSE); + } + //gMenuBarView->setItemVisible("BuildTools", gFloaterTools->getVisible()); + } + + LLFloaterBuildOptions* build_options_floater = LLFloaterReg::findTypedInstance<LLFloaterBuildOptions>("build_options"); + if (build_options_floater && build_options_floater->getVisible()) + { + build_options_floater->updateGridMode(); + } + + // Always update console + if(gConsole) + { + 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]); + + //RN: fix for asynchronous notification of mouse leaving window not working + LLCoordWindow mouse_pos; + mWindow->getCursorPosition(&mouse_pos); + if (mouse_pos.mX < 0 || + mouse_pos.mY < 0 || + mouse_pos.mX > mWindowRectRaw.getWidth() || + mouse_pos.mY > mWindowRectRaw.getHeight()) + { + mMouseInWindow = FALSE; + } + else + { + mMouseInWindow = TRUE; + } + + LLVector2 mouse_vel; + + if (gSavedSettings.getBOOL("MouseSmooth")) + { + static F32 fdx = 0.f; + static F32 fdy = 0.f; + + F32 amount = 16.f; + fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f); + fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f); + + 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()); +} + +void LLViewerWindow::updateKeyboardFocus() +{ + if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { + gFocusMgr.setKeyboardFocus(NULL); + } + + // clean up current focus + LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); + if (cur_focus) + { + if (!cur_focus->isInVisibleChain() || !cur_focus->isInEnabledChain()) + { + // don't release focus, just reassign so that if being given + // to a sibling won't call onFocusLost on all the ancestors + // gFocusMgr.releaseFocusIfNeeded(cur_focus); + + LLUICtrl* parent = cur_focus->getParentUICtrl(); + const LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot(); + bool new_focus_found = false; + while(parent) + { + if (parent->isCtrl() + && (parent->hasTabStop() || parent == focus_root) + && !parent->getIsChrome() + && parent->isInVisibleChain() + && parent->isInEnabledChain()) + { + if (!parent->focusFirstItem()) + { + parent->setFocus(TRUE); + } + new_focus_found = true; + break; + } + parent = parent->getParentUICtrl(); + } + + // if we didn't find a better place to put focus, just release it + // hasFocus() will return true if and only if we didn't touch focus since we + // are only moving focus higher in the hierarchy + if (!new_focus_found) + { + cur_focus->setFocus(FALSE); + } + } + else if (cur_focus->isFocusRoot()) + { + // focus roots keep trying to delegate focus to their first valid descendant + // this assumes that focus roots are not valid focus holders on their own + cur_focus->focusFirstItem(); + } + } + + // last ditch force of edit menu to selection manager + if (LLEditMenuHandler::gEditMenuHandler == NULL && LLSelectMgr::getInstance()->getSelection()->getObjectCount()) + { + LLEditMenuHandler::gEditMenuHandler = LLSelectMgr::getInstance(); + } + + if (gFloaterView->getCycleMode()) + { + // sync all floaters with their focus state + gFloaterView->highlightFocusedFloater(); + gSnapshotFloaterView->highlightFocusedFloater(); + MASK mask = gKeyboard->currentMask(TRUE); + if ((mask & MASK_CONTROL) == 0) + { + // control key no longer held down, finish cycle mode + gFloaterView->setCycleMode(FALSE); + + gFloaterView->syncFloaterTabOrder(); + } + else + { + // user holding down CTRL, don't update tab order of floaters + } + } + else + { + // update focused floater + gFloaterView->highlightFocusedFloater(); + gSnapshotFloaterView->highlightFocusedFloater(); + // make sure floater visible order is in sync with tab order + gFloaterView->syncFloaterTabOrder(); + } +} + +static 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()) + { + 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]); + } + + if (mWorldViewRectRaw != new_world_rect) + { + mWorldViewRectRaw = new_world_rect; + gResizeScreenTexture = TRUE; + LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() ); + LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() ); + + LLRect old_world_rect_scaled = mWorldViewRectScaled; + mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale); + + // sending a signal with a new WorldView rect + mOnWorldViewRectUpdated(old_world_rect_scaled, mWorldViewRectScaled); + } +} + +void LLViewerWindow::saveLastMouse(const LLCoordGL &point) +{ + // Store last mouse location. + // If mouse leaves window, pretend last point was on edge of window + if (point.mX < 0) + { + mCurrentMousePoint.mX = 0; + } + else if (point.mX > getWindowWidthScaled()) + { + mCurrentMousePoint.mX = getWindowWidthScaled(); + } + else + { + mCurrentMousePoint.mX = point.mX; + } + + if (point.mY < 0) + { + mCurrentMousePoint.mY = 0; + } + else if (point.mY > getWindowHeightScaled() ) + { + mCurrentMousePoint.mY = getWindowHeightScaled(); + } + else + { + mCurrentMousePoint.mY = point.mY; + } +} + + +// Draws the selection outlines for the currently selected objects +// Must be called after displayObjects is called, which sets the mGLName parameter +// NOTE: This function gets called 3 times: +// render_ui_3d: FALSE, FALSE, TRUE +// render_hud_elements: FALSE, FALSE, FALSE +void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, BOOL for_hud ) +{ + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + + if (!for_hud && !for_gl_pick) + { + // Call this once and only once + LLSelectMgr::getInstance()->updateSilhouettes(); + } + + // Draw fence around land selections + if (for_gl_pick) + { + if (pick_parcel_walls) + { + LLViewerParcelMgr::getInstance()->renderParcelCollision(); + } + } + else if (( for_hud && selection->getSelectType() == SELECT_TYPE_HUD) || + (!for_hud && selection->getSelectType() != SELECT_TYPE_HUD)) + { + LLSelectMgr::getInstance()->renderSilhouettes(for_hud); + + stop_glerror(); + + // setup HUD render + if (selection->getSelectType() == SELECT_TYPE_HUD && LLSelectMgr::getInstance()->getSelection()->getObjectCount()) + { + LLBBox hud_bbox = gAgentAvatarp->getHUDBBox(); + + // set up transform to encompass bounding box of HUD + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + F32 depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f); + gGL.ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, depth); + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.loadMatrix(OGL_TO_CFR_ROTATION); // Load Cory's favorite reference frame + gGL.translatef(-hud_bbox.getCenterLocal().mV[VX] + (depth *0.5f), 0.f, 0.f); + } + + // Render light for editing + if (LLSelectMgr::sRenderLightRadius && LLToolMgr::getInstance()->inEdit()) + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + LLGLEnable gls_blend(GL_BLEND); + LLGLEnable gls_cull(GL_CULL_FACE); + LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + if (selection->getSelectType() == SELECT_TYPE_HUD) + { + F32 zoom = gAgentCamera.mHUDCurZoom; + gGL.scalef(zoom, zoom, zoom); + } + + struct f : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* object) + { + LLDrawable* drawable = object->mDrawable; + if (drawable && drawable->isLight()) + { + LLVOVolume* vovolume = drawable->getVOVolume(); + gGL.pushMatrix(); + + LLVector3 center = drawable->getPositionAgent(); + gGL.translatef(center[0], center[1], center[2]); + F32 scale = vovolume->getLightRadius(); + gGL.scalef(scale, scale, scale); + + LLColor4 color(vovolume->getLightColor(), .5f); + gGL.color4fv(color.mV); + + //F32 pixel_area = 100000.f; + // Render Outside + gSphere.render(); + + // Render Inside + glCullFace(GL_FRONT); + gSphere.render(); + glCullFace(GL_BACK); + + gGL.popMatrix(); + } + return true; + } + } func; + LLSelectMgr::getInstance()->getSelection()->applyToObjects(&func); + + gGL.popMatrix(); + } + + // NOTE: The average position for the axis arrows of the selected objects should + // not be recalculated at this time. If they are, then group rotations will break. + + // Draw arrows at average center of all selected objects + LLTool* tool = LLToolMgr::getInstance()->getCurrentTool(); + if (tool) + { + if(tool->isAlwaysRendered()) + { + tool->render(); + } + else + { + if( !LLSelectMgr::getInstance()->getSelection()->isEmpty() ) + { + BOOL 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 = LLSelectMgr::getInstance()->getSelection()->begin(); + iter != LLSelectMgr::getInstance()->getSelection()->end(); iter++) + { + LLSelectNode* nodep = *iter; + LLViewerObject* object = nodep->getObject(); + BOOL this_object_movable = FALSE; + if (object->permMove() && (object->permModify() || selecting_linked_set)) + { + moveable_object_selected = TRUE; + this_object_movable = TRUE; + } + all_selected_objects_move = all_selected_objects_move && this_object_movable; + all_selected_objects_modify = all_selected_objects_modify && object->permModify(); + } + + BOOL draw_handles = TRUE; + + if (tool == LLToolCompTranslate::getInstance() && (!moveable_object_selected || !all_selected_objects_move)) + { + draw_handles = FALSE; + } + + if (tool == LLToolCompRotate::getInstance() && (!moveable_object_selected || !all_selected_objects_move)) + { + draw_handles = FALSE; + } + + if ( !all_selected_objects_modify && tool == LLToolCompScale::getInstance() ) + { + draw_handles = FALSE; + } + + if( draw_handles ) + { + tool->render(); + } + } + } + if (selection->getSelectType() == SELECT_TYPE_HUD && selection->getObjectCount()) + { + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + stop_glerror(); + } + } + } +} + +// Return a point near the clicked object representative of the place the object was clicked. +LLVector3d LLViewerWindow::clickPointInWorldGlobal(S32 x, S32 y_from_bot, LLViewerObject* clicked_object) const +{ + // create a normalized vector pointing from the camera center into the + // world at the location of the mouse click + LLVector3 mouse_direction_global = mouseDirectionGlobal( x, y_from_bot ); + + LLVector3d relative_object = clicked_object->getPositionGlobal() - gAgentCamera.getCameraPositionGlobal(); + + // make mouse vector as long as object vector, so it touchs a point near + // where the user clicked on the object + mouse_direction_global *= (F32) relative_object.magVec(); + + LLVector3d new_pos; + new_pos.setVec(mouse_direction_global); + // transform mouse vector back to world coords + new_pos += gAgentCamera.getCameraPositionGlobal(); + + return new_pos; +} + + +BOOL LLViewerWindow::clickPointOnSurfaceGlobal(const S32 x, const S32 y, LLViewerObject *objectp, LLVector3d &point_global) const +{ + BOOL intersect = FALSE; + +// U8 shape = objectp->mPrimitiveCode & LL_PCODE_BASE_MASK; + if (!intersect) + { + point_global = clickPointInWorldGlobal(x, y, objectp); + llinfos << "approx intersection at " << (objectp->getPositionGlobal() - point_global) << llendl; + } + else + { + llinfos << "good intersection at " << (objectp->getPositionGlobal() - point_global) << llendl; + } + + return intersect; +} + +void LLViewerWindow::pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(const LLPickInfo& info), BOOL pick_transparent) +{ + 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; + } + + LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, TRUE, callback); + schedulePick(pick_info); +} + +void LLViewerWindow::schedulePick(LLPickInfo& pick_info) +{ + if (mPicks.size() >= 1024 || mWindow->getMinimized()) + { //something went wrong, picks are being scheduled but not processed + + if (pick_info.mPickCallback) + { + pick_info.mPickCallback(pick_info); + } + + return; + } + mPicks.push_back(pick_info); + + // delay further event processing until we receive results of pick + // only do this for async picks so that handleMouseUp won't be called + // until the pick triggered in handleMouseDown has been processed, for example + mWindow->delayInputProcessing(); +} + + +void LLViewerWindow::performPick() +{ + if (!mPicks.empty()) + { + std::vector<LLPickInfo>::iterator pick_it; + for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it) + { + pick_it->fetchResults(); + } + + mLastPick = mPicks.back(); + mPicks.clear(); + } +} + +void LLViewerWindow::returnEmptyPicks() +{ + std::vector<LLPickInfo>::iterator pick_it; + for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it) + { + mLastPick = *pick_it; + // just trigger callback with empty results + if (pick_it->mPickCallback) + { + pick_it->mPickCallback(*pick_it); + } + } + mPicks.clear(); +} + +// Performs the GL object/land pick. +LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_transparent) +{ + BOOL 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; + } + + // shortcut queueing in mPicks and just update mLastPick in place + MASK key_mask = gKeyboard->currentMask(TRUE); + mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), key_mask, pick_transparent, TRUE, NULL); + mLastPick.fetchResults(); + + return mLastPick; +} + +LLHUDIcon* LLViewerWindow::cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 depth, + LLVector3* intersection) +{ + S32 x = mouse_x; + S32 y = mouse_y; + + if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position + { + x = getCurrentMouseX(); + y = getCurrentMouseY(); + } + + // world coordinates of mouse + 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; + + return LLHUDIcon::lineSegmentIntersectAll(mouse_world_start, mouse_world_end, intersection); + + +} + +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, + LLVector3* start, + LLVector3* end) +{ + S32 x = mouse_x; + S32 y = mouse_y; + + if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position + { + x = getCurrentMouseX(); + y = getCurrentMouseY(); + } + + // HUD coordinates of mouse + LLVector3 mouse_point_hud = mousePointHUD(x, y); + LLVector3 mouse_hud_start = mouse_point_hud - LLVector3(depth, 0, 0); + LLVector3 mouse_hud_end = mouse_point_hud + LLVector3(depth, 0, 0); + + // world coordinates of mouse + LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y); + LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin(); + + //get near clip plane + LLVector3 n = LLViewerCamera::getInstance()->getAtAxis(); + LLVector3 p = mouse_point_global + n * LLViewerCamera::getInstance()->getNear(); + + //project mouse point onto plane + LLVector3 pos; + line_plane(mouse_point_global, mouse_direction_global, p, n, pos); + mouse_point_global = pos; + + LLVector3 mouse_world_start = mouse_point_global; + LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth; + + if (!LLViewerJoystick::getInstance()->getOverrideCamera()) + { //always set raycast intersection to mouse_world_end unless + //flycam is on (for DoF effect) + gDebugRaycastIntersection = mouse_world_end; + } + + if (start) + { + *start = mouse_world_start; + } + + if (end) + { + *end = mouse_world_end; + } + + LLViewerObject* found = NULL; + + if (this_object) // check only this object + { + if (this_object->isHUDAttachment()) // is a HUD object? + { + if (this_object->lineSegmentIntersect(mouse_hud_start, mouse_hud_end, this_face, pick_transparent, + face_hit, intersection, uv, normal, binormal)) + { + found = this_object; + } + } + else // is a world object + { + if (this_object->lineSegmentIntersect(mouse_world_start, mouse_world_end, this_face, pick_transparent, + face_hit, intersection, uv, normal, binormal)) + { + found = this_object; + } + } + } + else // check ALL objects + { + 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: + { + found = gPipeline.lineSegmentIntersectInWorld(mouse_world_start, mouse_world_end, pick_transparent, + face_hit, intersection, uv, normal, binormal); + if (found && !pick_transparent) + { + gDebugRaycastIntersection = *intersection; + } + } + } + + return found; +} + +// Returns unit vector relative to camera +// indicating direction of point on screen x,y +LLVector3 LLViewerWindow::mouseDirectionGlobal(const S32 x, const S32 y) const +{ + // find vertical field of view + F32 fov = LLViewerCamera::getInstance()->getView(); + + // find world view center in scaled ui coordinates + F32 center_x = getWorldViewRectScaled().getCenterX(); + F32 center_y = getWorldViewRectScaled().getCenterY(); + + // calculate pixel distance to screen + F32 distance = ((F32)getWorldViewHeightScaled() * 0.5f) / (tan(fov / 2.f)); + + // calculate click point relative to middle of screen + F32 click_x = x - center_x; + F32 click_y = y - center_y; + + // compute mouse vector + LLVector3 mouse_vector = distance * LLViewerCamera::getInstance()->getAtAxis() + - click_x * LLViewerCamera::getInstance()->getLeftAxis() + + click_y * LLViewerCamera::getInstance()->getUpAxis(); + + mouse_vector.normVec(); + + return mouse_vector; +} + +LLVector3 LLViewerWindow::mousePointHUD(const S32 x, const S32 y) const +{ + // find screen resolution + S32 height = getWorldViewHeightScaled(); + + // find world view center + F32 center_x = getWorldViewRectScaled().getCenterX(); + F32 center_y = getWorldViewRectScaled().getCenterY(); + + // remap with uniform scale (1/height) so that top is -0.5, bottom is +0.5 + F32 hud_x = -((F32)x - center_x) / height; + F32 hud_y = ((F32)y - center_y) / height; + + return LLVector3(0.f, hud_x/gAgentCamera.mHUDCurZoom, hud_y/gAgentCamera.mHUDCurZoom); +} + +// Returns unit vector relative to camera in camera space +// indicating direction of point on screen x,y +LLVector3 LLViewerWindow::mouseDirectionCamera(const S32 x, const S32 y) const +{ + // find vertical field of view + F32 fov_height = LLViewerCamera::getInstance()->getView(); + F32 fov_width = fov_height * LLViewerCamera::getInstance()->getAspect(); + + // find screen resolution + S32 height = getWorldViewHeightScaled(); + S32 width = getWorldViewWidthScaled(); + + // find world view center + F32 center_x = getWorldViewRectScaled().getCenterX(); + F32 center_y = getWorldViewRectScaled().getCenterY(); + + // calculate click point relative to middle of screen + F32 click_x = (((F32)x - center_x) / (F32)width) * fov_width * -1.f; + F32 click_y = (((F32)y - center_y) / (F32)height) * fov_height; + + // compute mouse vector + LLVector3 mouse_vector = LLVector3(0.f, 0.f, -1.f); + LLQuaternion mouse_rotate; + mouse_rotate.setQuat(click_y, click_x, 0.f); + + mouse_vector = mouse_vector * mouse_rotate; + // project to z = -1 plane; + mouse_vector = mouse_vector * (-1.f / mouse_vector.mV[VZ]); + + return mouse_vector; +} + + + +BOOL LLViewerWindow::mousePointOnPlaneGlobal(LLVector3d& point, const S32 x, const S32 y, + const LLVector3d &plane_point_global, + const LLVector3 &plane_normal_global) +{ + LLVector3d mouse_direction_global_d; + + mouse_direction_global_d.setVec(mouseDirectionGlobal(x,y)); + LLVector3d plane_normal_global_d; + plane_normal_global_d.setVec(plane_normal_global); + F64 plane_mouse_dot = (plane_normal_global_d * mouse_direction_global_d); + LLVector3d plane_origin_camera_rel = plane_point_global - gAgentCamera.getCameraPositionGlobal(); + F64 mouse_look_at_scale = (plane_normal_global_d * plane_origin_camera_rel) + / plane_mouse_dot; + if (llabs(plane_mouse_dot) < 0.00001) + { + // if mouse is parallel to plane, return closest point on line through plane origin + // that is parallel to camera plane by scaling mouse direction vector + // by distance to plane origin, modulated by deviation of mouse direction from plane origin + LLVector3d plane_origin_dir = plane_origin_camera_rel; + plane_origin_dir.normVec(); + + mouse_look_at_scale = plane_origin_camera_rel.magVec() / (plane_origin_dir * mouse_direction_global_d); + } + + point = gAgentCamera.getCameraPositionGlobal() + mouse_look_at_scale * mouse_direction_global_d; + + return mouse_look_at_scale > 0.0; +} + + +// Returns global position +BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d *land_position_global) +{ + LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y); + F32 mouse_dir_scale; + BOOL hit_land = FALSE; + LLViewerRegion *regionp; + F32 land_z; + const F32 FIRST_PASS_STEP = 1.0f; // meters + const F32 SECOND_PASS_STEP = 0.1f; // meters + LLVector3d camera_pos_global; + + camera_pos_global = gAgentCamera.getCameraPositionGlobal(); + LLVector3d probe_point_global; + LLVector3 probe_point_region; + + // walk forwards to find the point + for (mouse_dir_scale = FIRST_PASS_STEP; mouse_dir_scale < 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 = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global); + + if (!regionp) + { + // ...we're outside the world somehow + continue; + } + + S32 i = (S32) (probe_point_region.mV[VX]/regionp->getLand().getMetersPerGrid()); + S32 j = (S32) (probe_point_region.mV[VY]/regionp->getLand().getMetersPerGrid()); + S32 grids_per_edge = (S32) regionp->getLand().mGridsPerEdge; + if ((i >= grids_per_edge) || (j >= grids_per_edge)) + { + //llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl; + continue; + } + + land_z = regionp->getLand().resolveHeightRegion(probe_point_region); + + //llinfos << "mousePointOnLand initial z " << land_z << llendl; + + if (probe_point_region.mV[VZ] < land_z) + { + // ...just went under land + + // cout << "under land at " << probe_point << " scale " << mouse_vec_scale << endl; + + hit_land = TRUE; + break; + } + } + + + if (hit_land) + { + // Don't go more than one step beyond where we stopped above. + // This can't just be "mouse_vec_scale" because floating point error + // will stop the loop before the last increment.... X - 1.0 + 0.1 + 0.1 + ... + 0.1 != X + F32 stop_mouse_dir_scale = mouse_dir_scale + FIRST_PASS_STEP; + + // take a step backwards, then walk forwards again to refine position + for ( mouse_dir_scale -= FIRST_PASS_STEP; mouse_dir_scale <= stop_mouse_dir_scale; mouse_dir_scale += SECOND_PASS_STEP) + { + LLVector3d mouse_direction_global_d; + mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale); + probe_point_global = camera_pos_global + mouse_direction_global_d; + + regionp = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global); + + if (!regionp) + { + // ...we're outside the world somehow + continue; + } + + /* + i = (S32) (local_probe_point.mV[VX]/regionp->getLand().getMetersPerGrid()); + j = (S32) (local_probe_point.mV[VY]/regionp->getLand().getMetersPerGrid()); + if ((i >= regionp->getLand().mGridsPerEdge) || (j >= regionp->getLand().mGridsPerEdge)) + { + // llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl; + continue; + } + land_z = regionp->getLand().mSurfaceZ[ i + j * (regionp->getLand().mGridsPerEdge) ]; + */ + + land_z = regionp->getLand().resolveHeightRegion(probe_point_region); + + //llinfos << "mousePointOnLand refine z " << land_z << llendl; + + if (probe_point_region.mV[VZ] < land_z) + { + // ...just went under land again + + *land_position_global = probe_point_global; + return TRUE; + } + } + } + + return FALSE; +} + +// Saves an image to the harddrive as "SnapshotX" where X >= 1. +BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image, bool force_picker) +{ + if (!image) + { + llwarns << "No image to save" << llendl; + return FALSE; + } + + 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 base file location if needed. + if (force_picker || !isSnapshotLocSet()) + { + std::string proposed_name( sSnapshotBaseName ); + + // getSaveFile will append an appropriate extension to the proposed name, based on the ESaveFilter constant passed in. + + // pick a directory in which to save + LLFilePicker& picker = LLFilePicker::instance(); + if (!picker.getSaveFile(pick_type, proposed_name)) + { + // Clicked cancel + return FALSE; + } + + // Copy the directory + file name + std::string filepath = picker.getFirstFile(); + + LLViewerWindow::sSnapshotBaseName = gDirUtilp->getBaseFileName(filepath, true); + LLViewerWindow::sSnapshotDir = gDirUtilp->getDirName(filepath); + } + + // Look for an unused file name + std::string filepath; + S32 i = 1; + S32 err = 0; + + do + { + filepath = sSnapshotDir; + filepath += gDirUtilp->getDirDelimiter(); + filepath += sSnapshotBaseName; + filepath += llformat("_%.3d",i); + filepath += extension; + + llstat stat_info; + err = LLFile::stat( filepath, &stat_info ); + i++; + } + while( -1 != err ); // search until the file is not found (i.e., stat() gives an error). + + llinfos << "Saving snapshot to " << filepath << llendl; + return image->save(filepath); +} + +void LLViewerWindow::resetSnapshotLoc() +{ + sSnapshotDir.clear(); +} + +// static +void LLViewerWindow::movieSize(S32 new_width, S32 new_height) +{ + LLCoordWindow size; + gViewerWindow->getWindow()->getSize(&size); + if ( size.mX != new_width + || size.mY != new_height) + { + LLCoordWindow new_size(new_width, new_height); + LLCoordScreen screen_size; + gViewerWindow->getWindow()->convertCoords(new_size, &screen_size); + gViewerWindow->getWindow()->setSize(screen_size); + } +} + +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; + + LLPointer<LLImageRaw> raw = new LLImageRaw; + BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, do_rebuild); + + if (success) + { + LLPointer<LLImageBMP> bmp_image = new LLImageBMP; + success = bmp_image->encode(raw, 0.0f); + if( success ) + { + success = bmp_image->save(filepath); + } + else + { + llwarns << "Unable to encode bmp snapshot" << llendl; + } + } + else + { + llwarns << "Unable to capture raw snapshot" << llendl; + } + + return success; +} + + +void LLViewerWindow::playSnapshotAnimAndSound() +{ + if (gSavedSettings.getBOOL("QuietSnapshotsToDisk")) + { + return; + } + gAgent.sendAnimationRequest(ANIM_AGENT_SNAPSHOT, ANIM_REQUEST_START); + send_sound_trigger(LLUUID(gSavedSettings.getString("UISndSnapshot")), 1.0f); +} + +BOOL LLViewerWindow::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 a raw image +// Since the required size might be bigger than the available screen, this method rerenders the scene in parts (called subimages) and copy +// the results over to the final raw image. +BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, + BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL do_rebuild, ESnapshotType type, S32 max_size) +{ + if (!raw) + { + return FALSE; + } + //check if there is enough memory for the snapshot image + if(LLPipeline::sMemAllocationThrottled) + { + return FALSE ; //snapshot taking is disabled due to memory restriction. + } + if(image_width * image_height > (1 << 22)) //if snapshot image is larger than 2K by 2K + { + if(!LLMemory::tryToAlloc(NULL, image_width * image_height * 3)) + { + llwarns << "No enough memory to take the snapshot with size (w : h): " << image_width << " : " << image_height << llendl ; + return FALSE ; //there is no enough memory for taking this snapshot. + } + } + + // PRE SNAPSHOT + gDisplaySwapBuffers = FALSE; + + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + setCursor(UI_CURSOR_WAIT); + + // Hide all the UI widgets first and draw a frame + BOOL prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI) ? TRUE : FALSE; + + if ( prev_draw_ui != show_ui) + { + LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI); + } + + BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && LLPipeline::sShowHUDAttachments; + if (hide_hud) + { + LLPipeline::sShowHUDAttachments = FALSE; + } + + // if not showing ui, use full window to render world view + updateWorldViewRect(!show_ui); + + // Copy screen to a buffer + // crop sides or top and bottom, if taking a snapshot of different aspect ratio + // from window + LLRect window_rect = show_ui ? getWindowRectRaw() : getWorldViewRectRaw(); + + S32 snapshot_width = window_rect.getWidth(); + S32 snapshot_height = window_rect.getHeight(); + // SNAPSHOT + S32 window_width = snapshot_width; + S32 window_height = snapshot_height; + + // Note: Scaling of the UI is currently *not* supported so we limit the output size if UI is requested + if (show_ui) + { + // If the user wants the UI, limit the output size to the available screen size + image_width = llmin(image_width, window_width); + image_height = llmin(image_height, window_height); + } + + F32 scale_factor = 1.0f ; + if (!keep_window_aspect || (image_width > window_width) || (image_height > window_height)) + { + // if image cropping or need to enlarge the scene, compute a scale_factor + F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ; + snapshot_width = (S32)(ratio * image_width) ; + snapshot_height = (S32)(ratio * image_height) ; + scale_factor = llmax(1.0f, 1.0f / ratio) ; + } + + if (show_ui && scale_factor > 1.f) + { + // Note: we should never get there... + llwarns << "over scaling UI not supported." << llendl; + } + + S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f); + S32 buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f); + + S32 image_buffer_x = llfloor(snapshot_width * scale_factor) ; + S32 image_buffer_y = llfloor(snapshot_height * scale_factor) ; + + if ((image_buffer_x > max_size) || (image_buffer_y > max_size)) // boundary check to avoid memory overflow + { + scale_factor *= llmin((F32)max_size / image_buffer_x, (F32)max_size / image_buffer_y) ; + image_buffer_x = llfloor(snapshot_width * scale_factor) ; + image_buffer_y = llfloor(snapshot_height * scale_factor) ; + } + if ((image_buffer_x > 0) && (image_buffer_y > 0)) + { + raw->resize(image_buffer_x, image_buffer_y, 3); + } + else + { + return FALSE ; + } + if (raw->isBufferInvalid()) + { + return FALSE ; + } + + BOOL high_res = scale_factor >= 2.f; // Font scaling is slow, only do so if rez is much higher + if (high_res && show_ui) + { + // Note: we should never get there... + llwarns << "High res UI snapshot not supported. " << llendl; + /*send_agent_pause(); + //rescale fonts + initFonts(scale_factor); + LLHUDObject::reshapeAll();*/ + } + + S32 output_buffer_offset_y = 0; + + F32 depth_conversion_factor_1 = (LLViewerCamera::getInstance()->getFar() + LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear()); + F32 depth_conversion_factor_2 = (LLViewerCamera::getInstance()->getFar() - LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear()); + + gObjectList.generatePickList(*LLViewerCamera::getInstance()); + + // Subimages are in fact partial rendering of the final view. This happens when the final view is bigger than the screen. + // In most common cases, scale_factor is 1 and there's no more than 1 iteration on x and y + for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y) + { + S32 subimage_y_offset = llclamp(buffer_y_offset - (subimage_y * window_height), 0, window_height);; + // handle fractional columns + U32 read_height = llmax(0, (window_height - subimage_y_offset) - + llmax(0, (window_height * (subimage_y + 1)) - (buffer_y_offset + raw->getHeight()))); + + S32 output_buffer_offset_x = 0; + for (int subimage_x = 0; subimage_x < scale_factor; ++subimage_x) + { + gDisplaySwapBuffers = FALSE; + gDepthDirty = TRUE; + + S32 subimage_x_offset = llclamp(buffer_x_offset - (subimage_x * window_width), 0, window_width); + // handle fractional rows + U32 read_width = llmax(0, (window_width - subimage_x_offset) - + llmax(0, (window_width * (subimage_x + 1)) - (buffer_x_offset + raw->getWidth()))); + + // Skip rendering and sampling altogether if either width or height is degenerated to 0 (common in cropping cases) + if (read_width && read_height) + { + const U32 subfield = subimage_x+(subimage_y*llceil(scale_factor)); + display(do_rebuild, scale_factor, subfield, TRUE); + + if (!LLPipeline::sRenderDeferred) + { + // Required for showing the GUI in snapshots and performing bloom composite overlay + // Call even if show_ui is FALSE + render_ui(scale_factor, subfield); + } + + for (U32 out_y = 0; out_y < read_height ; out_y++) + { + S32 output_buffer_offset = ( + (out_y * (raw->getWidth())) // ...plus iterated y... + + (window_width * subimage_x) // ...plus subimage start in x... + + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y... + - output_buffer_offset_x // ...minus buffer padding x... + - (output_buffer_offset_y * (raw->getWidth())) // ...minus buffer padding y... + ) * raw->getComponents(); + + // Ping the watchdog thread every 100 lines to keep us alive (arbitrary number, feel free to change) + if (out_y % 100 == 0) + { + LLAppViewer::instance()->pingMainloopTimeout("LLViewerWindow::rawSnapshot"); + } + + if (type == SNAPSHOT_TYPE_COLOR) + { + glReadPixels( + subimage_x_offset, out_y + subimage_y_offset, + read_width, 1, + GL_RGB, GL_UNSIGNED_BYTE, + raw->getData() + output_buffer_offset + ); + } + else // SNAPSHOT_TYPE_DEPTH + { + LLPointer<LLImageRaw> depth_line_buffer = new LLImageRaw(read_width, 1, sizeof(GL_FLOAT)); // need to store floating point values + glReadPixels( + subimage_x_offset, out_y + subimage_y_offset, + read_width, 1, + GL_DEPTH_COMPONENT, GL_FLOAT, + depth_line_buffer->getData()// current output pixel is beginning of buffer... + ); + + for (S32 i = 0; i < (S32)read_width; i++) + { + F32 depth_float = *(F32*)(depth_line_buffer->getData() + (i * sizeof(F32))); + + F32 linear_depth_float = 1.f / (depth_conversion_factor_1 - (depth_float * depth_conversion_factor_2)); + U8 depth_byte = F32_to_U8(linear_depth_float, LLViewerCamera::getInstance()->getNear(), LLViewerCamera::getInstance()->getFar()); + // write converted scanline out to result image + for (S32 j = 0; j < raw->getComponents(); j++) + { + *(raw->getData() + output_buffer_offset + (i * raw->getComponents()) + j) = depth_byte; + } + } + } + } + } + output_buffer_offset_x += subimage_x_offset; + stop_glerror(); + } + output_buffer_offset_y += subimage_y_offset; + } + + gDisplaySwapBuffers = FALSE; + gDepthDirty = TRUE; + + // POST SNAPSHOT + if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { + LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI); + } + + if (hide_hud) + { + LLPipeline::sShowHUDAttachments = TRUE; + } + + /*if (high_res) + { + initFonts(1.f); + LLHUDObject::reshapeAll(); + }*/ + + // Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding) + // Note: this formula depends on the number of components being 3. Not obvious, but it's correct. + image_width += (image_width * 3) % 4; + + BOOL ret = TRUE ; + // Resize image + if(llabs(image_width - image_buffer_x) > 4 || llabs(image_height - image_buffer_y) > 4) + { + ret = raw->scale( image_width, image_height ); + } + else if(image_width != image_buffer_x || image_height != image_buffer_y) + { + ret = raw->scale( image_width, image_height, FALSE ); + } + + + setCursor(UI_CURSOR_ARROW); + + if (do_rebuild) + { + // If we had to do a rebuild, that means that the lists of drawables to be rendered + // was empty before we started. + // Need to reset these, otherwise we call state sort on it again when render gets called the next time + // and we stand a good chance of crashing on rebuild because the render drawable arrays have multiple copies of + // objects on them. + gPipeline.resetDrawOrders(); + } + + if (high_res) + { + send_agent_resume(); + } + + return ret; +} + +void LLViewerWindow::destroyWindow() +{ + if (mWindow) + { + LLWindowManager::destroyWindow(mWindow); + } + mWindow = NULL; +} + + +void LLViewerWindow::drawMouselookInstructions() +{ + // Draw instructions for mouselook ("Press ESC to return to World View" partially transparent at the bottom of the screen.) + const std::string instructions = LLTrans::getString("LeaveMouselook"); + const LLFontGL* font = LLFontGL::getFont(LLFontDescriptor("SansSerif", "Large", LLFontGL::BOLD)); + + //to be on top of Bottom bar when it is opened + const S32 INSTRUCTIONS_PAD = 50; + + font->renderUTF8( + instructions, 0, + getWorldViewRectScaled().getCenterX(), + getWorldViewRectScaled().mBottom + INSTRUCTIONS_PAD, + LLColor4( 1.0f, 1.0f, 1.0f, 0.5f ), + LLFontGL::HCENTER, LLFontGL::TOP, + LLFontGL::NORMAL,LLFontGL::DROP_SHADOW); +} + +void* LLViewerWindow::getPlatformWindow() const +{ + return mWindow->getPlatformWindow(); +} + +void* LLViewerWindow::getMediaWindow() const +{ + return mWindow->getMediaWindow(); +} + +void LLViewerWindow::focusClient() const +{ + return mWindow->focusClient(); +} + +LLRootView* LLViewerWindow::getRootView() const +{ + return mRootView; +} + +LLRect LLViewerWindow::getWorldViewRectScaled() const +{ + return mWorldViewRectScaled; +} + +S32 LLViewerWindow::getWorldViewHeightScaled() const +{ + return mWorldViewRectScaled.getHeight(); +} + +S32 LLViewerWindow::getWorldViewWidthScaled() const +{ + return mWorldViewRectScaled.getWidth(); +} + + +S32 LLViewerWindow::getWorldViewHeightRaw() const +{ + return mWorldViewRectRaw.getHeight(); +} + +S32 LLViewerWindow::getWorldViewWidthRaw() const +{ + return mWorldViewRectRaw.getWidth(); +} + +S32 LLViewerWindow::getWindowHeightScaled() const +{ + return mWindowRectScaled.getHeight(); +} + +S32 LLViewerWindow::getWindowWidthScaled() const +{ + return mWindowRectScaled.getWidth(); +} + +S32 LLViewerWindow::getWindowHeightRaw() const +{ + return mWindowRectRaw.getHeight(); +} + +S32 LLViewerWindow::getWindowWidthRaw() const +{ + return mWindowRectRaw.getWidth(); +} + +void LLViewerWindow::setup2DRender() +{ + // setup ortho camera + gl_state_for_2d(mWindowRectRaw.getWidth(), mWindowRectRaw.getHeight()); + setup2DViewport(); +} + +void LLViewerWindow::setup2DViewport(S32 x_offset, S32 y_offset) +{ + gGLViewport[0] = mWindowRectRaw.mLeft + x_offset; + gGLViewport[1] = mWindowRectRaw.mBottom + y_offset; + gGLViewport[2] = mWindowRectRaw.getWidth(); + gGLViewport[3] = mWindowRectRaw.getHeight(); + glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); +} + + +void LLViewerWindow::setup3DRender() +{ + // setup perspective camera + LLViewerCamera::getInstance()->setPerspective(NOT_FOR_SELECTION, mWorldViewRectRaw.mLeft, mWorldViewRectRaw.mBottom, mWorldViewRectRaw.getWidth(), mWorldViewRectRaw.getHeight(), FALSE, LLViewerCamera::getInstance()->getNear(), MAX_FAR_CLIP*2.f); + setup3DViewport(); +} + +void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset) +{ + gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset; + gGLViewport[1] = mWorldViewRectRaw.mBottom + y_offset; + gGLViewport[2] = mWorldViewRectRaw.getWidth(); + gGLViewport[3] = mWorldViewRectRaw.getHeight(); + glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); +} + +void LLViewerWindow::revealIntroPanel() +{ + if (mProgressView) + { + mProgressView->revealIntroPanel(); + } +} + +void LLViewerWindow::setShowProgress(const BOOL show) +{ + if (mProgressView) + { + mProgressView->setVisible(show); + } +} + +void LLViewerWindow::setStartupComplete() +{ + if (mProgressView) + { + mProgressView->setStartupComplete(); + } +} + +BOOL LLViewerWindow::getShowProgress() const +{ + return (mProgressView && mProgressView->getVisible()); +} + +void LLViewerWindow::setProgressString(const std::string& string) +{ + if (mProgressView) + { + mProgressView->setText(string); + } +} + +void LLViewerWindow::setProgressMessage(const std::string& msg) +{ + if(mProgressView) + { + mProgressView->setMessage(msg); + } +} + +void LLViewerWindow::setProgressPercent(const F32 percent) +{ + if (mProgressView) + { + mProgressView->setPercent(percent); + } +} + +void LLViewerWindow::setProgressCancelButtonVisible( BOOL b, const std::string& label ) +{ + if (mProgressView) + { + mProgressView->setCancelButtonVisible( b, label ); + } +} + + +LLProgressView *LLViewerWindow::getProgressView() const +{ + return mProgressView; +} + +void LLViewerWindow::dumpState() +{ + llinfos << "LLViewerWindow Active " << S32(mActive) << llendl; + llinfos << "mWindow visible " << S32(mWindow->getVisible()) + << " minimized " << S32(mWindow->getMinimized()) + << llendl; +} + +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; + + // Pause texture decode threads (will get unpaused during main loop) + LLAppViewer::getTextureCache()->pause(); + LLAppViewer::getImageDecodeThread()->pause(); + LLAppViewer::getTextureFetch()->pause(); + + gSky.destroyGL(); + stop_glerror(); + + LLManipTranslate::destroyGL() ; + stop_glerror(); + + gBumpImageList.destroyGL(); + stop_glerror(); + + LLFontGL::destroyAllGL(); + stop_glerror(); + + LLVOAvatar::destroyGL(); + stop_glerror(); + + LLViewerDynamicTexture::destroyGL(); + stop_glerror(); + + if (gPipeline.isInit()) + { + gPipeline.destroyGL(); + } + + gBox.cleanupGL(); + + if(gPostProcess) + { + gPostProcess->invalidate(); + } + + gTextureList.destroyGL(save_state); + stop_glerror(); + + gGLManager.mIsDisabled = TRUE; + stop_glerror(); + + llinfos << "Remaining allocated texture memory: " << LLImageGL::sGlobalTextureMemoryInBytes << " bytes" << llendl; + } +} + +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(); + + gSky.restoreGL(); + gPipeline.restoreGL(); + LLDrawPoolWater::restoreGL(); + LLManipTranslate::restoreGL(); + + gBumpImageList.restoreGL(); + LLViewerDynamicTexture::restoreGL(); + LLVOAvatar::restoreGL(); + + gResizeScreenTexture = TRUE; + gWindowResized = TRUE; + + if (isAgentAvatarValid() && !gAgentAvatarp->isUsingBakedTextures()) + { + LLVisualParamHint::requestHintUpdates(); + } + + if (!progress_message.empty()) + { + gRestoreGLTimer.reset(); + gRestoreGL = TRUE; + setShowProgress(TRUE); + setProgressString(progress_message); + } + llinfos << "...Restoring GL done" << llendl; + if(!LLAppViewer::instance()->restoreErrorTrap()) + { + llwarns << " Someone took over my signal/exception handler (post restoreGL)!" << llendl; + } + + } +} + +void LLViewerWindow::initFonts(F32 zoom_factor) +{ + LLFontGL::destroyAllGL(); + // Initialize with possibly different zoom factor + + LLFontManager::initClass(); + + LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"), + mDisplayScale.mV[VX] * zoom_factor, + mDisplayScale.mV[VY] * zoom_factor, + gDirUtilp->getAppRODataDir(), + LLUI::getXUIPaths()); + // Force font reloads, which can be very slow + LLFontGL::loadDefaultFonts(); +} + +void LLViewerWindow::requestResolutionUpdate() +{ + mResDirty = true; +} + +void LLViewerWindow::checkSettings() +{ + if (mStatesDirty) + { + gGL.refreshState(); + LLViewerShaderMgr::instance()->setShaders(); + mStatesDirty = false; + } + + // We want to update the resolution AFTER the states getting refreshed not before. + if (mResDirty) + { + reshape(getWindowWidthRaw(), getWindowHeightRaw()); + mResDirty = false; + } +} + +void LLViewerWindow::restartDisplay(BOOL show_progress_bar) +{ + llinfos << "Restaring GL" << llendl; + stopGL(); + if (show_progress_bar) + { + restoreGL(LLTrans::getString("ProgressChangingResolution")); + } + else + { + restoreGL(); + } +} + +BOOL LLViewerWindow::changeDisplaySettings(LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar) +{ + //BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized"); + + //gResizeScreenTexture = TRUE; + + + //U32 fsaa = gSavedSettings.getU32("RenderFSAASamples"); + //U32 old_fsaa = mWindow->getFSAASamples(); + + // if not maximized, use the request size + if (!mWindow->getMaximized()) + { + mWindow->setSize(size); + } + + //if (fsaa == old_fsaa) + { + return TRUE; + } + +/* + + // Close floaters that don't handle settings change + LLFloaterReg::hideInstance("snapshot"); + + BOOL result_first_try = FALSE; + BOOL result_second_try = FALSE; + + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); + send_agent_pause(); + llinfos << "Stopping GL during changeDisplaySettings" << llendl; + stopGL(); + mIgnoreActivate = TRUE; + LLCoordScreen old_size; + LLCoordScreen old_pos; + mWindow->getSize(&old_size); + + //mWindow->setFSAASamples(fsaa); + + result_first_try = mWindow->switchContext(false, size, disable_vsync); + if (!result_first_try) + { + // try to switch back + //mWindow->setFSAASamples(old_fsaa); + result_second_try = mWindow->switchContext(false, old_size, disable_vsync); + + if (!result_second_try) + { + // we are stuck...try once again with a minimal resolution? + send_agent_resume(); + mIgnoreActivate = FALSE; + return FALSE; + } + } + send_agent_resume(); + + llinfos << "Restoring GL during resolution change" << llendl; + if (show_progress_bar) + { + restoreGL(LLTrans::getString("ProgressChangingResolution")); + } + else + { + restoreGL(); + } + + if (!result_first_try) + { + LLSD args; + args["RESX"] = llformat("%d",size.mX); + args["RESY"] = llformat("%d",size.mY); + LLNotificationsUtil::add("ResolutionSwitchFail", args); + size = old_size; // for reshape below + } + + BOOL success = result_first_try || result_second_try; + + if (success) + { + // maximize window if was maximized, else reposition + if (was_maximized) + { + mWindow->maximize(); + } + else + { + S32 windowX = gSavedSettings.getS32("WindowX"); + S32 windowY = gSavedSettings.getS32("WindowY"); + + mWindow->setPosition(LLCoordScreen ( windowX, windowY ) ); + } + } + + mIgnoreActivate = FALSE; + gFocusMgr.setKeyboardFocus(keyboard_focus); + + return success; + + */ +} + +F32 LLViewerWindow::getWorldViewAspectRatio() const +{ + F32 world_aspect = (F32)mWorldViewRectRaw.getWidth() / (F32)mWorldViewRectRaw.getHeight(); + return world_aspect; +} + +void LLViewerWindow::calcDisplayScale() +{ + F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor"); + LLVector2 display_scale; + display_scale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f)); + display_scale *= ui_scale_factor; + + // limit minimum display scale + if (display_scale.mV[VX] < MIN_DISPLAY_SCALE || display_scale.mV[VY] < MIN_DISPLAY_SCALE) + { + display_scale *= MIN_DISPLAY_SCALE / llmin(display_scale.mV[VX], display_scale.mV[VY]); + } + + if (display_scale != mDisplayScale) + { + llinfos << "Setting display scale to " << display_scale << llendl; + + mDisplayScale = display_scale; + // Init default fonts + initFonts(); + } +} + +//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]); + + return res; +} + +S32 LLViewerWindow::getChatConsoleBottomPad() +{ + S32 offset = 0; + + if(gToolBarView) + offset += gToolBarView->getChild<LLView>("bottom_toolbar_panel")->getRect().getHeight(); + + return offset; +} + +LLRect LLViewerWindow::getChatConsoleRect() +{ + LLRect full_window(0, getWindowHeightScaled(), getWindowWidthScaled(), 0); + LLRect console_rect = full_window; + + const S32 CONSOLE_PADDING_TOP = 24; + const S32 CONSOLE_PADDING_LEFT = 24; + const S32 CONSOLE_PADDING_RIGHT = 10; + + console_rect.mTop -= CONSOLE_PADDING_TOP; + console_rect.mBottom += getChatConsoleBottomPad(); + + console_rect.mLeft += CONSOLE_PADDING_LEFT; + + static const BOOL CHAT_FULL_WIDTH = gSavedSettings.getBOOL("ChatFullWidth"); + + if (CHAT_FULL_WIDTH) + { + console_rect.mRight -= CONSOLE_PADDING_RIGHT; + } + else + { + // Make console rect somewhat narrow so having inventory open is + // less of a problem. + console_rect.mRight = console_rect.mLeft + 2 * getWindowWidthScaled() / 3; + } + + return console_rect; +} +//---------------------------------------------------------------------------- + + +//static +bool LLViewerWindow::onAlert(const LLSD& notify) +{ + LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); + + if (gHeadlessClient) + { + llinfos << "Alert: " << notification->getName() << llendl; + } + + // 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( gAgentCamera.cameraMouselook() ) + { + gAgentCamera.changeCameraToDefault(); + } + return false; +} + +void LLViewerWindow::setUIVisibility(bool visible) +{ + mUIVisible = visible; + + if (!visible) + { + gAgentCamera.changeCameraToThirdPerson(FALSE); + gFloaterView->hideAllFloaters(); + } + else + { + gFloaterView->showHiddenFloaters(); + } + + if (gToolBarView) + { + gToolBarView->setToolBarsVisible(visible); + } + + LLNavigationBar::getInstance()->setVisible(visible ? gSavedSettings.getBOOL("ShowNavbarNavigationPanel") : FALSE); + LLPanelTopInfoBar::getInstance()->setVisible(visible? gSavedSettings.getBOOL("ShowMiniLocationPanel") : FALSE); + mRootView->getChildView("status_bar_container")->setVisible(visible); +} + +bool LLViewerWindow::getUIVisibility() +{ + return mUIVisible; +} + +//////////////////////////////////////////////////////////////////////////// +// +// LLPickInfo +// +LLPickInfo::LLPickInfo() + : mKeyMask(MASK_NONE), + mPickCallback(NULL), + mPickType(PICK_INVALID), + mWantSurfaceInfo(FALSE), + mObjectFace(-1), + mUVCoords(-1.f, -1.f), + mSTCoords(-1.f, -1.f), + mXYCoords(-1, -1), + mIntersection(), + mNormal(), + mBinormal(), + mHUDIcon(NULL), + mPickTransparent(FALSE) +{ +} + +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) +{ +} + +void LLPickInfo::fetchResults() +{ + + 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) + { + 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; + + 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())) + { + // was this name referring to a hud icon? + mHUDIcon = hit_icon; + mPickType = PICK_ICON; + mPosGlobal = mHUDIcon->getPositionGlobal(); + } + else if (objectp) + { + if( objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH ) + { + // Hit land + mPickType = PICK_LAND; + mObjectID.setNull(); // land has no id + + // put global position into land_pos + LLVector3d land_pos; + if (!gViewerWindow->mousePointOnLandGlobal(mPickPt.mX, mPickPt.mY, &land_pos)) + { + // The selected point is beyond the draw distance or is otherwise + // not selectable. Return before calling mPickCallback(). + return; + } + + // Fudge the land focus a little bit above ground. + mPosGlobal = land_pos + LLVector3d::z_axis * 0.1f; + } + else + { + if(isFlora(objectp)) + { + mPickType = PICK_FLORA; + } + else + { + mPickType = PICK_OBJECT; + } + mObjectOffset = gAgentCamera.calcFocusOffset(objectp, intersection, mPickPt.mX, mPickPt.mY); + mObjectID = objectp->mID; + mObjectFace = (te_offset == NO_FACE) ? -1 : (S32)te_offset; + + mPosGlobal = gAgent.getPosGlobalFromAgent(intersection); + + if (mWantSurfaceInfo) + { + getSurfaceInfo(); + } + } + } + + if (mPickCallback) + { + mPickCallback(*this); + } +} + +LLPointer<LLViewerObject> LLPickInfo::getObject() const +{ + return gObjectList.findObject( mObjectID ); +} + +void LLPickInfo::updateXYCoords() +{ + if (mObjectFace > -1) + { + const LLTextureEntry* tep = getObject()->getTE(mObjectFace); + LLPointer<LLViewerTexture> imagep = LLViewerTextureManager::getFetchedTexture(tep->getID()); + if(mUVCoords.mV[VX] >= 0.f && mUVCoords.mV[VY] >= 0.f && imagep.notNull()) + { + mXYCoords.mX = llround(mUVCoords.mV[VX] * (F32)imagep->getWidth()); + mXYCoords.mY = llround((1.f - mUVCoords.mV[VY]) * (F32)imagep->getHeight()); + } + } +} + +void LLPickInfo::getSurfaceInfo() +{ + // set values to uninitialized - this is what we return if no intersection is found + mObjectFace = -1; + mUVCoords = LLVector2(-1, -1); + mSTCoords = LLVector2(-1, -1); + mXYCoords = LLCoordScreen(-1, -1); + mIntersection = LLVector3(0,0,0); + mNormal = LLVector3(0,0,0); + mBinormal = LLVector3(0,0,0); + + 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(); + + } + } +} + + +/* code to get UV via a special UV render - removed in lieu of raycast method +LLVector2 LLPickInfo::pickUV() +{ + 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); + + 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) +{ + 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; +} diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 61ec02c4e2..a929d7a6dd 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -1,9806 +1,9806 @@ -/**
- * @file pipeline.cpp
- * @brief Rendering pipeline.
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "pipeline.h"
-
-// library includes
-#include "llaudioengine.h" // For debugging.
-#include "imageids.h"
-#include "llerror.h"
-#include "llviewercontrol.h"
-#include "llfasttimer.h"
-#include "llfontgl.h"
-#include "llmemtype.h"
-#include "llnamevalue.h"
-#include "llpointer.h"
-#include "llprimitive.h"
-#include "llvolume.h"
-#include "material_codes.h"
-#include "timing.h"
-#include "v3color.h"
-#include "llui.h"
-#include "llglheaders.h"
-#include "llrender.h"
-#include "llwindow.h" // swapBuffers()
-
-// newview includes
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "lldrawable.h"
-#include "lldrawpoolalpha.h"
-#include "lldrawpoolavatar.h"
-#include "lldrawpoolground.h"
-#include "lldrawpoolbump.h"
-#include "lldrawpooltree.h"
-#include "lldrawpoolwater.h"
-#include "llface.h"
-#include "llfeaturemanager.h"
-#include "llfloatertelehub.h"
-#include "llfloaterreg.h"
-#include "llgldbg.h"
-#include "llhudmanager.h"
-#include "llhudnametag.h"
-#include "llhudtext.h"
-#include "lllightconstants.h"
-#include "llmeshrepository.h"
-#include "llresmgr.h"
-#include "llselectmgr.h"
-#include "llsky.h"
-#include "lltracker.h"
-#include "lltool.h"
-#include "lltoolmgr.h"
-#include "llviewercamera.h"
-#include "llviewermediafocus.h"
-#include "llviewertexturelist.h"
-#include "llviewerobject.h"
-#include "llviewerobjectlist.h"
-#include "llviewerparcelmgr.h"
-#include "llviewerregion.h" // for audio debugging.
-#include "llviewerwindow.h" // For getSpinAxis
-#include "llvoavatarself.h"
-#include "llvoground.h"
-#include "llvosky.h"
-#include "llvotree.h"
-#include "llvovolume.h"
-#include "llvosurfacepatch.h"
-#include "llvowater.h"
-#include "llvotree.h"
-#include "llvopartgroup.h"
-#include "llworld.h"
-#include "llcubemap.h"
-#include "llviewershadermgr.h"
-#include "llviewerstats.h"
-#include "llviewerjoystick.h"
-#include "llviewerdisplay.h"
-#include "llwlparammanager.h"
-#include "llwaterparammanager.h"
-#include "llspatialpartition.h"
-#include "llmutelist.h"
-#include "lltoolpie.h"
-#include "llcurl.h"
-#include "llnotifications.h"
-#include "llphysicsextensions.h"
-
-#ifdef _DEBUG
-// Debug indices is disabled for now for debug performance - djs 4/24/02
-//#define DEBUG_INDICES
-#else
-//#define DEBUG_INDICES
-#endif
-
-//cached settings
-BOOL LLPipeline::RenderAvatarVP;
-BOOL LLPipeline::VertexShaderEnable;
-BOOL LLPipeline::WindLightUseAtmosShaders;
-BOOL LLPipeline::RenderDeferred;
-F32 LLPipeline::RenderDeferredSunWash;
-U32 LLPipeline::RenderFSAASamples;
-U32 LLPipeline::RenderResolutionDivisor;
-BOOL LLPipeline::RenderUIBuffer;
-S32 LLPipeline::RenderShadowDetail;
-BOOL LLPipeline::RenderDeferredSSAO;
-F32 LLPipeline::RenderShadowResolutionScale;
-BOOL LLPipeline::RenderLocalLights;
-BOOL LLPipeline::RenderDelayCreation;
-BOOL LLPipeline::RenderAnimateRes;
-BOOL LLPipeline::FreezeTime;
-S32 LLPipeline::DebugBeaconLineWidth;
-F32 LLPipeline::RenderHighlightBrightness;
-LLColor4 LLPipeline::RenderHighlightColor;
-F32 LLPipeline::RenderHighlightThickness;
-BOOL LLPipeline::RenderSpotLightsInNondeferred;
-LLColor4 LLPipeline::PreviewAmbientColor;
-LLColor4 LLPipeline::PreviewDiffuse0;
-LLColor4 LLPipeline::PreviewSpecular0;
-LLColor4 LLPipeline::PreviewDiffuse1;
-LLColor4 LLPipeline::PreviewSpecular1;
-LLColor4 LLPipeline::PreviewDiffuse2;
-LLColor4 LLPipeline::PreviewSpecular2;
-LLVector3 LLPipeline::PreviewDirection0;
-LLVector3 LLPipeline::PreviewDirection1;
-LLVector3 LLPipeline::PreviewDirection2;
-F32 LLPipeline::RenderGlowMinLuminance;
-F32 LLPipeline::RenderGlowMaxExtractAlpha;
-F32 LLPipeline::RenderGlowWarmthAmount;
-LLVector3 LLPipeline::RenderGlowLumWeights;
-LLVector3 LLPipeline::RenderGlowWarmthWeights;
-S32 LLPipeline::RenderGlowResolutionPow;
-S32 LLPipeline::RenderGlowIterations;
-F32 LLPipeline::RenderGlowWidth;
-F32 LLPipeline::RenderGlowStrength;
-BOOL LLPipeline::RenderDepthOfField;
-F32 LLPipeline::CameraFocusTransitionTime;
-F32 LLPipeline::CameraFNumber;
-F32 LLPipeline::CameraFocalLength;
-F32 LLPipeline::CameraFieldOfView;
-F32 LLPipeline::RenderShadowNoise;
-F32 LLPipeline::RenderShadowBlurSize;
-F32 LLPipeline::RenderSSAOScale;
-U32 LLPipeline::RenderSSAOMaxScale;
-F32 LLPipeline::RenderSSAOFactor;
-LLVector3 LLPipeline::RenderSSAOEffect;
-F32 LLPipeline::RenderShadowOffsetError;
-F32 LLPipeline::RenderShadowBiasError;
-F32 LLPipeline::RenderShadowOffset;
-F32 LLPipeline::RenderShadowBias;
-F32 LLPipeline::RenderSpotShadowOffset;
-F32 LLPipeline::RenderSpotShadowBias;
-F32 LLPipeline::RenderEdgeDepthCutoff;
-F32 LLPipeline::RenderEdgeNormCutoff;
-LLVector3 LLPipeline::RenderShadowGaussian;
-F32 LLPipeline::RenderShadowBlurDistFactor;
-BOOL LLPipeline::RenderDeferredAtmospheric;
-S32 LLPipeline::RenderReflectionDetail;
-F32 LLPipeline::RenderHighlightFadeTime;
-LLVector3 LLPipeline::RenderShadowClipPlanes;
-LLVector3 LLPipeline::RenderShadowOrthoClipPlanes;
-LLVector3 LLPipeline::RenderShadowNearDist;
-F32 LLPipeline::RenderFarClip;
-LLVector3 LLPipeline::RenderShadowSplitExponent;
-F32 LLPipeline::RenderShadowErrorCutoff;
-F32 LLPipeline::RenderShadowFOVCutoff;
-BOOL LLPipeline::CameraOffset;
-F32 LLPipeline::CameraMaxCoF;
-F32 LLPipeline::CameraDoFResScale;
-
-const F32 BACKLIGHT_DAY_MAGNITUDE_AVATAR = 0.2f;
-const F32 BACKLIGHT_NIGHT_MAGNITUDE_AVATAR = 0.1f;
-const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f;
-const F32 BACKLIGHT_NIGHT_MAGNITUDE_OBJECT = 0.08f;
-const S32 MAX_OFFSCREEN_GEOMETRY_CHANGES_PER_FRAME = 10;
-const U32 REFLECTION_MAP_RES = 128;
-const U32 DEFERRED_VB_MASK = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1;
-// Max number of occluders to search for. JC
-const S32 MAX_OCCLUDER_COUNT = 2;
-
-extern S32 gBoxFrame;
-//extern BOOL gHideSelectedObjects;
-extern BOOL gDisplaySwapBuffers;
-extern BOOL gDebugGL;
-
-// hack counter for rendering a fixed number of frames after toggling
-// fullscreen to work around DEV-5361
-static S32 sDelayedVBOEnable = 0;
-
-BOOL gAvatarBacklight = FALSE;
-
-BOOL gDebugPipeline = FALSE;
-LLPipeline gPipeline;
-const LLMatrix4* gGLLastMatrix = NULL;
-
-LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Geometry");
-LLFastTimer::DeclareTimer FTM_RENDER_GRASS("Grass");
-LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE("Invisible");
-LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION("Occlusion");
-LLFastTimer::DeclareTimer FTM_RENDER_SHINY("Shiny");
-LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE("Simple");
-LLFastTimer::DeclareTimer FTM_RENDER_TERRAIN("Terrain");
-LLFastTimer::DeclareTimer FTM_RENDER_TREES("Trees");
-LLFastTimer::DeclareTimer FTM_RENDER_UI("UI");
-LLFastTimer::DeclareTimer FTM_RENDER_WATER("Water");
-LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY("Windlight Sky");
-LLFastTimer::DeclareTimer FTM_RENDER_ALPHA("Alpha Objects");
-LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS("Avatars");
-LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump");
-LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright");
-LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow");
-LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update");
-LLFastTimer::DeclareTimer FTM_POOLRENDER("RenderPool");
-LLFastTimer::DeclareTimer FTM_POOLS("Pools");
-LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO");
-LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State");
-LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline");
-LLFastTimer::DeclareTimer FTM_CLIENT_COPY("Client Copy");
-LLFastTimer::DeclareTimer FTM_RENDER_DEFERRED("Deferred Shading");
-
-
-static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables");
-static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort");
-
-//----------------------------------------
-std::string gPoolNames[] =
-{
- // Correspond to LLDrawpool enum render type
- "NONE",
- "POOL_SIMPLE",
- "POOL_GROUND",
- "POOL_FULLBRIGHT",
- "POOL_BUMP",
- "POOL_TERRAIN,"
- "POOL_SKY",
- "POOL_WL_SKY",
- "POOL_TREE",
- "POOL_GRASS",
- "POOL_INVISIBLE",
- "POOL_AVATAR",
- "POOL_VOIDWATER",
- "POOL_WATER",
- "POOL_GLOW",
- "POOL_ALPHA"
-};
-
-void drawBox(const LLVector3& c, const LLVector3& r);
-void drawBoxOutline(const LLVector3& pos, const LLVector3& size);
-U32 nhpo2(U32 v);
-
-glh::matrix4f glh_copy_matrix(F32* src)
-{
- glh::matrix4f ret;
- ret.set_value(src);
- return ret;
-}
-
-glh::matrix4f glh_get_current_modelview()
-{
- return glh_copy_matrix(gGLModelView);
-}
-
-glh::matrix4f glh_get_current_projection()
-{
- return glh_copy_matrix(gGLProjection);
-}
-
-glh::matrix4f glh_get_last_modelview()
-{
- return glh_copy_matrix(gGLLastModelView);
-}
-
-glh::matrix4f glh_get_last_projection()
-{
- return glh_copy_matrix(gGLLastProjection);
-}
-
-void glh_copy_matrix(const glh::matrix4f& src, F32* dst)
-{
- for (U32 i = 0; i < 16; i++)
- {
- dst[i] = src.m[i];
- }
-}
-
-void glh_set_current_modelview(const glh::matrix4f& mat)
-{
- glh_copy_matrix(mat, gGLModelView);
-}
-
-void glh_set_current_projection(glh::matrix4f& mat)
-{
- glh_copy_matrix(mat, gGLProjection);
-}
-
-glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar)
-{
- glh::matrix4f ret(
- 2.f/(right-left), 0.f, 0.f, -(right+left)/(right-left),
- 0.f, 2.f/(top-bottom), 0.f, -(top+bottom)/(top-bottom),
- 0.f, 0.f, -2.f/(zfar-znear), -(zfar+znear)/(zfar-znear),
- 0.f, 0.f, 0.f, 1.f);
-
- return ret;
-}
-
-void display_update_camera();
-//----------------------------------------
-
-S32 LLPipeline::sCompiles = 0;
-
-BOOL LLPipeline::sPickAvatar = TRUE;
-BOOL LLPipeline::sDynamicLOD = TRUE;
-BOOL LLPipeline::sShowHUDAttachments = TRUE;
-BOOL LLPipeline::sRenderMOAPBeacons = FALSE;
-BOOL LLPipeline::sRenderPhysicalBeacons = TRUE;
-BOOL LLPipeline::sRenderScriptedBeacons = FALSE;
-BOOL LLPipeline::sRenderScriptedTouchBeacons = TRUE;
-BOOL LLPipeline::sRenderParticleBeacons = FALSE;
-BOOL LLPipeline::sRenderSoundBeacons = FALSE;
-BOOL LLPipeline::sRenderBeacons = FALSE;
-BOOL LLPipeline::sRenderHighlight = TRUE;
-BOOL LLPipeline::sForceOldBakedUpload = FALSE;
-S32 LLPipeline::sUseOcclusion = 0;
-BOOL LLPipeline::sDelayVBUpdate = TRUE;
-BOOL LLPipeline::sAutoMaskAlphaDeferred = TRUE;
-BOOL LLPipeline::sAutoMaskAlphaNonDeferred = FALSE;
-BOOL LLPipeline::sDisableShaders = FALSE;
-BOOL LLPipeline::sRenderBump = TRUE;
-BOOL LLPipeline::sBakeSunlight = FALSE;
-BOOL LLPipeline::sNoAlpha = FALSE;
-BOOL LLPipeline::sUseTriStrips = TRUE;
-BOOL LLPipeline::sUseFarClip = TRUE;
-BOOL LLPipeline::sShadowRender = FALSE;
-BOOL LLPipeline::sWaterReflections = FALSE;
-BOOL LLPipeline::sRenderGlow = FALSE;
-BOOL LLPipeline::sReflectionRender = FALSE;
-BOOL LLPipeline::sImpostorRender = FALSE;
-BOOL LLPipeline::sUnderWaterRender = FALSE;
-BOOL LLPipeline::sTextureBindTest = FALSE;
-BOOL LLPipeline::sRenderFrameTest = FALSE;
-BOOL LLPipeline::sRenderAttachedLights = TRUE;
-BOOL LLPipeline::sRenderAttachedParticles = TRUE;
-BOOL LLPipeline::sRenderDeferred = FALSE;
-BOOL LLPipeline::sMemAllocationThrottled = FALSE;
-S32 LLPipeline::sVisibleLightCount = 0;
-F32 LLPipeline::sMinRenderSize = 0.f;
-
-
-static LLCullResult* sCull = NULL;
-
-static const U32 gl_cube_face[] =
-{
- GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
- GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
- GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
-};
-
-void validate_framebuffer_object();
-
-
-bool addDeferredAttachments(LLRenderTarget& target)
-{
- return target.addColorAttachment(GL_RGBA) && //specular
- target.addColorAttachment(GL_RGBA); //normal+z
-}
-
-LLPipeline::LLPipeline() :
- mBackfaceCull(FALSE),
- mBatchCount(0),
- mMatrixOpCount(0),
- mTextureMatrixOps(0),
- mMaxBatchSize(0),
- mMinBatchSize(0),
- mMeanBatchSize(0),
- mTrianglesDrawn(0),
- mNumVisibleNodes(0),
- mVerticesRelit(0),
- mLightingChanges(0),
- mGeometryChanges(0),
- mNumVisibleFaces(0),
-
- mInitialized(FALSE),
- mVertexShadersEnabled(FALSE),
- mVertexShadersLoaded(0),
- mRenderDebugFeatureMask(0),
- mRenderDebugMask(0),
- mOldRenderDebugMask(0),
- mGroupQ1Locked(false),
- mGroupQ2Locked(false),
- mLastRebuildPool(NULL),
- mAlphaPool(NULL),
- mSkyPool(NULL),
- mTerrainPool(NULL),
- mWaterPool(NULL),
- mGroundPool(NULL),
- mSimplePool(NULL),
- mFullbrightPool(NULL),
- mInvisiblePool(NULL),
- mGlowPool(NULL),
- mBumpPool(NULL),
- mWLSkyPool(NULL),
- mLightMask(0),
- mLightMovingMask(0),
- mLightingDetail(0),
- mScreenWidth(0),
- mScreenHeight(0)
-{
- mNoiseMap = 0;
- mTrueNoiseMap = 0;
- mLightFunc = 0;
-}
-
-void LLPipeline::init()
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_INIT);
-
- refreshCachedSettings();
-
- gOctreeMaxCapacity = gSavedSettings.getU32("OctreeMaxNodeCapacity");
- sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD");
- sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
- sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
- LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
- LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO");
- LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw");
- sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
- sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles");
-
- mInitialized = TRUE;
-
- stop_glerror();
-
- //create render pass pools
- getPool(LLDrawPool::POOL_ALPHA);
- getPool(LLDrawPool::POOL_SIMPLE);
- getPool(LLDrawPool::POOL_GRASS);
- getPool(LLDrawPool::POOL_FULLBRIGHT);
- getPool(LLDrawPool::POOL_INVISIBLE);
- getPool(LLDrawPool::POOL_BUMP);
- getPool(LLDrawPool::POOL_GLOW);
-
- LLViewerStats::getInstance()->mTrianglesDrawnStat.reset();
- resetFrameStats();
-
- for (U32 i = 0; i < NUM_RENDER_TYPES; ++i)
- {
- mRenderTypeEnabled[i] = TRUE; //all rendering types start enabled
- }
-
- mRenderDebugFeatureMask = 0xffffffff; // All debugging features on
- mRenderDebugMask = 0; // All debug starts off
-
- // Don't turn on ground when this is set
- // Mac Books with intel 950s need this
- if(!gSavedSettings.getBOOL("RenderGround"))
- {
- toggleRenderType(RENDER_TYPE_GROUND);
- }
-
- // make sure RenderPerformanceTest persists (hackity hack hack)
- // disables non-object rendering (UI, sky, water, etc)
- if (gSavedSettings.getBOOL("RenderPerformanceTest"))
- {
- gSavedSettings.setBOOL("RenderPerformanceTest", FALSE);
- gSavedSettings.setBOOL("RenderPerformanceTest", TRUE);
- }
-
- mOldRenderDebugMask = mRenderDebugMask;
-
- mBackfaceCull = TRUE;
-
- stop_glerror();
-
- // Enable features
-
- LLViewerShaderMgr::instance()->setShaders();
-
- stop_glerror();
-
- for (U32 i = 0; i < 2; ++i)
- {
- mSpotLightFade[i] = 1.f;
- }
-
- mDeferredVB = new LLVertexBuffer(DEFERRED_VB_MASK, 0);
- mDeferredVB->allocateBuffer(8, 0, true);
- setLightingDetail(-1);
-
- //
- // Update all settings to trigger a cached settings refresh
- //
-
- gSavedSettings.getControl("RenderAutoMaskAlphaDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderUseFarClip")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderAvatarMaxVisible")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderDelayVBUpdate")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
-
- gSavedSettings.getControl("UseOcclusion")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
-
- gSavedSettings.getControl("VertexShaderEnable")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderAvatarVP")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("WindLightUseAtmosShaders")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderDeferredSunWash")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderFSAASamples")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderResolutionDivisor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderUIBuffer")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderShadowDetail")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderDeferredSSAO")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderShadowResolutionScale")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderLocalLights")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderDelayCreation")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderAnimateRes")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("FreezeTime")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("DebugBeaconLineWidth")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderHighlightBrightness")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderHighlightColor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderHighlightThickness")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderSpotLightsInNondeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("PreviewAmbientColor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("PreviewDiffuse0")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("PreviewSpecular0")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("PreviewDiffuse1")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("PreviewSpecular1")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("PreviewDiffuse2")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("PreviewSpecular2")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("PreviewDirection0")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("PreviewDirection1")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("PreviewDirection2")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderGlowMinLuminance")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderGlowMaxExtractAlpha")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderGlowWarmthAmount")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderGlowLumWeights")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderGlowWarmthWeights")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderGlowResolutionPow")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderGlowIterations")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderGlowWidth")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderGlowStrength")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderDepthOfField")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("CameraFocusTransitionTime")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("CameraFNumber")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("CameraFocalLength")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("CameraFieldOfView")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderShadowNoise")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderShadowBlurSize")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderSSAOScale")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderSSAOMaxScale")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderSSAOFactor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderSSAOEffect")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderShadowOffsetError")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderShadowBiasError")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderShadowOffset")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderShadowBias")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderSpotShadowOffset")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderSpotShadowBias")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderEdgeDepthCutoff")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderEdgeNormCutoff")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderShadowGaussian")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderShadowBlurDistFactor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderDeferredAtmospheric")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderReflectionDetail")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderHighlightFadeTime")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderShadowClipPlanes")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderShadowOrthoClipPlanes")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderShadowNearDist")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderFarClip")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderShadowSplitExponent")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderShadowErrorCutoff")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("RenderShadowFOVCutoff")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("CameraOffset")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("CameraMaxCoF")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
- gSavedSettings.getControl("CameraDoFResScale")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
-}
-
-LLPipeline::~LLPipeline()
-{
-
-}
-
-void LLPipeline::cleanup()
-{
- assertInitialized();
-
- mGroupQ1.clear() ;
- mGroupQ2.clear() ;
-
- for(pool_set_t::iterator iter = mPools.begin();
- iter != mPools.end(); )
- {
- pool_set_t::iterator curiter = iter++;
- LLDrawPool* poolp = *curiter;
- if (poolp->isFacePool())
- {
- LLFacePool* face_pool = (LLFacePool*) poolp;
- if (face_pool->mReferences.empty())
- {
- mPools.erase(curiter);
- removeFromQuickLookup( poolp );
- delete poolp;
- }
- }
- else
- {
- mPools.erase(curiter);
- removeFromQuickLookup( poolp );
- delete poolp;
- }
- }
-
- if (!mTerrainPools.empty())
- {
- llwarns << "Terrain Pools not cleaned up" << llendl;
- }
- if (!mTreePools.empty())
- {
- llwarns << "Tree Pools not cleaned up" << llendl;
- }
-
- delete mAlphaPool;
- mAlphaPool = NULL;
- delete mSkyPool;
- mSkyPool = NULL;
- delete mTerrainPool;
- mTerrainPool = NULL;
- delete mWaterPool;
- mWaterPool = NULL;
- delete mGroundPool;
- mGroundPool = NULL;
- delete mSimplePool;
- mSimplePool = NULL;
- delete mFullbrightPool;
- mFullbrightPool = NULL;
- delete mInvisiblePool;
- mInvisiblePool = NULL;
- delete mGlowPool;
- mGlowPool = NULL;
- delete mBumpPool;
- mBumpPool = NULL;
- // don't delete wl sky pool it was handled above in the for loop
- //delete mWLSkyPool;
- mWLSkyPool = NULL;
-
- releaseGLBuffers();
-
- mFaceSelectImagep = NULL;
-
- mMovedBridge.clear();
-
- mInitialized = FALSE;
-
- mDeferredVB = NULL;
-}
-
-//============================================================================
-
-void LLPipeline::destroyGL()
-{
- stop_glerror();
- unloadShaders();
- mHighlightFaces.clear();
-
- resetDrawOrders();
-
- resetVertexBuffers();
-
- releaseGLBuffers();
-
- if (LLVertexBuffer::sEnableVBOs)
- {
- // render 30 frames after switching to work around DEV-5361
- sDelayedVBOEnable = 30;
- LLVertexBuffer::sEnableVBOs = FALSE;
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture");
-
-//static
-void LLPipeline::throttleNewMemoryAllocation(BOOL disable)
-{
- if(sMemAllocationThrottled != disable)
- {
- sMemAllocationThrottled = disable ;
-
- if(sMemAllocationThrottled)
- {
- //send out notification
- LLNotification::Params params("LowMemory");
- LLNotifications::instance().add(params);
-
- //release some memory.
- }
- }
-}
-
-void LLPipeline::resizeScreenTexture()
-{
- LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE);
- if (gPipeline.canUseVertexShaders() && assertInitialized())
- {
- GLuint resX = gViewerWindow->getWorldViewWidthRaw();
- GLuint resY = gViewerWindow->getWorldViewHeightRaw();
-
- allocateScreenBuffer(resX,resY);
- }
-}
-
-void LLPipeline::allocatePhysicsBuffer()
-{
- GLuint resX = gViewerWindow->getWorldViewWidthRaw();
- GLuint resY = gViewerWindow->getWorldViewHeightRaw();
-
- if (mPhysicsDisplay.getWidth() != resX || mPhysicsDisplay.getHeight() != resY)
- {
- mPhysicsDisplay.allocate(resX, resY, GL_RGBA, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
- }
-}
-
-void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
-{
- refreshCachedSettings();
- U32 samples = RenderFSAASamples;
-
- //try to allocate screen buffers at requested resolution and samples
- // - on failure, shrink number of samples and try again
- // - if not multisampled, shrink resolution and try again (favor X resolution over Y)
- // Make sure to call "releaseScreenBuffers" after each failure to cleanup the partially loaded state
-
- if (!allocateScreenBuffer(resX, resY, samples))
- {
- releaseScreenBuffers();
- //reduce number of samples
- while (samples > 0)
- {
- samples /= 2;
- if (allocateScreenBuffer(resX, resY, samples))
- { //success
- return;
- }
- releaseScreenBuffers();
- }
-
- samples = 0;
-
- //reduce resolution
- while (resY > 0 && resX > 0)
- {
- resY /= 2;
- if (allocateScreenBuffer(resX, resY, samples))
- {
- return;
- }
- releaseScreenBuffers();
-
- resX /= 2;
- if (allocateScreenBuffer(resX, resY, samples))
- {
- return;
- }
- releaseScreenBuffers();
- }
-
- llwarns << "Unable to allocate screen buffer at any resolution!" << llendl;
- }
-}
-
-
-bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
-{
- refreshCachedSettings();
-
- // remember these dimensions
- mScreenWidth = resX;
- mScreenHeight = resY;
-
- U32 res_mod = RenderResolutionDivisor;
-
- if (res_mod > 1 && res_mod < resX && res_mod < resY)
- {
- resX /= res_mod;
- resY /= res_mod;
- }
-
- if (RenderUIBuffer)
- {
- if (!mUIScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE))
- {
- return false;
- }
- }
-
- if (LLPipeline::sRenderDeferred)
- {
- S32 shadow_detail = RenderShadowDetail;
- BOOL ssao = RenderDeferredSSAO;
-
- //allocate deferred rendering color buffers
- if (!mDeferredScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
- if (!mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
- if (!addDeferredAttachments(mDeferredScreen)) return false;
-
- if (!mScreen.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
- if (samples > 0)
- {
- if (!mFXAABuffer.allocate(nhpo2(resX), nhpo2(resY), GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE, samples)) return false;
- }
- else
- {
- mFXAABuffer.release();
- }
-
- if (shadow_detail > 0 || ssao || RenderDepthOfField || samples > 0)
- { //only need mDeferredLight for shadows OR ssao OR dof OR fxaa
- if (!mDeferredLight.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false;
- }
- else
- {
- mDeferredLight.release();
- }
-
- F32 scale = RenderShadowResolutionScale;
-
- if (shadow_detail > 0)
- { //allocate 4 sun shadow maps
- for (U32 i = 0; i < 4; i++)
- {
- if (!mShadow[i].allocate(U32(resX*scale),U32(resY*scale), 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE)) return false;
- }
- }
- else
- {
- for (U32 i = 0; i < 4; i++)
- {
- mShadow[i].release();
- }
- }
-
- U32 width = nhpo2(U32(resX*scale))/2;
- U32 height = width;
-
- if (shadow_detail > 1)
- { //allocate two spot shadow maps
- for (U32 i = 4; i < 6; i++)
- {
- if (!mShadow[i].allocate(width, height, 0, TRUE, FALSE)) return false;
- }
- }
- else
- {
- for (U32 i = 4; i < 6; i++)
- {
- mShadow[i].release();
- }
- }
- }
- else
- {
- mDeferredLight.release();
-
- for (U32 i = 0; i < 6; i++)
- {
- mShadow[i].release();
- }
- mFXAABuffer.release();
- mScreen.release();
- mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first
- mDeferredDepth.release();
-
- if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false;
- }
-
- if (LLPipeline::sRenderDeferred)
- { //share depth buffer between deferred targets
- mDeferredScreen.shareDepthBuffer(mScreen);
- }
-
- gGL.getTexUnit(0)->disable();
-
- stop_glerror();
-
- return true;
-}
-
-//static
-void LLPipeline::updateRenderDeferred()
-{
- BOOL deferred = ((RenderDeferred &&
- LLRenderTarget::sUseFBO &&
- LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
- VertexShaderEnable &&
- RenderAvatarVP &&
- WindLightUseAtmosShaders) ? TRUE : FALSE) &&
- !gUseWireframe;
-
- sRenderDeferred = deferred;
- if (deferred)
- { //must render glow when rendering deferred since post effect pass is needed to present any lighting at all
- sRenderGlow = TRUE;
- }
-}
-
-//static
-void LLPipeline::refreshCachedSettings()
-{
- LLPipeline::sAutoMaskAlphaDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaDeferred");
- LLPipeline::sAutoMaskAlphaNonDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaNonDeferred");
- LLPipeline::sUseFarClip = gSavedSettings.getBOOL("RenderUseFarClip");
- LLVOAvatar::sMaxVisible = (U32)gSavedSettings.getS32("RenderAvatarMaxVisible");
- LLPipeline::sDelayVBUpdate = gSavedSettings.getBOOL("RenderDelayVBUpdate");
-
- LLPipeline::sUseOcclusion =
- (!gUseWireframe
- && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion")
- && gSavedSettings.getBOOL("UseOcclusion")
- && gGLManager.mHasOcclusionQuery) ? 2 : 0;
-
- VertexShaderEnable = gSavedSettings.getBOOL("VertexShaderEnable");
- RenderAvatarVP = gSavedSettings.getBOOL("RenderAvatarVP");
- WindLightUseAtmosShaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders");
- RenderDeferred = gSavedSettings.getBOOL("RenderDeferred");
- RenderDeferredSunWash = gSavedSettings.getF32("RenderDeferredSunWash");
- RenderFSAASamples = gSavedSettings.getU32("RenderFSAASamples");
- RenderResolutionDivisor = gSavedSettings.getU32("RenderResolutionDivisor");
- RenderUIBuffer = gSavedSettings.getBOOL("RenderUIBuffer");
- RenderShadowDetail = gSavedSettings.getS32("RenderShadowDetail");
- RenderDeferredSSAO = gSavedSettings.getBOOL("RenderDeferredSSAO");
- RenderShadowResolutionScale = gSavedSettings.getF32("RenderShadowResolutionScale");
- RenderLocalLights = gSavedSettings.getBOOL("RenderLocalLights");
- RenderDelayCreation = gSavedSettings.getBOOL("RenderDelayCreation");
- RenderAnimateRes = gSavedSettings.getBOOL("RenderAnimateRes");
- FreezeTime = gSavedSettings.getBOOL("FreezeTime");
- DebugBeaconLineWidth = gSavedSettings.getS32("DebugBeaconLineWidth");
- RenderHighlightBrightness = gSavedSettings.getF32("RenderHighlightBrightness");
- RenderHighlightColor = gSavedSettings.getColor4("RenderHighlightColor");
- RenderHighlightThickness = gSavedSettings.getF32("RenderHighlightThickness");
- RenderSpotLightsInNondeferred = gSavedSettings.getBOOL("RenderSpotLightsInNondeferred");
- PreviewAmbientColor = gSavedSettings.getColor4("PreviewAmbientColor");
- PreviewDiffuse0 = gSavedSettings.getColor4("PreviewDiffuse0");
- PreviewSpecular0 = gSavedSettings.getColor4("PreviewSpecular0");
- PreviewDiffuse1 = gSavedSettings.getColor4("PreviewDiffuse1");
- PreviewSpecular1 = gSavedSettings.getColor4("PreviewSpecular1");
- PreviewDiffuse2 = gSavedSettings.getColor4("PreviewDiffuse2");
- PreviewSpecular2 = gSavedSettings.getColor4("PreviewSpecular2");
- PreviewDirection0 = gSavedSettings.getVector3("PreviewDirection0");
- PreviewDirection1 = gSavedSettings.getVector3("PreviewDirection1");
- PreviewDirection2 = gSavedSettings.getVector3("PreviewDirection2");
- RenderGlowMinLuminance = gSavedSettings.getF32("RenderGlowMinLuminance");
- RenderGlowMaxExtractAlpha = gSavedSettings.getF32("RenderGlowMaxExtractAlpha");
- RenderGlowWarmthAmount = gSavedSettings.getF32("RenderGlowWarmthAmount");
- RenderGlowLumWeights = gSavedSettings.getVector3("RenderGlowLumWeights");
- RenderGlowWarmthWeights = gSavedSettings.getVector3("RenderGlowWarmthWeights");
- RenderGlowResolutionPow = gSavedSettings.getS32("RenderGlowResolutionPow");
- RenderGlowIterations = gSavedSettings.getS32("RenderGlowIterations");
- RenderGlowWidth = gSavedSettings.getF32("RenderGlowWidth");
- RenderGlowStrength = gSavedSettings.getF32("RenderGlowStrength");
- RenderDepthOfField = gSavedSettings.getBOOL("RenderDepthOfField");
- CameraFocusTransitionTime = gSavedSettings.getF32("CameraFocusTransitionTime");
- CameraFNumber = gSavedSettings.getF32("CameraFNumber");
- CameraFocalLength = gSavedSettings.getF32("CameraFocalLength");
- CameraFieldOfView = gSavedSettings.getF32("CameraFieldOfView");
- RenderShadowNoise = gSavedSettings.getF32("RenderShadowNoise");
- RenderShadowBlurSize = gSavedSettings.getF32("RenderShadowBlurSize");
- RenderSSAOScale = gSavedSettings.getF32("RenderSSAOScale");
- RenderSSAOMaxScale = gSavedSettings.getU32("RenderSSAOMaxScale");
- RenderSSAOFactor = gSavedSettings.getF32("RenderSSAOFactor");
- RenderSSAOEffect = gSavedSettings.getVector3("RenderSSAOEffect");
- RenderShadowOffsetError = gSavedSettings.getF32("RenderShadowOffsetError");
- RenderShadowBiasError = gSavedSettings.getF32("RenderShadowBiasError");
- RenderShadowOffset = gSavedSettings.getF32("RenderShadowOffset");
- RenderShadowBias = gSavedSettings.getF32("RenderShadowBias");
- RenderSpotShadowOffset = gSavedSettings.getF32("RenderSpotShadowOffset");
- RenderSpotShadowBias = gSavedSettings.getF32("RenderSpotShadowBias");
- RenderEdgeDepthCutoff = gSavedSettings.getF32("RenderEdgeDepthCutoff");
- RenderEdgeNormCutoff = gSavedSettings.getF32("RenderEdgeNormCutoff");
- RenderShadowGaussian = gSavedSettings.getVector3("RenderShadowGaussian");
- RenderShadowBlurDistFactor = gSavedSettings.getF32("RenderShadowBlurDistFactor");
- RenderDeferredAtmospheric = gSavedSettings.getBOOL("RenderDeferredAtmospheric");
- RenderReflectionDetail = gSavedSettings.getS32("RenderReflectionDetail");
- RenderHighlightFadeTime = gSavedSettings.getF32("RenderHighlightFadeTime");
- RenderShadowClipPlanes = gSavedSettings.getVector3("RenderShadowClipPlanes");
- RenderShadowOrthoClipPlanes = gSavedSettings.getVector3("RenderShadowOrthoClipPlanes");
- RenderShadowNearDist = gSavedSettings.getVector3("RenderShadowNearDist");
- RenderFarClip = gSavedSettings.getF32("RenderFarClip");
- RenderShadowSplitExponent = gSavedSettings.getVector3("RenderShadowSplitExponent");
- RenderShadowErrorCutoff = gSavedSettings.getF32("RenderShadowErrorCutoff");
- RenderShadowFOVCutoff = gSavedSettings.getF32("RenderShadowFOVCutoff");
- CameraOffset = gSavedSettings.getBOOL("CameraOffset");
- CameraMaxCoF = gSavedSettings.getF32("CameraMaxCoF");
- CameraDoFResScale = gSavedSettings.getF32("CameraDoFResScale");
-
- updateRenderDeferred();
-}
-
-void LLPipeline::releaseGLBuffers()
-{
- assertInitialized();
-
- if (mNoiseMap)
- {
- LLImageGL::deleteTextures(1, &mNoiseMap);
- mNoiseMap = 0;
- }
-
- if (mTrueNoiseMap)
- {
- LLImageGL::deleteTextures(1, &mTrueNoiseMap);
- mTrueNoiseMap = 0;
- }
-
- if (mLightFunc)
- {
- LLImageGL::deleteTextures(1, &mLightFunc);
- mLightFunc = 0;
- }
-
- mWaterRef.release();
- mWaterDis.release();
-
- for (U32 i = 0; i < 3; i++)
- {
- mGlow[i].release();
- }
-
- releaseScreenBuffers();
-
- gBumpImageList.destroyGL();
- LLVOAvatar::resetImpostors();
-}
-
-void LLPipeline::releaseScreenBuffers()
-{
- mUIScreen.release();
- mScreen.release();
- mFXAABuffer.release();
- mPhysicsDisplay.release();
- mDeferredScreen.release();
- mDeferredDepth.release();
- mDeferredLight.release();
-
- mHighlight.release();
-
- for (U32 i = 0; i < 6; i++)
- {
- mShadow[i].release();
- }
-}
-
-
-void LLPipeline::createGLBuffers()
-{
- stop_glerror();
- LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_CREATE_BUFFERS);
- assertInitialized();
-
- updateRenderDeferred();
-
- if (LLPipeline::sWaterReflections)
- { //water reflection texture
- U32 res = (U32) gSavedSettings.getS32("RenderWaterRefResolution");
-
- mWaterRef.allocate(res,res,GL_RGBA,TRUE,FALSE);
- mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE);
- }
-
- mHighlight.allocate(256,256,GL_RGBA, FALSE, FALSE);
-
- stop_glerror();
-
- GLuint resX = gViewerWindow->getWorldViewWidthRaw();
- GLuint resY = gViewerWindow->getWorldViewHeightRaw();
-
- if (LLPipeline::sRenderGlow)
- { //screen space glow buffers
- const U32 glow_res = llmax(1,
- llmin(512, 1 << gSavedSettings.getS32("RenderGlowResolutionPow")));
-
- for (U32 i = 0; i < 3; i++)
- {
- mGlow[i].allocate(512,glow_res,GL_RGBA,FALSE,FALSE);
- }
-
- allocateScreenBuffer(resX,resY);
- mScreenWidth = 0;
- mScreenHeight = 0;
- }
-
- if (sRenderDeferred)
- {
- if (!mNoiseMap)
- {
- const U32 noiseRes = 128;
- LLVector3 noise[noiseRes*noiseRes];
-
- F32 scaler = gSavedSettings.getF32("RenderDeferredNoise")/100.f;
- for (U32 i = 0; i < noiseRes*noiseRes; ++i)
- {
- noise[i] = LLVector3(ll_frand()-0.5f, ll_frand()-0.5f, 0.f);
- noise[i].normVec();
- noise[i].mV[2] = ll_frand()*scaler+1.f-scaler/2.f;
- }
-
- LLImageGL::generateTextures(1, &mNoiseMap);
-
- gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap);
- LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- if (!mTrueNoiseMap)
- {
- const U32 noiseRes = 128;
- F32 noise[noiseRes*noiseRes*3];
- for (U32 i = 0; i < noiseRes*noiseRes*3; i++)
- {
- noise[i] = ll_frand()*2.0-1.0;
- }
-
- LLImageGL::generateTextures(1, &mTrueNoiseMap);
- gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap);
- LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- if (!mLightFunc)
- {
- U32 lightResX = gSavedSettings.getU32("RenderSpecularResX");
- U32 lightResY = gSavedSettings.getU32("RenderSpecularResY");
- U8* lg = new U8[lightResX*lightResY];
-
- for (U32 y = 0; y < lightResY; ++y)
- {
- for (U32 x = 0; x < lightResX; ++x)
- {
- //spec func
- F32 sa = (F32) x/(lightResX-1);
- F32 spec = (F32) y/(lightResY-1);
- //lg[y*lightResX+x] = (U8) (powf(sa, 128.f*spec*spec)*255);
-
- //F32 sp = acosf(sa)/(1.f-spec);
-
- sa = powf(sa, gSavedSettings.getF32("RenderSpecularExponent"));
- F32 a = acosf(sa*0.25f+0.75f);
- F32 m = llmax(0.5f-spec*0.5f, 0.001f);
- F32 t2 = tanf(a)/m;
- t2 *= t2;
-
- F32 c4a = (3.f+4.f*cosf(2.f*a)+cosf(4.f*a))/8.f;
- F32 bd = 1.f/(4.f*m*m*c4a)*powf(F_E, -t2);
-
- lg[y*lightResX+x] = (U8) (llclamp(bd, 0.f, 1.f)*255);
- }
- }
-
- LLImageGL::generateTextures(1, &mLightFunc);
- gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
- LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_R8, lightResX, lightResY, GL_RED, GL_UNSIGNED_BYTE, lg);
- gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
-
- delete [] lg;
- }
- }
-
- gBumpImageList.restoreGL();
-}
-
-void LLPipeline::restoreGL()
-{
- LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_RESTORE_GL);
- assertInitialized();
-
- if (mVertexShadersEnabled)
- {
- LLViewerShaderMgr::instance()->setShaders();
- }
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- part->restoreGL();
- }
- }
- }
-}
-
-
-BOOL LLPipeline::canUseVertexShaders()
-{
- if (sDisableShaders ||
- !gGLManager.mHasVertexShader ||
- !gGLManager.mHasFragmentShader ||
- !LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable") ||
- (assertInitialized() && mVertexShadersLoaded != 1) )
- {
- return FALSE;
- }
- else
- {
- return TRUE;
- }
-}
-
-BOOL LLPipeline::canUseWindLightShaders() const
-{
- return (!LLPipeline::sDisableShaders &&
- gWLSkyProgram.mProgramObject != 0 &&
- LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1);
-}
-
-BOOL LLPipeline::canUseWindLightShadersOnObjects() const
-{
- return (canUseWindLightShaders()
- && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0);
-}
-
-BOOL LLPipeline::canUseAntiAliasing() const
-{
- return TRUE;
-}
-
-void LLPipeline::unloadShaders()
-{
- LLMemType mt_us(LLMemType::MTYPE_PIPELINE_UNLOAD_SHADERS);
- LLViewerShaderMgr::instance()->unloadShaders();
-
- mVertexShadersLoaded = 0;
-}
-
-void LLPipeline::assertInitializedDoError()
-{
- llerrs << "LLPipeline used when uninitialized." << llendl;
-}
-
-//============================================================================
-
-void LLPipeline::enableShadows(const BOOL enable_shadows)
-{
- //should probably do something here to wrangle shadows....
-}
-
-S32 LLPipeline::getMaxLightingDetail() const
-{
- /*if (mVertexShaderLevel[SHADER_OBJECT] >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS)
- {
- return 3;
- }
- else*/
- {
- return 1;
- }
-}
-
-S32 LLPipeline::setLightingDetail(S32 level)
-{
- LLMemType mt_ld(LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL);
- refreshCachedSettings();
-
- if (level < 0)
- {
- if (RenderLocalLights)
- {
- level = 1;
- }
- else
- {
- level = 0;
- }
- }
- level = llclamp(level, 0, getMaxLightingDetail());
- mLightingDetail = level;
-
- return mLightingDetail;
-}
-
-class LLOctreeDirtyTexture : public LLOctreeTraveler<LLDrawable>
-{
-public:
- const std::set<LLViewerFetchedTexture*>& mTextures;
-
- LLOctreeDirtyTexture(const std::set<LLViewerFetchedTexture*>& textures) : mTextures(textures) { }
-
- virtual void visit(const LLOctreeNode<LLDrawable>* node)
- {
- LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
-
- if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->getData().empty())
- {
- for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
- {
- for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
- {
- LLDrawInfo* params = *j;
- LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(params->mTexture);
- if (tex && mTextures.find(tex) != mTextures.end())
- {
- group->setState(LLSpatialGroup::GEOM_DIRTY);
- }
- }
- }
- }
-
- for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i)
- {
- LLSpatialBridge* bridge = *i;
- traverse(bridge->mOctree);
- }
- }
-};
-
-// Called when a texture changes # of channels (causes faces to move to alpha pool)
-void LLPipeline::dirtyPoolObjectTextures(const std::set<LLViewerFetchedTexture*>& textures)
-{
- assertInitialized();
-
- // *TODO: This is inefficient and causes frame spikes; need a better way to do this
- // Most of the time is spent in dirty.traverse.
-
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- if (poolp->isFacePool())
- {
- ((LLFacePool*) poolp)->dirtyTextures(textures);
- }
- }
-
- LLOctreeDirtyTexture dirty(textures);
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- dirty.traverse(part->mOctree);
- }
- }
- }
-}
-
-LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0)
-{
- assertInitialized();
-
- LLDrawPool *poolp = NULL;
- switch( type )
- {
- case LLDrawPool::POOL_SIMPLE:
- poolp = mSimplePool;
- break;
-
- case LLDrawPool::POOL_GRASS:
- poolp = mGrassPool;
- break;
-
- case LLDrawPool::POOL_FULLBRIGHT:
- poolp = mFullbrightPool;
- break;
-
- case LLDrawPool::POOL_INVISIBLE:
- poolp = mInvisiblePool;
- break;
-
- case LLDrawPool::POOL_GLOW:
- poolp = mGlowPool;
- break;
-
- case LLDrawPool::POOL_TREE:
- poolp = get_if_there(mTreePools, (uintptr_t)tex0, (LLDrawPool*)0 );
- break;
-
- case LLDrawPool::POOL_TERRAIN:
- poolp = get_if_there(mTerrainPools, (uintptr_t)tex0, (LLDrawPool*)0 );
- break;
-
- case LLDrawPool::POOL_BUMP:
- poolp = mBumpPool;
- break;
-
- case LLDrawPool::POOL_ALPHA:
- poolp = mAlphaPool;
- break;
-
- case LLDrawPool::POOL_AVATAR:
- break; // Do nothing
-
- case LLDrawPool::POOL_SKY:
- poolp = mSkyPool;
- break;
-
- case LLDrawPool::POOL_WATER:
- poolp = mWaterPool;
- break;
-
- case LLDrawPool::POOL_GROUND:
- poolp = mGroundPool;
- break;
-
- case LLDrawPool::POOL_WL_SKY:
- poolp = mWLSkyPool;
- break;
-
- default:
- llassert(0);
- llerrs << "Invalid Pool Type in LLPipeline::findPool() type=" << type << llendl;
- break;
- }
-
- return poolp;
-}
-
-
-LLDrawPool *LLPipeline::getPool(const U32 type, LLViewerTexture *tex0)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
- LLDrawPool *poolp = findPool(type, tex0);
- if (poolp)
- {
- return poolp;
- }
-
- LLDrawPool *new_poolp = LLDrawPool::createPool(type, tex0);
- addPool( new_poolp );
-
- return new_poolp;
-}
-
-
-// static
-LLDrawPool* LLPipeline::getPoolFromTE(const LLTextureEntry* te, LLViewerTexture* imagep)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
- U32 type = getPoolTypeFromTE(te, imagep);
- return gPipeline.getPool(type, imagep);
-}
-
-//static
-U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* imagep)
-{
- LLMemType mt_gpt(LLMemType::MTYPE_PIPELINE_GET_POOL_TYPE);
-
- if (!te || !imagep)
- {
- return 0;
- }
-
- bool alpha = te->getColor().mV[3] < 0.999f;
- if (imagep)
- {
- alpha = alpha || (imagep->getComponents() == 4 && imagep->getType() != LLViewerTexture::MEDIA_TEXTURE) || (imagep->getComponents() == 2);
- }
-
- if (alpha)
- {
- return LLDrawPool::POOL_ALPHA;
- }
- else if ((te->getBumpmap() || te->getShiny()))
- {
- return LLDrawPool::POOL_BUMP;
- }
- else
- {
- return LLDrawPool::POOL_SIMPLE;
- }
-}
-
-
-void LLPipeline::addPool(LLDrawPool *new_poolp)
-{
- LLMemType mt_a(LLMemType::MTYPE_PIPELINE_ADD_POOL);
- assertInitialized();
- mPools.insert(new_poolp);
- addToQuickLookup( new_poolp );
-}
-
-void LLPipeline::allocDrawable(LLViewerObject *vobj)
-{
- LLMemType mt_ad(LLMemType::MTYPE_PIPELINE_ALLOCATE_DRAWABLE);
- LLDrawable *drawable = new LLDrawable();
- vobj->mDrawable = drawable;
-
- drawable->mVObjp = vobj;
-
- //encompass completely sheared objects by taking
- //the most extreme point possible (<1,1,0.5>)
- drawable->setRadius(LLVector3(1,1,0.5f).scaleVec(vobj->getScale()).length());
- if (vobj->isOrphaned())
- {
- drawable->setState(LLDrawable::FORCE_INVISIBLE);
- }
- drawable->updateXform(TRUE);
-}
-
-
-static LLFastTimer::DeclareTimer FTM_UNLINK("Unlink");
-static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_MOVE_LIST("Movelist");
-static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_SPATIAL_PARTITION("Spatial Partition");
-static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_LIGHT_SET("Light Set");
-static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_HIGHLIGHT_SET("Highlight Set");
-
-void LLPipeline::unlinkDrawable(LLDrawable *drawable)
-{
- LLFastTimer t(FTM_UNLINK);
-
- assertInitialized();
-
- LLPointer<LLDrawable> drawablep = drawable; // make sure this doesn't get deleted before we are done
-
- // Based on flags, remove the drawable from the queues that it's on.
- if (drawablep->isState(LLDrawable::ON_MOVE_LIST))
- {
- LLFastTimer t(FTM_REMOVE_FROM_MOVE_LIST);
- LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep);
- if (iter != mMovedList.end())
- {
- mMovedList.erase(iter);
- }
- }
-
- if (drawablep->getSpatialGroup())
- {
- LLFastTimer t(FTM_REMOVE_FROM_SPATIAL_PARTITION);
- if (!drawablep->getSpatialGroup()->mSpatialPartition->remove(drawablep, drawablep->getSpatialGroup()))
- {
-#ifdef LL_RELEASE_FOR_DOWNLOAD
- llwarns << "Couldn't remove object from spatial group!" << llendl;
-#else
- llerrs << "Couldn't remove object from spatial group!" << llendl;
-#endif
- }
- }
-
- {
- LLFastTimer t(FTM_REMOVE_FROM_LIGHT_SET);
- mLights.erase(drawablep);
-
- for (light_set_t::iterator iter = mNearbyLights.begin();
- iter != mNearbyLights.end(); iter++)
- {
- if (iter->drawable == drawablep)
- {
- mNearbyLights.erase(iter);
- break;
- }
- }
- }
-
- {
- LLFastTimer t(FTM_REMOVE_FROM_HIGHLIGHT_SET);
- HighlightItem item(drawablep);
- mHighlightSet.erase(item);
-
- if (mHighlightObject == drawablep)
- {
- mHighlightObject = NULL;
- }
- }
-
- for (U32 i = 0; i < 2; ++i)
- {
- if (mShadowSpotLight[i] == drawablep)
- {
- mShadowSpotLight[i] = NULL;
- }
-
- if (mTargetShadowSpotLight[i] == drawablep)
- {
- mTargetShadowSpotLight[i] = NULL;
- }
- }
-
-
-}
-
-U32 LLPipeline::addObject(LLViewerObject *vobj)
-{
- LLMemType mt_ao(LLMemType::MTYPE_PIPELINE_ADD_OBJECT);
-
- if (RenderDelayCreation)
- {
- mCreateQ.push_back(vobj);
- }
- else
- {
- createObject(vobj);
- }
-
- return 1;
-}
-
-void LLPipeline::createObjects(F32 max_dtime)
-{
- LLFastTimer ftm(FTM_GEO_UPDATE);
- LLMemType mt(LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS);
-
- LLTimer update_timer;
-
- while (!mCreateQ.empty() && update_timer.getElapsedTimeF32() < max_dtime)
- {
- LLViewerObject* vobj = mCreateQ.front();
- if (!vobj->isDead())
- {
- createObject(vobj);
- }
- mCreateQ.pop_front();
- }
-
- //for (LLViewerObject::vobj_list_t::iterator iter = mCreateQ.begin(); iter != mCreateQ.end(); ++iter)
- //{
- // createObject(*iter);
- //}
-
- //mCreateQ.clear();
-}
-
-void LLPipeline::createObject(LLViewerObject* vobj)
-{
- LLDrawable* drawablep = vobj->mDrawable;
-
- if (!drawablep)
- {
- drawablep = vobj->createDrawable(this);
- }
- else
- {
- llerrs << "Redundant drawable creation!" << llendl;
- }
-
- llassert(drawablep);
-
- if (vobj->getParent())
- {
- vobj->setDrawableParent(((LLViewerObject*)vobj->getParent())->mDrawable); // LLPipeline::addObject 1
- }
- else
- {
- vobj->setDrawableParent(NULL); // LLPipeline::addObject 2
- }
-
- markRebuild(drawablep, LLDrawable::REBUILD_ALL, TRUE);
-
- if (drawablep->getVOVolume() && RenderAnimateRes)
- {
- // fun animated res
- drawablep->updateXform(TRUE);
- drawablep->clearState(LLDrawable::MOVE_UNDAMPED);
- drawablep->setScale(LLVector3(0,0,0));
- drawablep->makeActive();
- }
-}
-
-
-void LLPipeline::resetFrameStats()
-{
- assertInitialized();
-
- LLViewerStats::getInstance()->mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f);
-
- if (mBatchCount > 0)
- {
- mMeanBatchSize = gPipeline.mTrianglesDrawn/gPipeline.mBatchCount;
- }
- mTrianglesDrawn = 0;
- sCompiles = 0;
- mVerticesRelit = 0;
- mLightingChanges = 0;
- mGeometryChanges = 0;
- mNumVisibleFaces = 0;
-
- if (mOldRenderDebugMask != mRenderDebugMask)
- {
- gObjectList.clearDebugText();
- mOldRenderDebugMask = mRenderDebugMask;
- }
-
-}
-
-//external functions for asynchronous updating
-void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep)
-{
- if (FreezeTime)
- {
- return;
- }
- if (!drawablep)
- {
- llerrs << "updateMove called with NULL drawablep" << llendl;
- return;
- }
- if (drawablep->isState(LLDrawable::EARLY_MOVE))
- {
- return;
- }
-
- assertInitialized();
-
- // update drawable now
- drawablep->clearState(LLDrawable::MOVE_UNDAMPED); // force to DAMPED
- drawablep->updateMove(); // returns done
- drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame
- // Put on move list so that EARLY_MOVE gets cleared
- if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
- {
- mMovedList.push_back(drawablep);
- drawablep->setState(LLDrawable::ON_MOVE_LIST);
- }
-}
-
-void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep)
-{
- if (FreezeTime)
- {
- return;
- }
- if (!drawablep)
- {
- llerrs << "updateMove called with NULL drawablep" << llendl;
- return;
- }
- if (drawablep->isState(LLDrawable::EARLY_MOVE))
- {
- return;
- }
-
- assertInitialized();
-
- // update drawable now
- drawablep->setState(LLDrawable::MOVE_UNDAMPED); // force to UNDAMPED
- drawablep->updateMove();
- drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame
- // Put on move list so that EARLY_MOVE gets cleared
- if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
- {
- mMovedList.push_back(drawablep);
- drawablep->setState(LLDrawable::ON_MOVE_LIST);
- }
-}
-
-void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list)
-{
- for (LLDrawable::drawable_vector_t::iterator iter = moved_list.begin();
- iter != moved_list.end(); )
- {
- LLDrawable::drawable_vector_t::iterator curiter = iter++;
- LLDrawable *drawablep = *curiter;
- BOOL done = TRUE;
- if (!drawablep->isDead() && (!drawablep->isState(LLDrawable::EARLY_MOVE)))
- {
- done = drawablep->updateMove();
- }
- drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED);
- if (done)
- {
- drawablep->clearState(LLDrawable::ON_MOVE_LIST);
- iter = moved_list.erase(curiter);
- }
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_OCTREE_BALANCE("Balance Octree");
-static LLFastTimer::DeclareTimer FTM_UPDATE_MOVE("Update Move");
-
-void LLPipeline::updateMove()
-{
- LLFastTimer t(FTM_UPDATE_MOVE);
- LLMemType mt_um(LLMemType::MTYPE_PIPELINE_UPDATE_MOVE);
-
- if (FreezeTime)
- {
- return;
- }
-
- assertInitialized();
-
- {
- static LLFastTimer::DeclareTimer ftm("Retexture");
- LLFastTimer t(ftm);
-
- for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin();
- iter != mRetexturedList.end(); ++iter)
- {
- LLDrawable* drawablep = *iter;
- if (drawablep && !drawablep->isDead())
- {
- drawablep->updateTexture();
- }
- }
- mRetexturedList.clear();
- }
-
- {
- static LLFastTimer::DeclareTimer ftm("Moved List");
- LLFastTimer t(ftm);
- updateMovedList(mMovedList);
- }
-
- //balance octrees
- {
- LLFastTimer ot(FTM_OCTREE_BALANCE);
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- part->mOctree->balance();
- }
- }
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// Culling and occlusion testing
-/////////////////////////////////////////////////////////////////////////////
-
-//static
-F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera)
-{
- LLVector3 lookAt = center - camera.getOrigin();
- F32 dist = lookAt.length();
-
- //ramp down distance for nearby objects
- //shrink dist by dist/16.
- if (dist < 16.f)
- {
- dist /= 16.f;
- dist *= dist;
- dist *= 16.f;
- }
-
- //get area of circle around node
- F32 app_angle = atanf(size.length()/dist);
- F32 radius = app_angle*LLDrawable::sCurPixelAngle;
- return radius*radius * F_PI;
-}
-
-//static
-F32 LLPipeline::calcPixelArea(const LLVector4a& center, const LLVector4a& size, LLCamera &camera)
-{
- LLVector4a origin;
- origin.load3(camera.getOrigin().mV);
-
- LLVector4a lookAt;
- lookAt.setSub(center, origin);
- F32 dist = lookAt.getLength3().getF32();
-
- //ramp down distance for nearby objects
- //shrink dist by dist/16.
- if (dist < 16.f)
- {
- dist /= 16.f;
- dist *= dist;
- dist *= 16.f;
- }
-
- //get area of circle around node
- F32 app_angle = atanf(size.getLength3().getF32()/dist);
- F32 radius = app_angle*LLDrawable::sCurPixelAngle;
- return radius*radius * F_PI;
-}
-
-void LLPipeline::grabReferences(LLCullResult& result)
-{
- sCull = &result;
-}
-
-void LLPipeline::clearReferences()
-{
- sCull = NULL;
-}
-
-void check_references(LLSpatialGroup* group, LLDrawable* drawable)
-{
- for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
- {
- if (drawable == *i)
- {
- llerrs << "LLDrawable deleted while actively reference by LLPipeline." << llendl;
- }
- }
-}
-
-void check_references(LLDrawable* drawable, LLFace* face)
-{
- for (S32 i = 0; i < drawable->getNumFaces(); ++i)
- {
- if (drawable->getFace(i) == face)
- {
- llerrs << "LLFace deleted while actively referenced by LLPipeline." << llendl;
- }
- }
-}
-
-void check_references(LLSpatialGroup* group, LLFace* face)
-{
- for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
- {
- LLDrawable* drawable = *i;
- check_references(drawable, face);
- }
-}
-
-void LLPipeline::checkReferences(LLFace* face)
-{
-#if 0
- if (sCull)
- {
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, face);
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, face);
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, face);
- }
-
- for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter)
- {
- LLDrawable* drawable = *iter;
- check_references(drawable, face);
- }
- }
-#endif
-}
-
-void LLPipeline::checkReferences(LLDrawable* drawable)
-{
-#if 0
- if (sCull)
- {
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, drawable);
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, drawable);
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, drawable);
- }
-
- for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter)
- {
- if (drawable == *iter)
- {
- llerrs << "LLDrawable deleted while actively referenced by LLPipeline." << llendl;
- }
- }
- }
-#endif
-}
-
-void check_references(LLSpatialGroup* group, LLDrawInfo* draw_info)
-{
- for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
- {
- LLSpatialGroup::drawmap_elem_t& draw_vec = i->second;
- for (LLSpatialGroup::drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
- {
- LLDrawInfo* params = *j;
- if (params == draw_info)
- {
- llerrs << "LLDrawInfo deleted while actively referenced by LLPipeline." << llendl;
- }
- }
- }
-}
-
-
-void LLPipeline::checkReferences(LLDrawInfo* draw_info)
-{
-#if 0
- if (sCull)
- {
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, draw_info);
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, draw_info);
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, draw_info);
- }
- }
-#endif
-}
-
-void LLPipeline::checkReferences(LLSpatialGroup* group)
-{
-#if 0
- if (sCull)
- {
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
- {
- if (group == *iter)
- {
- llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl;
- }
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
- {
- if (group == *iter)
- {
- llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl;
- }
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
- {
- if (group == *iter)
- {
- llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl;
- }
- }
- }
-#endif
-}
-
-
-BOOL LLPipeline::visibleObjectsInFrustum(LLCamera& camera)
-{
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
-
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- if (hasRenderType(part->mDrawableType))
- {
- if (part->visibleObjectsInFrustum(camera))
- {
- return TRUE;
- }
- }
- }
- }
- }
-
- return FALSE;
-}
-
-BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& max)
-{
- const F32 X = 65536.f;
-
- min = LLVector3(X,X,X);
- max = LLVector3(-X,-X,-X);
-
- U32 saved_camera_id = LLViewerCamera::sCurCameraID;
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
-
- BOOL res = TRUE;
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
-
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- if (hasRenderType(part->mDrawableType))
- {
- if (!part->getVisibleExtents(camera, min, max))
- {
- res = FALSE;
- }
- }
- }
- }
- }
-
- LLViewerCamera::sCurCameraID = saved_camera_id;
-
- return res;
-}
-
-static LLFastTimer::DeclareTimer FTM_CULL("Object Culling");
-
-void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip, LLPlane* planep)
-{
- LLFastTimer t(FTM_CULL);
- LLMemType mt_uc(LLMemType::MTYPE_PIPELINE_UPDATE_CULL);
-
- grabReferences(result);
-
- sCull->clear();
-
- BOOL to_texture = LLPipeline::sUseOcclusion > 1 &&
- !hasRenderType(LLPipeline::RENDER_TYPE_HUD) &&
- LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD &&
- gPipeline.canUseVertexShaders() &&
- sRenderGlow;
-
- if (to_texture)
- {
- mScreen.bindTarget();
- }
-
- if (sUseOcclusion > 1)
- {
- gGL.setColorMask(false, false);
- }
-
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.pushMatrix();
- gGL.loadMatrix(gGLLastProjection);
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.pushMatrix();
- gGLLastMatrix = NULL;
- gGL.loadMatrix(gGLLastModelView);
-
-
- LLVertexBuffer::unbind();
- LLGLDisable blend(GL_BLEND);
- LLGLDisable test(GL_ALPHA_TEST);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
-
- //setup a clip plane in projection matrix for reflection renders (prevents flickering from occlusion culling)
- LLViewerRegion* region = gAgent.getRegion();
- LLPlane plane;
-
- if (planep)
- {
- plane = *planep;
- }
- else
- {
- if (region)
- {
- LLVector3 pnorm;
- F32 height = region->getWaterHeight();
- if (water_clip < 0)
- { //camera is above water, clip plane points up
- pnorm.setVec(0,0,1);
- plane.setVec(pnorm, -height);
- }
- else if (water_clip > 0)
- { //camera is below water, clip plane points down
- pnorm = LLVector3(0,0,-1);
- plane.setVec(pnorm, height);
- }
- }
- }
-
- glh::matrix4f modelview = glh_get_last_modelview();
- glh::matrix4f proj = glh_get_last_projection();
- LLGLUserClipPlane clip(plane, modelview, proj, water_clip != 0 && LLPipeline::sReflectionRender);
-
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
-
- bool bound_shader = false;
- if (gPipeline.canUseVertexShaders() && LLGLSLShader::sCurBoundShader == 0)
- { //if no shader is currently bound, use the occlusion shader instead of fixed function if we can
- // (shadow render uses a special shader that clamps to clip planes)
- bound_shader = true;
- gOcclusionProgram.bind();
- }
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- if (water_clip != 0)
- {
- LLPlane plane(LLVector3(0,0, (F32) -water_clip), (F32) water_clip*region->getWaterHeight());
- camera.setUserClipPlane(plane);
- }
- else
- {
- camera.disableUserClipPlane();
- }
-
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- if (hasRenderType(part->mDrawableType))
- {
- part->cull(camera);
- }
- }
- }
- }
-
- if (bound_shader)
- {
- gOcclusionProgram.unbind();
- }
-
- camera.disableUserClipPlane();
-
- if (hasRenderType(LLPipeline::RENDER_TYPE_SKY) &&
- gSky.mVOSkyp.notNull() &&
- gSky.mVOSkyp->mDrawable.notNull())
- {
- gSky.mVOSkyp->mDrawable->setVisible(camera);
- sCull->pushDrawable(gSky.mVOSkyp->mDrawable);
- gSky.updateCull();
- stop_glerror();
- }
-
- if (hasRenderType(LLPipeline::RENDER_TYPE_GROUND) &&
- !gPipeline.canUseWindLightShaders() &&
- gSky.mVOGroundp.notNull() &&
- gSky.mVOGroundp->mDrawable.notNull() &&
- !LLPipeline::sWaterReflections)
- {
- gSky.mVOGroundp->mDrawable->setVisible(camera);
- sCull->pushDrawable(gSky.mVOGroundp->mDrawable);
- }
-
-
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.popMatrix();
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.popMatrix();
-
- if (sUseOcclusion > 1)
- {
- gGL.setColorMask(true, false);
- }
-
- if (to_texture)
- {
- mScreen.flush();
- }
-}
-
-void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
-{
- if (group->getData().empty())
- {
- return;
- }
-
- group->setVisible();
-
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
- {
- group->updateDistance(camera);
- }
-
- const F32 MINIMUM_PIXEL_AREA = 16.f;
-
- if (group->mPixelArea < MINIMUM_PIXEL_AREA)
- {
- return;
- }
-
- if (sMinRenderSize > 0.f &&
- llmax(llmax(group->mBounds[1][0], group->mBounds[1][1]), group->mBounds[1][2]) < sMinRenderSize)
- {
- return;
- }
-
- assertInitialized();
-
- if (!group->mSpatialPartition->mRenderByGroup)
- { //render by drawable
- sCull->pushDrawableGroup(group);
- }
- else
- { //render by group
- sCull->pushVisibleGroup(group);
- }
-
- mNumVisibleNodes++;
-}
-
-void LLPipeline::markOccluder(LLSpatialGroup* group)
-{
- if (sUseOcclusion > 1 && group && !group->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION))
- {
- LLSpatialGroup* parent = group->getParent();
-
- if (!parent || !parent->isOcclusionState(LLSpatialGroup::OCCLUDED))
- { //only mark top most occluders as active occlusion
- sCull->pushOcclusionGroup(group);
- group->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
-
- if (parent &&
- !parent->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION) &&
- parent->getElementCount() == 0 &&
- parent->needsUpdate())
- {
- sCull->pushOcclusionGroup(group);
- parent->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
- }
- }
- }
-}
-
-void LLPipeline::doOcclusion(LLCamera& camera)
-{
- if (LLPipeline::sUseOcclusion > 1 && sCull->hasOcclusionGroups())
- {
- LLVertexBuffer::unbind();
-
- if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
- {
- gGL.setColorMask(true, false, false, false);
- }
- else
- {
- gGL.setColorMask(false, false);
- }
- LLGLDisable blend(GL_BLEND);
- LLGLDisable test(GL_ALPHA_TEST);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
-
- LLGLDisable cull(GL_CULL_FACE);
-
-
- bool bind_shader = LLGLSLShader::sNoFixedFunction && LLGLSLShader::sCurBoundShader == 0;
- if (bind_shader)
- {
- if (LLPipeline::sShadowRender)
- {
- gDeferredShadowProgram.bind();
- }
- else
- {
- gOcclusionProgram.bind();
- }
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- group->doOcclusion(&camera);
- group->clearOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
- }
-
- if (bind_shader)
- {
- if (LLPipeline::sShadowRender)
- {
- gDeferredShadowProgram.unbind();
- }
- else
- {
- gOcclusionProgram.unbind();
- }
- }
-
- gGL.setColorMask(true, false);
- }
-}
-
-BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority)
-{
- BOOL update_complete = drawablep->updateGeometry(priority);
- if (update_complete && assertInitialized())
- {
- drawablep->setState(LLDrawable::BUILT);
- mGeometryChanges++;
- }
- return update_complete;
-}
-
-void LLPipeline::updateGL()
-{
- while (!LLGLUpdate::sGLQ.empty())
- {
- LLGLUpdate* glu = LLGLUpdate::sGLQ.front();
- glu->updateGL();
- glu->mInQ = FALSE;
- LLGLUpdate::sGLQ.pop_front();
- }
-}
-
-void LLPipeline::rebuildPriorityGroups()
-{
- LLTimer update_timer;
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
-
- assertInitialized();
-
- gMeshRepo.notifyLoadedMeshes();
-
- mGroupQ1Locked = true;
- // Iterate through all drawables on the priority build queue,
- for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ1.begin();
- iter != mGroupQ1.end(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- group->rebuildGeom();
- group->clearState(LLSpatialGroup::IN_BUILD_Q1);
- }
-
- mGroupQ1.clear();
- mGroupQ1Locked = false;
-
-}
-
-void LLPipeline::rebuildGroups()
-{
- if (mGroupQ2.empty())
- {
- return;
- }
-
- mGroupQ2Locked = true;
- // Iterate through some drawables on the non-priority build queue
- S32 size = (S32) mGroupQ2.size();
- S32 min_count = llclamp((S32) ((F32) (size * size)/4096*0.25f), 1, size);
-
- S32 count = 0;
-
- std::sort(mGroupQ2.begin(), mGroupQ2.end(), LLSpatialGroup::CompareUpdateUrgency());
-
- LLSpatialGroup::sg_vector_t::iterator iter;
- LLSpatialGroup::sg_vector_t::iterator last_iter = mGroupQ2.begin();
-
- for (iter = mGroupQ2.begin();
- iter != mGroupQ2.end() && count <= min_count; ++iter)
- {
- LLSpatialGroup* group = *iter;
- last_iter = iter;
-
- if (!group->isDead())
- {
- group->rebuildGeom();
-
- if (group->mSpatialPartition->mRenderByGroup)
- {
- count++;
- }
- }
-
- group->clearState(LLSpatialGroup::IN_BUILD_Q2);
- }
-
- mGroupQ2.erase(mGroupQ2.begin(), ++last_iter);
-
- mGroupQ2Locked = false;
-
- updateMovedList(mMovedBridge);
-}
-
-void LLPipeline::updateGeom(F32 max_dtime)
-{
- LLTimer update_timer;
- LLMemType mt(LLMemType::MTYPE_PIPELINE_UPDATE_GEOM);
- LLPointer<LLDrawable> drawablep;
-
- LLFastTimer t(FTM_GEO_UPDATE);
-
- assertInitialized();
-
- if (sDelayedVBOEnable > 0)
- {
- if (--sDelayedVBOEnable <= 0)
- {
- resetVertexBuffers();
- LLVertexBuffer::sEnableVBOs = TRUE;
- }
- }
-
- // notify various object types to reset internal cost metrics, etc.
- // for now, only LLVOVolume does this to throttle LOD changes
- LLVOVolume::preUpdateGeom();
-
- // Iterate through all drawables on the priority build queue,
- for (LLDrawable::drawable_list_t::iterator iter = mBuildQ1.begin();
- iter != mBuildQ1.end();)
- {
- LLDrawable::drawable_list_t::iterator curiter = iter++;
- LLDrawable* drawablep = *curiter;
- if (drawablep && !drawablep->isDead())
- {
- if (drawablep->isState(LLDrawable::IN_REBUILD_Q2))
- {
- drawablep->clearState(LLDrawable::IN_REBUILD_Q2);
- LLDrawable::drawable_list_t::iterator find = std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep);
- if (find != mBuildQ2.end())
- {
- mBuildQ2.erase(find);
- }
- }
-
- if (updateDrawableGeom(drawablep, TRUE))
- {
- drawablep->clearState(LLDrawable::IN_REBUILD_Q1);
- mBuildQ1.erase(curiter);
- }
- }
- else
- {
- mBuildQ1.erase(curiter);
- }
- }
-
- // Iterate through some drawables on the non-priority build queue
- S32 min_count = 16;
- S32 size = (S32) mBuildQ2.size();
- if (size > 1024)
- {
- min_count = llclamp((S32) (size * (F32) size/4096), 16, size);
- }
-
- S32 count = 0;
-
- max_dtime = llmax(update_timer.getElapsedTimeF32()+0.001f, max_dtime);
- LLSpatialGroup* last_group = NULL;
- LLSpatialBridge* last_bridge = NULL;
-
- for (LLDrawable::drawable_list_t::iterator iter = mBuildQ2.begin();
- iter != mBuildQ2.end(); )
- {
- LLDrawable::drawable_list_t::iterator curiter = iter++;
- LLDrawable* drawablep = *curiter;
-
- LLSpatialBridge* bridge = drawablep->isRoot() ? drawablep->getSpatialBridge() :
- drawablep->getParent()->getSpatialBridge();
-
- if (drawablep->getSpatialGroup() != last_group &&
- (!last_bridge || bridge != last_bridge) &&
- (update_timer.getElapsedTimeF32() >= max_dtime) && count > min_count)
- {
- break;
- }
-
- //make sure updates don't stop in the middle of a spatial group
- //to avoid thrashing (objects are enqueued by group)
- last_group = drawablep->getSpatialGroup();
- last_bridge = bridge;
-
- BOOL update_complete = TRUE;
- if (!drawablep->isDead())
- {
- update_complete = updateDrawableGeom(drawablep, FALSE);
- count++;
- }
- if (update_complete)
- {
- drawablep->clearState(LLDrawable::IN_REBUILD_Q2);
- mBuildQ2.erase(curiter);
- }
- }
-
- updateMovedList(mMovedBridge);
-}
-
-void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_VISIBLE);
-
- if(drawablep && !drawablep->isDead())
- {
- if (drawablep->isSpatialBridge())
- {
- const LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable;
- llassert(root); // trying to catch a bad assumption
- if (root && // // this test may not be needed, see above
- root->getVObj()->isAttachment())
- {
- LLDrawable* rootparent = root->getParent();
- if (rootparent) // this IS sometimes NULL
- {
- LLViewerObject *vobj = rootparent->getVObj();
- llassert(vobj); // trying to catch a bad assumption
- if (vobj) // this test may not be needed, see above
- {
- const LLVOAvatar* av = vobj->asAvatar();
- if (av && av->isImpostor())
- {
- return;
- }
- }
- }
- }
- sCull->pushBridge((LLSpatialBridge*) drawablep);
- }
- else
- {
- sCull->pushDrawable(drawablep);
- }
-
- drawablep->setVisible(camera);
- }
-}
-
-void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion)
-{
- LLMemType mt_mm(LLMemType::MTYPE_PIPELINE_MARK_MOVED);
-
- if (!drawablep)
- {
- //llerrs << "Sending null drawable to moved list!" << llendl;
- return;
- }
-
- if (drawablep->isDead())
- {
- llwarns << "Marking NULL or dead drawable moved!" << llendl;
- return;
- }
-
- if (drawablep->getParent())
- {
- //ensure that parent drawables are moved first
- markMoved(drawablep->getParent(), damped_motion);
- }
-
- assertInitialized();
-
- if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
- {
- if (drawablep->isSpatialBridge())
- {
- mMovedBridge.push_back(drawablep);
- }
- else
- {
- mMovedList.push_back(drawablep);
- }
- drawablep->setState(LLDrawable::ON_MOVE_LIST);
- }
- if (damped_motion == FALSE)
- {
- drawablep->setState(LLDrawable::MOVE_UNDAMPED); // UNDAMPED trumps DAMPED
- }
- else if (drawablep->isState(LLDrawable::MOVE_UNDAMPED))
- {
- drawablep->clearState(LLDrawable::MOVE_UNDAMPED);
- }
-}
-
-void LLPipeline::markShift(LLDrawable *drawablep)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_SHIFT);
-
- if (!drawablep || drawablep->isDead())
- {
- return;
- }
-
- assertInitialized();
-
- if (!drawablep->isState(LLDrawable::ON_SHIFT_LIST))
- {
- drawablep->getVObj()->setChanged(LLXform::SHIFTED | LLXform::SILHOUETTE);
- if (drawablep->getParent())
- {
- markShift(drawablep->getParent());
- }
- mShiftList.push_back(drawablep);
- drawablep->setState(LLDrawable::ON_SHIFT_LIST);
- }
-}
-
-void LLPipeline::shiftObjects(const LLVector3 &offset)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS);
-
- assertInitialized();
-
- glClear(GL_DEPTH_BUFFER_BIT);
- gDepthDirty = TRUE;
-
- LLVector4a offseta;
- offseta.load3(offset.mV);
-
- for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin();
- iter != mShiftList.end(); iter++)
- {
- LLDrawable *drawablep = *iter;
- if (drawablep->isDead())
- {
- continue;
- }
- drawablep->shiftPos(offseta);
- drawablep->clearState(LLDrawable::ON_SHIFT_LIST);
- }
- mShiftList.resize(0);
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- part->shift(offseta);
- }
- }
- }
-
- LLHUDText::shiftAll(offset);
- LLHUDNameTag::shiftAll(offset);
- display_update_camera();
-}
-
-void LLPipeline::markTextured(LLDrawable *drawablep)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_TEXTURED);
-
- if (drawablep && !drawablep->isDead() && assertInitialized())
- {
- mRetexturedList.insert(drawablep);
- }
-}
-
-void LLPipeline::markGLRebuild(LLGLUpdate* glu)
-{
- if (glu && !glu->mInQ)
- {
- LLGLUpdate::sGLQ.push_back(glu);
- glu->mInQ = TRUE;
- }
-}
-
-void LLPipeline::markPartitionMove(LLDrawable* drawable)
-{
- if (!drawable->isState(LLDrawable::PARTITION_MOVE) &&
- !drawable->getPositionGroup().equals3(LLVector4a::getZero()))
- {
- drawable->setState(LLDrawable::PARTITION_MOVE);
- mPartitionQ.push_back(drawable);
- }
-}
-
-void LLPipeline::processPartitionQ()
-{
- for (LLDrawable::drawable_list_t::iterator iter = mPartitionQ.begin(); iter != mPartitionQ.end(); ++iter)
- {
- LLDrawable* drawable = *iter;
- if (!drawable->isDead())
- {
- drawable->updateBinRadius();
- drawable->movePartition();
- }
- drawable->clearState(LLDrawable::PARTITION_MOVE);
- }
-
- mPartitionQ.clear();
-}
-
-void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
-
- if (group && !group->isDead() && group->mSpatialPartition)
- {
- if (group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD)
- {
- priority = TRUE;
- }
-
- if (priority)
- {
- if (!group->isState(LLSpatialGroup::IN_BUILD_Q1))
- {
- llassert_always(!mGroupQ1Locked);
-
- mGroupQ1.push_back(group);
- group->setState(LLSpatialGroup::IN_BUILD_Q1);
-
- if (group->isState(LLSpatialGroup::IN_BUILD_Q2))
- {
- LLSpatialGroup::sg_vector_t::iterator iter = std::find(mGroupQ2.begin(), mGroupQ2.end(), group);
- if (iter != mGroupQ2.end())
- {
- mGroupQ2.erase(iter);
- }
- group->clearState(LLSpatialGroup::IN_BUILD_Q2);
- }
- }
- }
- else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1))
- {
- llassert_always(!mGroupQ2Locked);
- mGroupQ2.push_back(group);
- group->setState(LLSpatialGroup::IN_BUILD_Q2);
-
- }
- }
-}
-
-void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag, BOOL priority)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_REBUILD);
-
- if (drawablep && !drawablep->isDead() && assertInitialized())
- {
- if (!drawablep->isState(LLDrawable::BUILT))
- {
- priority = TRUE;
- }
- if (priority)
- {
- if (!drawablep->isState(LLDrawable::IN_REBUILD_Q1))
- {
- mBuildQ1.push_back(drawablep);
- drawablep->setState(LLDrawable::IN_REBUILD_Q1); // mark drawable as being in priority queue
- }
- }
- else if (!drawablep->isState(LLDrawable::IN_REBUILD_Q2))
- {
- mBuildQ2.push_back(drawablep);
- drawablep->setState(LLDrawable::IN_REBUILD_Q2); // need flag here because it is just a list
- }
- if (flag & (LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION))
- {
- drawablep->getVObj()->setChanged(LLXform::SILHOUETTE);
- }
- drawablep->setState(flag);
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_RESET_DRAWORDER("Reset Draw Order");
-
-void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
-{
- if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR,
- LLPipeline::RENDER_TYPE_GROUND,
- LLPipeline::RENDER_TYPE_TERRAIN,
- LLPipeline::RENDER_TYPE_TREE,
- LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_VOIDWATER,
- LLPipeline::RENDER_TYPE_WATER,
- LLPipeline::END_RENDER_TYPES))
- {
- //clear faces from face pools
- LLFastTimer t(FTM_RESET_DRAWORDER);
- gPipeline.resetDrawOrders();
- }
-
- LLFastTimer ftm(FTM_STATESORT);
- LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
-
- //LLVertexBuffer::unbind();
-
- grabReferences(result);
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- group->checkOcclusion();
- if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- markOccluder(group);
- }
- else
- {
- group->setVisible();
- for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
- {
- markVisible(*i, camera);
- }
-
- if (!sDelayVBUpdate)
- { //rebuild mesh as soon as we know it's visible
- group->rebuildMesh();
- }
- }
- }
-
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
- {
- LLSpatialGroup* last_group = NULL;
- for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
- {
- LLCullResult::bridge_list_t::iterator cur_iter = i;
- LLSpatialBridge* bridge = *cur_iter;
- LLSpatialGroup* group = bridge->getSpatialGroup();
-
- if (last_group == NULL)
- {
- last_group = group;
- }
-
- if (!bridge->isDead() && group && !group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- stateSort(bridge, camera);
- }
-
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD &&
- last_group != group && last_group->changeLOD())
- {
- last_group->mLastUpdateDistance = last_group->mDistance;
- }
-
- last_group = group;
- }
-
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD &&
- last_group && last_group->changeLOD())
- {
- last_group->mLastUpdateDistance = last_group->mDistance;
- }
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- group->checkOcclusion();
- if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- markOccluder(group);
- }
- else
- {
- group->setVisible();
- stateSort(group, camera);
-
- if (!sDelayVBUpdate)
- { //rebuild mesh as soon as we know it's visible
- group->rebuildMesh();
- }
- }
- }
-
- {
- LLFastTimer ftm(FTM_STATESORT_DRAWABLE);
- for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList();
- iter != sCull->endVisibleList(); ++iter)
- {
- LLDrawable *drawablep = *iter;
- if (!drawablep->isDead())
- {
- stateSort(drawablep, camera);
- }
- }
- }
-
- postSort(camera);
-}
-
-void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
- if (group->changeLOD())
- {
- for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
- {
- LLDrawable* drawablep = *i;
- stateSort(drawablep, camera);
- }
-
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
- { //avoid redundant stateSort calls
- group->mLastUpdateDistance = group->mDistance;
- }
- }
-
-}
-
-void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
- if (bridge->getSpatialGroup()->changeLOD())
- {
- bool force_update = false;
- bridge->updateDistance(camera, force_update);
- }
-}
-
-void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
-
- if (!drawablep
- || drawablep->isDead()
- || !hasRenderType(drawablep->getRenderType()))
- {
- return;
- }
-
- if (LLSelectMgr::getInstance()->mHideSelectedObjects)
- {
- if (drawablep->getVObj().notNull() &&
- drawablep->getVObj()->isSelected())
- {
- return;
- }
- }
-
- if (drawablep->isAvatar())
- { //don't draw avatars beyond render distance or if we don't have a spatial group.
- if ((drawablep->getSpatialGroup() == NULL) ||
- (drawablep->getSpatialGroup()->mDistance > LLVOAvatar::sRenderDistance))
- {
- return;
- }
-
- LLVOAvatar* avatarp = (LLVOAvatar*) drawablep->getVObj().get();
- if (!avatarp->isVisible())
- {
- return;
- }
- }
-
- assertInitialized();
-
- if (hasRenderType(drawablep->mRenderType))
- {
- if (!drawablep->isState(LLDrawable::INVISIBLE|LLDrawable::FORCE_INVISIBLE))
- {
- drawablep->setVisible(camera, NULL, FALSE);
- }
- else if (drawablep->isState(LLDrawable::CLEAR_INVISIBLE))
- {
- // clear invisible flag here to avoid single frame glitch
- drawablep->clearState(LLDrawable::FORCE_INVISIBLE|LLDrawable::CLEAR_INVISIBLE);
- }
- }
-
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
- {
- //if (drawablep->isVisible()) isVisible() check here is redundant, if it wasn't visible, it wouldn't be here
- {
- if (!drawablep->isActive())
- {
- bool force_update = false;
- drawablep->updateDistance(camera, force_update);
- }
- else if (drawablep->isAvatar())
- {
- bool force_update = false;
- drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility()
- }
- }
- }
-
- if (!drawablep->getVOVolume())
- {
- for (LLDrawable::face_list_t::iterator iter = drawablep->mFaces.begin();
- iter != drawablep->mFaces.end(); iter++)
- {
- LLFace* facep = *iter;
-
- if (facep->hasGeometry())
- {
- if (facep->getPool())
- {
- facep->getPool()->enqueue(facep);
- }
- else
- {
- break;
- }
- }
- }
- }
-
-
- mNumVisibleFaces += drawablep->getNumFaces();
-}
-
-
-void forAllDrawables(LLCullResult::sg_list_t::iterator begin,
- LLCullResult::sg_list_t::iterator end,
- void (*func)(LLDrawable*))
-{
- for (LLCullResult::sg_list_t::iterator i = begin; i != end; ++i)
- {
- for (LLSpatialGroup::element_iter j = (*i)->getData().begin(); j != (*i)->getData().end(); ++j)
- {
- func(*j);
- }
- }
-}
-
-void LLPipeline::forAllVisibleDrawables(void (*func)(LLDrawable*))
-{
- forAllDrawables(sCull->beginDrawableGroups(), sCull->endDrawableGroups(), func);
- forAllDrawables(sCull->beginVisibleGroups(), sCull->endVisibleGroups(), func);
-}
-
-//function for creating scripted beacons
-void renderScriptedBeacons(LLDrawable* drawablep)
-{
- LLViewerObject *vobj = drawablep->getVObj();
- if (vobj
- && !vobj->isAvatar()
- && !vobj->getParent()
- && vobj->flagScripted())
- {
- if (gPipeline.sRenderBeacons)
- {
- gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth);
- }
-
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void renderScriptedTouchBeacons(LLDrawable* drawablep)
-{
- LLViewerObject *vobj = drawablep->getVObj();
- if (vobj
- && !vobj->isAvatar()
- && !vobj->getParent()
- && vobj->flagScripted()
- && vobj->flagHandleTouch())
- {
- if (gPipeline.sRenderBeacons)
- {
- gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth);
- }
-
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void renderPhysicalBeacons(LLDrawable* drawablep)
-{
- LLViewerObject *vobj = drawablep->getVObj();
- if (vobj
- && !vobj->isAvatar()
- //&& !vobj->getParent()
- && vobj->usePhysics())
- {
- if (gPipeline.sRenderBeacons)
- {
- gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth);
- }
-
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void renderMOAPBeacons(LLDrawable* drawablep)
-{
- LLViewerObject *vobj = drawablep->getVObj();
-
- if(!vobj || vobj->isAvatar())
- return;
-
- BOOL beacon=FALSE;
- U8 tecount=vobj->getNumTEs();
- for(int x=0;x<tecount;x++)
- {
- if(vobj->getTE(x)->hasMedia())
- {
- beacon=TRUE;
- break;
- }
- }
- if(beacon==TRUE)
- {
- if (gPipeline.sRenderBeacons)
- {
- gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 1.f, 1.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth);
- }
-
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void renderParticleBeacons(LLDrawable* drawablep)
-{
- // Look for attachments, objects, etc.
- LLViewerObject *vobj = drawablep->getVObj();
- if (vobj
- && vobj->isParticleSource())
- {
- if (gPipeline.sRenderBeacons)
- {
- LLColor4 light_blue(0.5f, 0.5f, 1.f, 0.5f);
- gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", light_blue, LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth);
- }
-
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void renderSoundHighlights(LLDrawable* drawablep)
-{
- // Look for attachments, objects, etc.
- LLViewerObject *vobj = drawablep->getVObj();
- if (vobj && vobj->isAudioSource())
- {
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void LLPipeline::postSort(LLCamera& camera)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_POST_SORT);
- LLFastTimer ftm(FTM_STATESORT_POSTSORT);
-
- assertInitialized();
-
- llpushcallstacks ;
- //rebuild drawable geometry
- for (LLCullResult::sg_list_t::iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i)
- {
- LLSpatialGroup* group = *i;
- if (!sUseOcclusion ||
- !group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- group->rebuildGeom();
- }
- }
- llpushcallstacks ;
- //rebuild groups
- sCull->assertDrawMapsEmpty();
-
- rebuildPriorityGroups();
- llpushcallstacks ;
-
- const S32 bin_count = 1024*8;
-
- static LLCullResult::drawinfo_list_t alpha_bins[bin_count];
- static U32 bin_size[bin_count];
-
- //clear one bin per frame to avoid memory bloat
- static S32 clear_idx = 0;
- clear_idx = (1+clear_idx)%bin_count;
- alpha_bins[clear_idx].clear();
-
- for (U32 j = 0; j < bin_count; j++)
- {
- bin_size[j] = 0;
- }
-
- //build render map
- for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
- {
- LLSpatialGroup* group = *i;
- if (sUseOcclusion &&
- group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- continue;
- }
-
- if (group->isState(LLSpatialGroup::NEW_DRAWINFO) && group->isState(LLSpatialGroup::GEOM_DIRTY))
- { //no way this group is going to be drawable without a rebuild
- group->rebuildGeom();
- }
-
- for (LLSpatialGroup::draw_map_t::iterator j = group->mDrawMap.begin(); j != group->mDrawMap.end(); ++j)
- {
- LLSpatialGroup::drawmap_elem_t& src_vec = j->second;
- if (!hasRenderType(j->first))
- {
- continue;
- }
-
- for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k)
- {
- if (sMinRenderSize > 0.f)
- {
- LLVector4a bounds;
- bounds.setSub((*k)->mExtents[1],(*k)->mExtents[0]);
-
- if (llmax(llmax(bounds[0], bounds[1]), bounds[2]) > sMinRenderSize)
- {
- sCull->pushDrawInfo(j->first, *k);
- }
- }
- else
- {
- sCull->pushDrawInfo(j->first, *k);
- }
- }
- }
-
- if (hasRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA))
- {
- LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA);
-
- if (alpha != group->mDrawMap.end())
- { //store alpha groups for sorting
- LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
- {
- if (bridge)
- {
- LLCamera trans_camera = bridge->transformCamera(camera);
- group->updateDistance(trans_camera);
- }
- else
- {
- group->updateDistance(camera);
- }
- }
-
- if (hasRenderType(LLDrawPool::POOL_ALPHA))
- {
- sCull->pushAlphaGroup(group);
- }
- }
- }
- }
-
- if (!sShadowRender)
- {
- std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater());
- }
- llpushcallstacks ;
- // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus
- if (LLFloaterReg::instanceVisible("beacons") && !sShadowRender)
- {
- if (sRenderScriptedTouchBeacons)
- {
- // Only show the beacon on the root object.
- forAllVisibleDrawables(renderScriptedTouchBeacons);
- }
- else
- if (sRenderScriptedBeacons)
- {
- // Only show the beacon on the root object.
- forAllVisibleDrawables(renderScriptedBeacons);
- }
-
- if (sRenderPhysicalBeacons)
- {
- // Only show the beacon on the root object.
- forAllVisibleDrawables(renderPhysicalBeacons);
- }
-
- if(sRenderMOAPBeacons)
- {
- forAllVisibleDrawables(renderMOAPBeacons);
- }
-
- if (sRenderParticleBeacons)
- {
- forAllVisibleDrawables(renderParticleBeacons);
- }
-
- // If god mode, also show audio cues
- if (sRenderSoundBeacons && gAudiop)
- {
- // Walk all sound sources and render out beacons for them. Note, this isn't done in the ForAllVisibleDrawables function, because some are not visible.
- LLAudioEngine::source_map::iterator iter;
- for (iter = gAudiop->mAllSources.begin(); iter != gAudiop->mAllSources.end(); ++iter)
- {
- LLAudioSource *sourcep = iter->second;
-
- LLVector3d pos_global = sourcep->getPositionGlobal();
- LLVector3 pos = gAgent.getPosAgentFromGlobal(pos_global);
- if (gPipeline.sRenderBeacons)
- {
- //pos += LLVector3(0.f, 0.f, 0.2f);
- gObjectList.addDebugBeacon(pos, "", LLColor4(1.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), DebugBeaconLineWidth);
- }
- }
- // now deal with highlights for all those seeable sound sources
- forAllVisibleDrawables(renderSoundHighlights);
- }
- }
- llpushcallstacks ;
- // If managing your telehub, draw beacons at telehub and currently selected spawnpoint.
- if (LLFloaterTelehub::renderBeacons())
- {
- LLFloaterTelehub::addBeacons();
- }
-
- if (!sShadowRender)
- {
- mSelectedFaces.clear();
-
- // Draw face highlights for selected faces.
- if (LLSelectMgr::getInstance()->getTEMode())
- {
- struct f : public LLSelectedTEFunctor
- {
- virtual bool apply(LLViewerObject* object, S32 te)
- {
- if (object->mDrawable)
- {
- gPipeline.mSelectedFaces.push_back(object->mDrawable->getFace(te));
- }
- return true;
- }
- } func;
- LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func);
- }
- }
-
- //LLSpatialGroup::sNoDelete = FALSE;
- llpushcallstacks ;
-}
-
-
-void render_hud_elements()
-{
- LLMemType mt_rhe(LLMemType::MTYPE_PIPELINE_RENDER_HUD_ELS);
- LLFastTimer t(FTM_RENDER_UI);
- gPipeline.disableLights();
-
- LLGLDisable fog(GL_FOG);
- LLGLSUIDefault gls_ui;
-
- LLGLEnable stencil(GL_STENCIL_TEST);
- glStencilFunc(GL_ALWAYS, 255, 0xFFFFFFFF);
- glStencilMask(0xFFFFFFFF);
- glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
-
- gGL.color4f(1,1,1,1);
-
- if (LLGLSLShader::sNoFixedFunction)
- {
- gUIProgram.bind();
- }
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
-
- if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- LLGLEnable multisample(LLPipeline::RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
- gViewerWindow->renderSelections(FALSE, FALSE, FALSE); // For HUD version in render_ui_3d()
-
- // Draw the tracking overlays
- LLTracker::render3D();
-
- // Show the property lines
- LLWorld::getInstance()->renderPropertyLines();
- LLViewerParcelMgr::getInstance()->render();
- LLViewerParcelMgr::getInstance()->renderParcelCollision();
-
- // Render name tags.
- LLHUDObject::renderAll();
- }
- else if (gForceRenderLandFence)
- {
- // This is only set when not rendering the UI, for parcel snapshots
- LLViewerParcelMgr::getInstance()->render();
- }
- else if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- LLHUDText::renderAllHUD();
- }
-
- if (LLGLSLShader::sNoFixedFunction)
- {
- gUIProgram.unbind();
- }
- gGL.flush();
-}
-
-void LLPipeline::renderHighlights()
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_HL);
-
- assertInitialized();
-
- // Draw 3D UI elements here (before we clear the Z buffer in POOL_HUD)
- // Render highlighted faces.
- LLGLSPipelineAlpha gls_pipeline_alpha;
- LLColor4 color(1.f, 1.f, 1.f, 0.5f);
- LLGLEnable color_mat(GL_COLOR_MATERIAL);
- disableLights();
-
- if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD) && !mHighlightSet.empty())
- { //draw blurry highlight image over screen
- LLGLEnable blend(GL_BLEND);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
- LLGLDisable test(GL_ALPHA_TEST);
-
- LLGLEnable stencil(GL_STENCIL_TEST);
- gGL.flush();
- glStencilMask(0xFFFFFFFF);
- glClearStencil(1);
- glClear(GL_STENCIL_BUFFER_BIT);
-
- glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF);
- glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
-
- gGL.setColorMask(false, false);
- for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ++iter)
- {
- renderHighlight(iter->mItem->getVObj(), 1.f);
- }
- gGL.setColorMask(true, false);
-
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
-
- //gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
-
- gGL.pushMatrix();
- gGL.loadIdentity();
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.pushMatrix();
- gGL.loadIdentity();
-
- gGL.getTexUnit(0)->bind(&mHighlight);
-
- LLVector2 tc1;
- LLVector2 tc2;
-
- tc1.setVec(0,0);
- tc2.setVec(2,2);
-
- gGL.begin(LLRender::TRIANGLES);
-
- F32 scale = RenderHighlightBrightness;
- LLColor4 color = RenderHighlightColor;
- F32 thickness = RenderHighlightThickness;
-
- for (S32 pass = 0; pass < 2; ++pass)
- {
- if (pass == 0)
- {
- gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
- }
- else
- {
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- }
-
- for (S32 i = 0; i < 8; ++i)
- {
- for (S32 j = 0; j < 8; ++j)
- {
- LLVector2 tc(i-4+0.5f, j-4+0.5f);
-
- F32 dist = 1.f-(tc.length()/sqrtf(32.f));
- dist *= scale/64.f;
-
- tc *= thickness;
- tc.mV[0] = (tc.mV[0])/mHighlight.getWidth();
- tc.mV[1] = (tc.mV[1])/mHighlight.getHeight();
-
- gGL.color4f(color.mV[0],
- color.mV[1],
- color.mV[2],
- color.mV[3]*dist);
-
- gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc.mV[0]+tc2.mV[0], tc.mV[1]+tc1.mV[1]);
- gGL.vertex2f(3,-1);
- }
- }
- }
-
- gGL.end();
-
- gGL.popMatrix();
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.popMatrix();
-
- //gGL.setSceneBlendType(LLRender::BT_ALPHA);
- }
-
- if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
- {
- gHighlightProgram.bind();
- gGL.diffuseColor4f(1,1,1,0.5f);
- }
-
- if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED))
- {
- // Make sure the selection image gets downloaded and decoded
- if (!mFaceSelectImagep)
- {
- mFaceSelectImagep = LLViewerTextureManager::getFetchedTexture(IMG_FACE_SELECT);
- }
- mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA);
-
- U32 count = mSelectedFaces.size();
- for (U32 i = 0; i < count; i++)
- {
- LLFace *facep = mSelectedFaces[i];
- if (!facep || facep->getDrawable()->isDead())
- {
- llerrs << "Bad face on selection" << llendl;
- return;
- }
-
- facep->renderSelected(mFaceSelectImagep, color);
- }
- }
-
- if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED))
- {
- // Paint 'em red!
- color.setVec(1.f, 0.f, 0.f, 0.5f);
-
- int count = mHighlightFaces.size();
- for (S32 i = 0; i < count; i++)
- {
- LLFace* facep = mHighlightFaces[i];
- facep->renderSelected(LLViewerTexture::sNullImagep, color);
- }
- }
-
- // Contains a list of the faces of objects that are physical or
- // have touch-handlers.
- mHighlightFaces.clear();
-
- if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)
- {
- gHighlightProgram.unbind();
- }
-}
-
-//debug use
-U32 LLPipeline::sCurRenderPoolType = 0 ;
-
-void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_GEOM);
- LLFastTimer t(FTM_RENDER_GEOMETRY);
-
- assertInitialized();
-
- F32 saved_modelview[16];
- F32 saved_projection[16];
-
- //HACK: preserve/restore matrices around HUD render
- if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- for (U32 i = 0; i < 16; i++)
- {
- saved_modelview[i] = gGLModelView[i];
- saved_projection[i] = gGLProjection[i];
- }
- }
-
- ///////////////////////////////////////////
- //
- // Sync and verify GL state
- //
- //
-
- stop_glerror();
-
- LLVertexBuffer::unbind();
-
- // Do verification of GL state
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
- if (mRenderDebugMask & RENDER_DEBUG_VERIFY)
- {
- if (!verify())
- {
- llerrs << "Pipeline verification failed!" << llendl;
- }
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:ForceVBO");
-
- // Initialize lots of GL state to "safe" values
- gGL.matrixMode(LLRender::MM_TEXTURE);
- gGL.loadIdentity();
- gGL.matrixMode(LLRender::MM_MODELVIEW);
-
- LLGLSPipeline gls_pipeline;
- LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
-
- LLGLState gls_color_material(GL_COLOR_MATERIAL, mLightingDetail < 2);
-
- // Toggle backface culling for debugging
- LLGLEnable cull_face(mBackfaceCull ? GL_CULL_FACE : 0);
- // Set fog
- BOOL use_fog = hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG);
- LLGLEnable fog_enable(use_fog &&
- !gPipeline.canUseWindLightShadersOnObjects() ? GL_FOG : 0);
- gSky.updateFog(camera.getFar());
- if (!use_fog)
- {
- sUnderWaterRender = FALSE;
- }
-
- gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sDefaultImagep);
- LLViewerFetchedTexture::sDefaultImagep->setAddressMode(LLTexUnit::TAM_WRAP);
-
-
- //////////////////////////////////////////////
- //
- // Actually render all of the geometry
- //
- //
- stop_glerror();
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPools");
-
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- if (hasRenderType(poolp->getType()))
- {
- poolp->prerender();
- }
- }
-
- {
- LLFastTimer t(FTM_POOLS);
-
- // HACK: don't calculate local lights if we're rendering the HUD!
- // Removing this check will cause bad flickering when there are
- // HUD elements being rendered AND the user is in flycam mode -nyx
- if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- calcNearbyLights(camera);
- setupHWLights(NULL);
- }
-
- BOOL occlude = sUseOcclusion > 1;
- U32 cur_type = 0;
-
- pool_set_t::iterator iter1 = mPools.begin();
- while ( iter1 != mPools.end() )
- {
- LLDrawPool *poolp = *iter1;
-
- cur_type = poolp->getType();
-
- //debug use
- sCurRenderPoolType = cur_type ;
-
- if (occlude && cur_type >= LLDrawPool::POOL_GRASS)
- {
- occlude = FALSE;
- gGLLastMatrix = NULL;
- gGL.loadMatrix(gGLModelView);
- LLGLSLShader::bindNoShader();
- doOcclusion(camera);
- }
-
- pool_set_t::iterator iter2 = iter1;
- if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0)
- {
- LLFastTimer t(FTM_POOLRENDER);
-
- gGLLastMatrix = NULL;
- gGL.loadMatrix(gGLModelView);
-
- for( S32 i = 0; i < poolp->getNumPasses(); i++ )
- {
- LLVertexBuffer::unbind();
- poolp->beginRenderPass(i);
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
-
- p->render(i);
- }
- poolp->endRenderPass(i);
- LLVertexBuffer::unbind();
- if (gDebugGL)
- {
- std::string msg = llformat("pass %d", i);
- LLGLState::checkStates(msg);
- //LLGLState::checkTextureChannels(msg);
- //LLGLState::checkClientArrays(msg);
- }
- }
- }
- else
- {
- // Skip all pools of this type
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
- }
- }
- iter1 = iter2;
- stop_glerror();
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPoolsEnd");
-
- LLVertexBuffer::unbind();
-
- gGLLastMatrix = NULL;
- gGL.loadMatrix(gGLModelView);
-
- if (occlude)
- {
- occlude = FALSE;
- gGLLastMatrix = NULL;
- gGL.loadMatrix(gGLModelView);
- LLGLSLShader::bindNoShader();
- doOcclusion(camera);
- }
- }
-
- LLVertexBuffer::unbind();
- LLGLState::checkStates();
-
- if (!LLPipeline::sImpostorRender)
- {
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderHighlights");
-
- if (!sReflectionRender)
- {
- renderHighlights();
- }
-
- // Contains a list of the faces of objects that are physical or
- // have touch-handlers.
- mHighlightFaces.clear();
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDebug");
-
- renderDebug();
-
- LLVertexBuffer::unbind();
-
- if (!LLPipeline::sReflectionRender && !LLPipeline::sRenderDeferred)
- {
- if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- // Render debugging beacons.
- gObjectList.renderObjectBeacons();
- gObjectList.resetObjectBeacons();
- }
- else
- {
- // Make sure particle effects disappear
- LLHUDObject::renderAllForTimer();
- }
- }
- else
- {
- // Make sure particle effects disappear
- LLHUDObject::renderAllForTimer();
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomEnd");
-
- //HACK: preserve/restore matrices around HUD render
- if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- for (U32 i = 0; i < 16; i++)
- {
- gGLModelView[i] = saved_modelview[i];
- gGLProjection[i] = saved_projection[i];
- }
- }
- }
-
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
-// LLGLState::checkTextureChannels();
-// LLGLState::checkClientArrays();
-}
-
-void LLPipeline::renderGeomDeferred(LLCamera& camera)
-{
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred");
-
- LLMemType mt_rgd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED);
- LLFastTimer t(FTM_RENDER_GEOMETRY);
-
- LLFastTimer t2(FTM_POOLS);
-
- LLGLEnable cull(GL_CULL_FACE);
-
- LLGLEnable stencil(GL_STENCIL_TEST);
- glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
- stop_glerror();
- glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
- stop_glerror();
-
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- if (hasRenderType(poolp->getType()))
- {
- poolp->prerender();
- }
- }
-
- LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
-
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- U32 cur_type = 0;
-
- gGL.setColorMask(true, true);
-
- pool_set_t::iterator iter1 = mPools.begin();
-
- while ( iter1 != mPools.end() )
- {
- LLDrawPool *poolp = *iter1;
-
- cur_type = poolp->getType();
-
- pool_set_t::iterator iter2 = iter1;
- if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0)
- {
- LLFastTimer t(FTM_POOLRENDER);
-
- gGLLastMatrix = NULL;
- gGL.loadMatrix(gGLModelView);
-
- for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ )
- {
- LLVertexBuffer::unbind();
- poolp->beginDeferredPass(i);
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
-
- p->renderDeferred(i);
- }
- poolp->endDeferredPass(i);
- LLVertexBuffer::unbind();
-
- if (gDebugGL || gDebugPipeline)
- {
- LLGLState::checkStates();
- }
- }
- }
- else
- {
- // Skip all pools of this type
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
- }
- }
- iter1 = iter2;
- stop_glerror();
- }
-
- gGLLastMatrix = NULL;
- gGL.loadMatrix(gGLModelView);
-
- gGL.setColorMask(true, false);
-}
-
-void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
-{
- LLMemType mt_rgpd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF);
- LLFastTimer t(FTM_POOLS);
- U32 cur_type = 0;
-
- LLGLEnable cull(GL_CULL_FACE);
-
- LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
-
- calcNearbyLights(camera);
- setupHWLights(NULL);
-
- gGL.setColorMask(true, false);
-
- pool_set_t::iterator iter1 = mPools.begin();
- BOOL occlude = LLPipeline::sUseOcclusion > 1;
-
- while ( iter1 != mPools.end() )
- {
- LLDrawPool *poolp = *iter1;
-
- cur_type = poolp->getType();
-
- if (occlude && cur_type >= LLDrawPool::POOL_GRASS)
- {
- occlude = FALSE;
- gGLLastMatrix = NULL;
- gGL.loadMatrix(gGLModelView);
- LLGLSLShader::bindNoShader();
- doOcclusion(camera);
- gGL.setColorMask(true, false);
- }
-
- pool_set_t::iterator iter2 = iter1;
- if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0)
- {
- LLFastTimer t(FTM_POOLRENDER);
-
- gGLLastMatrix = NULL;
- gGL.loadMatrix(gGLModelView);
-
- for( S32 i = 0; i < poolp->getNumPostDeferredPasses(); i++ )
- {
- LLVertexBuffer::unbind();
- poolp->beginPostDeferredPass(i);
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
-
- p->renderPostDeferred(i);
- }
- poolp->endPostDeferredPass(i);
- LLVertexBuffer::unbind();
-
- if (gDebugGL || gDebugPipeline)
- {
- LLGLState::checkStates();
- }
- }
- }
- else
- {
- // Skip all pools of this type
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
- }
- }
- iter1 = iter2;
- stop_glerror();
- }
-
- gGLLastMatrix = NULL;
- gGL.loadMatrix(gGLModelView);
-
- if (occlude)
- {
- occlude = FALSE;
- gGLLastMatrix = NULL;
- gGL.loadMatrix(gGLModelView);
- LLGLSLShader::bindNoShader();
- doOcclusion(camera);
- gGLLastMatrix = NULL;
- gGL.loadMatrix(gGLModelView);
- }
-}
-
-void LLPipeline::renderGeomShadow(LLCamera& camera)
-{
- LLMemType mt_rgs(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_SHADOW);
- U32 cur_type = 0;
-
- LLGLEnable cull(GL_CULL_FACE);
-
- LLVertexBuffer::unbind();
-
- pool_set_t::iterator iter1 = mPools.begin();
-
- while ( iter1 != mPools.end() )
- {
- LLDrawPool *poolp = *iter1;
-
- cur_type = poolp->getType();
-
- pool_set_t::iterator iter2 = iter1;
- if (hasRenderType(poolp->getType()) && poolp->getNumShadowPasses() > 0)
- {
- poolp->prerender() ;
-
- gGLLastMatrix = NULL;
- gGL.loadMatrix(gGLModelView);
-
- for( S32 i = 0; i < poolp->getNumShadowPasses(); i++ )
- {
- LLVertexBuffer::unbind();
- poolp->beginShadowPass(i);
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
-
- p->renderShadow(i);
- }
- poolp->endShadowPass(i);
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- }
- }
- else
- {
- // Skip all pools of this type
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
- }
- }
- iter1 = iter2;
- stop_glerror();
- }
-
- gGLLastMatrix = NULL;
- gGL.loadMatrix(gGLModelView);
-}
-
-
-void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type)
-{
- assertInitialized();
- S32 count = 0;
- if (render_type == LLRender::TRIANGLE_STRIP)
- {
- count = index_count-2;
- }
- else
- {
- count = index_count/3;
- }
-
- mTrianglesDrawn += count;
- mBatchCount++;
- mMaxBatchSize = llmax(mMaxBatchSize, count);
- mMinBatchSize = llmin(mMinBatchSize, count);
-
- if (LLPipeline::sRenderFrameTest)
- {
- gViewerWindow->getWindow()->swapBuffers();
- ms_sleep(16);
- }
-}
-
-void LLPipeline::renderPhysicsDisplay()
-{
- if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES))
- {
- return;
- }
-
- allocatePhysicsBuffer();
-
- gGL.flush();
- mPhysicsDisplay.bindTarget();
- glClearColor(0,0,0,1);
- gGL.setColorMask(true, true);
- mPhysicsDisplay.clear();
- glClearColor(0,0,0,0);
-
- gGL.setColorMask(true, false);
-
- if (LLGLSLShader::sNoFixedFunction)
- {
- gDebugProgram.bind();
- }
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- if (hasRenderType(part->mDrawableType))
- {
- part->renderPhysicsShapes();
- }
- }
- }
- }
-
- for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
- {
- LLSpatialBridge* bridge = *i;
- if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
- {
- gGL.pushMatrix();
- gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
- bridge->renderPhysicsShapes();
- gGL.popMatrix();
- }
- }
-
- gGL.flush();
-
- if (LLGLSLShader::sNoFixedFunction)
- {
- gDebugProgram.unbind();
- }
-
- mPhysicsDisplay.flush();
-}
-
-
-void LLPipeline::renderDebug()
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
-
- assertInitialized();
-
- gGL.color4f(1,1,1,1);
-
- gGLLastMatrix = NULL;
- gGL.loadMatrix(gGLModelView);
- gGL.setColorMask(true, false);
-
- bool hud_only = hasRenderType(LLPipeline::RENDER_TYPE_HUD);
-
-
- if (!hud_only && !mDebugBlips.empty())
- { //render debug blips
- if (LLGLSLShader::sNoFixedFunction)
- {
- gUIProgram.bind();
- }
-
- gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep, true);
-
- glPointSize(8.f);
- LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS);
-
- gGL.begin(LLRender::POINTS);
- for (std::list<DebugBlip>::iterator iter = mDebugBlips.begin(); iter != mDebugBlips.end(); )
- {
- DebugBlip& blip = *iter;
-
- blip.mAge += gFrameIntervalSeconds;
- if (blip.mAge > 2.f)
- {
- mDebugBlips.erase(iter++);
- }
- else
- {
- iter++;
- }
-
- blip.mPosition.mV[2] += gFrameIntervalSeconds*2.f;
-
- gGL.color4fv(blip.mColor.mV);
- gGL.vertex3fv(blip.mPosition.mV);
- }
- gGL.end();
- gGL.flush();
- glPointSize(1.f);
- }
-
-
- // Debug stuff.
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- if ( hud_only && (part->mDrawableType == RENDER_TYPE_HUD || part->mDrawableType == RENDER_TYPE_HUD_PARTICLES) ||
- !hud_only && hasRenderType(part->mDrawableType) )
- {
- part->renderDebug();
- }
- }
- }
- }
-
- for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
- {
- LLSpatialBridge* bridge = *i;
- if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
- {
- gGL.pushMatrix();
- gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
- bridge->renderDebug();
- gGL.popMatrix();
- }
- }
-
- if (LLGLSLShader::sNoFixedFunction)
- {
- gUIProgram.bind();
- }
-
- if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- LLVertexBuffer::unbind();
-
- LLGLEnable blend(GL_BLEND);
- LLGLDepthTest depth(TRUE, FALSE);
- LLGLDisable cull(GL_CULL_FACE);
-
- gGL.color4f(1,1,1,1);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- F32 a = 0.1f;
-
- F32 col[] =
- {
- 1,0,0,a,
- 0,1,0,a,
- 0,0,1,a,
- 1,0,1,a,
-
- 1,1,0,a,
- 0,1,1,a,
- 1,1,1,a,
- 1,0,1,a,
- };
-
- for (U32 i = 0; i < 8; i++)
- {
- LLVector3* frust = mShadowCamera[i].mAgentFrustum;
-
- if (i > 3)
- { //render shadow frusta as volumes
- if (mShadowFrustPoints[i-4].empty())
- {
- continue;
- }
-
- gGL.color4fv(col+(i-4)*4);
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
- gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
- gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
- gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
- gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
- gGL.end();
-
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.vertex3fv(frust[0].mV);
- gGL.vertex3fv(frust[1].mV);
- gGL.vertex3fv(frust[3].mV);
- gGL.vertex3fv(frust[2].mV);
- gGL.end();
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.vertex3fv(frust[4].mV);
- gGL.vertex3fv(frust[5].mV);
- gGL.vertex3fv(frust[7].mV);
- gGL.vertex3fv(frust[6].mV);
- gGL.end();
- }
-
-
- if (i < 4)
- {
-
- //if (i == 0 || !mShadowFrustPoints[i].empty())
- {
- //render visible point cloud
- gGL.flush();
- glPointSize(8.f);
- gGL.begin(LLRender::POINTS);
-
- F32* c = col+i*4;
- gGL.color3fv(c);
-
- for (U32 j = 0; j < mShadowFrustPoints[i].size(); ++j)
- {
- gGL.vertex3fv(mShadowFrustPoints[i][j].mV);
-
- }
- gGL.end();
-
- gGL.flush();
- glPointSize(1.f);
-
- LLVector3* ext = mShadowExtents[i];
- LLVector3 pos = (ext[0]+ext[1])*0.5f;
- LLVector3 size = (ext[1]-ext[0])*0.5f;
- drawBoxOutline(pos, size);
-
- //render camera frustum splits as outlines
- gGL.begin(LLRender::LINES);
- gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[1].mV);
- gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[2].mV);
- gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[3].mV);
- gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[0].mV);
- gGL.vertex3fv(frust[4].mV); gGL.vertex3fv(frust[5].mV);
- gGL.vertex3fv(frust[5].mV); gGL.vertex3fv(frust[6].mV);
- gGL.vertex3fv(frust[6].mV); gGL.vertex3fv(frust[7].mV);
- gGL.vertex3fv(frust[7].mV); gGL.vertex3fv(frust[4].mV);
- gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
- gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
- gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
- gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
- gGL.end();
- }
- }
-
- /*gGL.flush();
- glLineWidth(16-i*2);
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(j);
- if (part)
- {
- if (hasRenderType(part->mDrawableType))
- {
- part->renderIntersectingBBoxes(&mShadowCamera[i]);
- }
- }
- }
- }
- gGL.flush();
- glLineWidth(1.f);*/
- }
- }
-
- if (mRenderDebugMask & RENDER_DEBUG_WIND_VECTORS)
- {
- gAgent.getRegion()->mWind.renderVectors();
- }
-
- if (mRenderDebugMask & RENDER_DEBUG_COMPOSITION)
- {
- // Debug composition layers
- F32 x, y;
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- if (gAgent.getRegion())
- {
- gGL.begin(LLRender::POINTS);
- // Draw the composition layer for the region that I'm in.
- for (x = 0; x <= 260; x++)
- {
- for (y = 0; y <= 260; y++)
- {
- if ((x > 255) || (y > 255))
- {
- gGL.color4f(1.f, 0.f, 0.f, 1.f);
- }
- else
- {
- gGL.color4f(0.f, 0.f, 1.f, 1.f);
- }
- F32 z = gAgent.getRegion()->getCompositionXY((S32)x, (S32)y);
- z *= 5.f;
- z += 50.f;
- gGL.vertex3f(x, y, z);
- }
- }
- gGL.end();
- }
- }
-
- if (mRenderDebugMask & LLPipeline::RENDER_DEBUG_BUILD_QUEUE)
- {
- U32 count = 0;
- U32 size = mGroupQ2.size();
- LLColor4 col;
-
- LLVertexBuffer::unbind();
- LLGLEnable blend(GL_BLEND);
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
- gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
-
- gGL.pushMatrix();
- gGL.loadMatrix(gGLModelView);
- gGLLastMatrix = NULL;
-
- for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ2.begin(); iter != mGroupQ2.end(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- if (group->isDead())
- {
- continue;
- }
-
- LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
-
- if (bridge && (!bridge->mDrawable || bridge->mDrawable->isDead()))
- {
- continue;
- }
-
- if (bridge)
- {
- gGL.pushMatrix();
- gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
- }
-
- F32 alpha = llclamp((F32) (size-count)/size, 0.f, 1.f);
-
-
- LLVector2 c(1.f-alpha, alpha);
- c.normVec();
-
-
- ++count;
- col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.5f);
- group->drawObjectBox(col);
-
- if (bridge)
- {
- gGL.popMatrix();
- }
- }
-
- gGL.popMatrix();
- }
-
- gGL.flush();
- if (LLGLSLShader::sNoFixedFunction)
- {
- gUIProgram.unbind();
- }
-}
-
-void LLPipeline::rebuildPools()
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_REBUILD_POOLS);
-
- assertInitialized();
-
- S32 max_count = mPools.size();
- pool_set_t::iterator iter1 = mPools.upper_bound(mLastRebuildPool);
- while(max_count > 0 && mPools.size() > 0) // && num_rebuilds < MAX_REBUILDS)
- {
- if (iter1 == mPools.end())
- {
- iter1 = mPools.begin();
- }
- LLDrawPool* poolp = *iter1;
-
- if (poolp->isDead())
- {
- mPools.erase(iter1++);
- removeFromQuickLookup( poolp );
- if (poolp == mLastRebuildPool)
- {
- mLastRebuildPool = NULL;
- }
- delete poolp;
- }
- else
- {
- mLastRebuildPool = poolp;
- iter1++;
- }
- max_count--;
- }
-
- if (isAgentAvatarValid())
- {
- gAgentAvatarp->rebuildHUD();
- }
-}
-
-void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_QUICK_LOOKUP);
-
- assertInitialized();
-
- switch( new_poolp->getType() )
- {
- case LLDrawPool::POOL_SIMPLE:
- if (mSimplePool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate simple pool." << llendl;
- }
- else
- {
- mSimplePool = (LLRenderPass*) new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_GRASS:
- if (mGrassPool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate grass pool." << llendl;
- }
- else
- {
- mGrassPool = (LLRenderPass*) new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_FULLBRIGHT:
- if (mFullbrightPool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate simple pool." << llendl;
- }
- else
- {
- mFullbrightPool = (LLRenderPass*) new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_INVISIBLE:
- if (mInvisiblePool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate simple pool." << llendl;
- }
- else
- {
- mInvisiblePool = (LLRenderPass*) new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_GLOW:
- if (mGlowPool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate glow pool." << llendl;
- }
- else
- {
- mGlowPool = (LLRenderPass*) new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_TREE:
- mTreePools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ;
- break;
-
- case LLDrawPool::POOL_TERRAIN:
- mTerrainPools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ;
- break;
-
- case LLDrawPool::POOL_BUMP:
- if (mBumpPool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate bump pool." << llendl;
- }
- else
- {
- mBumpPool = new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_ALPHA:
- if( mAlphaPool )
- {
- llassert(0);
- llwarns << "LLPipeline::addPool(): Ignoring duplicate Alpha pool" << llendl;
- }
- else
- {
- mAlphaPool = new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_AVATAR:
- break; // Do nothing
-
- case LLDrawPool::POOL_SKY:
- if( mSkyPool )
- {
- llassert(0);
- llwarns << "LLPipeline::addPool(): Ignoring duplicate Sky pool" << llendl;
- }
- else
- {
- mSkyPool = new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_WATER:
- if( mWaterPool )
- {
- llassert(0);
- llwarns << "LLPipeline::addPool(): Ignoring duplicate Water pool" << llendl;
- }
- else
- {
- mWaterPool = new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_GROUND:
- if( mGroundPool )
- {
- llassert(0);
- llwarns << "LLPipeline::addPool(): Ignoring duplicate Ground Pool" << llendl;
- }
- else
- {
- mGroundPool = new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_WL_SKY:
- if( mWLSkyPool )
- {
- llassert(0);
- llwarns << "LLPipeline::addPool(): Ignoring duplicate WLSky Pool" << llendl;
- }
- else
- {
- mWLSkyPool = new_poolp;
- }
- break;
-
- default:
- llassert(0);
- llwarns << "Invalid Pool Type in LLPipeline::addPool()" << llendl;
- break;
- }
-}
-
-void LLPipeline::removePool( LLDrawPool* poolp )
-{
- assertInitialized();
- removeFromQuickLookup(poolp);
- mPools.erase(poolp);
- delete poolp;
-}
-
-void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
-{
- assertInitialized();
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
- switch( poolp->getType() )
- {
- case LLDrawPool::POOL_SIMPLE:
- llassert(mSimplePool == poolp);
- mSimplePool = NULL;
- break;
-
- case LLDrawPool::POOL_GRASS:
- llassert(mGrassPool == poolp);
- mGrassPool = NULL;
- break;
-
- case LLDrawPool::POOL_FULLBRIGHT:
- llassert(mFullbrightPool == poolp);
- mFullbrightPool = NULL;
- break;
-
- case LLDrawPool::POOL_INVISIBLE:
- llassert(mInvisiblePool == poolp);
- mInvisiblePool = NULL;
- break;
-
- case LLDrawPool::POOL_WL_SKY:
- llassert(mWLSkyPool == poolp);
- mWLSkyPool = NULL;
- break;
-
- case LLDrawPool::POOL_GLOW:
- llassert(mGlowPool == poolp);
- mGlowPool = NULL;
- break;
-
- case LLDrawPool::POOL_TREE:
- #ifdef _DEBUG
- {
- BOOL found = mTreePools.erase( (uintptr_t)poolp->getTexture() );
- llassert( found );
- }
- #else
- mTreePools.erase( (uintptr_t)poolp->getTexture() );
- #endif
- break;
-
- case LLDrawPool::POOL_TERRAIN:
- #ifdef _DEBUG
- {
- BOOL found = mTerrainPools.erase( (uintptr_t)poolp->getTexture() );
- llassert( found );
- }
- #else
- mTerrainPools.erase( (uintptr_t)poolp->getTexture() );
- #endif
- break;
-
- case LLDrawPool::POOL_BUMP:
- llassert( poolp == mBumpPool );
- mBumpPool = NULL;
- break;
-
- case LLDrawPool::POOL_ALPHA:
- llassert( poolp == mAlphaPool );
- mAlphaPool = NULL;
- break;
-
- case LLDrawPool::POOL_AVATAR:
- break; // Do nothing
-
- case LLDrawPool::POOL_SKY:
- llassert( poolp == mSkyPool );
- mSkyPool = NULL;
- break;
-
- case LLDrawPool::POOL_WATER:
- llassert( poolp == mWaterPool );
- mWaterPool = NULL;
- break;
-
- case LLDrawPool::POOL_GROUND:
- llassert( poolp == mGroundPool );
- mGroundPool = NULL;
- break;
-
- default:
- llassert(0);
- llwarns << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << llendl;
- break;
- }
-}
-
-void LLPipeline::resetDrawOrders()
-{
- assertInitialized();
- // Iterate through all of the draw pools and rebuild them.
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- poolp->resetDrawOrders();
- }
-}
-
-//============================================================================
-// Once-per-frame setup of hardware lights,
-// including sun/moon, avatar backlight, and up to 6 local lights
-
-void LLPipeline::setupAvatarLights(BOOL for_edit)
-{
- assertInitialized();
-
- if (for_edit)
- {
- LLColor4 diffuse(1.f, 1.f, 1.f, 0.f);
- LLVector4 light_pos_cam(-8.f, 0.25f, 10.f, 0.f); // w==0 => directional light
- LLMatrix4 camera_mat = LLViewerCamera::getInstance()->getModelview();
- LLMatrix4 camera_rot(camera_mat.getMat3());
- camera_rot.invert();
- LLVector4 light_pos = light_pos_cam * camera_rot;
-
- light_pos.normalize();
-
- LLLightState* light = gGL.getLight(1);
-
- mHWLightColors[1] = diffuse;
-
- light->setDiffuse(diffuse);
- light->setAmbient(LLColor4::black);
- light->setSpecular(LLColor4::black);
- light->setPosition(light_pos);
- light->setConstantAttenuation(1.f);
- light->setLinearAttenuation(0.f);
- light->setQuadraticAttenuation(0.f);
- light->setSpotExponent(0.f);
- light->setSpotCutoff(180.f);
- }
- else if (gAvatarBacklight) // Always true (unless overridden in a devs .ini)
- {
- LLVector3 opposite_pos = -1.f * mSunDir;
- LLVector3 orthog_light_pos = mSunDir % LLVector3::z_axis;
- LLVector4 backlight_pos = LLVector4(lerp(opposite_pos, orthog_light_pos, 0.3f), 0.0f);
- backlight_pos.normalize();
-
- LLColor4 light_diffuse = mSunDiffuse;
- LLColor4 backlight_diffuse(1.f - light_diffuse.mV[VRED], 1.f - light_diffuse.mV[VGREEN], 1.f - light_diffuse.mV[VBLUE], 1.f);
- F32 max_component = 0.001f;
- for (S32 i = 0; i < 3; i++)
- {
- if (backlight_diffuse.mV[i] > max_component)
- {
- max_component = backlight_diffuse.mV[i];
- }
- }
- F32 backlight_mag;
- if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS)
- {
- backlight_mag = BACKLIGHT_DAY_MAGNITUDE_OBJECT;
- }
- else
- {
- backlight_mag = BACKLIGHT_NIGHT_MAGNITUDE_OBJECT;
- }
- backlight_diffuse *= backlight_mag / max_component;
-
- mHWLightColors[1] = backlight_diffuse;
-
- LLLightState* light = gGL.getLight(1);
-
- light->setPosition(backlight_pos);
- light->setDiffuse(backlight_diffuse);
- light->setAmbient(LLColor4::black);
- light->setSpecular(LLColor4::black);
- light->setConstantAttenuation(1.f);
- light->setLinearAttenuation(0.f);
- light->setQuadraticAttenuation(0.f);
- light->setSpotExponent(0.f);
- light->setSpotCutoff(180.f);
- }
- else
- {
- LLLightState* light = gGL.getLight(1);
-
- mHWLightColors[1] = LLColor4::black;
-
- light->setDiffuse(LLColor4::black);
- light->setAmbient(LLColor4::black);
- light->setSpecular(LLColor4::black);
- }
-}
-
-static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_dist)
-{
- F32 inten = light->getLightIntensity();
- if (inten < .001f)
- {
- return max_dist;
- }
- F32 radius = light->getLightRadius();
- BOOL selected = light->isSelected();
- LLVector3 dpos = light->getRenderPosition() - cam_pos;
- F32 dist2 = dpos.lengthSquared();
- if (!selected && dist2 > (max_dist + radius)*(max_dist + radius))
- {
- return max_dist;
- }
- F32 dist = (F32) sqrt(dist2);
- dist *= 1.f / inten;
- dist -= radius;
- if (selected)
- {
- dist -= 10000.f; // selected lights get highest priority
- }
- if (light->mDrawable.notNull() && light->mDrawable->isState(LLDrawable::ACTIVE))
- {
- // moving lights get a little higher priority (too much causes artifacts)
- dist -= light->getLightRadius()*0.25f;
- }
- return dist;
-}
-
-void LLPipeline::calcNearbyLights(LLCamera& camera)
-{
- assertInitialized();
-
- if (LLPipeline::sReflectionRender)
- {
- return;
- }
-
- if (mLightingDetail >= 1)
- {
- // mNearbyLight (and all light_set_t's) are sorted such that
- // begin() == the closest light and rbegin() == the farthest light
- const S32 MAX_LOCAL_LIGHTS = 6;
-// LLVector3 cam_pos = gAgent.getCameraPositionAgent();
- LLVector3 cam_pos = LLViewerJoystick::getInstance()->getOverrideCamera() ?
- camera.getOrigin() :
- gAgent.getPositionAgent();
-
- F32 max_dist = LIGHT_MAX_RADIUS * 4.f; // ignore enitrely lights > 4 * max light rad
-
- // UPDATE THE EXISTING NEARBY LIGHTS
- light_set_t cur_nearby_lights;
- for (light_set_t::iterator iter = mNearbyLights.begin();
- iter != mNearbyLights.end(); iter++)
- {
- const Light* light = &(*iter);
- LLDrawable* drawable = light->drawable;
- LLVOVolume* volight = drawable->getVOVolume();
- if (!volight || !drawable->isState(LLDrawable::LIGHT))
- {
- drawable->clearState(LLDrawable::NEARBY_LIGHT);
- continue;
- }
- if (light->fade <= -LIGHT_FADE_TIME)
- {
- drawable->clearState(LLDrawable::NEARBY_LIGHT);
- continue;
- }
- if (!sRenderAttachedLights && volight && volight->isAttachment())
- {
- drawable->clearState(LLDrawable::NEARBY_LIGHT);
- continue;
- }
-
- F32 dist = calc_light_dist(volight, cam_pos, max_dist);
- cur_nearby_lights.insert(Light(drawable, dist, light->fade));
- }
- mNearbyLights = cur_nearby_lights;
-
- // FIND NEW LIGHTS THAT ARE IN RANGE
- light_set_t new_nearby_lights;
- for (LLDrawable::drawable_set_t::iterator iter = mLights.begin();
- iter != mLights.end(); ++iter)
- {
- LLDrawable* drawable = *iter;
- LLVOVolume* light = drawable->getVOVolume();
- if (!light || drawable->isState(LLDrawable::NEARBY_LIGHT))
- {
- continue;
- }
- if (light->isHUDAttachment())
- {
- continue; // no lighting from HUD objects
- }
- F32 dist = calc_light_dist(light, cam_pos, max_dist);
- if (dist >= max_dist)
- {
- continue;
- }
- if (!sRenderAttachedLights && light && light->isAttachment())
- {
- continue;
- }
- new_nearby_lights.insert(Light(drawable, dist, 0.f));
- if (new_nearby_lights.size() > (U32)MAX_LOCAL_LIGHTS)
- {
- new_nearby_lights.erase(--new_nearby_lights.end());
- const Light& last = *new_nearby_lights.rbegin();
- max_dist = last.dist;
- }
- }
-
- // INSERT ANY NEW LIGHTS
- for (light_set_t::iterator iter = new_nearby_lights.begin();
- iter != new_nearby_lights.end(); iter++)
- {
- const Light* light = &(*iter);
- if (mNearbyLights.size() < (U32)MAX_LOCAL_LIGHTS)
- {
- mNearbyLights.insert(*light);
- ((LLDrawable*) light->drawable)->setState(LLDrawable::NEARBY_LIGHT);
- }
- else
- {
- // crazy cast so that we can overwrite the fade value
- // even though gcc enforces sets as const
- // (fade value doesn't affect sort so this is safe)
- Light* farthest_light = ((Light*) (&(*(mNearbyLights.rbegin()))));
- if (light->dist < farthest_light->dist)
- {
- if (farthest_light->fade >= 0.f)
- {
- farthest_light->fade = -gFrameIntervalSeconds;
- }
- }
- else
- {
- break; // none of the other lights are closer
- }
- }
- }
-
- }
-}
-
-void LLPipeline::setupHWLights(LLDrawPool* pool)
-{
- assertInitialized();
-
- // Ambient
- if (!LLGLSLShader::sNoFixedFunction)
- {
- gGL.syncMatrices();
- LLColor4 ambient = gSky.getTotalAmbientColor();
- gGL.setAmbientLightColor(ambient);
- }
-
- // Light 0 = Sun or Moon (All objects)
- {
- if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS)
- {
- mSunDir.setVec(gSky.getSunDirection());
- mSunDiffuse.setVec(gSky.getSunDiffuseColor());
- }
- else
- {
- mSunDir.setVec(gSky.getMoonDirection());
- mSunDiffuse.setVec(gSky.getMoonDiffuseColor());
- }
-
- F32 max_color = llmax(mSunDiffuse.mV[0], mSunDiffuse.mV[1], mSunDiffuse.mV[2]);
- if (max_color > 1.f)
- {
- mSunDiffuse *= 1.f/max_color;
- }
- mSunDiffuse.clamp();
-
- LLVector4 light_pos(mSunDir, 0.0f);
- LLColor4 light_diffuse = mSunDiffuse;
- mHWLightColors[0] = light_diffuse;
-
- LLLightState* light = gGL.getLight(0);
- light->setPosition(light_pos);
- light->setDiffuse(light_diffuse);
- light->setAmbient(LLColor4::black);
- light->setSpecular(LLColor4::black);
- light->setConstantAttenuation(1.f);
- light->setLinearAttenuation(0.f);
- light->setQuadraticAttenuation(0.f);
- light->setSpotExponent(0.f);
- light->setSpotCutoff(180.f);
- }
-
- // Light 1 = Backlight (for avatars)
- // (set by enableLightsAvatar)
-
- S32 cur_light = 2;
-
- // Nearby lights = LIGHT 2-7
-
- mLightMovingMask = 0;
-
- if (mLightingDetail >= 1)
- {
- for (light_set_t::iterator iter = mNearbyLights.begin();
- iter != mNearbyLights.end(); ++iter)
- {
- LLDrawable* drawable = iter->drawable;
- LLVOVolume* light = drawable->getVOVolume();
- if (!light)
- {
- continue;
- }
- if (drawable->isState(LLDrawable::ACTIVE))
- {
- mLightMovingMask |= (1<<cur_light);
- }
-
- LLColor4 light_color = light->getLightColor();
- light_color.mV[3] = 0.0f;
-
- F32 fade = iter->fade;
- if (fade < LIGHT_FADE_TIME)
- {
- // fade in/out light
- if (fade >= 0.f)
- {
- fade = fade / LIGHT_FADE_TIME;
- ((Light*) (&(*iter)))->fade += gFrameIntervalSeconds;
- }
- else
- {
- fade = 1.f + fade / LIGHT_FADE_TIME;
- ((Light*) (&(*iter)))->fade -= gFrameIntervalSeconds;
- }
- fade = llclamp(fade,0.f,1.f);
- light_color *= fade;
- }
-
- LLVector3 light_pos(light->getRenderPosition());
- LLVector4 light_pos_gl(light_pos, 1.0f);
-
- F32 light_radius = llmax(light->getLightRadius(), 0.001f);
-
- F32 x = (3.f * (1.f + light->getLightFalloff())); // why this magic? probably trying to match a historic behavior.
- float linatten = x / (light_radius); // % of brightness at radius
-
- mHWLightColors[cur_light] = light_color;
- LLLightState* light_state = gGL.getLight(cur_light);
-
- light_state->setPosition(light_pos_gl);
- light_state->setDiffuse(light_color);
- light_state->setAmbient(LLColor4::black);
- light_state->setConstantAttenuation(0.f);
- if (sRenderDeferred)
- {
- light_state->setLinearAttenuation(light_radius*1.5f);
- light_state->setQuadraticAttenuation(light->getLightFalloff()*0.5f+1.f);
- }
- else
- {
- light_state->setLinearAttenuation(linatten);
- light_state->setQuadraticAttenuation(0.f);
- }
-
-
- if (light->isLightSpotlight() // directional (spot-)light
- && (LLPipeline::sRenderDeferred || RenderSpotLightsInNondeferred)) // these are only rendered as GL spotlights if we're in deferred rendering mode *or* the setting forces them on
- {
- LLVector3 spotparams = light->getSpotLightParams();
- LLQuaternion quat = light->getRenderRotation();
- LLVector3 at_axis(0,0,-1); // this matches deferred rendering's object light direction
- at_axis *= quat;
-
- light_state->setSpotDirection(at_axis);
- light_state->setSpotCutoff(90.f);
- light_state->setSpotExponent(2.f);
-
- light_state->setSpecular(LLColor4::black);
- }
- else // omnidirectional (point) light
- {
- light_state->setSpotExponent(0.f);
- light_state->setSpotCutoff(180.f);
-
- // we use specular.w = 1.0 as a cheap hack for the shaders to know that this is omnidirectional rather than a spotlight
- const LLColor4 specular(0.f, 0.f, 0.f, 1.f);
- light_state->setSpecular(specular);
- }
- cur_light++;
- if (cur_light >= 8)
- {
- break; // safety
- }
- }
- }
- for ( ; cur_light < 8 ; cur_light++)
- {
- mHWLightColors[cur_light] = LLColor4::black;
- LLLightState* light = gGL.getLight(cur_light);
-
- light->setDiffuse(LLColor4::black);
- light->setAmbient(LLColor4::black);
- light->setSpecular(LLColor4::black);
- }
- if (gAgentAvatarp &&
- gAgentAvatarp->mSpecialRenderMode == 3)
- {
- LLColor4 light_color = LLColor4::white;
- light_color.mV[3] = 0.0f;
-
- LLVector3 light_pos(LLViewerCamera::getInstance()->getOrigin());
- LLVector4 light_pos_gl(light_pos, 1.0f);
-
- F32 light_radius = 16.f;
-
- F32 x = 3.f;
- float linatten = x / (light_radius); // % of brightness at radius
-
- mHWLightColors[2] = light_color;
- LLLightState* light = gGL.getLight(2);
-
- light->setPosition(light_pos_gl);
- light->setDiffuse(light_color);
- light->setAmbient(LLColor4::black);
- light->setSpecular(LLColor4::black);
- light->setQuadraticAttenuation(0.f);
- light->setConstantAttenuation(0.f);
- light->setLinearAttenuation(linatten);
- light->setSpotExponent(0.f);
- light->setSpotCutoff(180.f);
- }
-
- // Init GL state
- if (!LLGLSLShader::sNoFixedFunction)
- {
- glDisable(GL_LIGHTING);
- }
-
- for (S32 i = 0; i < 8; ++i)
- {
- gGL.getLight(i)->disable();
- }
- mLightMask = 0;
-}
-
-void LLPipeline::enableLights(U32 mask)
-{
- assertInitialized();
-
- if (mLightingDetail == 0)
- {
- mask &= 0xf003; // sun and backlight only (and fullbright bit)
- }
- if (mLightMask != mask)
- {
- stop_glerror();
- if (!mLightMask)
- {
- if (!LLGLSLShader::sNoFixedFunction)
- {
- glEnable(GL_LIGHTING);
- }
- }
- if (mask)
- {
- stop_glerror();
- for (S32 i=0; i<8; i++)
- {
- LLLightState* light = gGL.getLight(i);
- if (mask & (1<<i))
- {
- light->enable();
- light->setDiffuse(mHWLightColors[i]);
- }
- else
- {
- light->disable();
- light->setDiffuse(LLColor4::black);
- }
- }
- stop_glerror();
- }
- else
- {
- if (!LLGLSLShader::sNoFixedFunction)
- {
- glDisable(GL_LIGHTING);
- }
- }
- mLightMask = mask;
- stop_glerror();
-
- LLColor4 ambient = gSky.getTotalAmbientColor();
- gGL.setAmbientLightColor(ambient);
- }
-}
-
-void LLPipeline::enableLightsStatic()
-{
- assertInitialized();
- U32 mask = 0x01; // Sun
- if (mLightingDetail >= 2)
- {
- mask |= mLightMovingMask; // Hardware moving lights
- }
- else
- {
- mask |= 0xff & (~2); // Hardware local lights
- }
- enableLights(mask);
-}
-
-void LLPipeline::enableLightsDynamic()
-{
- assertInitialized();
- U32 mask = 0xff & (~2); // Local lights
- enableLights(mask);
-
- if (isAgentAvatarValid() && getLightingDetail() <= 0)
- {
- if (gAgentAvatarp->mSpecialRenderMode == 0) // normal
- {
- gPipeline.enableLightsAvatar();
- }
- else if (gAgentAvatarp->mSpecialRenderMode >= 1) // anim preview
- {
- gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f));
- }
- }
-}
-
-void LLPipeline::enableLightsAvatar()
-{
- U32 mask = 0xff; // All lights
- setupAvatarLights(FALSE);
- enableLights(mask);
-}
-
-void LLPipeline::enableLightsPreview()
-{
- disableLights();
-
- if (!LLGLSLShader::sNoFixedFunction)
- {
- glEnable(GL_LIGHTING);
- }
-
- LLColor4 ambient = PreviewAmbientColor;
- gGL.setAmbientLightColor(ambient);
-
- LLColor4 diffuse0 = PreviewDiffuse0;
- LLColor4 specular0 = PreviewSpecular0;
- LLColor4 diffuse1 = PreviewDiffuse1;
- LLColor4 specular1 = PreviewSpecular1;
- LLColor4 diffuse2 = PreviewDiffuse2;
- LLColor4 specular2 = PreviewSpecular2;
-
- LLVector3 dir0 = PreviewDirection0;
- LLVector3 dir1 = PreviewDirection1;
- LLVector3 dir2 = PreviewDirection2;
-
- dir0.normVec();
- dir1.normVec();
- dir2.normVec();
-
- LLVector4 light_pos(dir0, 0.0f);
-
- LLLightState* light = gGL.getLight(0);
-
- light->enable();
- light->setPosition(light_pos);
- light->setDiffuse(diffuse0);
- light->setAmbient(LLColor4::black);
- light->setSpecular(specular0);
- light->setSpotExponent(0.f);
- light->setSpotCutoff(180.f);
-
- light_pos = LLVector4(dir1, 0.f);
-
- light = gGL.getLight(1);
- light->enable();
- light->setPosition(light_pos);
- light->setDiffuse(diffuse1);
- light->setAmbient(LLColor4::black);
- light->setSpecular(specular1);
- light->setSpotExponent(0.f);
- light->setSpotCutoff(180.f);
-
- light_pos = LLVector4(dir2, 0.f);
- light = gGL.getLight(2);
- light->enable();
- light->setPosition(light_pos);
- light->setDiffuse(diffuse2);
- light->setAmbient(LLColor4::black);
- light->setSpecular(specular2);
- light->setSpotExponent(0.f);
- light->setSpotCutoff(180.f);
-}
-
-
-void LLPipeline::enableLightsAvatarEdit(const LLColor4& color)
-{
- U32 mask = 0x2002; // Avatar backlight only, set ambient
- setupAvatarLights(TRUE);
- enableLights(mask);
-
- gGL.setAmbientLightColor(color);
-}
-
-void LLPipeline::enableLightsFullbright(const LLColor4& color)
-{
- assertInitialized();
- U32 mask = 0x1000; // Non-0 mask, set ambient
- enableLights(mask);
-
- gGL.setAmbientLightColor(color);
-}
-
-void LLPipeline::disableLights()
-{
- enableLights(0); // no lighting (full bright)
-}
-
-//============================================================================
-
-class LLMenuItemGL;
-class LLInvFVBridge;
-struct cat_folder_pair;
-class LLVOBranch;
-class LLVOLeaf;
-
-void LLPipeline::findReferences(LLDrawable *drawablep)
-{
- assertInitialized();
- if (mLights.find(drawablep) != mLights.end())
- {
- llinfos << "In mLights" << llendl;
- }
- if (std::find(mMovedList.begin(), mMovedList.end(), drawablep) != mMovedList.end())
- {
- llinfos << "In mMovedList" << llendl;
- }
- if (std::find(mShiftList.begin(), mShiftList.end(), drawablep) != mShiftList.end())
- {
- llinfos << "In mShiftList" << llendl;
- }
- if (mRetexturedList.find(drawablep) != mRetexturedList.end())
- {
- llinfos << "In mRetexturedList" << llendl;
- }
-
- if (std::find(mBuildQ1.begin(), mBuildQ1.end(), drawablep) != mBuildQ1.end())
- {
- llinfos << "In mBuildQ1" << llendl;
- }
- if (std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep) != mBuildQ2.end())
- {
- llinfos << "In mBuildQ2" << llendl;
- }
-
- S32 count;
-
- count = gObjectList.findReferences(drawablep);
- if (count)
- {
- llinfos << "In other drawables: " << count << " references" << llendl;
- }
-}
-
-BOOL LLPipeline::verify()
-{
- BOOL ok = assertInitialized();
- if (ok)
- {
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- if (!poolp->verify())
- {
- ok = FALSE;
- }
- }
- }
-
- if (!ok)
- {
- llwarns << "Pipeline verify failed!" << llendl;
- }
- return ok;
-}
-
-//////////////////////////////
-//
-// Collision detection
-//
-//
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * A method to compute a ray-AABB intersection.
- * Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990
- * Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500)
- * Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only)
- *
- * Hence this version is faster as well as more robust than the original one.
- *
- * Should work provided:
- * 1) the integer representation of 0.0f is 0x00000000
- * 2) the sign bit of the float is the most significant one
- *
- * Report bugs: p.terdiman@codercorner.com
- *
- * \param aabb [in] the axis-aligned bounding box
- * \param origin [in] ray origin
- * \param dir [in] ray direction
- * \param coord [out] impact coordinates
- * \return true if ray intersects AABB
- */
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//#define RAYAABB_EPSILON 0.00001f
-#define IR(x) ((U32&)x)
-
-bool LLRayAABB(const LLVector3 ¢er, const LLVector3 &size, const LLVector3& origin, const LLVector3& dir, LLVector3 &coord, F32 epsilon)
-{
- BOOL Inside = TRUE;
- LLVector3 MinB = center - size;
- LLVector3 MaxB = center + size;
- LLVector3 MaxT;
- MaxT.mV[VX]=MaxT.mV[VY]=MaxT.mV[VZ]=-1.0f;
-
- // Find candidate planes.
- for(U32 i=0;i<3;i++)
- {
- if(origin.mV[i] < MinB.mV[i])
- {
- coord.mV[i] = MinB.mV[i];
- Inside = FALSE;
-
- // Calculate T distances to candidate planes
- if(IR(dir.mV[i])) MaxT.mV[i] = (MinB.mV[i] - origin.mV[i]) / dir.mV[i];
- }
- else if(origin.mV[i] > MaxB.mV[i])
- {
- coord.mV[i] = MaxB.mV[i];
- Inside = FALSE;
-
- // Calculate T distances to candidate planes
- if(IR(dir.mV[i])) MaxT.mV[i] = (MaxB.mV[i] - origin.mV[i]) / dir.mV[i];
- }
- }
-
- // Ray origin inside bounding box
- if(Inside)
- {
- coord = origin;
- return true;
- }
-
- // Get largest of the maxT's for final choice of intersection
- U32 WhichPlane = 0;
- if(MaxT.mV[1] > MaxT.mV[WhichPlane]) WhichPlane = 1;
- if(MaxT.mV[2] > MaxT.mV[WhichPlane]) WhichPlane = 2;
-
- // Check final candidate actually inside box
- if(IR(MaxT.mV[WhichPlane])&0x80000000) return false;
-
- for(U32 i=0;i<3;i++)
- {
- if(i!=WhichPlane)
- {
- coord.mV[i] = origin.mV[i] + MaxT.mV[WhichPlane] * dir.mV[i];
- if (epsilon > 0)
- {
- if(coord.mV[i] < MinB.mV[i] - epsilon || coord.mV[i] > MaxB.mV[i] + epsilon) return false;
- }
- else
- {
- if(coord.mV[i] < MinB.mV[i] || coord.mV[i] > MaxB.mV[i]) return false;
- }
- }
- }
- return true; // ray hits box
-}
-
-//////////////////////////////
-//
-// Macros, functions, and inline methods from other classes
-//
-//
-
-void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light)
-{
- if (drawablep && assertInitialized())
- {
- if (is_light)
- {
- mLights.insert(drawablep);
- drawablep->setState(LLDrawable::LIGHT);
- }
- else
- {
- drawablep->clearState(LLDrawable::LIGHT);
- mLights.erase(drawablep);
- }
- }
-}
-
-//static
-void LLPipeline::toggleRenderType(U32 type)
-{
- gPipeline.mRenderTypeEnabled[type] = !gPipeline.mRenderTypeEnabled[type];
- if (type == LLPipeline::RENDER_TYPE_WATER)
- {
- gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER] = !gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER];
- }
-}
-
-//static
-void LLPipeline::toggleRenderTypeControl(void* data)
-{
- U32 type = (U32)(intptr_t)data;
- U32 bit = (1<<type);
- if (gPipeline.hasRenderType(type))
- {
- llinfos << "Toggling render type mask " << std::hex << bit << " off" << std::dec << llendl;
- }
- else
- {
- llinfos << "Toggling render type mask " << std::hex << bit << " on" << std::dec << llendl;
- }
- gPipeline.toggleRenderType(type);
-}
-
-//static
-BOOL LLPipeline::hasRenderTypeControl(void* data)
-{
- U32 type = (U32)(intptr_t)data;
- return gPipeline.hasRenderType(type);
-}
-
-// Allows UI items labeled "Hide foo" instead of "Show foo"
-//static
-BOOL LLPipeline::toggleRenderTypeControlNegated(void* data)
-{
- S32 type = (S32)(intptr_t)data;
- return !gPipeline.hasRenderType(type);
-}
-
-//static
-void LLPipeline::toggleRenderDebug(void* data)
-{
- U32 bit = (U32)(intptr_t)data;
- if (gPipeline.hasRenderDebugMask(bit))
- {
- llinfos << "Toggling render debug mask " << std::hex << bit << " off" << std::dec << llendl;
- }
- else
- {
- llinfos << "Toggling render debug mask " << std::hex << bit << " on" << std::dec << llendl;
- }
- gPipeline.mRenderDebugMask ^= bit;
-}
-
-
-//static
-BOOL LLPipeline::toggleRenderDebugControl(void* data)
-{
- U32 bit = (U32)(intptr_t)data;
- return gPipeline.hasRenderDebugMask(bit);
-}
-
-//static
-void LLPipeline::toggleRenderDebugFeature(void* data)
-{
- U32 bit = (U32)(intptr_t)data;
- gPipeline.mRenderDebugFeatureMask ^= bit;
-}
-
-
-//static
-BOOL LLPipeline::toggleRenderDebugFeatureControl(void* data)
-{
- U32 bit = (U32)(intptr_t)data;
- return gPipeline.hasRenderDebugFeatureMask(bit);
-}
-
-void LLPipeline::setRenderDebugFeatureControl(U32 bit, bool value)
-{
- if (value)
- {
- gPipeline.mRenderDebugFeatureMask |= bit;
- }
- else
- {
- gPipeline.mRenderDebugFeatureMask &= !bit;
- }
-}
-
-// static
-void LLPipeline::setRenderScriptedBeacons(BOOL val)
-{
- sRenderScriptedBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderScriptedBeacons(void*)
-{
- sRenderScriptedBeacons = !sRenderScriptedBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderScriptedBeacons(void*)
-{
- return sRenderScriptedBeacons;
-}
-
-// static
-void LLPipeline::setRenderScriptedTouchBeacons(BOOL val)
-{
- sRenderScriptedTouchBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderScriptedTouchBeacons(void*)
-{
- sRenderScriptedTouchBeacons = !sRenderScriptedTouchBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderScriptedTouchBeacons(void*)
-{
- return sRenderScriptedTouchBeacons;
-}
-
-// static
-void LLPipeline::setRenderMOAPBeacons(BOOL val)
-{
- sRenderMOAPBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderMOAPBeacons(void*)
-{
- sRenderMOAPBeacons = !sRenderMOAPBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderMOAPBeacons(void*)
-{
- return sRenderMOAPBeacons;
-}
-
-// static
-void LLPipeline::setRenderPhysicalBeacons(BOOL val)
-{
- sRenderPhysicalBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderPhysicalBeacons(void*)
-{
- sRenderPhysicalBeacons = !sRenderPhysicalBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderPhysicalBeacons(void*)
-{
- return sRenderPhysicalBeacons;
-}
-
-// static
-void LLPipeline::setRenderParticleBeacons(BOOL val)
-{
- sRenderParticleBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderParticleBeacons(void*)
-{
- sRenderParticleBeacons = !sRenderParticleBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderParticleBeacons(void*)
-{
- return sRenderParticleBeacons;
-}
-
-// static
-void LLPipeline::setRenderSoundBeacons(BOOL val)
-{
- sRenderSoundBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderSoundBeacons(void*)
-{
- sRenderSoundBeacons = !sRenderSoundBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderSoundBeacons(void*)
-{
- return sRenderSoundBeacons;
-}
-
-// static
-void LLPipeline::setRenderBeacons(BOOL val)
-{
- sRenderBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderBeacons(void*)
-{
- sRenderBeacons = !sRenderBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderBeacons(void*)
-{
- return sRenderBeacons;
-}
-
-// static
-void LLPipeline::setRenderHighlights(BOOL val)
-{
- sRenderHighlight = val;
-}
-
-// static
-void LLPipeline::toggleRenderHighlights(void*)
-{
- sRenderHighlight = !sRenderHighlight;
-}
-
-// static
-BOOL LLPipeline::getRenderHighlights(void*)
-{
- return sRenderHighlight;
-}
-
-LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end,
- BOOL pick_transparent,
- S32* face_hit,
- LLVector3* intersection, // return the intersection point
- LLVector2* tex_coord, // return the texture coordinates of the intersection point
- LLVector3* normal, // return the surface normal at the intersection point
- LLVector3* bi_normal // return the surface bi-normal at the intersection point
- )
-{
- LLDrawable* drawable = NULL;
-
- LLVector3 local_end = end;
-
- LLVector3 position;
-
- sPickAvatar = FALSE; //LLToolMgr::getInstance()->inBuildMode() ? FALSE : TRUE;
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
-
- for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++)
- {
- if ((j == LLViewerRegion::PARTITION_VOLUME) ||
- (j == LLViewerRegion::PARTITION_BRIDGE) ||
- (j == LLViewerRegion::PARTITION_TERRAIN) ||
- (j == LLViewerRegion::PARTITION_TREE) ||
- (j == LLViewerRegion::PARTITION_GRASS)) // only check these partitions for now
- {
- LLSpatialPartition* part = region->getSpatialPartition(j);
- if (part && hasRenderType(part->mDrawableType))
- {
- LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal);
- if (hit)
- {
- drawable = hit;
- local_end = position;
- }
- }
- }
- }
- }
-
- if (!sPickAvatar)
- {
- //save hit info in case we need to restore
- //due to attachment override
- LLVector3 local_normal;
- LLVector3 local_binormal;
- LLVector2 local_texcoord;
- S32 local_face_hit = -1;
-
- if (face_hit)
- {
- local_face_hit = *face_hit;
- }
- if (tex_coord)
- {
- local_texcoord = *tex_coord;
- }
- if (bi_normal)
- {
- local_binormal = *bi_normal;
- }
- if (normal)
- {
- local_normal = *normal;
- }
-
- const F32 ATTACHMENT_OVERRIDE_DIST = 0.1f;
-
- //check against avatars
- sPickAvatar = TRUE;
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
-
- LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_BRIDGE);
- if (part && hasRenderType(part->mDrawableType))
- {
- LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal);
- if (hit)
- {
- if (!drawable ||
- !drawable->getVObj()->isAttachment() ||
- (position-local_end).magVec() > ATTACHMENT_OVERRIDE_DIST)
- { //avatar overrides if previously hit drawable is not an attachment or
- //attachment is far enough away from detected intersection
- drawable = hit;
- local_end = position;
- }
- else
- { //prioritize attachments over avatars
- position = local_end;
-
- if (face_hit)
- {
- *face_hit = local_face_hit;
- }
- if (tex_coord)
- {
- *tex_coord = local_texcoord;
- }
- if (bi_normal)
- {
- *bi_normal = local_binormal;
- }
- if (normal)
- {
- *normal = local_normal;
- }
- }
- }
- }
- }
- }
-
- //check all avatar nametags (silly, isn't it?)
- for (std::vector< LLCharacter* >::iterator iter = LLCharacter::sInstances.begin();
- iter != LLCharacter::sInstances.end();
- ++iter)
- {
- LLVOAvatar* av = (LLVOAvatar*) *iter;
- if (av->mNameText.notNull()
- && av->mNameText->lineSegmentIntersect(start, local_end, position))
- {
- drawable = av->mDrawable;
- local_end = position;
- }
- }
-
- if (intersection)
- {
- *intersection = position;
- }
-
- return drawable ? drawable->getVObj().get() : NULL;
-}
-
-LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector3& start, const LLVector3& end,
- BOOL pick_transparent,
- S32* face_hit,
- LLVector3* intersection, // return the intersection point
- LLVector2* tex_coord, // return the texture coordinates of the intersection point
- LLVector3* normal, // return the surface normal at the intersection point
- LLVector3* bi_normal // return the surface bi-normal at the intersection point
- )
-{
- LLDrawable* drawable = NULL;
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
-
- BOOL toggle = FALSE;
- if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
- toggle = TRUE;
- }
-
- LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_HUD);
- if (part)
- {
- LLDrawable* hit = part->lineSegmentIntersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal);
- if (hit)
- {
- drawable = hit;
- }
- }
-
- if (toggle)
- {
- toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
- }
- }
- return drawable ? drawable->getVObj().get() : NULL;
-}
-
-LLSpatialPartition* LLPipeline::getSpatialPartition(LLViewerObject* vobj)
-{
- if (vobj)
- {
- LLViewerRegion* region = vobj->getRegion();
- if (region)
- {
- return region->getSpatialPartition(vobj->getPartitionType());
- }
- }
- return NULL;
-}
-
-void LLPipeline::resetVertexBuffers(LLDrawable* drawable)
-{
- if (!drawable || drawable->isDead())
- {
- return;
- }
-
- for (S32 i = 0; i < drawable->getNumFaces(); i++)
- {
- LLFace* facep = drawable->getFace(i);
- facep->clearVertexBuffer();
- }
-}
-
-void LLPipeline::resetVertexBuffers()
-{
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- part->resetVertexBuffers();
- }
- }
- }
-
- resetDrawOrders();
-
- gSky.resetVertexBuffers();
-
- if ( LLPathingLib::getInstance() )
- {
- LLPathingLib::getInstance()->cleanupVBOManger();
- }
- LLVertexBuffer::cleanupClass();
-
- //delete all name pool caches
- LLGLNamePool::cleanupPools();
-
- if (LLVertexBuffer::sGLCount > 0)
- {
- llwarns << "VBO wipe failed." << llendl;
- }
-
- llassert(LLVertexBuffer::sGLCount == 0);
-
- LLVertexBuffer::unbind();
-
- sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
- sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
- LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
- LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO");
- LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw");
- LLVertexBuffer::sEnableVBOs = gSavedSettings.getBOOL("RenderVBOEnable");
- LLVertexBuffer::sDisableVBOMapping = LLVertexBuffer::sEnableVBOs && gSavedSettings.getBOOL("RenderVBOMappingDisable") ;
- sBakeSunlight = gSavedSettings.getBOOL("RenderBakeSunlight");
- sNoAlpha = gSavedSettings.getBOOL("RenderNoAlpha");
- LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind");
-
- LLVertexBuffer::initClass(LLVertexBuffer::sEnableVBOs, LLVertexBuffer::sDisableVBOMapping);
-}
-
-void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture, BOOL batch_texture)
-{
- LLMemType mt_ro(LLMemType::MTYPE_PIPELINE_RENDER_OBJECTS);
- assertInitialized();
- gGL.loadMatrix(gGLModelView);
- gGLLastMatrix = NULL;
- mSimplePool->pushBatches(type, mask, texture, batch_texture);
- gGL.loadMatrix(gGLModelView);
- gGLLastMatrix = NULL;
-}
-
-void apply_cube_face_rotation(U32 face)
-{
- switch (face)
- {
- case 0:
- gGL.rotatef(90.f, 0, 1, 0);
- gGL.rotatef(180.f, 1, 0, 0);
- break;
- case 2:
- gGL.rotatef(-90.f, 1, 0, 0);
- break;
- case 4:
- gGL.rotatef(180.f, 0, 1, 0);
- gGL.rotatef(180.f, 0, 0, 1);
- break;
- case 1:
- gGL.rotatef(-90.f, 0, 1, 0);
- gGL.rotatef(180.f, 1, 0, 0);
- break;
- case 3:
- gGL.rotatef(90, 1, 0, 0);
- break;
- case 5:
- gGL.rotatef(180, 0, 0, 1);
- break;
- }
-}
-
-void validate_framebuffer_object()
-{
- GLenum status;
- status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
- switch(status)
- {
- case GL_FRAMEBUFFER_COMPLETE:
- //framebuffer OK, no error.
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
- // frame buffer not OK: probably means unsupported depth buffer format
- llerrs << "Framebuffer Incomplete Missing Attachment." << llendl;
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
- // frame buffer not OK: probably means unsupported depth buffer format
- llerrs << "Framebuffer Incomplete Attachment." << llendl;
- break;
- case GL_FRAMEBUFFER_UNSUPPORTED:
- /* choose different formats */
- llerrs << "Framebuffer unsupported." << llendl;
- break;
- default:
- llerrs << "Unknown framebuffer status." << llendl;
- break;
- }
-}
-
-void LLPipeline::bindScreenToTexture()
-{
-
-}
-
-static LLFastTimer::DeclareTimer FTM_RENDER_BLOOM("Bloom");
-
-void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
-{
- LLMemType mt_ru(LLMemType::MTYPE_PIPELINE_RENDER_BLOOM);
- if (!(gPipeline.canUseVertexShaders() &&
- sRenderGlow))
- {
- return;
- }
-
- LLVertexBuffer::unbind();
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
- assertInitialized();
-
- if (gUseWireframe)
- {
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- }
-
- LLVector2 tc1(0,0);
- LLVector2 tc2((F32) mScreen.getWidth()*2,
- (F32) mScreen.getHeight()*2);
-
- LLFastTimer ftm(FTM_RENDER_BLOOM);
- gGL.color4f(1,1,1,1);
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable blend(GL_BLEND);
- LLGLDisable cull(GL_CULL_FACE);
-
- enableLightsFullbright(LLColor4(1,1,1,1));
-
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.pushMatrix();
- gGL.loadIdentity();
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.pushMatrix();
- gGL.loadIdentity();
-
- LLGLDisable test(GL_ALPHA_TEST);
-
- gGL.setColorMask(true, true);
- glClearColor(0,0,0,0);
-
- {
- {
- LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
- mGlow[2].bindTarget();
- mGlow[2].clear();
- }
-
- gGlowExtractProgram.bind();
- F32 minLum = llmax((F32) RenderGlowMinLuminance, 0.0f);
- F32 maxAlpha = RenderGlowMaxExtractAlpha;
- F32 warmthAmount = RenderGlowWarmthAmount;
- LLVector3 lumWeights = RenderGlowLumWeights;
- LLVector3 warmthWeights = RenderGlowWarmthWeights;
-
-
- gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MIN_LUMINANCE, minLum);
- gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MAX_EXTRACT_ALPHA, maxAlpha);
- gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_LUM_WEIGHTS, lumWeights.mV[0], lumWeights.mV[1], lumWeights.mV[2]);
- gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_WARMTH_WEIGHTS, warmthWeights.mV[0], warmthWeights.mV[1], warmthWeights.mV[2]);
- gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_WARMTH_AMOUNT, warmthAmount);
- LLGLEnable blend_on(GL_BLEND);
- LLGLEnable test(GL_ALPHA_TEST);
-
- gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
-
- mScreen.bindTexture(0, 0);
-
- gGL.color4f(1,1,1,1);
- gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
- gGL.vertex2f(3,-1);
-
- gGL.end();
-
- gGL.getTexUnit(0)->unbind(mScreen.getUsage());
-
- mGlow[2].flush();
- }
-
- tc1.setVec(0,0);
- tc2.setVec(2,2);
-
- // power of two between 1 and 1024
- U32 glowResPow = RenderGlowResolutionPow;
- const U32 glow_res = llmax(1,
- llmin(1024, 1 << glowResPow));
-
- S32 kernel = RenderGlowIterations*2;
- F32 delta = RenderGlowWidth / glow_res;
- // Use half the glow width if we have the res set to less than 9 so that it looks
- // almost the same in either case.
- if (glowResPow < 9)
- {
- delta *= 0.5f;
- }
- F32 strength = RenderGlowStrength;
-
- gGlowProgram.bind();
- gGlowProgram.uniform1f(LLShaderMgr::GLOW_STRENGTH, strength);
-
- for (S32 i = 0; i < kernel; i++)
- {
- {
- LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
- mGlow[i%2].bindTarget();
- mGlow[i%2].clear();
- }
-
- if (i == 0)
- {
- gGL.getTexUnit(0)->bind(&mGlow[2]);
- }
- else
- {
- gGL.getTexUnit(0)->bind(&mGlow[(i-1)%2]);
- }
-
- if (i%2 == 0)
- {
- gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, delta, 0);
- }
- else
- {
- gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, 0, delta);
- }
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
- gGL.vertex2f(3,-1);
-
- gGL.end();
-
- mGlow[i%2].flush();
- }
-
- gGlowProgram.unbind();
-
- if (LLRenderTarget::sUseFBO)
- {
- LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- }
-
- gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
- gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
- gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
- gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
- glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
-
- tc2.setVec((F32) mScreen.getWidth(),
- (F32) mScreen.getHeight());
-
- gGL.flush();
-
- LLVertexBuffer::unbind();
-
- if (LLPipeline::sRenderDeferred)
- {
-
- bool dof_enabled = !LLViewerCamera::getInstance()->cameraUnderWater() &&
- !LLToolMgr::getInstance()->inBuildMode() &&
- RenderDepthOfField;
-
-
- bool multisample = RenderFSAASamples > 1 && mFXAABuffer.isComplete();
-
- gViewerWindow->setup3DViewport();
-
- if (dof_enabled)
- {
- LLGLSLShader* shader = &gDeferredPostProgram;
- LLGLDisable blend(GL_BLEND);
-
- //depth of field focal plane calculations
- static F32 current_distance = 16.f;
- static F32 start_distance = 16.f;
- static F32 transition_time = 1.f;
-
- LLVector3 focus_point;
-
- LLViewerObject* obj = LLViewerMediaFocus::getInstance()->getFocusedObject();
- if (obj && obj->mDrawable && obj->isSelected())
- { //focus on selected media object
- S32 face_idx = LLViewerMediaFocus::getInstance()->getFocusedFace();
- if (obj && obj->mDrawable)
- {
- LLFace* face = obj->mDrawable->getFace(face_idx);
- if (face)
- {
- focus_point = face->getPositionAgent();
- }
- }
- }
-
- if (focus_point.isExactlyZero())
- {
- if (LLViewerJoystick::getInstance()->getOverrideCamera())
- { //focus on point under cursor
- focus_point = gDebugRaycastIntersection;
- }
- else if (gAgentCamera.cameraMouselook())
- { //focus on point under mouselook crosshairs
- gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE,
- NULL,
- &focus_point);
- }
- else
- {
- LLViewerObject* obj = gAgentCamera.getFocusObject();
- if (obj)
- { //focus on alt-zoom target
- focus_point = LLVector3(gAgentCamera.getFocusGlobal()-gAgent.getRegion()->getOriginGlobal());
- }
- else
- { //focus on your avatar
- focus_point = gAgent.getPositionAgent();
- }
- }
- }
-
- LLVector3 eye = LLViewerCamera::getInstance()->getOrigin();
- F32 target_distance = 16.f;
- if (!focus_point.isExactlyZero())
- {
- target_distance = LLViewerCamera::getInstance()->getAtAxis() * (focus_point-eye);
- }
-
- if (transition_time >= 1.f &&
- fabsf(current_distance-target_distance)/current_distance > 0.01f)
- { //large shift happened, interpolate smoothly to new target distance
- transition_time = 0.f;
- start_distance = current_distance;
- }
- else if (transition_time < 1.f)
- { //currently in a transition, continue interpolating
- transition_time += 1.f/CameraFocusTransitionTime*gFrameIntervalSeconds;
- transition_time = llmin(transition_time, 1.f);
-
- F32 t = cosf(transition_time*F_PI+F_PI)*0.5f+0.5f;
- current_distance = start_distance + (target_distance-start_distance)*t;
- }
- else
- { //small or no change, just snap to target distance
- current_distance = target_distance;
- }
-
- //convert to mm
- F32 subject_distance = current_distance*1000.f;
- F32 fnumber = CameraFNumber;
- F32 default_focal_length = CameraFocalLength;
-
- F32 fov = LLViewerCamera::getInstance()->getView();
-
- const F32 default_fov = CameraFieldOfView * F_PI/180.f;
- //const F32 default_aspect_ratio = gSavedSettings.getF32("CameraAspectRatio");
-
- //F32 aspect_ratio = (F32) mScreen.getWidth()/(F32)mScreen.getHeight();
-
- F32 dv = 2.f*default_focal_length * tanf(default_fov/2.f);
- //F32 dh = 2.f*default_focal_length * tanf(default_fov*default_aspect_ratio/2.f);
-
- F32 focal_length = dv/(2*tanf(fov/2.f));
-
- //F32 tan_pixel_angle = tanf(LLDrawable::sCurPixelAngle);
-
- // from wikipedia -- c = |s2-s1|/s2 * f^2/(N(S1-f))
- // where N = fnumber
- // s2 = dot distance
- // s1 = subject distance
- // f = focal length
- //
-
- F32 blur_constant = focal_length*focal_length/(fnumber*(subject_distance-focal_length));
- blur_constant /= 1000.f; //convert to meters for shader
- F32 magnification = focal_length/(subject_distance-focal_length);
-
- { //build diffuse+bloom+CoF
- mDeferredLight.bindTarget();
- shader = &gDeferredCoFProgram;
-
- bindDeferredShader(*shader);
-
- S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage());
- if (channel > -1)
- {
- mScreen.bindTexture(0, channel);
- }
-
- shader->uniform1f(LLShaderMgr::DOF_FOCAL_DISTANCE, -subject_distance/1000.f);
- shader->uniform1f(LLShaderMgr::DOF_BLUR_CONSTANT, blur_constant);
- shader->uniform1f(LLShaderMgr::DOF_TAN_PIXEL_ANGLE, tanf(1.f/LLDrawable::sCurPixelAngle));
- shader->uniform1f(LLShaderMgr::DOF_MAGNIFICATION, magnification);
- shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF);
- shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale);
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
- gGL.vertex2f(3,-1);
-
- gGL.end();
-
- unbindDeferredShader(*shader);
- mDeferredLight.flush();
- }
-
- { //perform DoF sampling at half-res (preserve alpha channel)
- mScreen.bindTarget();
- glViewport(0,0,(GLsizei) (mScreen.getWidth()*CameraDoFResScale), (GLsizei) (mScreen.getHeight()*CameraDoFResScale));
- gGL.setColorMask(true, false);
-
- shader = &gDeferredPostProgram;
- bindDeferredShader(*shader);
- S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage());
- if (channel > -1)
- {
- mDeferredLight.bindTexture(0, channel);
- }
-
- shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF);
- shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale);
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
- gGL.vertex2f(3,-1);
-
- gGL.end();
-
- unbindDeferredShader(*shader);
- mScreen.flush();
- gGL.setColorMask(true, true);
- }
-
- { //combine result based on alpha
- if (multisample)
- {
- mDeferredLight.bindTarget();
- glViewport(0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight());
- }
- else
- {
- gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
- gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
- gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
- gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
- glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
- }
-
- shader = &gDeferredDoFCombineProgram;
- bindDeferredShader(*shader);
-
- S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage());
- if (channel > -1)
- {
- mScreen.bindTexture(0, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF);
- shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale);
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
- gGL.vertex2f(3,-1);
-
- gGL.end();
-
- unbindDeferredShader(*shader);
-
- if (multisample)
- {
- mDeferredLight.flush();
- }
- }
- }
- else
- {
- if (multisample)
- {
- mDeferredLight.bindTarget();
- }
- LLGLSLShader* shader = &gDeferredPostNoDoFProgram;
-
- bindDeferredShader(*shader);
-
- S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage());
- if (channel > -1)
- {
- mScreen.bindTexture(0, channel);
- }
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
- gGL.vertex2f(3,-1);
-
- gGL.end();
-
- unbindDeferredShader(*shader);
-
- if (multisample)
- {
- mDeferredLight.flush();
- }
- }
-
- if (multisample)
- {
- //bake out texture2D with RGBL for FXAA shader
- mFXAABuffer.bindTarget();
-
- S32 width = mScreen.getWidth();
- S32 height = mScreen.getHeight();
- glViewport(0, 0, width, height);
-
- LLGLSLShader* shader = &gGlowCombineFXAAProgram;
-
- shader->bind();
- shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, width, height);
-
- S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage());
- if (channel > -1)
- {
- mDeferredLight.bindTexture(0, channel);
- }
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.vertex2f(-1,-1);
- gGL.vertex2f(-1,3);
- gGL.vertex2f(3,-1);
- gGL.end();
-
- gGL.flush();
-
- shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage());
- shader->unbind();
-
- mFXAABuffer.flush();
-
- shader = &gFXAAProgram;
- shader->bind();
-
- channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP, mFXAABuffer.getUsage());
- if (channel > -1)
- {
- mFXAABuffer.bindTexture(0, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
- gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
- gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
- gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
- glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
-
- F32 scale_x = (F32) width/mFXAABuffer.getWidth();
- F32 scale_y = (F32) height/mFXAABuffer.getHeight();
- shader->uniform2f(LLShaderMgr::FXAA_TC_SCALE, scale_x, scale_y);
- shader->uniform2f(LLShaderMgr::FXAA_RCP_SCREEN_RES, 1.f/width*scale_x, 1.f/height*scale_y);
- shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT, -0.5f/width*scale_x, -0.5f/height*scale_y, 0.5f/width*scale_x, 0.5f/height*scale_y);
- shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT2, -2.f/width*scale_x, -2.f/height*scale_y, 2.f/width*scale_x, 2.f/height*scale_y);
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.vertex2f(-1,-1);
- gGL.vertex2f(-1,3);
- gGL.vertex2f(3,-1);
- gGL.end();
-
- gGL.flush();
- shader->unbind();
- }
- }
- else
- {
- U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1;
- LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask, 0);
- buff->allocateBuffer(3,0,TRUE);
-
- LLStrider<LLVector3> v;
- LLStrider<LLVector2> uv1;
- LLStrider<LLVector2> uv2;
-
- buff->getVertexStrider(v);
- buff->getTexCoord0Strider(uv1);
- buff->getTexCoord1Strider(uv2);
-
- uv1[0] = LLVector2(0, 0);
- uv1[1] = LLVector2(0, 2);
- uv1[2] = LLVector2(2, 0);
-
- uv2[0] = LLVector2(0, 0);
- uv2[1] = LLVector2(0, tc2.mV[1]*2.f);
- uv2[2] = LLVector2(tc2.mV[0]*2.f, 0);
-
- v[0] = LLVector3(-1,-1,0);
- v[1] = LLVector3(-1,3,0);
- v[2] = LLVector3(3,-1,0);
-
- buff->flush();
-
- LLGLDisable blend(GL_BLEND);
-
- if (LLGLSLShader::sNoFixedFunction)
- {
- gGlowCombineProgram.bind();
- }
- else
- {
- //tex unit 0
- gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
- //tex unit 1
- gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
- }
-
- gGL.getTexUnit(0)->bind(&mGlow[1]);
- gGL.getTexUnit(1)->bind(&mScreen);
-
- LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
-
- buff->setBuffer(mask);
- buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3);
-
- if (LLGLSLShader::sNoFixedFunction)
- {
- gGlowCombineProgram.unbind();
- }
- else
- {
- gGL.getTexUnit(1)->disable();
- gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT);
-
- gGL.getTexUnit(0)->activate();
- gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
- }
-
- }
-
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
-
- if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES))
- {
- if (LLGLSLShader::sNoFixedFunction)
- {
- gSplatTextureRectProgram.bind();
- }
-
- gGL.setColorMask(true, false);
-
- LLVector2 tc1(0,0);
- LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2,
- (F32) gViewerWindow->getWorldViewHeightRaw()*2);
-
- LLGLEnable blend(GL_BLEND);
- gGL.color4f(1,1,1,0.75f);
-
- gGL.getTexUnit(0)->bind(&mPhysicsDisplay);
-
- gGL.begin(LLRender::TRIANGLES);
- gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
- gGL.vertex2f(3,-1);
-
- gGL.end();
- gGL.flush();
-
- if (LLGLSLShader::sNoFixedFunction)
- {
- gSplatTextureRectProgram.unbind();
- }
- }
-
-
- if (LLRenderTarget::sUseFBO)
- { //copy depth buffer from mScreen to framebuffer
- LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(),
- 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
- }
-
-
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.popMatrix();
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.popMatrix();
-
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
-}
-
-static LLFastTimer::DeclareTimer FTM_BIND_DEFERRED("Bind Deferred");
-
-void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 noise_map)
-{
- LLFastTimer t(FTM_BIND_DEFERRED);
-
- if (noise_map == 0xFFFFFFFF)
- {
- noise_map = mNoiseMap;
- }
-
- shader.bind();
- S32 channel = 0;
- channel = shader.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredScreen.getUsage());
- if (channel > -1)
- {
- mDeferredScreen.bindTexture(0,channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLShaderMgr::DEFERRED_SPECULAR, mDeferredScreen.getUsage());
- if (channel > -1)
- {
- mDeferredScreen.bindTexture(1, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLShaderMgr::DEFERRED_NORMAL, mDeferredScreen.getUsage());
- if (channel > -1)
- {
- mDeferredScreen.bindTexture(2, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, mDeferredDepth.getUsage());
- if (channel > -1)
- {
- gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE);
- stop_glerror();
-
- //glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
- //glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA);
-
- stop_glerror();
-
- glh::matrix4f projection = glh_get_current_projection();
- glh::matrix4f inv_proj = projection.inverse();
-
- shader.uniformMatrix4fv(LLShaderMgr::INVERSE_PROJECTION_MATRIX, 1, FALSE, inv_proj.m);
- shader.uniform4f(LLShaderMgr::VIEWPORT, (F32) gGLViewport[0],
- (F32) gGLViewport[1],
- (F32) gGLViewport[2],
- (F32) gGLViewport[3]);
- }
-
- channel = shader.enableTexture(LLShaderMgr::DEFERRED_NOISE);
- if (channel > -1)
- {
- gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, noise_map);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLShaderMgr::DEFERRED_LIGHTFUNC);
- if (channel > -1)
- {
- gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
- }
-
- stop_glerror();
-
- channel = shader.enableTexture(LLShaderMgr::DEFERRED_LIGHT, mDeferredLight.getUsage());
- if (channel > -1)
- {
- if (light_index > 0)
- {
- mScreen.bindTexture(0, channel);
- }
- else
- {
- mDeferredLight.bindTexture(0, channel);
- }
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLShaderMgr::DEFERRED_BLOOM);
- if (channel > -1)
- {
- mGlow[1].bindTexture(0, channel);
- }
-
- stop_glerror();
-
- for (U32 i = 0; i < 4; i++)
- {
- channel = shader.enableTexture(LLShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE);
- stop_glerror();
- if (channel > -1)
- {
- stop_glerror();
- gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
- stop_glerror();
-
- glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
- glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
- stop_glerror();
- }
- }
-
- for (U32 i = 4; i < 6; i++)
- {
- channel = shader.enableTexture(LLShaderMgr::DEFERRED_SHADOW0+i);
- stop_glerror();
- if (channel > -1)
- {
- stop_glerror();
- gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
- stop_glerror();
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
- stop_glerror();
- }
- }
-
- stop_glerror();
-
- F32 mat[16*6];
- for (U32 i = 0; i < 16; i++)
- {
- mat[i] = mSunShadowMatrix[0].m[i];
- mat[i+16] = mSunShadowMatrix[1].m[i];
- mat[i+32] = mSunShadowMatrix[2].m[i];
- mat[i+48] = mSunShadowMatrix[3].m[i];
- mat[i+64] = mSunShadowMatrix[4].m[i];
- mat[i+80] = mSunShadowMatrix[5].m[i];
- }
-
- shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_SHADOW_MATRIX, 6, FALSE, mat);
-
- stop_glerror();
-
- channel = shader.enableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
- if (channel > -1)
- {
- LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
- if (cube_map)
- {
- cube_map->enable(channel);
- cube_map->bind();
- F32* m = gGLModelView;
-
- F32 mat[] = { m[0], m[1], m[2],
- m[4], m[5], m[6],
- m[8], m[9], m[10] };
-
- shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_ENV_MAT, 1, TRUE, mat);
- }
- }
-
- shader.uniform4fv(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1, mSunClipPlanes.mV);
- shader.uniform1f(LLShaderMgr::DEFERRED_SUN_WASH, RenderDeferredSunWash);
- shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_NOISE, RenderShadowNoise);
- shader.uniform1f(LLShaderMgr::DEFERRED_BLUR_SIZE, RenderShadowBlurSize);
-
- shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_RADIUS, RenderSSAOScale);
- shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_MAX_RADIUS, RenderSSAOMaxScale);
-
- F32 ssao_factor = RenderSSAOFactor;
- shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR, ssao_factor);
- shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR_INV, 1.0/ssao_factor);
-
- LLVector3 ssao_effect = RenderSSAOEffect;
- F32 matrix_diag = (ssao_effect[0] + 2.0*ssao_effect[1])/3.0;
- F32 matrix_nondiag = (ssao_effect[0] - ssao_effect[1])/3.0;
- // This matrix scales (proj of color onto <1/rt(3),1/rt(3),1/rt(3)>) by
- // value factor, and scales remainder by saturation factor
- F32 ssao_effect_mat[] = { matrix_diag, matrix_nondiag, matrix_nondiag,
- matrix_nondiag, matrix_diag, matrix_nondiag,
- matrix_nondiag, matrix_nondiag, matrix_diag};
- shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_SSAO_EFFECT_MAT, 1, GL_FALSE, ssao_effect_mat);
-
- F32 shadow_offset_error = 1.f + RenderShadowOffsetError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]);
- F32 shadow_bias_error = 1.f + RenderShadowBiasError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]);
-
- shader.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredScreen.getWidth(), mDeferredScreen.getHeight());
- shader.uniform1f(LLShaderMgr::DEFERRED_NEAR_CLIP, LLViewerCamera::getInstance()->getNear()*2.f);
- shader.uniform1f (LLShaderMgr::DEFERRED_SHADOW_OFFSET, RenderShadowOffset*shadow_offset_error);
- shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_BIAS, RenderShadowBias*shadow_bias_error);
- shader.uniform1f(LLShaderMgr::DEFERRED_SPOT_SHADOW_OFFSET, RenderSpotShadowOffset);
- shader.uniform1f(LLShaderMgr::DEFERRED_SPOT_SHADOW_BIAS, RenderSpotShadowBias);
-
- shader.uniform3fv(LLShaderMgr::DEFERRED_SUN_DIR, 1, mTransformedSunDir.mV);
- shader.uniform2f(LLShaderMgr::DEFERRED_SHADOW_RES, mShadow[0].getWidth(), mShadow[0].getHeight());
- shader.uniform2f(LLShaderMgr::DEFERRED_PROJ_SHADOW_RES, mShadow[4].getWidth(), mShadow[4].getHeight());
- shader.uniform1f(LLShaderMgr::DEFERRED_DEPTH_CUTOFF, RenderEdgeDepthCutoff);
- shader.uniform1f(LLShaderMgr::DEFERRED_NORM_CUTOFF, RenderEdgeNormCutoff);
-
-
- if (shader.getUniformLocation("norm_mat") >= 0)
- {
- glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose();
- shader.uniformMatrix4fv("norm_mat", 1, FALSE, norm_mat.m);
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace");
-static LLFastTimer::DeclareTimer FTM_GI_GATHER("Gather");
-static LLFastTimer::DeclareTimer FTM_SUN_SHADOW("Shadow Map");
-static LLFastTimer::DeclareTimer FTM_SOFTEN_SHADOW("Shadow Soften");
-static LLFastTimer::DeclareTimer FTM_EDGE_DETECTION("Find Edges");
-static LLFastTimer::DeclareTimer FTM_LOCAL_LIGHTS("Local Lights");
-static LLFastTimer::DeclareTimer FTM_ATMOSPHERICS("Atmospherics");
-static LLFastTimer::DeclareTimer FTM_FULLSCREEN_LIGHTS("Fullscreen Lights");
-static LLFastTimer::DeclareTimer FTM_PROJECTORS("Projectors");
-static LLFastTimer::DeclareTimer FTM_POST("Post");
-
-
-void LLPipeline::renderDeferredLighting()
-{
- if (!sCull)
- {
- return;
- }
-
- {
- LLFastTimer ftm(FTM_RENDER_DEFERRED);
-
- LLViewerCamera* camera = LLViewerCamera::getInstance();
- {
- LLGLDepthTest depth(GL_TRUE);
- mDeferredDepth.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
- 0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
- }
-
- LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
-
- if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
- }
-
- //ati doesn't seem to love actually using the stencil buffer on FBO's
- LLGLDisable stencil(GL_STENCIL_TEST);
- //glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
- //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-
- gGL.setColorMask(true, true);
-
- //draw a cube around every light
- LLVertexBuffer::unbind();
-
- LLGLEnable cull(GL_CULL_FACE);
- LLGLEnable blend(GL_BLEND);
-
- glh::matrix4f mat = glh_copy_matrix(gGLModelView);
-
- LLStrider<LLVector3> vert;
- mDeferredVB->getVertexStrider(vert);
- LLStrider<LLVector2> tc0;
- LLStrider<LLVector2> tc1;
- mDeferredVB->getTexCoord0Strider(tc0);
- mDeferredVB->getTexCoord1Strider(tc1);
-
- vert[0].set(-1,1,0);
- vert[1].set(-1,-3,0);
- vert[2].set(3,1,0);
-
- {
- setupHWLights(NULL); //to set mSunDir;
- LLVector4 dir(mSunDir, 0.f);
- glh::vec4f tc(dir.mV);
- mat.mult_matrix_vec(tc);
- mTransformedSunDir.set(tc.v);
- }
-
- gGL.pushMatrix();
- gGL.loadIdentity();
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.pushMatrix();
- gGL.loadIdentity();
-
- if (RenderDeferredSSAO || RenderShadowDetail > 0)
- {
- mDeferredLight.bindTarget();
- { //paint shadow/SSAO light map (direct lighting lightmap)
- LLFastTimer ftm(FTM_SUN_SHADOW);
- bindDeferredShader(gDeferredSunProgram, 0);
- mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
- glClearColor(1,1,1,1);
- mDeferredLight.clear(GL_COLOR_BUFFER_BIT);
- glClearColor(0,0,0,0);
-
- glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose();
-
- const U32 slice = 32;
- F32 offset[slice*3];
- for (U32 i = 0; i < 4; i++)
- {
- for (U32 j = 0; j < 8; j++)
- {
- glh::vec3f v;
- v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i);
- v.normalize();
- inv_trans.mult_matrix_vec(v);
- v.normalize();
- offset[(i*8+j)*3+0] = v.v[0];
- offset[(i*8+j)*3+1] = v.v[2];
- offset[(i*8+j)*3+2] = v.v[1];
- }
- }
-
- gDeferredSunProgram.uniform3fv("offset", slice, offset);
- gDeferredSunProgram.uniform2f("screenRes", mDeferredLight.getWidth(), mDeferredLight.getHeight());
-
- {
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
- stop_glerror();
- mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
- stop_glerror();
- }
-
- unbindDeferredShader(gDeferredSunProgram);
- }
- mDeferredLight.flush();
- }
-
- if (RenderDeferredSSAO)
- { //soften direct lighting lightmap
- LLFastTimer ftm(FTM_SOFTEN_SHADOW);
- //blur lightmap
- mScreen.bindTarget();
- glClearColor(1,1,1,1);
- mScreen.clear(GL_COLOR_BUFFER_BIT);
- glClearColor(0,0,0,0);
-
- bindDeferredShader(gDeferredBlurLightProgram);
- mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
- LLVector3 go = RenderShadowGaussian;
- const U32 kern_length = 4;
- F32 blur_size = RenderShadowBlurSize;
- F32 dist_factor = RenderShadowBlurDistFactor;
-
- // sample symmetrically with the middle sample falling exactly on 0.0
- F32 x = 0.f;
-
- LLVector3 gauss[32]; // xweight, yweight, offset
-
- for (U32 i = 0; i < kern_length; i++)
- {
- gauss[i].mV[0] = llgaussian(x, go.mV[0]);
- gauss[i].mV[1] = llgaussian(x, go.mV[1]);
- gauss[i].mV[2] = x;
- x += 1.f;
- }
-
- gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f);
- gDeferredBlurLightProgram.uniform1f("dist_factor", dist_factor);
- gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV);
- gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f));
-
- {
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
- stop_glerror();
- mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
- stop_glerror();
- }
-
- mScreen.flush();
- unbindDeferredShader(gDeferredBlurLightProgram);
-
- bindDeferredShader(gDeferredBlurLightProgram, 1);
- mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
- mDeferredLight.bindTarget();
-
- gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f);
-
- {
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
- stop_glerror();
- mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
- stop_glerror();
- }
- mDeferredLight.flush();
- unbindDeferredShader(gDeferredBlurLightProgram);
- }
-
- stop_glerror();
- gGL.popMatrix();
- stop_glerror();
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- stop_glerror();
- gGL.popMatrix();
- stop_glerror();
-
- //copy depth and stencil from deferred screen
- //mScreen.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
- // 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
-
- mScreen.bindTarget();
- // clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky
- glClearColor(0,0,0,0);
- mScreen.clear(GL_COLOR_BUFFER_BIT);
-
- if (RenderDeferredAtmospheric)
- { //apply sunlight contribution
- LLFastTimer ftm(FTM_ATMOSPHERICS);
- bindDeferredShader(gDeferredSoftenProgram);
- {
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable blend(GL_BLEND);
- LLGLDisable test(GL_ALPHA_TEST);
-
- //full screen blit
- gGL.pushMatrix();
- gGL.loadIdentity();
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.pushMatrix();
- gGL.loadIdentity();
-
- mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
-
- mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
-
- gGL.popMatrix();
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.popMatrix();
- }
-
- unbindDeferredShader(gDeferredSoftenProgram);
- }
-
- { //render non-deferred geometry (fullbright, alpha, etc)
- LLGLDisable blend(GL_BLEND);
- LLGLDisable stencil(GL_STENCIL_TEST);
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
-
- gPipeline.pushRenderTypeMask();
-
- gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_CLOUDS,
- LLPipeline::RENDER_TYPE_WL_SKY,
- LLPipeline::END_RENDER_TYPES);
-
-
- renderGeomPostDeferred(*LLViewerCamera::getInstance());
- gPipeline.popRenderTypeMask();
- }
-
- BOOL render_local = RenderLocalLights;
-
- if (render_local)
- {
- gGL.setSceneBlendType(LLRender::BT_ADD);
- std::list<LLVector4> fullscreen_lights;
- LLDrawable::drawable_list_t spot_lights;
- LLDrawable::drawable_list_t fullscreen_spot_lights;
-
- for (U32 i = 0; i < 2; i++)
- {
- mTargetShadowSpotLight[i] = NULL;
- }
-
- std::list<LLVector4> light_colors;
-
- LLVertexBuffer::unbind();
- LLVector4a* v = (LLVector4a*) vert.get();
-
- {
- bindDeferredShader(gDeferredLightProgram);
- mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
-
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
- for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter)
- {
- LLDrawable* drawablep = *iter;
-
- LLVOVolume* volume = drawablep->getVOVolume();
- if (!volume)
- {
- continue;
- }
-
- if (volume->isAttachment())
- {
- if (!sRenderAttachedLights)
- {
- continue;
- }
- }
-
-
- LLVector4a center;
- center.load3(drawablep->getPositionAgent().mV);
- const F32* c = center.getF32ptr();
- F32 s = volume->getLightRadius()*1.5f;
-
- LLColor3 col = volume->getLightColor();
-
- if (col.magVecSquared() < 0.001f)
- {
- continue;
- }
-
- if (s <= 0.001f)
- {
- continue;
- }
-
- LLVector4a sa;
- sa.splat(s);
- if (camera->AABBInFrustumNoFarClip(center, sa) == 0)
- {
- continue;
- }
-
- sVisibleLightCount++;
-
- glh::vec3f tc(c);
- mat.mult_matrix_vec(tc);
-
- //vertex positions are encoded so the 3 bits of their vertex index
- //correspond to their axis facing, with bit position 3,2,1 matching
- //axis facing x,y,z, bit set meaning positive facing, bit clear
- //meaning negative facing
- mDeferredVB->getVertexStrider(vert);
- v[0].set(c[0]-s,c[1]-s,c[2]-s); // 0 - 0000
- v[1].set(c[0]-s,c[1]-s,c[2]+s); // 1 - 0001
- v[2].set(c[0]-s,c[1]+s,c[2]-s); // 2 - 0010
- v[3].set(c[0]-s,c[1]+s,c[2]+s); // 3 - 0011
-
- v[4].set(c[0]+s,c[1]-s,c[2]-s); // 4 - 0100
- v[5].set(c[0]+s,c[1]-s,c[2]+s); // 5 - 0101
- v[6].set(c[0]+s,c[1]+s,c[2]-s); // 6 - 0110
- v[7].set(c[0]+s,c[1]+s,c[2]+s); // 7 - 0111
-
- if (camera->getOrigin().mV[0] > c[0] + s + 0.2f ||
- camera->getOrigin().mV[0] < c[0] - s - 0.2f ||
- camera->getOrigin().mV[1] > c[1] + s + 0.2f ||
- camera->getOrigin().mV[1] < c[1] - s - 0.2f ||
- camera->getOrigin().mV[2] > c[2] + s + 0.2f ||
- camera->getOrigin().mV[2] < c[2] - s - 0.2f)
- { //draw box if camera is outside box
- if (render_local)
- {
- if (volume->isLightSpotlight())
- {
- drawablep->getVOVolume()->updateSpotLightPriority();
- spot_lights.push_back(drawablep);
- continue;
- }
-
- LLFastTimer ftm(FTM_LOCAL_LIGHTS);
- //glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
- gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v);
- gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s);
- gDeferredLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
- gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f);
- //gGL.diffuseColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
- gGL.syncMatrices();
- mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
- glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
- GL_UNSIGNED_SHORT, get_box_fan_indices_ptr(camera, center));
- stop_glerror();
- }
- }
- else
- {
- if (volume->isLightSpotlight())
- {
- drawablep->getVOVolume()->updateSpotLightPriority();
- fullscreen_spot_lights.push_back(drawablep);
- continue;
- }
-
- fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s));
- light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f));
- }
- }
- unbindDeferredShader(gDeferredLightProgram);
- }
-
- if (!spot_lights.empty())
- {
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
- bindDeferredShader(gDeferredSpotLightProgram);
-
- mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
-
- gDeferredSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
-
- for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter)
- {
- LLFastTimer ftm(FTM_PROJECTORS);
- LLDrawable* drawablep = *iter;
-
- LLVOVolume* volume = drawablep->getVOVolume();
-
- LLVector4a center;
- center.load3(drawablep->getPositionAgent().mV);
- const F32* c = center.getF32ptr();
- F32 s = volume->getLightRadius()*1.5f;
-
- sVisibleLightCount++;
-
- glh::vec3f tc(c);
- mat.mult_matrix_vec(tc);
-
- setupSpotLight(gDeferredSpotLightProgram, drawablep);
-
- LLColor3 col = volume->getLightColor();
-
- //vertex positions are encoded so the 3 bits of their vertex index
- //correspond to their axis facing, with bit position 3,2,1 matching
- //axis facing x,y,z, bit set meaning positive facing, bit clear
- //meaning negative facing
- mDeferredVB->getVertexStrider(vert);
- v[0].set(c[0]-s,c[1]-s,c[2]-s); // 0 - 0000
- v[1].set(c[0]-s,c[1]-s,c[2]+s); // 1 - 0001
- v[2].set(c[0]-s,c[1]+s,c[2]-s); // 2 - 0010
- v[3].set(c[0]-s,c[1]+s,c[2]+s); // 3 - 0011
-
- v[4].set(c[0]+s,c[1]-s,c[2]-s); // 4 - 0100
- v[5].set(c[0]+s,c[1]-s,c[2]+s); // 5 - 0101
- v[6].set(c[0]+s,c[1]+s,c[2]-s); // 6 - 0110
- v[7].set(c[0]+s,c[1]+s,c[2]+s); // 7 - 0111
-
- gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v);
- gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s);
- gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
- gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f);
- gGL.syncMatrices();
- mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
- glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
- GL_UNSIGNED_SHORT, get_box_fan_indices_ptr(camera, center));
- }
- gDeferredSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION);
- unbindDeferredShader(gDeferredSpotLightProgram);
- }
-
- //reset mDeferredVB to fullscreen triangle
- mDeferredVB->getVertexStrider(vert);
- vert[0].set(-1,1,0);
- vert[1].set(-1,-3,0);
- vert[2].set(3,1,0);
-
- {
- bindDeferredShader(gDeferredMultiLightProgram);
-
- mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
-
- LLGLDepthTest depth(GL_FALSE);
-
- //full screen blit
- gGL.pushMatrix();
- gGL.loadIdentity();
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.pushMatrix();
- gGL.loadIdentity();
-
- U32 count = 0;
-
- const U32 max_count = 8;
- LLVector4 light[max_count];
- LLVector4 col[max_count];
-
-// glVertexPointer(2, GL_FLOAT, 0, vert);
-
- F32 far_z = 0.f;
-
- while (!fullscreen_lights.empty())
- {
- LLFastTimer ftm(FTM_FULLSCREEN_LIGHTS);
- light[count] = fullscreen_lights.front();
- fullscreen_lights.pop_front();
- col[count] = light_colors.front();
- light_colors.pop_front();
-
- far_z = llmin(light[count].mV[2]-sqrtf(light[count].mV[3]), far_z);
-
- count++;
- if (count == max_count || fullscreen_lights.empty())
- {
- gDeferredMultiLightProgram.uniform1i(LLShaderMgr::MULTI_LIGHT_COUNT, count);
- gDeferredMultiLightProgram.uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat*) light);
- gDeferredMultiLightProgram.uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat*) col);
- gDeferredMultiLightProgram.uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z);
- far_z = 0.f;
- count = 0;
- mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
- }
- }
-
- unbindDeferredShader(gDeferredMultiLightProgram);
-
- bindDeferredShader(gDeferredMultiSpotLightProgram);
-
- gDeferredMultiSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
-
- mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
-
- for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter)
- {
- LLFastTimer ftm(FTM_PROJECTORS);
- LLDrawable* drawablep = *iter;
-
- LLVOVolume* volume = drawablep->getVOVolume();
-
- LLVector3 center = drawablep->getPositionAgent();
- F32* c = center.mV;
- F32 s = volume->getLightRadius()*1.5f;
-
- sVisibleLightCount++;
-
- glh::vec3f tc(c);
- mat.mult_matrix_vec(tc);
-
- setupSpotLight(gDeferredMultiSpotLightProgram, drawablep);
-
- LLColor3 col = volume->getLightColor();
-
- gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v);
- gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s);
- gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
- gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f);
- mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
- }
-
- gDeferredMultiSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION);
- unbindDeferredShader(gDeferredMultiSpotLightProgram);
-
- gGL.popMatrix();
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.popMatrix();
- }
- }
-
- gGL.setColorMask(true, true);
- }
-
- { //render non-deferred geometry (alpha, fullbright, glow)
- LLGLDisable blend(GL_BLEND);
- LLGLDisable stencil(GL_STENCIL_TEST);
-
- pushRenderTypeMask();
- andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA,
- LLPipeline::RENDER_TYPE_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_VOLUME,
- LLPipeline::RENDER_TYPE_GLOW,
- LLPipeline::RENDER_TYPE_BUMP,
- LLPipeline::RENDER_TYPE_PASS_SIMPLE,
- LLPipeline::RENDER_TYPE_PASS_ALPHA,
- LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
- LLPipeline::RENDER_TYPE_PASS_BUMP,
- LLPipeline::RENDER_TYPE_PASS_POST_BUMP,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
- LLPipeline::RENDER_TYPE_PASS_GLOW,
- LLPipeline::RENDER_TYPE_PASS_GRASS,
- LLPipeline::RENDER_TYPE_PASS_SHINY,
- LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
- LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
- LLPipeline::RENDER_TYPE_AVATAR,
- END_RENDER_TYPES);
-
- renderGeomPostDeferred(*LLViewerCamera::getInstance());
- popRenderTypeMask();
- }
-
- {
- //render highlights, etc.
- renderHighlights();
- mHighlightFaces.clear();
-
- renderDebug();
-
- LLVertexBuffer::unbind();
-
- if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- // Render debugging beacons.
- gObjectList.renderObjectBeacons();
- gObjectList.resetObjectBeacons();
- }
- }
-
- mScreen.flush();
-
-}
-
-void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep)
-{
- //construct frustum
- LLVOVolume* volume = drawablep->getVOVolume();
- LLVector3 params = volume->getSpotLightParams();
-
- F32 fov = params.mV[0];
- F32 focus = params.mV[1];
-
- LLVector3 pos = drawablep->getPositionAgent();
- LLQuaternion quat = volume->getRenderRotation();
- LLVector3 scale = volume->getScale();
-
- //get near clip plane
- LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
- at_axis *= quat;
-
- LLVector3 np = pos+at_axis;
- at_axis.normVec();
-
- //get origin that has given fov for plane np, at_axis, and given scale
- F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
-
- LLVector3 origin = np - at_axis*dist;
-
- //matrix from volume space to agent space
- LLMatrix4 light_mat(quat, LLVector4(origin,1.f));
-
- glh::matrix4f light_to_agent((F32*) light_mat.mMatrix);
- glh::matrix4f light_to_screen = glh_get_current_modelview() * light_to_agent;
-
- glh::matrix4f screen_to_light = light_to_screen.inverse();
-
- F32 s = volume->getLightRadius()*1.5f;
- F32 near_clip = dist;
- F32 width = scale.mV[VX];
- F32 height = scale.mV[VY];
- F32 far_clip = s+dist-scale.mV[VZ];
-
- F32 fovy = fov * RAD_TO_DEG;
- F32 aspect = width/height;
-
- glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
- 0.f, 0.5f, 0.f, 0.5f,
- 0.f, 0.f, 0.5f, 0.5f,
- 0.f, 0.f, 0.f, 1.f);
-
- glh::vec3f p1(0, 0, -(near_clip+0.01f));
- glh::vec3f p2(0, 0, -(near_clip+1.f));
-
- glh::vec3f screen_origin(0, 0, 0);
-
- light_to_screen.mult_matrix_vec(p1);
- light_to_screen.mult_matrix_vec(p2);
- light_to_screen.mult_matrix_vec(screen_origin);
-
- glh::vec3f n = p2-p1;
- n.normalize();
-
- F32 proj_range = far_clip - near_clip;
- glh::matrix4f light_proj = gl_perspective(fovy, aspect, near_clip, far_clip);
- screen_to_light = trans * light_proj * screen_to_light;
- shader.uniformMatrix4fv(LLShaderMgr::PROJECTOR_MATRIX, 1, FALSE, screen_to_light.m);
- shader.uniform1f(LLShaderMgr::PROJECTOR_NEAR, near_clip);
- shader.uniform3fv(LLShaderMgr::PROJECTOR_P, 1, p1.v);
- shader.uniform3fv(LLShaderMgr::PROJECTOR_N, 1, n.v);
- shader.uniform3fv(LLShaderMgr::PROJECTOR_ORIGIN, 1, screen_origin.v);
- shader.uniform1f(LLShaderMgr::PROJECTOR_RANGE, proj_range);
- shader.uniform1f(LLShaderMgr::PROJECTOR_AMBIANCE, params.mV[2]);
- S32 s_idx = -1;
-
- for (U32 i = 0; i < 2; i++)
- {
- if (mShadowSpotLight[i] == drawablep)
- {
- s_idx = i;
- }
- }
-
- shader.uniform1i(LLShaderMgr::PROJECTOR_SHADOW_INDEX, s_idx);
-
- if (s_idx >= 0)
- {
- shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f-mSpotLightFade[s_idx]);
- }
- else
- {
- shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f);
- }
-
- {
- LLDrawable* potential = drawablep;
- //determine if this is a good light for casting shadows
- F32 m_pri = volume->getSpotLightPriority();
-
- for (U32 i = 0; i < 2; i++)
- {
- F32 pri = 0.f;
-
- if (mTargetShadowSpotLight[i].notNull())
- {
- pri = mTargetShadowSpotLight[i]->getVOVolume()->getSpotLightPriority();
- }
-
- if (m_pri > pri)
- {
- LLDrawable* temp = mTargetShadowSpotLight[i];
- mTargetShadowSpotLight[i] = potential;
- potential = temp;
- m_pri = pri;
- }
- }
- }
-
- LLViewerTexture* img = volume->getLightTexture();
-
- if (img == NULL)
- {
- img = LLViewerFetchedTexture::sWhiteImagep;
- }
-
- S32 channel = shader.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
-
- if (channel > -1)
- {
- if (img)
- {
- gGL.getTexUnit(channel)->bind(img);
-
- F32 lod_range = logf(img->getWidth())/logf(2.f);
-
- shader.uniform1f(LLShaderMgr::PROJECTOR_FOCUS, focus);
- shader.uniform1f(LLShaderMgr::PROJECTOR_LOD, lod_range);
- shader.uniform1f(LLShaderMgr::PROJECTOR_AMBIENT_LOD, llclamp((proj_range-focus)/proj_range*lod_range, 0.f, 1.f));
- }
- }
-
-}
-
-void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
-{
- stop_glerror();
- shader.disableTexture(LLShaderMgr::DEFERRED_NORMAL, mDeferredScreen.getUsage());
- shader.disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredScreen.getUsage());
- shader.disableTexture(LLShaderMgr::DEFERRED_SPECULAR, mDeferredScreen.getUsage());
- shader.disableTexture(LLShaderMgr::DEFERRED_DEPTH, mDeferredScreen.getUsage());
- shader.disableTexture(LLShaderMgr::DEFERRED_LIGHT, mDeferredLight.getUsage());
- shader.disableTexture(LLShaderMgr::DIFFUSE_MAP);
- shader.disableTexture(LLShaderMgr::DEFERRED_BLOOM);
-
- for (U32 i = 0; i < 4; i++)
- {
- if (shader.disableTexture(LLShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE) > -1)
- {
- glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
- }
- }
-
- for (U32 i = 4; i < 6; i++)
- {
- if (shader.disableTexture(LLShaderMgr::DEFERRED_SHADOW0+i) > -1)
- {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
- }
- }
-
- shader.disableTexture(LLShaderMgr::DEFERRED_NOISE);
- shader.disableTexture(LLShaderMgr::DEFERRED_LIGHTFUNC);
-
- S32 channel = shader.disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
- if (channel > -1)
- {
- LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
- if (cube_map)
- {
- cube_map->disable();
- }
- }
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.getTexUnit(0)->activate();
- shader.unbind();
-}
-
-inline float sgn(float a)
-{
- if (a > 0.0F) return (1.0F);
- if (a < 0.0F) return (-1.0F);
- return (0.0F);
-}
-
-void LLPipeline::generateWaterReflection(LLCamera& camera_in)
-{
- if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate)
- {
- BOOL skip_avatar_update = FALSE;
- if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson)
- {
- skip_avatar_update = TRUE;
- }
-
- if (!skip_avatar_update)
- {
- gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON);
- }
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- LLCamera camera = camera_in;
- camera.setFar(camera.getFar()*0.87654321f);
- LLPipeline::sReflectionRender = TRUE;
-
- gPipeline.pushRenderTypeMask();
-
- glh::matrix4f projection = glh_get_current_projection();
- glh::matrix4f mat;
-
- stop_glerror();
- LLPlane plane;
-
- F32 height = gAgent.getRegion()->getWaterHeight();
- F32 to_clip = fabsf(camera.getOrigin().mV[2]-height);
- F32 pad = -to_clip*0.05f; //amount to "pad" clip plane by
-
- //plane params
- LLVector3 pnorm;
- F32 pd;
-
- S32 water_clip = 0;
- if (!LLViewerCamera::getInstance()->cameraUnderWater())
- { //camera is above water, clip plane points up
- pnorm.setVec(0,0,1);
- pd = -height;
- plane.setVec(pnorm, pd);
- water_clip = -1;
- }
- else
- { //camera is below water, clip plane points down
- pnorm = LLVector3(0,0,-1);
- pd = height;
- plane.setVec(pnorm, pd);
- water_clip = 1;
- }
-
- if (!LLViewerCamera::getInstance()->cameraUnderWater())
- { //generate planar reflection map
-
- //disable occlusion culling for reflection map for now
- S32 occlusion = LLPipeline::sUseOcclusion;
- LLPipeline::sUseOcclusion = 0;
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- glClearColor(0,0,0,0);
- mWaterRef.bindTarget();
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER0;
- gGL.setColorMask(true, true);
- mWaterRef.clear();
- gGL.setColorMask(true, false);
-
- mWaterRef.getViewport(gGLViewport);
-
- stop_glerror();
-
- gGL.pushMatrix();
-
- mat.set_scale(glh::vec3f(1,1,-1));
- mat.set_translate(glh::vec3f(0,0,height*2.f));
-
- glh::matrix4f current = glh_get_current_modelview();
-
- mat = current * mat;
-
- glh_set_current_modelview(mat);
- gGL.loadMatrix(mat.m);
-
- LLViewerCamera::updateFrustumPlanes(camera, FALSE, TRUE);
-
- glh::matrix4f inv_mat = mat.inverse();
-
- glh::vec3f origin(0,0,0);
- inv_mat.mult_matrix_vec(origin);
-
- camera.setOrigin(origin.v);
-
- glCullFace(GL_FRONT);
-
- static LLCullResult ref_result;
-
- if (LLDrawPoolWater::sNeedsReflectionUpdate)
- {
- //initial sky pass (no user clip plane)
- { //mask out everything but the sky
- gPipeline.pushRenderTypeMask();
- gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_WL_SKY,
- LLPipeline::RENDER_TYPE_CLOUDS,
- LLPipeline::END_RENDER_TYPES);
-
- static LLCullResult result;
- updateCull(camera, result);
- stateSort(camera, result);
-
- renderGeom(camera, TRUE);
-
- gPipeline.popRenderTypeMask();
- }
-
- gPipeline.pushRenderTypeMask();
-
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
- LLPipeline::RENDER_TYPE_VOIDWATER,
- LLPipeline::RENDER_TYPE_GROUND,
- LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_CLOUDS,
- LLPipeline::END_RENDER_TYPES);
-
- S32 detail = RenderReflectionDetail;
- if (detail > 0)
- { //mask out selected geometry based on reflection detail
- if (detail < 4)
- {
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES);
- if (detail < 3)
- {
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
- if (detail < 2)
- {
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES);
- }
- }
- }
-
- LLGLUserClipPlane clip_plane(plane, mat, projection);
- LLGLDisable cull(GL_CULL_FACE);
- updateCull(camera, ref_result, -water_clip, &plane);
- stateSort(camera, ref_result);
- }
-
- if (LLDrawPoolWater::sNeedsDistortionUpdate)
- {
- if (RenderReflectionDetail > 0)
- {
- gPipeline.grabReferences(ref_result);
- LLGLUserClipPlane clip_plane(plane, mat, projection);
- renderGeom(camera);
- }
- }
-
- gPipeline.popRenderTypeMask();
- }
- glCullFace(GL_BACK);
- gGL.popMatrix();
- mWaterRef.flush();
- glh_set_current_modelview(current);
- LLPipeline::sUseOcclusion = occlusion;
- }
-
- camera.setOrigin(camera_in.getOrigin());
- //render distortion map
- static BOOL last_update = TRUE;
- if (last_update)
- {
- camera.setFar(camera_in.getFar());
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
- LLPipeline::RENDER_TYPE_VOIDWATER,
- LLPipeline::RENDER_TYPE_GROUND,
- END_RENDER_TYPES);
- stop_glerror();
-
- LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? FALSE : TRUE;
-
- if (LLPipeline::sUnderWaterRender)
- {
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_GROUND,
- LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_CLOUDS,
- LLPipeline::RENDER_TYPE_WL_SKY,
- END_RENDER_TYPES);
- }
- LLViewerCamera::updateFrustumPlanes(camera);
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLColor4& col = LLDrawPoolWater::sWaterFogColor;
- glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
- mWaterDis.bindTarget();
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1;
- mWaterDis.getViewport(gGLViewport);
-
- if (!LLPipeline::sUnderWaterRender || LLDrawPoolWater::sNeedsReflectionUpdate)
- {
- //clip out geometry on the same side of water as the camera
- mat = glh_get_current_modelview();
- LLPlane plane(-pnorm, -(pd+pad));
-
- LLGLUserClipPlane clip_plane(plane, mat, projection);
- static LLCullResult result;
- updateCull(camera, result, water_clip, &plane);
- stateSort(camera, result);
-
- gGL.setColorMask(true, true);
- mWaterDis.clear();
- gGL.setColorMask(true, false);
-
- renderGeom(camera);
-
- }
-
- LLPipeline::sUnderWaterRender = FALSE;
- mWaterDis.flush();
- }
- last_update = LLDrawPoolWater::sNeedsReflectionUpdate && LLDrawPoolWater::sNeedsDistortionUpdate;
-
- LLRenderTarget::unbindTarget();
-
- LLPipeline::sReflectionRender = FALSE;
-
- if (!LLRenderTarget::sUseFBO)
- {
- glClear(GL_DEPTH_BUFFER_BIT);
- }
- glClearColor(0.f, 0.f, 0.f, 0.f);
- gViewerWindow->setup3DViewport();
- gPipeline.popRenderTypeMask();
- LLDrawPoolWater::sNeedsReflectionUpdate = FALSE;
- LLDrawPoolWater::sNeedsDistortionUpdate = FALSE;
- LLPlane npnorm(-pnorm, -pd);
- LLViewerCamera::getInstance()->setUserClipPlane(npnorm);
-
- LLGLState::checkStates();
-
- if (!skip_avatar_update)
- {
- gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode());
- }
-
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
- }
-}
-
-glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up)
-{
- glh::matrix4f ret;
-
- LLVector3 dirN;
- LLVector3 upN;
- LLVector3 lftN;
-
- lftN = dir % up;
- lftN.normVec();
-
- upN = lftN % dir;
- upN.normVec();
-
- dirN = dir;
- dirN.normVec();
-
- ret.m[ 0] = lftN[0];
- ret.m[ 1] = upN[0];
- ret.m[ 2] = -dirN[0];
- ret.m[ 3] = 0.f;
-
- ret.m[ 4] = lftN[1];
- ret.m[ 5] = upN[1];
- ret.m[ 6] = -dirN[1];
- ret.m[ 7] = 0.f;
-
- ret.m[ 8] = lftN[2];
- ret.m[ 9] = upN[2];
- ret.m[10] = -dirN[2];
- ret.m[11] = 0.f;
-
- ret.m[12] = -(lftN*pos);
- ret.m[13] = -(upN*pos);
- ret.m[14] = dirN*pos;
- ret.m[15] = 1.f;
-
- return ret;
-}
-
-glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max)
-{
- glh::matrix4f ret;
- ret.m[ 0] = 2/(max[0]-min[0]);
- ret.m[ 4] = 0;
- ret.m[ 8] = 0;
- ret.m[12] = -(max[0]+min[0])/(max[0]-min[0]);
-
- ret.m[ 1] = 0;
- ret.m[ 5] = 2/(max[1]-min[1]);
- ret.m[ 9] = 0;
- ret.m[13] = -(max[1]+min[1])/(max[1]-min[1]);
-
- ret.m[ 2] = 0;
- ret.m[ 6] = 0;
- ret.m[10] = 2/(max[2]-min[2]);
- ret.m[14] = -(max[2]+min[2])/(max[2]-min[2]);
-
- ret.m[ 3] = 0;
- ret.m[ 7] = 0;
- ret.m[11] = 0;
- ret.m[15] = 1;
-
- return ret;
-}
-
-static LLFastTimer::DeclareTimer FTM_SHADOW_RENDER("Render Shadows");
-static LLFastTimer::DeclareTimer FTM_SHADOW_ALPHA("Alpha Shadow");
-static LLFastTimer::DeclareTimer FTM_SHADOW_SIMPLE("Simple Shadow");
-
-void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, BOOL use_shader, BOOL use_occlusion)
-{
- LLFastTimer t(FTM_SHADOW_RENDER);
-
- //clip out geometry on the same side of water as the camera
- S32 occlude = LLPipeline::sUseOcclusion;
- if (!use_occlusion)
- {
- LLPipeline::sUseOcclusion = 0;
- }
- LLPipeline::sShadowRender = TRUE;
-
- U32 types[] = {
- LLRenderPass::PASS_SIMPLE,
- LLRenderPass::PASS_FULLBRIGHT,
- LLRenderPass::PASS_SHINY,
- LLRenderPass::PASS_BUMP,
- LLRenderPass::PASS_FULLBRIGHT_SHINY
- };
-
- LLGLEnable cull(GL_CULL_FACE);
-
- if (use_shader)
- {
- gDeferredShadowProgram.bind();
- }
-
- updateCull(shadow_cam, result);
- stateSort(shadow_cam, result);
-
- //generate shadow map
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.pushMatrix();
- gGL.loadMatrix(proj.m);
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.pushMatrix();
- gGL.loadMatrix(gGLModelView);
-
- stop_glerror();
- gGLLastMatrix = NULL;
-
- {
- //LLGLDepthTest depth(GL_TRUE);
- //glClear(GL_DEPTH_BUFFER_BIT);
- }
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- stop_glerror();
-
- //glCullFace(GL_FRONT);
-
- LLVertexBuffer::unbind();
-
- {
- if (!use_shader)
- { //occlusion program is general purpose depth-only no-textures
- gOcclusionProgram.bind();
- }
-
- gGL.diffuseColor4f(1,1,1,1);
- gGL.setColorMask(false, false);
-
- LLFastTimer ftm(FTM_SHADOW_SIMPLE);
- gGL.getTexUnit(0)->disable();
- for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i)
- {
- renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE);
- }
- gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
- if (!use_shader)
- {
- gOcclusionProgram.unbind();
- }
- }
-
- if (use_shader)
- {
- gDeferredShadowProgram.unbind();
- renderGeomShadow(shadow_cam);
- gDeferredShadowProgram.bind();
- }
- else
- {
- renderGeomShadow(shadow_cam);
- }
-
- {
- LLFastTimer ftm(FTM_SHADOW_ALPHA);
- gDeferredShadowAlphaMaskProgram.bind();
- gDeferredShadowAlphaMaskProgram.setMinimumAlpha(0.598f);
-
- U32 mask = LLVertexBuffer::MAP_VERTEX |
- LLVertexBuffer::MAP_TEXCOORD0 |
- LLVertexBuffer::MAP_COLOR |
- LLVertexBuffer::MAP_TEXTURE_INDEX;
-
- renderObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE);
- renderObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE);
- renderObjects(LLRenderPass::PASS_ALPHA, mask, TRUE, TRUE);
- gDeferredTreeShadowProgram.bind();
- gDeferredTreeShadowProgram.setMinimumAlpha(0.598f);
- renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE);
- }
-
- //glCullFace(GL_BACK);
-
- gDeferredShadowProgram.bind();
- gGLLastMatrix = NULL;
- gGL.loadMatrix(gGLModelView);
- doOcclusion(shadow_cam);
-
- if (use_shader)
- {
- gDeferredShadowProgram.unbind();
- }
-
- gGL.setColorMask(true, true);
-
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.popMatrix();
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.popMatrix();
- gGLLastMatrix = NULL;
-
- LLPipeline::sUseOcclusion = occlude;
- LLPipeline::sShadowRender = FALSE;
-}
-
-static LLFastTimer::DeclareTimer FTM_VISIBLE_CLOUD("Visible Cloud");
-BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir)
-{
- LLFastTimer t(FTM_VISIBLE_CLOUD);
- //get point cloud of intersection of frust and min, max
-
- if (getVisibleExtents(camera, min, max))
- {
- return FALSE;
- }
-
- //get set of planes on bounding box
- LLPlane bp[] = {
- LLPlane(min, LLVector3(-1,0,0)),
- LLPlane(min, LLVector3(0,-1,0)),
- LLPlane(min, LLVector3(0,0,-1)),
- LLPlane(max, LLVector3(1,0,0)),
- LLPlane(max, LLVector3(0,1,0)),
- LLPlane(max, LLVector3(0,0,1))};
-
- //potential points
- std::vector<LLVector3> pp;
-
- //add corners of AABB
- pp.push_back(LLVector3(min.mV[0], min.mV[1], min.mV[2]));
- pp.push_back(LLVector3(max.mV[0], min.mV[1], min.mV[2]));
- pp.push_back(LLVector3(min.mV[0], max.mV[1], min.mV[2]));
- pp.push_back(LLVector3(max.mV[0], max.mV[1], min.mV[2]));
- pp.push_back(LLVector3(min.mV[0], min.mV[1], max.mV[2]));
- pp.push_back(LLVector3(max.mV[0], min.mV[1], max.mV[2]));
- pp.push_back(LLVector3(min.mV[0], max.mV[1], max.mV[2]));
- pp.push_back(LLVector3(max.mV[0], max.mV[1], max.mV[2]));
-
- //add corners of camera frustum
- for (U32 i = 0; i < 8; i++)
- {
- pp.push_back(camera.mAgentFrustum[i]);
- }
-
-
- //bounding box line segments
- U32 bs[] =
- {
- 0,1,
- 1,3,
- 3,2,
- 2,0,
-
- 4,5,
- 5,7,
- 7,6,
- 6,4,
-
- 0,4,
- 1,5,
- 3,7,
- 2,6
- };
-
- for (U32 i = 0; i < 12; i++)
- { //for each line segment in bounding box
- for (U32 j = 0; j < 6; j++)
- { //for each plane in camera frustum
- const LLPlane& cp = camera.getAgentPlane(j);
- const LLVector3& v1 = pp[bs[i*2+0]];
- const LLVector3& v2 = pp[bs[i*2+1]];
- LLVector3 n;
- cp.getVector3(n);
-
- LLVector3 line = v1-v2;
-
- F32 d1 = line*n;
- F32 d2 = -cp.dist(v2);
-
- F32 t = d2/d1;
-
- if (t > 0.f && t < 1.f)
- {
- LLVector3 intersect = v2+line*t;
- pp.push_back(intersect);
- }
- }
- }
-
- //camera frustum line segments
- const U32 fs[] =
- {
- 0,1,
- 1,2,
- 2,3,
- 3,0,
-
- 4,5,
- 5,6,
- 6,7,
- 7,4,
-
- 0,4,
- 1,5,
- 2,6,
- 3,7
- };
-
- LLVector3 center = (max+min)*0.5f;
- LLVector3 size = (max-min)*0.5f;
-
- for (U32 i = 0; i < 12; i++)
- {
- for (U32 j = 0; j < 6; ++j)
- {
- const LLVector3& v1 = pp[fs[i*2+0]+8];
- const LLVector3& v2 = pp[fs[i*2+1]+8];
- const LLPlane& cp = bp[j];
- LLVector3 n;
- cp.getVector3(n);
-
- LLVector3 line = v1-v2;
-
- F32 d1 = line*n;
- F32 d2 = -cp.dist(v2);
-
- F32 t = d2/d1;
-
- if (t > 0.f && t < 1.f)
- {
- LLVector3 intersect = v2+line*t;
- pp.push_back(intersect);
- }
- }
- }
-
- LLVector3 ext[] = { min-LLVector3(0.05f,0.05f,0.05f),
- max+LLVector3(0.05f,0.05f,0.05f) };
-
- for (U32 i = 0; i < pp.size(); ++i)
- {
- bool found = true;
-
- const F32* p = pp[i].mV;
-
- for (U32 j = 0; j < 3; ++j)
- {
- if (p[j] < ext[0].mV[j] ||
- p[j] > ext[1].mV[j])
- {
- found = false;
- break;
- }
- }
-
- for (U32 j = 0; j < 6; ++j)
- {
- const LLPlane& cp = camera.getAgentPlane(j);
- F32 dist = cp.dist(pp[i]);
- if (dist > 0.05f) //point is above some plane, not contained
- {
- found = false;
- break;
- }
- }
-
- if (found)
- {
- fp.push_back(pp[i]);
- }
- }
-
- if (fp.empty())
- {
- return FALSE;
- }
-
- return TRUE;
-}
-
-void LLPipeline::renderHighlight(const LLViewerObject* obj, F32 fade)
-{
- if (obj && obj->getVolume())
- {
- for (LLViewerObject::child_list_t::const_iterator iter = obj->getChildren().begin(); iter != obj->getChildren().end(); ++iter)
- {
- renderHighlight(*iter, fade);
- }
-
- LLDrawable* drawable = obj->mDrawable;
- if (drawable)
- {
- for (S32 i = 0; i < drawable->getNumFaces(); ++i)
- {
- LLFace* face = drawable->getFace(i);
- if (face)
- {
- face->renderSelected(LLViewerTexture::sNullImagep, LLColor4(1,1,1,fade));
- }
- }
- }
- }
-}
-
-void LLPipeline::generateHighlight(LLCamera& camera)
-{
- //render highlighted object as white into offscreen render target
- if (mHighlightObject.notNull())
- {
- mHighlightSet.insert(HighlightItem(mHighlightObject));
- }
-
- if (!mHighlightSet.empty())
- {
- F32 transition = gFrameIntervalSeconds/RenderHighlightFadeTime;
-
- LLGLDisable test(GL_ALPHA_TEST);
- LLGLDepthTest depth(GL_FALSE);
- mHighlight.bindTarget();
- disableLights();
- gGL.setColorMask(true, true);
- mHighlight.clear();
-
- gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
- for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); )
- {
- std::set<HighlightItem>::iterator cur_iter = iter++;
-
- if (cur_iter->mItem.isNull())
- {
- mHighlightSet.erase(cur_iter);
- continue;
- }
-
- if (cur_iter->mItem == mHighlightObject)
- {
- cur_iter->incrFade(transition);
- }
- else
- {
- cur_iter->incrFade(-transition);
- if (cur_iter->mFade <= 0.f)
- {
- mHighlightSet.erase(cur_iter);
- continue;
- }
- }
-
- renderHighlight(cur_iter->mItem->getVObj(), cur_iter->mFade);
- }
-
- mHighlight.flush();
- gGL.setColorMask(true, false);
- gViewerWindow->setup3DViewport();
- }
-}
-
-
-void LLPipeline::generateSunShadow(LLCamera& camera)
-{
- if (!sRenderDeferred || RenderShadowDetail <= 0)
- {
- return;
- }
-
- BOOL skip_avatar_update = FALSE;
- if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson)
- {
-
- skip_avatar_update = TRUE;
- }
-
- if (!skip_avatar_update)
- {
- gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON);
- }
-
- F64 last_modelview[16];
- F64 last_projection[16];
- for (U32 i = 0; i < 16; i++)
- { //store last_modelview of world camera
- last_modelview[i] = gGLLastModelView[i];
- last_projection[i] = gGLLastProjection[i];
- }
-
- pushRenderTypeMask();
- andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE,
- LLPipeline::RENDER_TYPE_ALPHA,
- LLPipeline::RENDER_TYPE_GRASS,
- LLPipeline::RENDER_TYPE_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_BUMP,
- LLPipeline::RENDER_TYPE_VOLUME,
- LLPipeline::RENDER_TYPE_AVATAR,
- LLPipeline::RENDER_TYPE_TREE,
- LLPipeline::RENDER_TYPE_TERRAIN,
- LLPipeline::RENDER_TYPE_WATER,
- LLPipeline::RENDER_TYPE_VOIDWATER,
- LLPipeline::RENDER_TYPE_PASS_ALPHA,
- LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
- LLPipeline::RENDER_TYPE_PASS_GRASS,
- LLPipeline::RENDER_TYPE_PASS_SIMPLE,
- LLPipeline::RENDER_TYPE_PASS_BUMP,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_PASS_SHINY,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
- END_RENDER_TYPES);
-
- gGL.setColorMask(false, false);
-
- //get sun view matrix
-
- //store current projection/modelview matrix
- glh::matrix4f saved_proj = glh_get_current_projection();
- glh::matrix4f saved_view = glh_get_current_modelview();
- glh::matrix4f inv_view = saved_view.inverse();
-
- glh::matrix4f view[6];
- glh::matrix4f proj[6];
-
- //clip contains parallel split distances for 3 splits
- LLVector3 clip = RenderShadowClipPlanes;
-
- //F32 slope_threshold = gSavedSettings.getF32("RenderShadowSlopeThreshold");
-
- //far clip on last split is minimum of camera view distance and 128
- mSunClipPlanes = LLVector4(clip, clip.mV[2] * clip.mV[2]/clip.mV[1]);
-
- clip = RenderShadowOrthoClipPlanes;
- mSunOrthoClipPlanes = LLVector4(clip, clip.mV[2]*clip.mV[2]/clip.mV[1]);
-
- //currently used for amount to extrude frusta corners for constructing shadow frusta
- LLVector3 n = RenderShadowNearDist;
- //F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] };
-
- //put together a universal "near clip" plane for shadow frusta
- LLPlane shadow_near_clip;
- {
- LLVector3 p = gAgent.getPositionAgent();
- p += mSunDir * RenderFarClip*2.f;
- shadow_near_clip.setVec(p, mSunDir);
- }
-
- LLVector3 lightDir = -mSunDir;
- lightDir.normVec();
-
- glh::vec3f light_dir(lightDir.mV);
-
- //create light space camera matrix
-
- LLVector3 at = lightDir;
-
- LLVector3 up = camera.getAtAxis();
-
- if (fabsf(up*lightDir) > 0.75f)
- {
- up = camera.getUpAxis();
- }
-
- /*LLVector3 left = up%at;
- up = at%left;*/
-
- up.normVec();
- at.normVec();
-
-
- LLCamera main_camera = camera;
-
- F32 near_clip = 0.f;
- {
- //get visible point cloud
- std::vector<LLVector3> fp;
-
- main_camera.calcAgentFrustumPlanes(main_camera.mAgentFrustum);
-
- LLVector3 min,max;
- getVisiblePointCloud(main_camera,min,max,fp);
-
- if (fp.empty())
- {
- if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowCamera[0] = main_camera;
- mShadowExtents[0][0] = min;
- mShadowExtents[0][1] = max;
-
- mShadowFrustPoints[0].clear();
- mShadowFrustPoints[1].clear();
- mShadowFrustPoints[2].clear();
- mShadowFrustPoints[3].clear();
- }
- popRenderTypeMask();
-
- if (!skip_avatar_update)
- {
- gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode());
- }
-
- return;
- }
-
- //get good split distances for frustum
- for (U32 i = 0; i < fp.size(); ++i)
- {
- glh::vec3f v(fp[i].mV);
- saved_view.mult_matrix_vec(v);
- fp[i].setVec(v.v);
- }
-
- min = fp[0];
- max = fp[0];
-
- //get camera space bounding box
- for (U32 i = 1; i < fp.size(); ++i)
- {
- update_min_max(min, max, fp[i]);
- }
-
- near_clip = -max.mV[2];
- F32 far_clip = -min.mV[2]*2.f;
-
- //far_clip = llmin(far_clip, 128.f);
- far_clip = llmin(far_clip, camera.getFar());
-
- F32 range = far_clip-near_clip;
-
- LLVector3 split_exp = RenderShadowSplitExponent;
-
- F32 da = 1.f-llmax( fabsf(lightDir*up), fabsf(lightDir*camera.getLeftAxis()) );
-
- da = powf(da, split_exp.mV[2]);
-
-
- F32 sxp = split_exp.mV[1] + (split_exp.mV[0]-split_exp.mV[1])*da;
-
-
- for (U32 i = 0; i < 4; ++i)
- {
- F32 x = (F32)(i+1)/4.f;
- x = powf(x, sxp);
- mSunClipPlanes.mV[i] = near_clip+range*x;
- }
- }
-
- // convenience array of 4 near clip plane distances
- F32 dist[] = { near_clip, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] };
-
-
- if (mSunDiffuse == LLColor4::black)
- { //sun diffuse is totally black, shadows don't matter
- LLGLDepthTest depth(GL_TRUE);
-
- for (S32 j = 0; j < 4; j++)
- {
- mShadow[j].bindTarget();
- mShadow[j].clear();
- mShadow[j].flush();
- }
- }
- else
- {
- for (S32 j = 0; j < 4; j++)
- {
- if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowFrustPoints[j].clear();
- }
-
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+j;
-
- //restore render matrices
- glh_set_current_modelview(saved_view);
- glh_set_current_projection(saved_proj);
-
- LLVector3 eye = camera.getOrigin();
-
- //camera used for shadow cull/render
- LLCamera shadow_cam;
-
- //create world space camera frustum for this split
- shadow_cam = camera;
- shadow_cam.setFar(16.f);
-
- LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
-
- LLVector3* frust = shadow_cam.mAgentFrustum;
-
- LLVector3 pn = shadow_cam.getAtAxis();
-
- LLVector3 min, max;
-
- //construct 8 corners of split frustum section
- for (U32 i = 0; i < 4; i++)
- {
- LLVector3 delta = frust[i+4]-eye;
- delta += (frust[i+4]-frust[(i+2)%4+4])*0.05f;
- delta.normVec();
- F32 dp = delta*pn;
- frust[i] = eye + (delta*dist[j]*0.95f)/dp;
- frust[i+4] = eye + (delta*dist[j+1]*1.05f)/dp;
- }
-
- shadow_cam.calcAgentFrustumPlanes(frust);
- shadow_cam.mFrustumCornerDist = 0.f;
-
- if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowCamera[j] = shadow_cam;
- }
-
- std::vector<LLVector3> fp;
-
- if (!gPipeline.getVisiblePointCloud(shadow_cam, min, max, fp, lightDir))
- {
- //no possible shadow receivers
- if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowExtents[j][0] = LLVector3();
- mShadowExtents[j][1] = LLVector3();
- mShadowCamera[j+4] = shadow_cam;
- }
-
- mShadow[j].bindTarget();
- {
- LLGLDepthTest depth(GL_TRUE);
- mShadow[j].clear();
- }
- mShadow[j].flush();
-
- mShadowError.mV[j] = 0.f;
- mShadowFOV.mV[j] = 0.f;
-
- continue;
- }
-
- if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowExtents[j][0] = min;
- mShadowExtents[j][1] = max;
- mShadowFrustPoints[j] = fp;
- }
-
-
- //find a good origin for shadow projection
- LLVector3 origin;
-
- //get a temporary view projection
- view[j] = look(camera.getOrigin(), lightDir, -up);
-
- std::vector<LLVector3> wpf;
-
- for (U32 i = 0; i < fp.size(); i++)
- {
- glh::vec3f p = glh::vec3f(fp[i].mV);
- view[j].mult_matrix_vec(p);
- wpf.push_back(LLVector3(p.v));
- }
-
- min = wpf[0];
- max = wpf[0];
-
- for (U32 i = 0; i < fp.size(); ++i)
- { //get AABB in camera space
- update_min_max(min, max, wpf[i]);
- }
-
- // Construct a perspective transform with perspective along y-axis that contains
- // points in wpf
- //Known:
- // - far clip plane
- // - near clip plane
- // - points in frustum
- //Find:
- // - origin
-
- //get some "interesting" points of reference
- LLVector3 center = (min+max)*0.5f;
- LLVector3 size = (max-min)*0.5f;
- LLVector3 near_center = center;
- near_center.mV[1] += size.mV[1]*2.f;
-
-
- //put all points in wpf in quadrant 0, reletive to center of min/max
- //get the best fit line using least squares
- F32 bfm = 0.f;
- F32 bfb = 0.f;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- wpf[i] -= center;
- wpf[i].mV[0] = fabsf(wpf[i].mV[0]);
- wpf[i].mV[2] = fabsf(wpf[i].mV[2]);
- }
-
- if (!wpf.empty())
- {
- F32 sx = 0.f;
- F32 sx2 = 0.f;
- F32 sy = 0.f;
- F32 sxy = 0.f;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- sx += wpf[i].mV[0];
- sx2 += wpf[i].mV[0]*wpf[i].mV[0];
- sy += wpf[i].mV[1];
- sxy += wpf[i].mV[0]*wpf[i].mV[1];
- }
-
- bfm = (sy*sx-wpf.size()*sxy)/(sx*sx-wpf.size()*sx2);
- bfb = (sx*sxy-sy*sx2)/(sx*sx-bfm*sx2);
- }
-
- {
- // best fit line is y=bfm*x+bfb
-
- //find point that is furthest to the right of line
- F32 off_x = -1.f;
- LLVector3 lp;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- //y = bfm*x+bfb
- //x = (y-bfb)/bfm
- F32 lx = (wpf[i].mV[1]-bfb)/bfm;
-
- lx = wpf[i].mV[0]-lx;
-
- if (off_x < lx)
- {
- off_x = lx;
- lp = wpf[i];
- }
- }
-
- //get line with slope bfm through lp
- // bfb = y-bfm*x
- bfb = lp.mV[1]-bfm*lp.mV[0];
-
- //calculate error
- mShadowError.mV[j] = 0.f;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- F32 lx = (wpf[i].mV[1]-bfb)/bfm;
- mShadowError.mV[j] += fabsf(wpf[i].mV[0]-lx);
- }
-
- mShadowError.mV[j] /= wpf.size();
- mShadowError.mV[j] /= size.mV[0];
-
- if (mShadowError.mV[j] > RenderShadowErrorCutoff)
- { //just use ortho projection
- mShadowFOV.mV[j] = -1.f;
- origin.clearVec();
- proj[j] = gl_ortho(min.mV[0], max.mV[0],
- min.mV[1], max.mV[1],
- -max.mV[2], -min.mV[2]);
- }
- else
- {
- //origin is where line x = 0;
- origin.setVec(0,bfb,0);
-
- F32 fovz = 1.f;
- F32 fovx = 1.f;
-
- LLVector3 zp;
- LLVector3 xp;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- LLVector3 atz = wpf[i]-origin;
- atz.mV[0] = 0.f;
- atz.normVec();
- if (fovz > -atz.mV[1])
- {
- zp = wpf[i];
- fovz = -atz.mV[1];
- }
-
- LLVector3 atx = wpf[i]-origin;
- atx.mV[2] = 0.f;
- atx.normVec();
- if (fovx > -atx.mV[1])
- {
- fovx = -atx.mV[1];
- xp = wpf[i];
- }
- }
-
- fovx = acos(fovx);
- fovz = acos(fovz);
-
- F32 cutoff = llmin((F32) RenderShadowFOVCutoff, 1.4f);
-
- mShadowFOV.mV[j] = fovx;
-
- if (fovx < cutoff && fovz > cutoff)
- {
- //x is a good fit, but z is too big, move away from zp enough so that fovz matches cutoff
- F32 d = zp.mV[2]/tan(cutoff);
- F32 ny = zp.mV[1] + fabsf(d);
-
- origin.mV[1] = ny;
-
- fovz = 1.f;
- fovx = 1.f;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- LLVector3 atz = wpf[i]-origin;
- atz.mV[0] = 0.f;
- atz.normVec();
- fovz = llmin(fovz, -atz.mV[1]);
-
- LLVector3 atx = wpf[i]-origin;
- atx.mV[2] = 0.f;
- atx.normVec();
- fovx = llmin(fovx, -atx.mV[1]);
- }
-
- fovx = acos(fovx);
- fovz = acos(fovz);
-
- mShadowFOV.mV[j] = cutoff;
- }
-
-
- origin += center;
-
- F32 ynear = -(max.mV[1]-origin.mV[1]);
- F32 yfar = -(min.mV[1]-origin.mV[1]);
-
- if (ynear < 0.1f) //keep a sensible near clip plane
- {
- F32 diff = 0.1f-ynear;
- origin.mV[1] += diff;
- ynear += diff;
- yfar += diff;
- }
-
- if (fovx > cutoff)
- { //just use ortho projection
- origin.clearVec();
- mShadowError.mV[j] = -1.f;
- proj[j] = gl_ortho(min.mV[0], max.mV[0],
- min.mV[1], max.mV[1],
- -max.mV[2], -min.mV[2]);
- }
- else
- {
- //get perspective projection
- view[j] = view[j].inverse();
-
- glh::vec3f origin_agent(origin.mV);
-
- //translate view to origin
- view[j].mult_matrix_vec(origin_agent);
-
- eye = LLVector3(origin_agent.v);
-
- if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowFrustOrigin[j] = eye;
- }
-
- view[j] = look(LLVector3(origin_agent.v), lightDir, -up);
-
- F32 fx = 1.f/tanf(fovx);
- F32 fz = 1.f/tanf(fovz);
-
- proj[j] = glh::matrix4f(-fx, 0, 0, 0,
- 0, (yfar+ynear)/(ynear-yfar), 0, (2.f*yfar*ynear)/(ynear-yfar),
- 0, 0, -fz, 0,
- 0, -1.f, 0, 0);
- }
- }
- }
-
- //shadow_cam.setFar(128.f);
- shadow_cam.setOriginAndLookAt(eye, up, center);
-
- shadow_cam.setOrigin(0,0,0);
-
- glh_set_current_modelview(view[j]);
- glh_set_current_projection(proj[j]);
-
- LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
-
- //shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
- shadow_cam.getAgentPlane(LLCamera::AGENT_PLANE_NEAR).set(shadow_near_clip);
-
- //translate and scale to from [-1, 1] to [0, 1]
- glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
- 0.f, 0.5f, 0.f, 0.5f,
- 0.f, 0.f, 0.5f, 0.5f,
- 0.f, 0.f, 0.f, 1.f);
-
- glh_set_current_modelview(view[j]);
- glh_set_current_projection(proj[j]);
-
- for (U32 i = 0; i < 16; i++)
- {
- gGLLastModelView[i] = mShadowModelview[j].m[i];
- gGLLastProjection[i] = mShadowProjection[j].m[i];
- }
-
- mShadowModelview[j] = view[j];
- mShadowProjection[j] = proj[j];
-
-
- mSunShadowMatrix[j] = trans*proj[j]*view[j]*inv_view;
-
- stop_glerror();
-
- mShadow[j].bindTarget();
- mShadow[j].getViewport(gGLViewport);
- mShadow[j].clear();
-
- {
- static LLCullResult result[4];
-
- //LLGLEnable enable(GL_DEPTH_CLAMP_NV);
- renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE);
- }
-
- mShadow[j].flush();
-
- if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
- mShadowCamera[j+4] = shadow_cam;
- }
- }
- }
-
-
- //hack to disable projector shadows
- bool gen_shadow = RenderShadowDetail > 1;
-
- if (gen_shadow)
- {
- F32 fade_amt = gFrameIntervalSeconds * llmax(LLViewerCamera::getInstance()->getVelocityStat()->getCurrentPerSec(), 1.f);
-
- //update shadow targets
- for (U32 i = 0; i < 2; i++)
- { //for each current shadow
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW4+i;
-
- if (mShadowSpotLight[i].notNull() &&
- (mShadowSpotLight[i] == mTargetShadowSpotLight[0] ||
- mShadowSpotLight[i] == mTargetShadowSpotLight[1]))
- { //keep this spotlight
- mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f);
- }
- else
- { //fade out this light
- mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f);
-
- if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull())
- { //faded out, grab one of the pending spots (whichever one isn't already taken)
- if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2])
- {
- mShadowSpotLight[i] = mTargetShadowSpotLight[0];
- }
- else
- {
- mShadowSpotLight[i] = mTargetShadowSpotLight[1];
- }
- }
- }
- }
-
- for (S32 i = 0; i < 2; i++)
- {
- glh_set_current_modelview(saved_view);
- glh_set_current_projection(saved_proj);
-
- if (mShadowSpotLight[i].isNull())
- {
- continue;
- }
-
- LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume();
-
- if (!volume)
- {
- mShadowSpotLight[i] = NULL;
- continue;
- }
-
- LLDrawable* drawable = mShadowSpotLight[i];
-
- LLVector3 params = volume->getSpotLightParams();
- F32 fov = params.mV[0];
-
- //get agent->light space matrix (modelview)
- LLVector3 center = drawable->getPositionAgent();
- LLQuaternion quat = volume->getRenderRotation();
-
- //get near clip plane
- LLVector3 scale = volume->getScale();
- LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
- at_axis *= quat;
-
- LLVector3 np = center+at_axis;
- at_axis.normVec();
-
- //get origin that has given fov for plane np, at_axis, and given scale
- F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
-
- LLVector3 origin = np - at_axis*dist;
-
- LLMatrix4 mat(quat, LLVector4(origin, 1.f));
-
- view[i+4] = glh::matrix4f((F32*) mat.mMatrix);
-
- view[i+4] = view[i+4].inverse();
-
- //get perspective matrix
- F32 near_clip = dist+0.01f;
- F32 width = scale.mV[VX];
- F32 height = scale.mV[VY];
- F32 far_clip = dist+volume->getLightRadius()*1.5f;
-
- F32 fovy = fov * RAD_TO_DEG;
- F32 aspect = width/height;
-
- proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip);
-
- //translate and scale to from [-1, 1] to [0, 1]
- glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
- 0.f, 0.5f, 0.f, 0.5f,
- 0.f, 0.f, 0.5f, 0.5f,
- 0.f, 0.f, 0.f, 1.f);
-
- glh_set_current_modelview(view[i+4]);
- glh_set_current_projection(proj[i+4]);
-
- mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view;
-
- for (U32 j = 0; j < 16; j++)
- {
- gGLLastModelView[j] = mShadowModelview[i+4].m[j];
- gGLLastProjection[j] = mShadowProjection[i+4].m[j];
- }
-
- mShadowModelview[i+4] = view[i+4];
- mShadowProjection[i+4] = proj[i+4];
-
- LLCamera shadow_cam = camera;
- shadow_cam.setFar(far_clip);
- shadow_cam.setOrigin(origin);
-
- LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
-
- stop_glerror();
-
- mShadow[i+4].bindTarget();
- mShadow[i+4].getViewport(gGLViewport);
- mShadow[i+4].clear();
-
- static LLCullResult result[2];
-
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4;
-
- renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE);
-
- mShadow[i+4].flush();
- }
- }
- else
- { //no spotlight shadows
- mShadowSpotLight[0] = mShadowSpotLight[1] = NULL;
- }
-
-
- if (!CameraOffset)
- {
- glh_set_current_modelview(saved_view);
- glh_set_current_projection(saved_proj);
- }
- else
- {
- glh_set_current_modelview(view[1]);
- glh_set_current_projection(proj[1]);
- gGL.loadMatrix(view[1].m);
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.loadMatrix(proj[1].m);
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- }
- gGL.setColorMask(true, false);
-
- for (U32 i = 0; i < 16; i++)
- {
- gGLLastModelView[i] = last_modelview[i];
- gGLLastProjection[i] = last_projection[i];
- }
-
- popRenderTypeMask();
-
- if (!skip_avatar_update)
- {
- gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode());
- }
-}
-
-void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture)
-{
- for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
- {
- LLSpatialGroup* group = *i;
- if (!group->isDead() &&
- (!sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) &&
- gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) &&
- group->mDrawMap.find(type) != group->mDrawMap.end())
- {
- pass->renderGroup(group,type,mask,texture);
- }
- }
-}
-
-void LLPipeline::generateImpostor(LLVOAvatar* avatar)
-{
- LLMemType mt_gi(LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR);
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- static LLCullResult result;
- result.clear();
- grabReferences(result);
-
- if (!avatar || !avatar->mDrawable)
- {
- return;
- }
-
- assertInitialized();
-
- BOOL muted = LLMuteList::getInstance()->isMuted(avatar->getID());
-
- pushRenderTypeMask();
-
- if (muted)
- {
- andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
- }
- else
- {
- andRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME,
- LLPipeline::RENDER_TYPE_AVATAR,
- LLPipeline::RENDER_TYPE_BUMP,
- LLPipeline::RENDER_TYPE_GRASS,
- LLPipeline::RENDER_TYPE_SIMPLE,
- LLPipeline::RENDER_TYPE_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_ALPHA,
- LLPipeline::RENDER_TYPE_INVISIBLE,
- LLPipeline::RENDER_TYPE_PASS_SIMPLE,
- LLPipeline::RENDER_TYPE_PASS_ALPHA,
- LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
- LLPipeline::RENDER_TYPE_PASS_SHINY,
- LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
- LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
- END_RENDER_TYPES);
- }
-
- S32 occlusion = sUseOcclusion;
- sUseOcclusion = 0;
- sReflectionRender = sRenderDeferred ? FALSE : TRUE;
- sShadowRender = TRUE;
- sImpostorRender = TRUE;
-
- LLViewerCamera* viewer_camera = LLViewerCamera::getInstance();
- markVisible(avatar->mDrawable, *viewer_camera);
- LLVOAvatar::sUseImpostors = FALSE;
-
- LLVOAvatar::attachment_map_t::iterator iter;
- for (iter = avatar->mAttachmentPoints.begin();
- iter != avatar->mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment *attachment = iter->second;
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- if (LLViewerObject* attached_object = (*attachment_iter))
- {
- markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera);
- }
- }
- }
-
- stateSort(*LLViewerCamera::getInstance(), result);
-
- const LLVector4a* ext = avatar->mDrawable->getSpatialExtents();
- LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset());
-
- LLCamera camera = *viewer_camera;
-
- camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis());
-
- LLVector2 tdim;
-
-
- LLVector4a half_height;
- half_height.setSub(ext[1], ext[0]);
- half_height.mul(0.5f);
-
- LLVector4a left;
- left.load3(camera.getLeftAxis().mV);
- left.mul(left);
- left.normalize3fast();
-
- LLVector4a up;
- up.load3(camera.getUpAxis().mV);
- up.mul(up);
- up.normalize3fast();
-
- tdim.mV[0] = fabsf(half_height.dot3(left).getF32());
- tdim.mV[1] = fabsf(half_height.dot3(up).getF32());
-
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.pushMatrix();
-
- F32 distance = (pos-camera.getOrigin()).length();
- F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG;
- F32 aspect = tdim.mV[0]/tdim.mV[1];
- glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f);
- glh_set_current_projection(persp);
- gGL.loadMatrix(persp.m);
-
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.pushMatrix();
- glh::matrix4f mat;
- camera.getOpenGLTransform(mat.m);
-
- mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat;
-
- gGL.loadMatrix(mat.m);
- glh_set_current_modelview(mat);
-
- glClearColor(0.0f,0.0f,0.0f,0.0f);
- gGL.setColorMask(true, true);
-
- // get the number of pixels per angle
- F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView());
-
- //get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing)
- U32 resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512);
- U32 resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512);
-
- if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() ||
- resY != avatar->mImpostor.getHeight())
- {
- avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE);
-
- if (LLPipeline::sRenderDeferred)
- {
- addDeferredAttachments(avatar->mImpostor);
- }
-
- gGL.getTexUnit(0)->bind(&avatar->mImpostor);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- }
-
- avatar->mImpostor.bindTarget();
-
- if (LLPipeline::sRenderDeferred)
- {
- avatar->mImpostor.clear();
- renderGeomDeferred(camera);
- renderGeomPostDeferred(camera);
- }
- else
- {
- LLGLEnable scissor(GL_SCISSOR_TEST);
- glScissor(0, 0, resX, resY);
- avatar->mImpostor.clear();
- renderGeom(camera);
- }
-
- { //create alpha mask based on depth buffer (grey out if muted)
- if (LLPipeline::sRenderDeferred)
- {
- GLuint buff = GL_COLOR_ATTACHMENT0;
- glDrawBuffersARB(1, &buff);
- }
-
- LLGLDisable blend(GL_BLEND);
-
- if (muted)
- {
- gGL.setColorMask(true, true);
- }
- else
- {
- gGL.setColorMask(false, true);
- }
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER);
-
- gGL.flush();
-
- gGL.pushMatrix();
- gGL.loadIdentity();
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.pushMatrix();
- gGL.loadIdentity();
-
- static const F32 clip_plane = 0.99999f;
-
- if (LLGLSLShader::sNoFixedFunction)
- {
- gUIProgram.bind();
- }
-
- gGL.color4ub(64,64,64,255);
- gGL.begin(LLRender::QUADS);
- gGL.vertex3f(-1, -1, clip_plane);
- gGL.vertex3f(1, -1, clip_plane);
- gGL.vertex3f(1, 1, clip_plane);
- gGL.vertex3f(-1, 1, clip_plane);
- gGL.end();
- gGL.flush();
-
- if (LLGLSLShader::sNoFixedFunction)
- {
- gUIProgram.unbind();
- }
-
- gGL.popMatrix();
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.popMatrix();
- }
-
- avatar->mImpostor.flush();
-
- avatar->setImpostorDim(tdim);
-
- LLVOAvatar::sUseImpostors = TRUE;
- sUseOcclusion = occlusion;
- sReflectionRender = FALSE;
- sImpostorRender = FALSE;
- sShadowRender = FALSE;
- popRenderTypeMask();
-
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.popMatrix();
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.popMatrix();
-
- avatar->mNeedsImpostorUpdate = FALSE;
- avatar->cacheImpostorValues();
-
- LLVertexBuffer::unbind();
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-}
-
-BOOL LLPipeline::hasRenderBatches(const U32 type) const
-{
- return sCull->getRenderMapSize(type) > 0;
-}
-
-LLCullResult::drawinfo_list_t::iterator LLPipeline::beginRenderMap(U32 type)
-{
- return sCull->beginRenderMap(type);
-}
-
-LLCullResult::drawinfo_list_t::iterator LLPipeline::endRenderMap(U32 type)
-{
- return sCull->endRenderMap(type);
-}
-
-LLCullResult::sg_list_t::iterator LLPipeline::beginAlphaGroups()
-{
- return sCull->beginAlphaGroups();
-}
-
-LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups()
-{
- return sCull->endAlphaGroups();
-}
-
-BOOL LLPipeline::hasRenderType(const U32 type) const
-{
- // STORM-365 : LLViewerJointAttachment::setAttachmentVisibility() is setting type to 0 to actually mean "do not render"
- // We then need to test that value here and return FALSE to prevent attachment to render (in mouselook for instance)
- // TODO: reintroduce RENDER_TYPE_NONE in LLRenderTypeMask and initialize its mRenderTypeEnabled[RENDER_TYPE_NONE] to FALSE explicitely
- return (type == 0 ? FALSE : mRenderTypeEnabled[type]);
-}
-
-void LLPipeline::setRenderTypeMask(U32 type, ...)
-{
- va_list args;
-
- va_start(args, type);
- while (type < END_RENDER_TYPES)
- {
- mRenderTypeEnabled[type] = TRUE;
- type = va_arg(args, U32);
- }
- va_end(args);
-
- if (type > END_RENDER_TYPES)
- {
- llerrs << "Invalid render type." << llendl;
- }
-}
-
-BOOL LLPipeline::hasAnyRenderType(U32 type, ...) const
-{
- va_list args;
-
- va_start(args, type);
- while (type < END_RENDER_TYPES)
- {
- if (mRenderTypeEnabled[type])
- {
- return TRUE;
- }
- type = va_arg(args, U32);
- }
- va_end(args);
-
- if (type > END_RENDER_TYPES)
- {
- llerrs << "Invalid render type." << llendl;
- }
-
- return FALSE;
-}
-
-void LLPipeline::pushRenderTypeMask()
-{
- std::string cur_mask;
- cur_mask.assign((const char*) mRenderTypeEnabled, sizeof(mRenderTypeEnabled));
- mRenderTypeEnableStack.push(cur_mask);
-}
-
-void LLPipeline::popRenderTypeMask()
-{
- if (mRenderTypeEnableStack.empty())
- {
- llerrs << "Depleted render type stack." << llendl;
- }
-
- memcpy(mRenderTypeEnabled, mRenderTypeEnableStack.top().data(), sizeof(mRenderTypeEnabled));
- mRenderTypeEnableStack.pop();
-}
-
-void LLPipeline::andRenderTypeMask(U32 type, ...)
-{
- va_list args;
-
- BOOL tmp[NUM_RENDER_TYPES];
- for (U32 i = 0; i < NUM_RENDER_TYPES; ++i)
- {
- tmp[i] = FALSE;
- }
-
- va_start(args, type);
- while (type < END_RENDER_TYPES)
- {
- if (mRenderTypeEnabled[type])
- {
- tmp[type] = TRUE;
- }
-
- type = va_arg(args, U32);
- }
- va_end(args);
-
- if (type > END_RENDER_TYPES)
- {
- llerrs << "Invalid render type." << llendl;
- }
-
- for (U32 i = 0; i < LLPipeline::NUM_RENDER_TYPES; ++i)
- {
- mRenderTypeEnabled[i] = tmp[i];
- }
-
-}
-
-void LLPipeline::clearRenderTypeMask(U32 type, ...)
-{
- va_list args;
-
- va_start(args, type);
- while (type < END_RENDER_TYPES)
- {
- mRenderTypeEnabled[type] = FALSE;
-
- type = va_arg(args, U32);
- }
- va_end(args);
-
- if (type > END_RENDER_TYPES)
- {
- llerrs << "Invalid render type." << llendl;
- }
-}
-
-void LLPipeline::addDebugBlip(const LLVector3& position, const LLColor4& color)
-{
- DebugBlip blip(position, color);
- mDebugBlips.push_back(blip);
-}
-
+/** + * @file pipeline.cpp + * @brief Rendering pipeline. + * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "pipeline.h" + +// library includes +#include "llaudioengine.h" // For debugging. +#include "imageids.h" +#include "llerror.h" +#include "llviewercontrol.h" +#include "llfasttimer.h" +#include "llfontgl.h" +#include "llmemtype.h" +#include "llnamevalue.h" +#include "llpointer.h" +#include "llprimitive.h" +#include "llvolume.h" +#include "material_codes.h" +#include "timing.h" +#include "v3color.h" +#include "llui.h" +#include "llglheaders.h" +#include "llrender.h" +#include "llwindow.h" // swapBuffers() + +// newview includes +#include "llagent.h" +#include "llagentcamera.h" +#include "lldrawable.h" +#include "lldrawpoolalpha.h" +#include "lldrawpoolavatar.h" +#include "lldrawpoolground.h" +#include "lldrawpoolbump.h" +#include "lldrawpooltree.h" +#include "lldrawpoolwater.h" +#include "llface.h" +#include "llfeaturemanager.h" +#include "llfloatertelehub.h" +#include "llfloaterreg.h" +#include "llgldbg.h" +#include "llhudmanager.h" +#include "llhudnametag.h" +#include "llhudtext.h" +#include "lllightconstants.h" +#include "llmeshrepository.h" +#include "llresmgr.h" +#include "llselectmgr.h" +#include "llsky.h" +#include "lltracker.h" +#include "lltool.h" +#include "lltoolmgr.h" +#include "llviewercamera.h" +#include "llviewermediafocus.h" +#include "llviewertexturelist.h" +#include "llviewerobject.h" +#include "llviewerobjectlist.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" // for audio debugging. +#include "llviewerwindow.h" // For getSpinAxis +#include "llvoavatarself.h" +#include "llvoground.h" +#include "llvosky.h" +#include "llvotree.h" +#include "llvovolume.h" +#include "llvosurfacepatch.h" +#include "llvowater.h" +#include "llvotree.h" +#include "llvopartgroup.h" +#include "llworld.h" +#include "llcubemap.h" +#include "llviewershadermgr.h" +#include "llviewerstats.h" +#include "llviewerjoystick.h" +#include "llviewerdisplay.h" +#include "llwlparammanager.h" +#include "llwaterparammanager.h" +#include "llspatialpartition.h" +#include "llmutelist.h" +#include "lltoolpie.h" +#include "llcurl.h" +#include "llnotifications.h" +#include "LLPathingLib.h" + +#ifdef _DEBUG +// Debug indices is disabled for now for debug performance - djs 4/24/02 +//#define DEBUG_INDICES +#else +//#define DEBUG_INDICES +#endif + +//cached settings +BOOL LLPipeline::RenderAvatarVP; +BOOL LLPipeline::VertexShaderEnable; +BOOL LLPipeline::WindLightUseAtmosShaders; +BOOL LLPipeline::RenderDeferred; +F32 LLPipeline::RenderDeferredSunWash; +U32 LLPipeline::RenderFSAASamples; +U32 LLPipeline::RenderResolutionDivisor; +BOOL LLPipeline::RenderUIBuffer; +S32 LLPipeline::RenderShadowDetail; +BOOL LLPipeline::RenderDeferredSSAO; +F32 LLPipeline::RenderShadowResolutionScale; +BOOL LLPipeline::RenderLocalLights; +BOOL LLPipeline::RenderDelayCreation; +BOOL LLPipeline::RenderAnimateRes; +BOOL LLPipeline::FreezeTime; +S32 LLPipeline::DebugBeaconLineWidth; +F32 LLPipeline::RenderHighlightBrightness; +LLColor4 LLPipeline::RenderHighlightColor; +F32 LLPipeline::RenderHighlightThickness; +BOOL LLPipeline::RenderSpotLightsInNondeferred; +LLColor4 LLPipeline::PreviewAmbientColor; +LLColor4 LLPipeline::PreviewDiffuse0; +LLColor4 LLPipeline::PreviewSpecular0; +LLColor4 LLPipeline::PreviewDiffuse1; +LLColor4 LLPipeline::PreviewSpecular1; +LLColor4 LLPipeline::PreviewDiffuse2; +LLColor4 LLPipeline::PreviewSpecular2; +LLVector3 LLPipeline::PreviewDirection0; +LLVector3 LLPipeline::PreviewDirection1; +LLVector3 LLPipeline::PreviewDirection2; +F32 LLPipeline::RenderGlowMinLuminance; +F32 LLPipeline::RenderGlowMaxExtractAlpha; +F32 LLPipeline::RenderGlowWarmthAmount; +LLVector3 LLPipeline::RenderGlowLumWeights; +LLVector3 LLPipeline::RenderGlowWarmthWeights; +S32 LLPipeline::RenderGlowResolutionPow; +S32 LLPipeline::RenderGlowIterations; +F32 LLPipeline::RenderGlowWidth; +F32 LLPipeline::RenderGlowStrength; +BOOL LLPipeline::RenderDepthOfField; +F32 LLPipeline::CameraFocusTransitionTime; +F32 LLPipeline::CameraFNumber; +F32 LLPipeline::CameraFocalLength; +F32 LLPipeline::CameraFieldOfView; +F32 LLPipeline::RenderShadowNoise; +F32 LLPipeline::RenderShadowBlurSize; +F32 LLPipeline::RenderSSAOScale; +U32 LLPipeline::RenderSSAOMaxScale; +F32 LLPipeline::RenderSSAOFactor; +LLVector3 LLPipeline::RenderSSAOEffect; +F32 LLPipeline::RenderShadowOffsetError; +F32 LLPipeline::RenderShadowBiasError; +F32 LLPipeline::RenderShadowOffset; +F32 LLPipeline::RenderShadowBias; +F32 LLPipeline::RenderSpotShadowOffset; +F32 LLPipeline::RenderSpotShadowBias; +F32 LLPipeline::RenderEdgeDepthCutoff; +F32 LLPipeline::RenderEdgeNormCutoff; +LLVector3 LLPipeline::RenderShadowGaussian; +F32 LLPipeline::RenderShadowBlurDistFactor; +BOOL LLPipeline::RenderDeferredAtmospheric; +S32 LLPipeline::RenderReflectionDetail; +F32 LLPipeline::RenderHighlightFadeTime; +LLVector3 LLPipeline::RenderShadowClipPlanes; +LLVector3 LLPipeline::RenderShadowOrthoClipPlanes; +LLVector3 LLPipeline::RenderShadowNearDist; +F32 LLPipeline::RenderFarClip; +LLVector3 LLPipeline::RenderShadowSplitExponent; +F32 LLPipeline::RenderShadowErrorCutoff; +F32 LLPipeline::RenderShadowFOVCutoff; +BOOL LLPipeline::CameraOffset; +F32 LLPipeline::CameraMaxCoF; +F32 LLPipeline::CameraDoFResScale; + +const F32 BACKLIGHT_DAY_MAGNITUDE_AVATAR = 0.2f; +const F32 BACKLIGHT_NIGHT_MAGNITUDE_AVATAR = 0.1f; +const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f; +const F32 BACKLIGHT_NIGHT_MAGNITUDE_OBJECT = 0.08f; +const S32 MAX_OFFSCREEN_GEOMETRY_CHANGES_PER_FRAME = 10; +const U32 REFLECTION_MAP_RES = 128; +const U32 DEFERRED_VB_MASK = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1; +// Max number of occluders to search for. JC +const S32 MAX_OCCLUDER_COUNT = 2; + +extern S32 gBoxFrame; +//extern BOOL gHideSelectedObjects; +extern BOOL gDisplaySwapBuffers; +extern BOOL gDebugGL; + +// hack counter for rendering a fixed number of frames after toggling +// fullscreen to work around DEV-5361 +static S32 sDelayedVBOEnable = 0; + +BOOL gAvatarBacklight = FALSE; + +BOOL gDebugPipeline = FALSE; +LLPipeline gPipeline; +const LLMatrix4* gGLLastMatrix = NULL; + +LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Geometry"); +LLFastTimer::DeclareTimer FTM_RENDER_GRASS("Grass"); +LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE("Invisible"); +LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION("Occlusion"); +LLFastTimer::DeclareTimer FTM_RENDER_SHINY("Shiny"); +LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE("Simple"); +LLFastTimer::DeclareTimer FTM_RENDER_TERRAIN("Terrain"); +LLFastTimer::DeclareTimer FTM_RENDER_TREES("Trees"); +LLFastTimer::DeclareTimer FTM_RENDER_UI("UI"); +LLFastTimer::DeclareTimer FTM_RENDER_WATER("Water"); +LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY("Windlight Sky"); +LLFastTimer::DeclareTimer FTM_RENDER_ALPHA("Alpha Objects"); +LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS("Avatars"); +LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump"); +LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright"); +LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow"); +LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update"); +LLFastTimer::DeclareTimer FTM_POOLRENDER("RenderPool"); +LLFastTimer::DeclareTimer FTM_POOLS("Pools"); +LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO"); +LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State"); +LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline"); +LLFastTimer::DeclareTimer FTM_CLIENT_COPY("Client Copy"); +LLFastTimer::DeclareTimer FTM_RENDER_DEFERRED("Deferred Shading"); + + +static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables"); +static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort"); + +//---------------------------------------- +std::string gPoolNames[] = +{ + // Correspond to LLDrawpool enum render type + "NONE", + "POOL_SIMPLE", + "POOL_GROUND", + "POOL_FULLBRIGHT", + "POOL_BUMP", + "POOL_TERRAIN," + "POOL_SKY", + "POOL_WL_SKY", + "POOL_TREE", + "POOL_GRASS", + "POOL_INVISIBLE", + "POOL_AVATAR", + "POOL_VOIDWATER", + "POOL_WATER", + "POOL_GLOW", + "POOL_ALPHA" +}; + +void drawBox(const LLVector3& c, const LLVector3& r); +void drawBoxOutline(const LLVector3& pos, const LLVector3& size); +U32 nhpo2(U32 v); + +glh::matrix4f glh_copy_matrix(F32* src) +{ + glh::matrix4f ret; + ret.set_value(src); + return ret; +} + +glh::matrix4f glh_get_current_modelview() +{ + return glh_copy_matrix(gGLModelView); +} + +glh::matrix4f glh_get_current_projection() +{ + return glh_copy_matrix(gGLProjection); +} + +glh::matrix4f glh_get_last_modelview() +{ + return glh_copy_matrix(gGLLastModelView); +} + +glh::matrix4f glh_get_last_projection() +{ + return glh_copy_matrix(gGLLastProjection); +} + +void glh_copy_matrix(const glh::matrix4f& src, F32* dst) +{ + for (U32 i = 0; i < 16; i++) + { + dst[i] = src.m[i]; + } +} + +void glh_set_current_modelview(const glh::matrix4f& mat) +{ + glh_copy_matrix(mat, gGLModelView); +} + +void glh_set_current_projection(glh::matrix4f& mat) +{ + glh_copy_matrix(mat, gGLProjection); +} + +glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar) +{ + glh::matrix4f ret( + 2.f/(right-left), 0.f, 0.f, -(right+left)/(right-left), + 0.f, 2.f/(top-bottom), 0.f, -(top+bottom)/(top-bottom), + 0.f, 0.f, -2.f/(zfar-znear), -(zfar+znear)/(zfar-znear), + 0.f, 0.f, 0.f, 1.f); + + return ret; +} + +void display_update_camera(); +//---------------------------------------- + +S32 LLPipeline::sCompiles = 0; + +BOOL LLPipeline::sPickAvatar = TRUE; +BOOL LLPipeline::sDynamicLOD = TRUE; +BOOL LLPipeline::sShowHUDAttachments = TRUE; +BOOL LLPipeline::sRenderMOAPBeacons = FALSE; +BOOL LLPipeline::sRenderPhysicalBeacons = TRUE; +BOOL LLPipeline::sRenderScriptedBeacons = FALSE; +BOOL LLPipeline::sRenderScriptedTouchBeacons = TRUE; +BOOL LLPipeline::sRenderParticleBeacons = FALSE; +BOOL LLPipeline::sRenderSoundBeacons = FALSE; +BOOL LLPipeline::sRenderBeacons = FALSE; +BOOL LLPipeline::sRenderHighlight = TRUE; +BOOL LLPipeline::sForceOldBakedUpload = FALSE; +S32 LLPipeline::sUseOcclusion = 0; +BOOL LLPipeline::sDelayVBUpdate = TRUE; +BOOL LLPipeline::sAutoMaskAlphaDeferred = TRUE; +BOOL LLPipeline::sAutoMaskAlphaNonDeferred = FALSE; +BOOL LLPipeline::sDisableShaders = FALSE; +BOOL LLPipeline::sRenderBump = TRUE; +BOOL LLPipeline::sBakeSunlight = FALSE; +BOOL LLPipeline::sNoAlpha = FALSE; +BOOL LLPipeline::sUseTriStrips = TRUE; +BOOL LLPipeline::sUseFarClip = TRUE; +BOOL LLPipeline::sShadowRender = FALSE; +BOOL LLPipeline::sWaterReflections = FALSE; +BOOL LLPipeline::sRenderGlow = FALSE; +BOOL LLPipeline::sReflectionRender = FALSE; +BOOL LLPipeline::sImpostorRender = FALSE; +BOOL LLPipeline::sUnderWaterRender = FALSE; +BOOL LLPipeline::sTextureBindTest = FALSE; +BOOL LLPipeline::sRenderFrameTest = FALSE; +BOOL LLPipeline::sRenderAttachedLights = TRUE; +BOOL LLPipeline::sRenderAttachedParticles = TRUE; +BOOL LLPipeline::sRenderDeferred = FALSE; +BOOL LLPipeline::sMemAllocationThrottled = FALSE; +S32 LLPipeline::sVisibleLightCount = 0; +F32 LLPipeline::sMinRenderSize = 0.f; + + +static LLCullResult* sCull = NULL; + +static const U32 gl_cube_face[] = +{ + GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, +}; + +void validate_framebuffer_object(); + + +bool addDeferredAttachments(LLRenderTarget& target) +{ + return target.addColorAttachment(GL_RGBA) && //specular + target.addColorAttachment(GL_RGBA); //normal+z +} + +LLPipeline::LLPipeline() : + mBackfaceCull(FALSE), + mBatchCount(0), + mMatrixOpCount(0), + mTextureMatrixOps(0), + mMaxBatchSize(0), + mMinBatchSize(0), + mMeanBatchSize(0), + mTrianglesDrawn(0), + mNumVisibleNodes(0), + mVerticesRelit(0), + mLightingChanges(0), + mGeometryChanges(0), + mNumVisibleFaces(0), + + mInitialized(FALSE), + mVertexShadersEnabled(FALSE), + mVertexShadersLoaded(0), + mRenderDebugFeatureMask(0), + mRenderDebugMask(0), + mOldRenderDebugMask(0), + mGroupQ1Locked(false), + mGroupQ2Locked(false), + mLastRebuildPool(NULL), + mAlphaPool(NULL), + mSkyPool(NULL), + mTerrainPool(NULL), + mWaterPool(NULL), + mGroundPool(NULL), + mSimplePool(NULL), + mFullbrightPool(NULL), + mInvisiblePool(NULL), + mGlowPool(NULL), + mBumpPool(NULL), + mWLSkyPool(NULL), + mLightMask(0), + mLightMovingMask(0), + mLightingDetail(0), + mScreenWidth(0), + mScreenHeight(0) +{ + mNoiseMap = 0; + mTrueNoiseMap = 0; + mLightFunc = 0; +} + +void LLPipeline::init() +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_INIT); + + refreshCachedSettings(); + + gOctreeMaxCapacity = gSavedSettings.getU32("OctreeMaxNodeCapacity"); + sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD"); + sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); + sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips"); + LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO"); + LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO"); + LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw"); + sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); + sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); + + mInitialized = TRUE; + + stop_glerror(); + + //create render pass pools + getPool(LLDrawPool::POOL_ALPHA); + getPool(LLDrawPool::POOL_SIMPLE); + getPool(LLDrawPool::POOL_GRASS); + getPool(LLDrawPool::POOL_FULLBRIGHT); + getPool(LLDrawPool::POOL_INVISIBLE); + getPool(LLDrawPool::POOL_BUMP); + getPool(LLDrawPool::POOL_GLOW); + + LLViewerStats::getInstance()->mTrianglesDrawnStat.reset(); + resetFrameStats(); + + for (U32 i = 0; i < NUM_RENDER_TYPES; ++i) + { + mRenderTypeEnabled[i] = TRUE; //all rendering types start enabled + } + + mRenderDebugFeatureMask = 0xffffffff; // All debugging features on + mRenderDebugMask = 0; // All debug starts off + + // Don't turn on ground when this is set + // Mac Books with intel 950s need this + if(!gSavedSettings.getBOOL("RenderGround")) + { + toggleRenderType(RENDER_TYPE_GROUND); + } + + // make sure RenderPerformanceTest persists (hackity hack hack) + // disables non-object rendering (UI, sky, water, etc) + if (gSavedSettings.getBOOL("RenderPerformanceTest")) + { + gSavedSettings.setBOOL("RenderPerformanceTest", FALSE); + gSavedSettings.setBOOL("RenderPerformanceTest", TRUE); + } + + mOldRenderDebugMask = mRenderDebugMask; + + mBackfaceCull = TRUE; + + stop_glerror(); + + // Enable features + + LLViewerShaderMgr::instance()->setShaders(); + + stop_glerror(); + + for (U32 i = 0; i < 2; ++i) + { + mSpotLightFade[i] = 1.f; + } + + mDeferredVB = new LLVertexBuffer(DEFERRED_VB_MASK, 0); + mDeferredVB->allocateBuffer(8, 0, true); + setLightingDetail(-1); + + // + // Update all settings to trigger a cached settings refresh + // + + gSavedSettings.getControl("RenderAutoMaskAlphaDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderUseFarClip")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderAvatarMaxVisible")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderDelayVBUpdate")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + + gSavedSettings.getControl("UseOcclusion")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + + gSavedSettings.getControl("VertexShaderEnable")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderAvatarVP")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("WindLightUseAtmosShaders")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderDeferredSunWash")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderFSAASamples")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderResolutionDivisor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderUIBuffer")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderShadowDetail")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderDeferredSSAO")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderShadowResolutionScale")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderLocalLights")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderDelayCreation")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderAnimateRes")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("FreezeTime")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("DebugBeaconLineWidth")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderHighlightBrightness")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderHighlightColor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderHighlightThickness")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderSpotLightsInNondeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("PreviewAmbientColor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("PreviewDiffuse0")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("PreviewSpecular0")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("PreviewDiffuse1")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("PreviewSpecular1")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("PreviewDiffuse2")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("PreviewSpecular2")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("PreviewDirection0")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("PreviewDirection1")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("PreviewDirection2")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderGlowMinLuminance")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderGlowMaxExtractAlpha")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderGlowWarmthAmount")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderGlowLumWeights")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderGlowWarmthWeights")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderGlowResolutionPow")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderGlowIterations")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderGlowWidth")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderGlowStrength")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderDepthOfField")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("CameraFocusTransitionTime")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("CameraFNumber")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("CameraFocalLength")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("CameraFieldOfView")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderShadowNoise")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderShadowBlurSize")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderSSAOScale")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderSSAOMaxScale")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderSSAOFactor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderSSAOEffect")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderShadowOffsetError")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderShadowBiasError")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderShadowOffset")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderShadowBias")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderSpotShadowOffset")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderSpotShadowBias")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderEdgeDepthCutoff")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderEdgeNormCutoff")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderShadowGaussian")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderShadowBlurDistFactor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderDeferredAtmospheric")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderReflectionDetail")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderHighlightFadeTime")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderShadowClipPlanes")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderShadowOrthoClipPlanes")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderShadowNearDist")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderFarClip")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderShadowSplitExponent")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderShadowErrorCutoff")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderShadowFOVCutoff")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("CameraOffset")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("CameraMaxCoF")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("CameraDoFResScale")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); +} + +LLPipeline::~LLPipeline() +{ + +} + +void LLPipeline::cleanup() +{ + assertInitialized(); + + mGroupQ1.clear() ; + mGroupQ2.clear() ; + + for(pool_set_t::iterator iter = mPools.begin(); + iter != mPools.end(); ) + { + pool_set_t::iterator curiter = iter++; + LLDrawPool* poolp = *curiter; + if (poolp->isFacePool()) + { + LLFacePool* face_pool = (LLFacePool*) poolp; + if (face_pool->mReferences.empty()) + { + mPools.erase(curiter); + removeFromQuickLookup( poolp ); + delete poolp; + } + } + else + { + mPools.erase(curiter); + removeFromQuickLookup( poolp ); + delete poolp; + } + } + + if (!mTerrainPools.empty()) + { + llwarns << "Terrain Pools not cleaned up" << llendl; + } + if (!mTreePools.empty()) + { + llwarns << "Tree Pools not cleaned up" << llendl; + } + + delete mAlphaPool; + mAlphaPool = NULL; + delete mSkyPool; + mSkyPool = NULL; + delete mTerrainPool; + mTerrainPool = NULL; + delete mWaterPool; + mWaterPool = NULL; + delete mGroundPool; + mGroundPool = NULL; + delete mSimplePool; + mSimplePool = NULL; + delete mFullbrightPool; + mFullbrightPool = NULL; + delete mInvisiblePool; + mInvisiblePool = NULL; + delete mGlowPool; + mGlowPool = NULL; + delete mBumpPool; + mBumpPool = NULL; + // don't delete wl sky pool it was handled above in the for loop + //delete mWLSkyPool; + mWLSkyPool = NULL; + + releaseGLBuffers(); + + mFaceSelectImagep = NULL; + + mMovedBridge.clear(); + + mInitialized = FALSE; + + mDeferredVB = NULL; +} + +//============================================================================ + +void LLPipeline::destroyGL() +{ + stop_glerror(); + unloadShaders(); + mHighlightFaces.clear(); + + resetDrawOrders(); + + resetVertexBuffers(); + + releaseGLBuffers(); + + if (LLVertexBuffer::sEnableVBOs) + { + // render 30 frames after switching to work around DEV-5361 + sDelayedVBOEnable = 30; + LLVertexBuffer::sEnableVBOs = FALSE; + } +} + +static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture"); + +//static +void LLPipeline::throttleNewMemoryAllocation(BOOL disable) +{ + if(sMemAllocationThrottled != disable) + { + sMemAllocationThrottled = disable ; + + if(sMemAllocationThrottled) + { + //send out notification + LLNotification::Params params("LowMemory"); + LLNotifications::instance().add(params); + + //release some memory. + } + } +} + +void LLPipeline::resizeScreenTexture() +{ + LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE); + if (gPipeline.canUseVertexShaders() && assertInitialized()) + { + GLuint resX = gViewerWindow->getWorldViewWidthRaw(); + GLuint resY = gViewerWindow->getWorldViewHeightRaw(); + + allocateScreenBuffer(resX,resY); + } +} + +void LLPipeline::allocatePhysicsBuffer() +{ + GLuint resX = gViewerWindow->getWorldViewWidthRaw(); + GLuint resY = gViewerWindow->getWorldViewHeightRaw(); + + if (mPhysicsDisplay.getWidth() != resX || mPhysicsDisplay.getHeight() != resY) + { + mPhysicsDisplay.allocate(resX, resY, GL_RGBA, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); + } +} + +void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY) +{ + refreshCachedSettings(); + U32 samples = RenderFSAASamples; + + //try to allocate screen buffers at requested resolution and samples + // - on failure, shrink number of samples and try again + // - if not multisampled, shrink resolution and try again (favor X resolution over Y) + // Make sure to call "releaseScreenBuffers" after each failure to cleanup the partially loaded state + + if (!allocateScreenBuffer(resX, resY, samples)) + { + releaseScreenBuffers(); + //reduce number of samples + while (samples > 0) + { + samples /= 2; + if (allocateScreenBuffer(resX, resY, samples)) + { //success + return; + } + releaseScreenBuffers(); + } + + samples = 0; + + //reduce resolution + while (resY > 0 && resX > 0) + { + resY /= 2; + if (allocateScreenBuffer(resX, resY, samples)) + { + return; + } + releaseScreenBuffers(); + + resX /= 2; + if (allocateScreenBuffer(resX, resY, samples)) + { + return; + } + releaseScreenBuffers(); + } + + llwarns << "Unable to allocate screen buffer at any resolution!" << llendl; + } +} + + +bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) +{ + refreshCachedSettings(); + + // remember these dimensions + mScreenWidth = resX; + mScreenHeight = resY; + + U32 res_mod = RenderResolutionDivisor; + + if (res_mod > 1 && res_mod < resX && res_mod < resY) + { + resX /= res_mod; + resY /= res_mod; + } + + if (RenderUIBuffer) + { + if (!mUIScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) + { + return false; + } + } + + if (LLPipeline::sRenderDeferred) + { + S32 shadow_detail = RenderShadowDetail; + BOOL ssao = RenderDeferredSSAO; + + //allocate deferred rendering color buffers + if (!mDeferredScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false; + if (!mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false; + if (!addDeferredAttachments(mDeferredScreen)) return false; + + if (!mScreen.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false; + if (samples > 0) + { + if (!mFXAABuffer.allocate(nhpo2(resX), nhpo2(resY), GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE, samples)) return false; + } + else + { + mFXAABuffer.release(); + } + + if (shadow_detail > 0 || ssao || RenderDepthOfField || samples > 0) + { //only need mDeferredLight for shadows OR ssao OR dof OR fxaa + if (!mDeferredLight.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; + } + else + { + mDeferredLight.release(); + } + + F32 scale = RenderShadowResolutionScale; + + if (shadow_detail > 0) + { //allocate 4 sun shadow maps + for (U32 i = 0; i < 4; i++) + { + if (!mShadow[i].allocate(U32(resX*scale),U32(resY*scale), 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE)) return false; + } + } + else + { + for (U32 i = 0; i < 4; i++) + { + mShadow[i].release(); + } + } + + U32 width = nhpo2(U32(resX*scale))/2; + U32 height = width; + + if (shadow_detail > 1) + { //allocate two spot shadow maps + for (U32 i = 4; i < 6; i++) + { + if (!mShadow[i].allocate(width, height, 0, TRUE, FALSE)) return false; + } + } + else + { + for (U32 i = 4; i < 6; i++) + { + mShadow[i].release(); + } + } + } + else + { + mDeferredLight.release(); + + for (U32 i = 0; i < 6; i++) + { + mShadow[i].release(); + } + mFXAABuffer.release(); + mScreen.release(); + mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first + mDeferredDepth.release(); + + if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; + } + + if (LLPipeline::sRenderDeferred) + { //share depth buffer between deferred targets + mDeferredScreen.shareDepthBuffer(mScreen); + } + + gGL.getTexUnit(0)->disable(); + + stop_glerror(); + + return true; +} + +//static +void LLPipeline::updateRenderDeferred() +{ + BOOL deferred = ((RenderDeferred && + LLRenderTarget::sUseFBO && + LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && + VertexShaderEnable && + RenderAvatarVP && + WindLightUseAtmosShaders) ? TRUE : FALSE) && + !gUseWireframe; + + sRenderDeferred = deferred; + if (deferred) + { //must render glow when rendering deferred since post effect pass is needed to present any lighting at all + sRenderGlow = TRUE; + } +} + +//static +void LLPipeline::refreshCachedSettings() +{ + LLPipeline::sAutoMaskAlphaDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaDeferred"); + LLPipeline::sAutoMaskAlphaNonDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaNonDeferred"); + LLPipeline::sUseFarClip = gSavedSettings.getBOOL("RenderUseFarClip"); + LLVOAvatar::sMaxVisible = (U32)gSavedSettings.getS32("RenderAvatarMaxVisible"); + LLPipeline::sDelayVBUpdate = gSavedSettings.getBOOL("RenderDelayVBUpdate"); + + LLPipeline::sUseOcclusion = + (!gUseWireframe + && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") + && gSavedSettings.getBOOL("UseOcclusion") + && gGLManager.mHasOcclusionQuery) ? 2 : 0; + + VertexShaderEnable = gSavedSettings.getBOOL("VertexShaderEnable"); + RenderAvatarVP = gSavedSettings.getBOOL("RenderAvatarVP"); + WindLightUseAtmosShaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders"); + RenderDeferred = gSavedSettings.getBOOL("RenderDeferred"); + RenderDeferredSunWash = gSavedSettings.getF32("RenderDeferredSunWash"); + RenderFSAASamples = gSavedSettings.getU32("RenderFSAASamples"); + RenderResolutionDivisor = gSavedSettings.getU32("RenderResolutionDivisor"); + RenderUIBuffer = gSavedSettings.getBOOL("RenderUIBuffer"); + RenderShadowDetail = gSavedSettings.getS32("RenderShadowDetail"); + RenderDeferredSSAO = gSavedSettings.getBOOL("RenderDeferredSSAO"); + RenderShadowResolutionScale = gSavedSettings.getF32("RenderShadowResolutionScale"); + RenderLocalLights = gSavedSettings.getBOOL("RenderLocalLights"); + RenderDelayCreation = gSavedSettings.getBOOL("RenderDelayCreation"); + RenderAnimateRes = gSavedSettings.getBOOL("RenderAnimateRes"); + FreezeTime = gSavedSettings.getBOOL("FreezeTime"); + DebugBeaconLineWidth = gSavedSettings.getS32("DebugBeaconLineWidth"); + RenderHighlightBrightness = gSavedSettings.getF32("RenderHighlightBrightness"); + RenderHighlightColor = gSavedSettings.getColor4("RenderHighlightColor"); + RenderHighlightThickness = gSavedSettings.getF32("RenderHighlightThickness"); + RenderSpotLightsInNondeferred = gSavedSettings.getBOOL("RenderSpotLightsInNondeferred"); + PreviewAmbientColor = gSavedSettings.getColor4("PreviewAmbientColor"); + PreviewDiffuse0 = gSavedSettings.getColor4("PreviewDiffuse0"); + PreviewSpecular0 = gSavedSettings.getColor4("PreviewSpecular0"); + PreviewDiffuse1 = gSavedSettings.getColor4("PreviewDiffuse1"); + PreviewSpecular1 = gSavedSettings.getColor4("PreviewSpecular1"); + PreviewDiffuse2 = gSavedSettings.getColor4("PreviewDiffuse2"); + PreviewSpecular2 = gSavedSettings.getColor4("PreviewSpecular2"); + PreviewDirection0 = gSavedSettings.getVector3("PreviewDirection0"); + PreviewDirection1 = gSavedSettings.getVector3("PreviewDirection1"); + PreviewDirection2 = gSavedSettings.getVector3("PreviewDirection2"); + RenderGlowMinLuminance = gSavedSettings.getF32("RenderGlowMinLuminance"); + RenderGlowMaxExtractAlpha = gSavedSettings.getF32("RenderGlowMaxExtractAlpha"); + RenderGlowWarmthAmount = gSavedSettings.getF32("RenderGlowWarmthAmount"); + RenderGlowLumWeights = gSavedSettings.getVector3("RenderGlowLumWeights"); + RenderGlowWarmthWeights = gSavedSettings.getVector3("RenderGlowWarmthWeights"); + RenderGlowResolutionPow = gSavedSettings.getS32("RenderGlowResolutionPow"); + RenderGlowIterations = gSavedSettings.getS32("RenderGlowIterations"); + RenderGlowWidth = gSavedSettings.getF32("RenderGlowWidth"); + RenderGlowStrength = gSavedSettings.getF32("RenderGlowStrength"); + RenderDepthOfField = gSavedSettings.getBOOL("RenderDepthOfField"); + CameraFocusTransitionTime = gSavedSettings.getF32("CameraFocusTransitionTime"); + CameraFNumber = gSavedSettings.getF32("CameraFNumber"); + CameraFocalLength = gSavedSettings.getF32("CameraFocalLength"); + CameraFieldOfView = gSavedSettings.getF32("CameraFieldOfView"); + RenderShadowNoise = gSavedSettings.getF32("RenderShadowNoise"); + RenderShadowBlurSize = gSavedSettings.getF32("RenderShadowBlurSize"); + RenderSSAOScale = gSavedSettings.getF32("RenderSSAOScale"); + RenderSSAOMaxScale = gSavedSettings.getU32("RenderSSAOMaxScale"); + RenderSSAOFactor = gSavedSettings.getF32("RenderSSAOFactor"); + RenderSSAOEffect = gSavedSettings.getVector3("RenderSSAOEffect"); + RenderShadowOffsetError = gSavedSettings.getF32("RenderShadowOffsetError"); + RenderShadowBiasError = gSavedSettings.getF32("RenderShadowBiasError"); + RenderShadowOffset = gSavedSettings.getF32("RenderShadowOffset"); + RenderShadowBias = gSavedSettings.getF32("RenderShadowBias"); + RenderSpotShadowOffset = gSavedSettings.getF32("RenderSpotShadowOffset"); + RenderSpotShadowBias = gSavedSettings.getF32("RenderSpotShadowBias"); + RenderEdgeDepthCutoff = gSavedSettings.getF32("RenderEdgeDepthCutoff"); + RenderEdgeNormCutoff = gSavedSettings.getF32("RenderEdgeNormCutoff"); + RenderShadowGaussian = gSavedSettings.getVector3("RenderShadowGaussian"); + RenderShadowBlurDistFactor = gSavedSettings.getF32("RenderShadowBlurDistFactor"); + RenderDeferredAtmospheric = gSavedSettings.getBOOL("RenderDeferredAtmospheric"); + RenderReflectionDetail = gSavedSettings.getS32("RenderReflectionDetail"); + RenderHighlightFadeTime = gSavedSettings.getF32("RenderHighlightFadeTime"); + RenderShadowClipPlanes = gSavedSettings.getVector3("RenderShadowClipPlanes"); + RenderShadowOrthoClipPlanes = gSavedSettings.getVector3("RenderShadowOrthoClipPlanes"); + RenderShadowNearDist = gSavedSettings.getVector3("RenderShadowNearDist"); + RenderFarClip = gSavedSettings.getF32("RenderFarClip"); + RenderShadowSplitExponent = gSavedSettings.getVector3("RenderShadowSplitExponent"); + RenderShadowErrorCutoff = gSavedSettings.getF32("RenderShadowErrorCutoff"); + RenderShadowFOVCutoff = gSavedSettings.getF32("RenderShadowFOVCutoff"); + CameraOffset = gSavedSettings.getBOOL("CameraOffset"); + CameraMaxCoF = gSavedSettings.getF32("CameraMaxCoF"); + CameraDoFResScale = gSavedSettings.getF32("CameraDoFResScale"); + + updateRenderDeferred(); +} + +void LLPipeline::releaseGLBuffers() +{ + assertInitialized(); + + if (mNoiseMap) + { + LLImageGL::deleteTextures(1, &mNoiseMap); + mNoiseMap = 0; + } + + if (mTrueNoiseMap) + { + LLImageGL::deleteTextures(1, &mTrueNoiseMap); + mTrueNoiseMap = 0; + } + + if (mLightFunc) + { + LLImageGL::deleteTextures(1, &mLightFunc); + mLightFunc = 0; + } + + mWaterRef.release(); + mWaterDis.release(); + + for (U32 i = 0; i < 3; i++) + { + mGlow[i].release(); + } + + releaseScreenBuffers(); + + gBumpImageList.destroyGL(); + LLVOAvatar::resetImpostors(); +} + +void LLPipeline::releaseScreenBuffers() +{ + mUIScreen.release(); + mScreen.release(); + mFXAABuffer.release(); + mPhysicsDisplay.release(); + mDeferredScreen.release(); + mDeferredDepth.release(); + mDeferredLight.release(); + + mHighlight.release(); + + for (U32 i = 0; i < 6; i++) + { + mShadow[i].release(); + } +} + + +void LLPipeline::createGLBuffers() +{ + stop_glerror(); + LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_CREATE_BUFFERS); + assertInitialized(); + + updateRenderDeferred(); + + if (LLPipeline::sWaterReflections) + { //water reflection texture + U32 res = (U32) gSavedSettings.getS32("RenderWaterRefResolution"); + + mWaterRef.allocate(res,res,GL_RGBA,TRUE,FALSE); + mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE); + } + + mHighlight.allocate(256,256,GL_RGBA, FALSE, FALSE); + + stop_glerror(); + + GLuint resX = gViewerWindow->getWorldViewWidthRaw(); + GLuint resY = gViewerWindow->getWorldViewHeightRaw(); + + if (LLPipeline::sRenderGlow) + { //screen space glow buffers + const U32 glow_res = llmax(1, + llmin(512, 1 << gSavedSettings.getS32("RenderGlowResolutionPow"))); + + for (U32 i = 0; i < 3; i++) + { + mGlow[i].allocate(512,glow_res,GL_RGBA,FALSE,FALSE); + } + + allocateScreenBuffer(resX,resY); + mScreenWidth = 0; + mScreenHeight = 0; + } + + if (sRenderDeferred) + { + if (!mNoiseMap) + { + const U32 noiseRes = 128; + LLVector3 noise[noiseRes*noiseRes]; + + F32 scaler = gSavedSettings.getF32("RenderDeferredNoise")/100.f; + for (U32 i = 0; i < noiseRes*noiseRes; ++i) + { + noise[i] = LLVector3(ll_frand()-0.5f, ll_frand()-0.5f, 0.f); + noise[i].normVec(); + noise[i].mV[2] = ll_frand()*scaler+1.f-scaler/2.f; + } + + LLImageGL::generateTextures(1, &mNoiseMap); + + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap); + LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + if (!mTrueNoiseMap) + { + const U32 noiseRes = 128; + F32 noise[noiseRes*noiseRes*3]; + for (U32 i = 0; i < noiseRes*noiseRes*3; i++) + { + noise[i] = ll_frand()*2.0-1.0; + } + + LLImageGL::generateTextures(1, &mTrueNoiseMap); + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap); + LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + if (!mLightFunc) + { + U32 lightResX = gSavedSettings.getU32("RenderSpecularResX"); + U32 lightResY = gSavedSettings.getU32("RenderSpecularResY"); + U8* lg = new U8[lightResX*lightResY]; + + for (U32 y = 0; y < lightResY; ++y) + { + for (U32 x = 0; x < lightResX; ++x) + { + //spec func + F32 sa = (F32) x/(lightResX-1); + F32 spec = (F32) y/(lightResY-1); + //lg[y*lightResX+x] = (U8) (powf(sa, 128.f*spec*spec)*255); + + //F32 sp = acosf(sa)/(1.f-spec); + + sa = powf(sa, gSavedSettings.getF32("RenderSpecularExponent")); + F32 a = acosf(sa*0.25f+0.75f); + F32 m = llmax(0.5f-spec*0.5f, 0.001f); + F32 t2 = tanf(a)/m; + t2 *= t2; + + F32 c4a = (3.f+4.f*cosf(2.f*a)+cosf(4.f*a))/8.f; + F32 bd = 1.f/(4.f*m*m*c4a)*powf(F_E, -t2); + + lg[y*lightResX+x] = (U8) (llclamp(bd, 0.f, 1.f)*255); + } + } + + LLImageGL::generateTextures(1, &mLightFunc); + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc); + LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_R8, lightResX, lightResY, GL_RED, GL_UNSIGNED_BYTE, lg); + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR); + + delete [] lg; + } + } + + gBumpImageList.restoreGL(); +} + +void LLPipeline::restoreGL() +{ + LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_RESTORE_GL); + assertInitialized(); + + if (mVertexShadersEnabled) + { + LLViewerShaderMgr::instance()->setShaders(); + } + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + part->restoreGL(); + } + } + } +} + + +BOOL LLPipeline::canUseVertexShaders() +{ + if (sDisableShaders || + !gGLManager.mHasVertexShader || + !gGLManager.mHasFragmentShader || + !LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable") || + (assertInitialized() && mVertexShadersLoaded != 1) ) + { + return FALSE; + } + else + { + return TRUE; + } +} + +BOOL LLPipeline::canUseWindLightShaders() const +{ + return (!LLPipeline::sDisableShaders && + gWLSkyProgram.mProgramObject != 0 && + LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1); +} + +BOOL LLPipeline::canUseWindLightShadersOnObjects() const +{ + return (canUseWindLightShaders() + && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0); +} + +BOOL LLPipeline::canUseAntiAliasing() const +{ + return TRUE; +} + +void LLPipeline::unloadShaders() +{ + LLMemType mt_us(LLMemType::MTYPE_PIPELINE_UNLOAD_SHADERS); + LLViewerShaderMgr::instance()->unloadShaders(); + + mVertexShadersLoaded = 0; +} + +void LLPipeline::assertInitializedDoError() +{ + llerrs << "LLPipeline used when uninitialized." << llendl; +} + +//============================================================================ + +void LLPipeline::enableShadows(const BOOL enable_shadows) +{ + //should probably do something here to wrangle shadows.... +} + +S32 LLPipeline::getMaxLightingDetail() const +{ + /*if (mVertexShaderLevel[SHADER_OBJECT] >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS) + { + return 3; + } + else*/ + { + return 1; + } +} + +S32 LLPipeline::setLightingDetail(S32 level) +{ + LLMemType mt_ld(LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL); + refreshCachedSettings(); + + if (level < 0) + { + if (RenderLocalLights) + { + level = 1; + } + else + { + level = 0; + } + } + level = llclamp(level, 0, getMaxLightingDetail()); + mLightingDetail = level; + + return mLightingDetail; +} + +class LLOctreeDirtyTexture : public LLOctreeTraveler<LLDrawable> +{ +public: + const std::set<LLViewerFetchedTexture*>& mTextures; + + LLOctreeDirtyTexture(const std::set<LLViewerFetchedTexture*>& textures) : mTextures(textures) { } + + virtual void visit(const LLOctreeNode<LLDrawable>* node) + { + LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); + + if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->getData().empty()) + { + for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) + { + for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) + { + LLDrawInfo* params = *j; + LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(params->mTexture); + if (tex && mTextures.find(tex) != mTextures.end()) + { + group->setState(LLSpatialGroup::GEOM_DIRTY); + } + } + } + } + + for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i) + { + LLSpatialBridge* bridge = *i; + traverse(bridge->mOctree); + } + } +}; + +// Called when a texture changes # of channels (causes faces to move to alpha pool) +void LLPipeline::dirtyPoolObjectTextures(const std::set<LLViewerFetchedTexture*>& textures) +{ + assertInitialized(); + + // *TODO: This is inefficient and causes frame spikes; need a better way to do this + // Most of the time is spent in dirty.traverse. + + for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) + { + LLDrawPool *poolp = *iter; + if (poolp->isFacePool()) + { + ((LLFacePool*) poolp)->dirtyTextures(textures); + } + } + + LLOctreeDirtyTexture dirty(textures); + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + dirty.traverse(part->mOctree); + } + } + } +} + +LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0) +{ + assertInitialized(); + + LLDrawPool *poolp = NULL; + switch( type ) + { + case LLDrawPool::POOL_SIMPLE: + poolp = mSimplePool; + break; + + case LLDrawPool::POOL_GRASS: + poolp = mGrassPool; + break; + + case LLDrawPool::POOL_FULLBRIGHT: + poolp = mFullbrightPool; + break; + + case LLDrawPool::POOL_INVISIBLE: + poolp = mInvisiblePool; + break; + + case LLDrawPool::POOL_GLOW: + poolp = mGlowPool; + break; + + case LLDrawPool::POOL_TREE: + poolp = get_if_there(mTreePools, (uintptr_t)tex0, (LLDrawPool*)0 ); + break; + + case LLDrawPool::POOL_TERRAIN: + poolp = get_if_there(mTerrainPools, (uintptr_t)tex0, (LLDrawPool*)0 ); + break; + + case LLDrawPool::POOL_BUMP: + poolp = mBumpPool; + break; + + case LLDrawPool::POOL_ALPHA: + poolp = mAlphaPool; + break; + + case LLDrawPool::POOL_AVATAR: + break; // Do nothing + + case LLDrawPool::POOL_SKY: + poolp = mSkyPool; + break; + + case LLDrawPool::POOL_WATER: + poolp = mWaterPool; + break; + + case LLDrawPool::POOL_GROUND: + poolp = mGroundPool; + break; + + case LLDrawPool::POOL_WL_SKY: + poolp = mWLSkyPool; + break; + + default: + llassert(0); + llerrs << "Invalid Pool Type in LLPipeline::findPool() type=" << type << llendl; + break; + } + + return poolp; +} + + +LLDrawPool *LLPipeline::getPool(const U32 type, LLViewerTexture *tex0) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLDrawPool *poolp = findPool(type, tex0); + if (poolp) + { + return poolp; + } + + LLDrawPool *new_poolp = LLDrawPool::createPool(type, tex0); + addPool( new_poolp ); + + return new_poolp; +} + + +// static +LLDrawPool* LLPipeline::getPoolFromTE(const LLTextureEntry* te, LLViewerTexture* imagep) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE); + U32 type = getPoolTypeFromTE(te, imagep); + return gPipeline.getPool(type, imagep); +} + +//static +U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* imagep) +{ + LLMemType mt_gpt(LLMemType::MTYPE_PIPELINE_GET_POOL_TYPE); + + if (!te || !imagep) + { + return 0; + } + + bool alpha = te->getColor().mV[3] < 0.999f; + if (imagep) + { + alpha = alpha || (imagep->getComponents() == 4 && imagep->getType() != LLViewerTexture::MEDIA_TEXTURE) || (imagep->getComponents() == 2); + } + + if (alpha) + { + return LLDrawPool::POOL_ALPHA; + } + else if ((te->getBumpmap() || te->getShiny())) + { + return LLDrawPool::POOL_BUMP; + } + else + { + return LLDrawPool::POOL_SIMPLE; + } +} + + +void LLPipeline::addPool(LLDrawPool *new_poolp) +{ + LLMemType mt_a(LLMemType::MTYPE_PIPELINE_ADD_POOL); + assertInitialized(); + mPools.insert(new_poolp); + addToQuickLookup( new_poolp ); +} + +void LLPipeline::allocDrawable(LLViewerObject *vobj) +{ + LLMemType mt_ad(LLMemType::MTYPE_PIPELINE_ALLOCATE_DRAWABLE); + LLDrawable *drawable = new LLDrawable(); + vobj->mDrawable = drawable; + + drawable->mVObjp = vobj; + + //encompass completely sheared objects by taking + //the most extreme point possible (<1,1,0.5>) + drawable->setRadius(LLVector3(1,1,0.5f).scaleVec(vobj->getScale()).length()); + if (vobj->isOrphaned()) + { + drawable->setState(LLDrawable::FORCE_INVISIBLE); + } + drawable->updateXform(TRUE); +} + + +static LLFastTimer::DeclareTimer FTM_UNLINK("Unlink"); +static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_MOVE_LIST("Movelist"); +static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_SPATIAL_PARTITION("Spatial Partition"); +static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_LIGHT_SET("Light Set"); +static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_HIGHLIGHT_SET("Highlight Set"); + +void LLPipeline::unlinkDrawable(LLDrawable *drawable) +{ + LLFastTimer t(FTM_UNLINK); + + assertInitialized(); + + LLPointer<LLDrawable> drawablep = drawable; // make sure this doesn't get deleted before we are done + + // Based on flags, remove the drawable from the queues that it's on. + if (drawablep->isState(LLDrawable::ON_MOVE_LIST)) + { + LLFastTimer t(FTM_REMOVE_FROM_MOVE_LIST); + LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep); + if (iter != mMovedList.end()) + { + mMovedList.erase(iter); + } + } + + if (drawablep->getSpatialGroup()) + { + LLFastTimer t(FTM_REMOVE_FROM_SPATIAL_PARTITION); + if (!drawablep->getSpatialGroup()->mSpatialPartition->remove(drawablep, drawablep->getSpatialGroup())) + { +#ifdef LL_RELEASE_FOR_DOWNLOAD + llwarns << "Couldn't remove object from spatial group!" << llendl; +#else + llerrs << "Couldn't remove object from spatial group!" << llendl; +#endif + } + } + + { + LLFastTimer t(FTM_REMOVE_FROM_LIGHT_SET); + mLights.erase(drawablep); + + for (light_set_t::iterator iter = mNearbyLights.begin(); + iter != mNearbyLights.end(); iter++) + { + if (iter->drawable == drawablep) + { + mNearbyLights.erase(iter); + break; + } + } + } + + { + LLFastTimer t(FTM_REMOVE_FROM_HIGHLIGHT_SET); + HighlightItem item(drawablep); + mHighlightSet.erase(item); + + if (mHighlightObject == drawablep) + { + mHighlightObject = NULL; + } + } + + for (U32 i = 0; i < 2; ++i) + { + if (mShadowSpotLight[i] == drawablep) + { + mShadowSpotLight[i] = NULL; + } + + if (mTargetShadowSpotLight[i] == drawablep) + { + mTargetShadowSpotLight[i] = NULL; + } + } + + +} + +U32 LLPipeline::addObject(LLViewerObject *vobj) +{ + LLMemType mt_ao(LLMemType::MTYPE_PIPELINE_ADD_OBJECT); + + if (RenderDelayCreation) + { + mCreateQ.push_back(vobj); + } + else + { + createObject(vobj); + } + + return 1; +} + +void LLPipeline::createObjects(F32 max_dtime) +{ + LLFastTimer ftm(FTM_GEO_UPDATE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS); + + LLTimer update_timer; + + while (!mCreateQ.empty() && update_timer.getElapsedTimeF32() < max_dtime) + { + LLViewerObject* vobj = mCreateQ.front(); + if (!vobj->isDead()) + { + createObject(vobj); + } + mCreateQ.pop_front(); + } + + //for (LLViewerObject::vobj_list_t::iterator iter = mCreateQ.begin(); iter != mCreateQ.end(); ++iter) + //{ + // createObject(*iter); + //} + + //mCreateQ.clear(); +} + +void LLPipeline::createObject(LLViewerObject* vobj) +{ + LLDrawable* drawablep = vobj->mDrawable; + + if (!drawablep) + { + drawablep = vobj->createDrawable(this); + } + else + { + llerrs << "Redundant drawable creation!" << llendl; + } + + llassert(drawablep); + + if (vobj->getParent()) + { + vobj->setDrawableParent(((LLViewerObject*)vobj->getParent())->mDrawable); // LLPipeline::addObject 1 + } + else + { + vobj->setDrawableParent(NULL); // LLPipeline::addObject 2 + } + + markRebuild(drawablep, LLDrawable::REBUILD_ALL, TRUE); + + if (drawablep->getVOVolume() && RenderAnimateRes) + { + // fun animated res + drawablep->updateXform(TRUE); + drawablep->clearState(LLDrawable::MOVE_UNDAMPED); + drawablep->setScale(LLVector3(0,0,0)); + drawablep->makeActive(); + } +} + + +void LLPipeline::resetFrameStats() +{ + assertInitialized(); + + LLViewerStats::getInstance()->mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f); + + if (mBatchCount > 0) + { + mMeanBatchSize = gPipeline.mTrianglesDrawn/gPipeline.mBatchCount; + } + mTrianglesDrawn = 0; + sCompiles = 0; + mVerticesRelit = 0; + mLightingChanges = 0; + mGeometryChanges = 0; + mNumVisibleFaces = 0; + + if (mOldRenderDebugMask != mRenderDebugMask) + { + gObjectList.clearDebugText(); + mOldRenderDebugMask = mRenderDebugMask; + } + +} + +//external functions for asynchronous updating +void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep) +{ + if (FreezeTime) + { + return; + } + if (!drawablep) + { + llerrs << "updateMove called with NULL drawablep" << llendl; + return; + } + if (drawablep->isState(LLDrawable::EARLY_MOVE)) + { + return; + } + + assertInitialized(); + + // update drawable now + drawablep->clearState(LLDrawable::MOVE_UNDAMPED); // force to DAMPED + drawablep->updateMove(); // returns done + drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame + // Put on move list so that EARLY_MOVE gets cleared + if (!drawablep->isState(LLDrawable::ON_MOVE_LIST)) + { + mMovedList.push_back(drawablep); + drawablep->setState(LLDrawable::ON_MOVE_LIST); + } +} + +void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep) +{ + if (FreezeTime) + { + return; + } + if (!drawablep) + { + llerrs << "updateMove called with NULL drawablep" << llendl; + return; + } + if (drawablep->isState(LLDrawable::EARLY_MOVE)) + { + return; + } + + assertInitialized(); + + // update drawable now + drawablep->setState(LLDrawable::MOVE_UNDAMPED); // force to UNDAMPED + drawablep->updateMove(); + drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame + // Put on move list so that EARLY_MOVE gets cleared + if (!drawablep->isState(LLDrawable::ON_MOVE_LIST)) + { + mMovedList.push_back(drawablep); + drawablep->setState(LLDrawable::ON_MOVE_LIST); + } +} + +void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list) +{ + for (LLDrawable::drawable_vector_t::iterator iter = moved_list.begin(); + iter != moved_list.end(); ) + { + LLDrawable::drawable_vector_t::iterator curiter = iter++; + LLDrawable *drawablep = *curiter; + BOOL done = TRUE; + if (!drawablep->isDead() && (!drawablep->isState(LLDrawable::EARLY_MOVE))) + { + done = drawablep->updateMove(); + } + drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED); + if (done) + { + drawablep->clearState(LLDrawable::ON_MOVE_LIST); + iter = moved_list.erase(curiter); + } + } +} + +static LLFastTimer::DeclareTimer FTM_OCTREE_BALANCE("Balance Octree"); +static LLFastTimer::DeclareTimer FTM_UPDATE_MOVE("Update Move"); + +void LLPipeline::updateMove() +{ + LLFastTimer t(FTM_UPDATE_MOVE); + LLMemType mt_um(LLMemType::MTYPE_PIPELINE_UPDATE_MOVE); + + if (FreezeTime) + { + return; + } + + assertInitialized(); + + { + static LLFastTimer::DeclareTimer ftm("Retexture"); + LLFastTimer t(ftm); + + for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin(); + iter != mRetexturedList.end(); ++iter) + { + LLDrawable* drawablep = *iter; + if (drawablep && !drawablep->isDead()) + { + drawablep->updateTexture(); + } + } + mRetexturedList.clear(); + } + + { + static LLFastTimer::DeclareTimer ftm("Moved List"); + LLFastTimer t(ftm); + updateMovedList(mMovedList); + } + + //balance octrees + { + LLFastTimer ot(FTM_OCTREE_BALANCE); + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + part->mOctree->balance(); + } + } + } + } +} + +///////////////////////////////////////////////////////////////////////////// +// Culling and occlusion testing +///////////////////////////////////////////////////////////////////////////// + +//static +F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera) +{ + LLVector3 lookAt = center - camera.getOrigin(); + F32 dist = lookAt.length(); + + //ramp down distance for nearby objects + //shrink dist by dist/16. + if (dist < 16.f) + { + dist /= 16.f; + dist *= dist; + dist *= 16.f; + } + + //get area of circle around node + F32 app_angle = atanf(size.length()/dist); + F32 radius = app_angle*LLDrawable::sCurPixelAngle; + return radius*radius * F_PI; +} + +//static +F32 LLPipeline::calcPixelArea(const LLVector4a& center, const LLVector4a& size, LLCamera &camera) +{ + LLVector4a origin; + origin.load3(camera.getOrigin().mV); + + LLVector4a lookAt; + lookAt.setSub(center, origin); + F32 dist = lookAt.getLength3().getF32(); + + //ramp down distance for nearby objects + //shrink dist by dist/16. + if (dist < 16.f) + { + dist /= 16.f; + dist *= dist; + dist *= 16.f; + } + + //get area of circle around node + F32 app_angle = atanf(size.getLength3().getF32()/dist); + F32 radius = app_angle*LLDrawable::sCurPixelAngle; + return radius*radius * F_PI; +} + +void LLPipeline::grabReferences(LLCullResult& result) +{ + sCull = &result; +} + +void LLPipeline::clearReferences() +{ + sCull = NULL; +} + +void check_references(LLSpatialGroup* group, LLDrawable* drawable) +{ + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + { + if (drawable == *i) + { + llerrs << "LLDrawable deleted while actively reference by LLPipeline." << llendl; + } + } +} + +void check_references(LLDrawable* drawable, LLFace* face) +{ + for (S32 i = 0; i < drawable->getNumFaces(); ++i) + { + if (drawable->getFace(i) == face) + { + llerrs << "LLFace deleted while actively referenced by LLPipeline." << llendl; + } + } +} + +void check_references(LLSpatialGroup* group, LLFace* face) +{ + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + { + LLDrawable* drawable = *i; + check_references(drawable, face); + } +} + +void LLPipeline::checkReferences(LLFace* face) +{ +#if 0 + if (sCull) + { + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, face); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, face); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, face); + } + + for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) + { + LLDrawable* drawable = *iter; + check_references(drawable, face); + } + } +#endif +} + +void LLPipeline::checkReferences(LLDrawable* drawable) +{ +#if 0 + if (sCull) + { + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, drawable); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, drawable); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, drawable); + } + + for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) + { + if (drawable == *iter) + { + llerrs << "LLDrawable deleted while actively referenced by LLPipeline." << llendl; + } + } + } +#endif +} + +void check_references(LLSpatialGroup* group, LLDrawInfo* draw_info) +{ + for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) + { + LLSpatialGroup::drawmap_elem_t& draw_vec = i->second; + for (LLSpatialGroup::drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j) + { + LLDrawInfo* params = *j; + if (params == draw_info) + { + llerrs << "LLDrawInfo deleted while actively referenced by LLPipeline." << llendl; + } + } + } +} + + +void LLPipeline::checkReferences(LLDrawInfo* draw_info) +{ +#if 0 + if (sCull) + { + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, draw_info); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, draw_info); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, draw_info); + } + } +#endif +} + +void LLPipeline::checkReferences(LLSpatialGroup* group) +{ +#if 0 + if (sCull) + { + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + { + if (group == *iter) + { + llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; + } + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) + { + if (group == *iter) + { + llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; + } + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + { + if (group == *iter) + { + llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; + } + } + } +#endif +} + + +BOOL LLPipeline::visibleObjectsInFrustum(LLCamera& camera) +{ + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + if (hasRenderType(part->mDrawableType)) + { + if (part->visibleObjectsInFrustum(camera)) + { + return TRUE; + } + } + } + } + } + + return FALSE; +} + +BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& max) +{ + const F32 X = 65536.f; + + min = LLVector3(X,X,X); + max = LLVector3(-X,-X,-X); + + U32 saved_camera_id = LLViewerCamera::sCurCameraID; + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + + BOOL res = TRUE; + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + if (hasRenderType(part->mDrawableType)) + { + if (!part->getVisibleExtents(camera, min, max)) + { + res = FALSE; + } + } + } + } + } + + LLViewerCamera::sCurCameraID = saved_camera_id; + + return res; +} + +static LLFastTimer::DeclareTimer FTM_CULL("Object Culling"); + +void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip, LLPlane* planep) +{ + LLFastTimer t(FTM_CULL); + LLMemType mt_uc(LLMemType::MTYPE_PIPELINE_UPDATE_CULL); + + grabReferences(result); + + sCull->clear(); + + BOOL to_texture = LLPipeline::sUseOcclusion > 1 && + !hasRenderType(LLPipeline::RENDER_TYPE_HUD) && + LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && + gPipeline.canUseVertexShaders() && + sRenderGlow; + + if (to_texture) + { + mScreen.bindTarget(); + } + + if (sUseOcclusion > 1) + { + gGL.setColorMask(false, false); + } + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadMatrix(gGLLastProjection); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLLastModelView); + + + LLVertexBuffer::unbind(); + LLGLDisable blend(GL_BLEND); + LLGLDisable test(GL_ALPHA_TEST); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + + //setup a clip plane in projection matrix for reflection renders (prevents flickering from occlusion culling) + LLViewerRegion* region = gAgent.getRegion(); + LLPlane plane; + + if (planep) + { + plane = *planep; + } + else + { + if (region) + { + LLVector3 pnorm; + F32 height = region->getWaterHeight(); + if (water_clip < 0) + { //camera is above water, clip plane points up + pnorm.setVec(0,0,1); + plane.setVec(pnorm, -height); + } + else if (water_clip > 0) + { //camera is below water, clip plane points down + pnorm = LLVector3(0,0,-1); + plane.setVec(pnorm, height); + } + } + } + + glh::matrix4f modelview = glh_get_last_modelview(); + glh::matrix4f proj = glh_get_last_projection(); + LLGLUserClipPlane clip(plane, modelview, proj, water_clip != 0 && LLPipeline::sReflectionRender); + + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + + bool bound_shader = false; + if (gPipeline.canUseVertexShaders() && LLGLSLShader::sCurBoundShader == 0) + { //if no shader is currently bound, use the occlusion shader instead of fixed function if we can + // (shadow render uses a special shader that clamps to clip planes) + bound_shader = true; + gOcclusionProgram.bind(); + } + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + if (water_clip != 0) + { + LLPlane plane(LLVector3(0,0, (F32) -water_clip), (F32) water_clip*region->getWaterHeight()); + camera.setUserClipPlane(plane); + } + else + { + camera.disableUserClipPlane(); + } + + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + if (hasRenderType(part->mDrawableType)) + { + part->cull(camera); + } + } + } + } + + if (bound_shader) + { + gOcclusionProgram.unbind(); + } + + camera.disableUserClipPlane(); + + if (hasRenderType(LLPipeline::RENDER_TYPE_SKY) && + gSky.mVOSkyp.notNull() && + gSky.mVOSkyp->mDrawable.notNull()) + { + gSky.mVOSkyp->mDrawable->setVisible(camera); + sCull->pushDrawable(gSky.mVOSkyp->mDrawable); + gSky.updateCull(); + stop_glerror(); + } + + if (hasRenderType(LLPipeline::RENDER_TYPE_GROUND) && + !gPipeline.canUseWindLightShaders() && + gSky.mVOGroundp.notNull() && + gSky.mVOGroundp->mDrawable.notNull() && + !LLPipeline::sWaterReflections) + { + gSky.mVOGroundp->mDrawable->setVisible(camera); + sCull->pushDrawable(gSky.mVOGroundp->mDrawable); + } + + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + + if (sUseOcclusion > 1) + { + gGL.setColorMask(true, false); + } + + if (to_texture) + { + mScreen.flush(); + } +} + +void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera) +{ + if (group->getData().empty()) + { + return; + } + + group->setVisible(); + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + { + group->updateDistance(camera); + } + + const F32 MINIMUM_PIXEL_AREA = 16.f; + + if (group->mPixelArea < MINIMUM_PIXEL_AREA) + { + return; + } + + if (sMinRenderSize > 0.f && + llmax(llmax(group->mBounds[1][0], group->mBounds[1][1]), group->mBounds[1][2]) < sMinRenderSize) + { + return; + } + + assertInitialized(); + + if (!group->mSpatialPartition->mRenderByGroup) + { //render by drawable + sCull->pushDrawableGroup(group); + } + else + { //render by group + sCull->pushVisibleGroup(group); + } + + mNumVisibleNodes++; +} + +void LLPipeline::markOccluder(LLSpatialGroup* group) +{ + if (sUseOcclusion > 1 && group && !group->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION)) + { + LLSpatialGroup* parent = group->getParent(); + + if (!parent || !parent->isOcclusionState(LLSpatialGroup::OCCLUDED)) + { //only mark top most occluders as active occlusion + sCull->pushOcclusionGroup(group); + group->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION); + + if (parent && + !parent->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION) && + parent->getElementCount() == 0 && + parent->needsUpdate()) + { + sCull->pushOcclusionGroup(group); + parent->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION); + } + } + } +} + +void LLPipeline::doOcclusion(LLCamera& camera) +{ + if (LLPipeline::sUseOcclusion > 1 && sCull->hasOcclusionGroups()) + { + LLVertexBuffer::unbind(); + + if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION)) + { + gGL.setColorMask(true, false, false, false); + } + else + { + gGL.setColorMask(false, false); + } + LLGLDisable blend(GL_BLEND); + LLGLDisable test(GL_ALPHA_TEST); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + + LLGLDisable cull(GL_CULL_FACE); + + + bool bind_shader = LLGLSLShader::sNoFixedFunction && LLGLSLShader::sCurBoundShader == 0; + if (bind_shader) + { + if (LLPipeline::sShadowRender) + { + gDeferredShadowProgram.bind(); + } + else + { + gOcclusionProgram.bind(); + } + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + group->doOcclusion(&camera); + group->clearOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION); + } + + if (bind_shader) + { + if (LLPipeline::sShadowRender) + { + gDeferredShadowProgram.unbind(); + } + else + { + gOcclusionProgram.unbind(); + } + } + + gGL.setColorMask(true, false); + } +} + +BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority) +{ + BOOL update_complete = drawablep->updateGeometry(priority); + if (update_complete && assertInitialized()) + { + drawablep->setState(LLDrawable::BUILT); + mGeometryChanges++; + } + return update_complete; +} + +void LLPipeline::updateGL() +{ + while (!LLGLUpdate::sGLQ.empty()) + { + LLGLUpdate* glu = LLGLUpdate::sGLQ.front(); + glu->updateGL(); + glu->mInQ = FALSE; + LLGLUpdate::sGLQ.pop_front(); + } +} + +void LLPipeline::rebuildPriorityGroups() +{ + LLTimer update_timer; + LLMemType mt(LLMemType::MTYPE_PIPELINE); + + assertInitialized(); + + gMeshRepo.notifyLoadedMeshes(); + + mGroupQ1Locked = true; + // Iterate through all drawables on the priority build queue, + for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ1.begin(); + iter != mGroupQ1.end(); ++iter) + { + LLSpatialGroup* group = *iter; + group->rebuildGeom(); + group->clearState(LLSpatialGroup::IN_BUILD_Q1); + } + + mGroupQ1.clear(); + mGroupQ1Locked = false; + +} + +void LLPipeline::rebuildGroups() +{ + if (mGroupQ2.empty()) + { + return; + } + + mGroupQ2Locked = true; + // Iterate through some drawables on the non-priority build queue + S32 size = (S32) mGroupQ2.size(); + S32 min_count = llclamp((S32) ((F32) (size * size)/4096*0.25f), 1, size); + + S32 count = 0; + + std::sort(mGroupQ2.begin(), mGroupQ2.end(), LLSpatialGroup::CompareUpdateUrgency()); + + LLSpatialGroup::sg_vector_t::iterator iter; + LLSpatialGroup::sg_vector_t::iterator last_iter = mGroupQ2.begin(); + + for (iter = mGroupQ2.begin(); + iter != mGroupQ2.end() && count <= min_count; ++iter) + { + LLSpatialGroup* group = *iter; + last_iter = iter; + + if (!group->isDead()) + { + group->rebuildGeom(); + + if (group->mSpatialPartition->mRenderByGroup) + { + count++; + } + } + + group->clearState(LLSpatialGroup::IN_BUILD_Q2); + } + + mGroupQ2.erase(mGroupQ2.begin(), ++last_iter); + + mGroupQ2Locked = false; + + updateMovedList(mMovedBridge); +} + +void LLPipeline::updateGeom(F32 max_dtime) +{ + LLTimer update_timer; + LLMemType mt(LLMemType::MTYPE_PIPELINE_UPDATE_GEOM); + LLPointer<LLDrawable> drawablep; + + LLFastTimer t(FTM_GEO_UPDATE); + + assertInitialized(); + + if (sDelayedVBOEnable > 0) + { + if (--sDelayedVBOEnable <= 0) + { + resetVertexBuffers(); + LLVertexBuffer::sEnableVBOs = TRUE; + } + } + + // notify various object types to reset internal cost metrics, etc. + // for now, only LLVOVolume does this to throttle LOD changes + LLVOVolume::preUpdateGeom(); + + // Iterate through all drawables on the priority build queue, + for (LLDrawable::drawable_list_t::iterator iter = mBuildQ1.begin(); + iter != mBuildQ1.end();) + { + LLDrawable::drawable_list_t::iterator curiter = iter++; + LLDrawable* drawablep = *curiter; + if (drawablep && !drawablep->isDead()) + { + if (drawablep->isState(LLDrawable::IN_REBUILD_Q2)) + { + drawablep->clearState(LLDrawable::IN_REBUILD_Q2); + LLDrawable::drawable_list_t::iterator find = std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep); + if (find != mBuildQ2.end()) + { + mBuildQ2.erase(find); + } + } + + if (updateDrawableGeom(drawablep, TRUE)) + { + drawablep->clearState(LLDrawable::IN_REBUILD_Q1); + mBuildQ1.erase(curiter); + } + } + else + { + mBuildQ1.erase(curiter); + } + } + + // Iterate through some drawables on the non-priority build queue + S32 min_count = 16; + S32 size = (S32) mBuildQ2.size(); + if (size > 1024) + { + min_count = llclamp((S32) (size * (F32) size/4096), 16, size); + } + + S32 count = 0; + + max_dtime = llmax(update_timer.getElapsedTimeF32()+0.001f, max_dtime); + LLSpatialGroup* last_group = NULL; + LLSpatialBridge* last_bridge = NULL; + + for (LLDrawable::drawable_list_t::iterator iter = mBuildQ2.begin(); + iter != mBuildQ2.end(); ) + { + LLDrawable::drawable_list_t::iterator curiter = iter++; + LLDrawable* drawablep = *curiter; + + LLSpatialBridge* bridge = drawablep->isRoot() ? drawablep->getSpatialBridge() : + drawablep->getParent()->getSpatialBridge(); + + if (drawablep->getSpatialGroup() != last_group && + (!last_bridge || bridge != last_bridge) && + (update_timer.getElapsedTimeF32() >= max_dtime) && count > min_count) + { + break; + } + + //make sure updates don't stop in the middle of a spatial group + //to avoid thrashing (objects are enqueued by group) + last_group = drawablep->getSpatialGroup(); + last_bridge = bridge; + + BOOL update_complete = TRUE; + if (!drawablep->isDead()) + { + update_complete = updateDrawableGeom(drawablep, FALSE); + count++; + } + if (update_complete) + { + drawablep->clearState(LLDrawable::IN_REBUILD_Q2); + mBuildQ2.erase(curiter); + } + } + + updateMovedList(mMovedBridge); +} + +void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_VISIBLE); + + if(drawablep && !drawablep->isDead()) + { + if (drawablep->isSpatialBridge()) + { + const LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable; + llassert(root); // trying to catch a bad assumption + if (root && // // this test may not be needed, see above + root->getVObj()->isAttachment()) + { + LLDrawable* rootparent = root->getParent(); + if (rootparent) // this IS sometimes NULL + { + LLViewerObject *vobj = rootparent->getVObj(); + llassert(vobj); // trying to catch a bad assumption + if (vobj) // this test may not be needed, see above + { + const LLVOAvatar* av = vobj->asAvatar(); + if (av && av->isImpostor()) + { + return; + } + } + } + } + sCull->pushBridge((LLSpatialBridge*) drawablep); + } + else + { + sCull->pushDrawable(drawablep); + } + + drawablep->setVisible(camera); + } +} + +void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion) +{ + LLMemType mt_mm(LLMemType::MTYPE_PIPELINE_MARK_MOVED); + + if (!drawablep) + { + //llerrs << "Sending null drawable to moved list!" << llendl; + return; + } + + if (drawablep->isDead()) + { + llwarns << "Marking NULL or dead drawable moved!" << llendl; + return; + } + + if (drawablep->getParent()) + { + //ensure that parent drawables are moved first + markMoved(drawablep->getParent(), damped_motion); + } + + assertInitialized(); + + if (!drawablep->isState(LLDrawable::ON_MOVE_LIST)) + { + if (drawablep->isSpatialBridge()) + { + mMovedBridge.push_back(drawablep); + } + else + { + mMovedList.push_back(drawablep); + } + drawablep->setState(LLDrawable::ON_MOVE_LIST); + } + if (damped_motion == FALSE) + { + drawablep->setState(LLDrawable::MOVE_UNDAMPED); // UNDAMPED trumps DAMPED + } + else if (drawablep->isState(LLDrawable::MOVE_UNDAMPED)) + { + drawablep->clearState(LLDrawable::MOVE_UNDAMPED); + } +} + +void LLPipeline::markShift(LLDrawable *drawablep) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_SHIFT); + + if (!drawablep || drawablep->isDead()) + { + return; + } + + assertInitialized(); + + if (!drawablep->isState(LLDrawable::ON_SHIFT_LIST)) + { + drawablep->getVObj()->setChanged(LLXform::SHIFTED | LLXform::SILHOUETTE); + if (drawablep->getParent()) + { + markShift(drawablep->getParent()); + } + mShiftList.push_back(drawablep); + drawablep->setState(LLDrawable::ON_SHIFT_LIST); + } +} + +void LLPipeline::shiftObjects(const LLVector3 &offset) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS); + + assertInitialized(); + + glClear(GL_DEPTH_BUFFER_BIT); + gDepthDirty = TRUE; + + LLVector4a offseta; + offseta.load3(offset.mV); + + for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin(); + iter != mShiftList.end(); iter++) + { + LLDrawable *drawablep = *iter; + if (drawablep->isDead()) + { + continue; + } + drawablep->shiftPos(offseta); + drawablep->clearState(LLDrawable::ON_SHIFT_LIST); + } + mShiftList.resize(0); + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + part->shift(offseta); + } + } + } + + LLHUDText::shiftAll(offset); + LLHUDNameTag::shiftAll(offset); + display_update_camera(); +} + +void LLPipeline::markTextured(LLDrawable *drawablep) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_TEXTURED); + + if (drawablep && !drawablep->isDead() && assertInitialized()) + { + mRetexturedList.insert(drawablep); + } +} + +void LLPipeline::markGLRebuild(LLGLUpdate* glu) +{ + if (glu && !glu->mInQ) + { + LLGLUpdate::sGLQ.push_back(glu); + glu->mInQ = TRUE; + } +} + +void LLPipeline::markPartitionMove(LLDrawable* drawable) +{ + if (!drawable->isState(LLDrawable::PARTITION_MOVE) && + !drawable->getPositionGroup().equals3(LLVector4a::getZero())) + { + drawable->setState(LLDrawable::PARTITION_MOVE); + mPartitionQ.push_back(drawable); + } +} + +void LLPipeline::processPartitionQ() +{ + for (LLDrawable::drawable_list_t::iterator iter = mPartitionQ.begin(); iter != mPartitionQ.end(); ++iter) + { + LLDrawable* drawable = *iter; + if (!drawable->isDead()) + { + drawable->updateBinRadius(); + drawable->movePartition(); + } + drawable->clearState(LLDrawable::PARTITION_MOVE); + } + + mPartitionQ.clear(); +} + +void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE); + + if (group && !group->isDead() && group->mSpatialPartition) + { + if (group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD) + { + priority = TRUE; + } + + if (priority) + { + if (!group->isState(LLSpatialGroup::IN_BUILD_Q1)) + { + llassert_always(!mGroupQ1Locked); + + mGroupQ1.push_back(group); + group->setState(LLSpatialGroup::IN_BUILD_Q1); + + if (group->isState(LLSpatialGroup::IN_BUILD_Q2)) + { + LLSpatialGroup::sg_vector_t::iterator iter = std::find(mGroupQ2.begin(), mGroupQ2.end(), group); + if (iter != mGroupQ2.end()) + { + mGroupQ2.erase(iter); + } + group->clearState(LLSpatialGroup::IN_BUILD_Q2); + } + } + } + else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1)) + { + llassert_always(!mGroupQ2Locked); + mGroupQ2.push_back(group); + group->setState(LLSpatialGroup::IN_BUILD_Q2); + + } + } +} + +void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag, BOOL priority) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_REBUILD); + + if (drawablep && !drawablep->isDead() && assertInitialized()) + { + if (!drawablep->isState(LLDrawable::BUILT)) + { + priority = TRUE; + } + if (priority) + { + if (!drawablep->isState(LLDrawable::IN_REBUILD_Q1)) + { + mBuildQ1.push_back(drawablep); + drawablep->setState(LLDrawable::IN_REBUILD_Q1); // mark drawable as being in priority queue + } + } + else if (!drawablep->isState(LLDrawable::IN_REBUILD_Q2)) + { + mBuildQ2.push_back(drawablep); + drawablep->setState(LLDrawable::IN_REBUILD_Q2); // need flag here because it is just a list + } + if (flag & (LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION)) + { + drawablep->getVObj()->setChanged(LLXform::SILHOUETTE); + } + drawablep->setState(flag); + } +} + +static LLFastTimer::DeclareTimer FTM_RESET_DRAWORDER("Reset Draw Order"); + +void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) +{ + if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_GROUND, + LLPipeline::RENDER_TYPE_TERRAIN, + LLPipeline::RENDER_TYPE_TREE, + LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_VOIDWATER, + LLPipeline::RENDER_TYPE_WATER, + LLPipeline::END_RENDER_TYPES)) + { + //clear faces from face pools + LLFastTimer t(FTM_RESET_DRAWORDER); + gPipeline.resetDrawOrders(); + } + + LLFastTimer ftm(FTM_STATESORT); + LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); + + //LLVertexBuffer::unbind(); + + grabReferences(result); + for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + group->checkOcclusion(); + if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED)) + { + markOccluder(group); + } + else + { + group->setVisible(); + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + { + markVisible(*i, camera); + } + + if (!sDelayVBUpdate) + { //rebuild mesh as soon as we know it's visible + group->rebuildMesh(); + } + } + } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + { + LLSpatialGroup* last_group = NULL; + for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) + { + LLCullResult::bridge_list_t::iterator cur_iter = i; + LLSpatialBridge* bridge = *cur_iter; + LLSpatialGroup* group = bridge->getSpatialGroup(); + + if (last_group == NULL) + { + last_group = group; + } + + if (!bridge->isDead() && group && !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) + { + stateSort(bridge, camera); + } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && + last_group != group && last_group->changeLOD()) + { + last_group->mLastUpdateDistance = last_group->mDistance; + } + + last_group = group; + } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && + last_group && last_group->changeLOD()) + { + last_group->mLastUpdateDistance = last_group->mDistance; + } + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + group->checkOcclusion(); + if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED)) + { + markOccluder(group); + } + else + { + group->setVisible(); + stateSort(group, camera); + + if (!sDelayVBUpdate) + { //rebuild mesh as soon as we know it's visible + group->rebuildMesh(); + } + } + } + + { + LLFastTimer ftm(FTM_STATESORT_DRAWABLE); + for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); + iter != sCull->endVisibleList(); ++iter) + { + LLDrawable *drawablep = *iter; + if (!drawablep->isDead()) + { + stateSort(drawablep, camera); + } + } + } + + postSort(camera); +} + +void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); + if (group->changeLOD()) + { + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + { + LLDrawable* drawablep = *i; + stateSort(drawablep, camera); + } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + { //avoid redundant stateSort calls + group->mLastUpdateDistance = group->mDistance; + } + } + +} + +void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); + if (bridge->getSpatialGroup()->changeLOD()) + { + bool force_update = false; + bridge->updateDistance(camera, force_update); + } +} + +void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); + + if (!drawablep + || drawablep->isDead() + || !hasRenderType(drawablep->getRenderType())) + { + return; + } + + if (LLSelectMgr::getInstance()->mHideSelectedObjects) + { + if (drawablep->getVObj().notNull() && + drawablep->getVObj()->isSelected()) + { + return; + } + } + + if (drawablep->isAvatar()) + { //don't draw avatars beyond render distance or if we don't have a spatial group. + if ((drawablep->getSpatialGroup() == NULL) || + (drawablep->getSpatialGroup()->mDistance > LLVOAvatar::sRenderDistance)) + { + return; + } + + LLVOAvatar* avatarp = (LLVOAvatar*) drawablep->getVObj().get(); + if (!avatarp->isVisible()) + { + return; + } + } + + assertInitialized(); + + if (hasRenderType(drawablep->mRenderType)) + { + if (!drawablep->isState(LLDrawable::INVISIBLE|LLDrawable::FORCE_INVISIBLE)) + { + drawablep->setVisible(camera, NULL, FALSE); + } + else if (drawablep->isState(LLDrawable::CLEAR_INVISIBLE)) + { + // clear invisible flag here to avoid single frame glitch + drawablep->clearState(LLDrawable::FORCE_INVISIBLE|LLDrawable::CLEAR_INVISIBLE); + } + } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + { + //if (drawablep->isVisible()) isVisible() check here is redundant, if it wasn't visible, it wouldn't be here + { + if (!drawablep->isActive()) + { + bool force_update = false; + drawablep->updateDistance(camera, force_update); + } + else if (drawablep->isAvatar()) + { + bool force_update = false; + drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility() + } + } + } + + if (!drawablep->getVOVolume()) + { + for (LLDrawable::face_list_t::iterator iter = drawablep->mFaces.begin(); + iter != drawablep->mFaces.end(); iter++) + { + LLFace* facep = *iter; + + if (facep->hasGeometry()) + { + if (facep->getPool()) + { + facep->getPool()->enqueue(facep); + } + else + { + break; + } + } + } + } + + + mNumVisibleFaces += drawablep->getNumFaces(); +} + + +void forAllDrawables(LLCullResult::sg_list_t::iterator begin, + LLCullResult::sg_list_t::iterator end, + void (*func)(LLDrawable*)) +{ + for (LLCullResult::sg_list_t::iterator i = begin; i != end; ++i) + { + for (LLSpatialGroup::element_iter j = (*i)->getData().begin(); j != (*i)->getData().end(); ++j) + { + func(*j); + } + } +} + +void LLPipeline::forAllVisibleDrawables(void (*func)(LLDrawable*)) +{ + forAllDrawables(sCull->beginDrawableGroups(), sCull->endDrawableGroups(), func); + forAllDrawables(sCull->beginVisibleGroups(), sCull->endVisibleGroups(), func); +} + +//function for creating scripted beacons +void renderScriptedBeacons(LLDrawable* drawablep) +{ + LLViewerObject *vobj = drawablep->getVObj(); + if (vobj + && !vobj->isAvatar() + && !vobj->getParent() + && vobj->flagScripted()) + { + if (gPipeline.sRenderBeacons) + { + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth); + } + + if (gPipeline.sRenderHighlight) + { + S32 face_id; + S32 count = drawablep->getNumFaces(); + for (face_id = 0; face_id < count; face_id++) + { + gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + } + } + } +} + +void renderScriptedTouchBeacons(LLDrawable* drawablep) +{ + LLViewerObject *vobj = drawablep->getVObj(); + if (vobj + && !vobj->isAvatar() + && !vobj->getParent() + && vobj->flagScripted() + && vobj->flagHandleTouch()) + { + if (gPipeline.sRenderBeacons) + { + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth); + } + + if (gPipeline.sRenderHighlight) + { + S32 face_id; + S32 count = drawablep->getNumFaces(); + for (face_id = 0; face_id < count; face_id++) + { + gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + } + } + } +} + +void renderPhysicalBeacons(LLDrawable* drawablep) +{ + LLViewerObject *vobj = drawablep->getVObj(); + if (vobj + && !vobj->isAvatar() + //&& !vobj->getParent() + && vobj->usePhysics()) + { + if (gPipeline.sRenderBeacons) + { + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth); + } + + if (gPipeline.sRenderHighlight) + { + S32 face_id; + S32 count = drawablep->getNumFaces(); + for (face_id = 0; face_id < count; face_id++) + { + gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + } + } + } +} + +void renderMOAPBeacons(LLDrawable* drawablep) +{ + LLViewerObject *vobj = drawablep->getVObj(); + + if(!vobj || vobj->isAvatar()) + return; + + BOOL beacon=FALSE; + U8 tecount=vobj->getNumTEs(); + for(int x=0;x<tecount;x++) + { + if(vobj->getTE(x)->hasMedia()) + { + beacon=TRUE; + break; + } + } + if(beacon==TRUE) + { + if (gPipeline.sRenderBeacons) + { + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 1.f, 1.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth); + } + + if (gPipeline.sRenderHighlight) + { + S32 face_id; + S32 count = drawablep->getNumFaces(); + for (face_id = 0; face_id < count; face_id++) + { + gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + } + } + } +} + +void renderParticleBeacons(LLDrawable* drawablep) +{ + // Look for attachments, objects, etc. + LLViewerObject *vobj = drawablep->getVObj(); + if (vobj + && vobj->isParticleSource()) + { + if (gPipeline.sRenderBeacons) + { + LLColor4 light_blue(0.5f, 0.5f, 1.f, 0.5f); + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", light_blue, LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth); + } + + if (gPipeline.sRenderHighlight) + { + S32 face_id; + S32 count = drawablep->getNumFaces(); + for (face_id = 0; face_id < count; face_id++) + { + gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + } + } + } +} + +void renderSoundHighlights(LLDrawable* drawablep) +{ + // Look for attachments, objects, etc. + LLViewerObject *vobj = drawablep->getVObj(); + if (vobj && vobj->isAudioSource()) + { + if (gPipeline.sRenderHighlight) + { + S32 face_id; + S32 count = drawablep->getNumFaces(); + for (face_id = 0; face_id < count; face_id++) + { + gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + } + } + } +} + +void LLPipeline::postSort(LLCamera& camera) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_POST_SORT); + LLFastTimer ftm(FTM_STATESORT_POSTSORT); + + assertInitialized(); + + llpushcallstacks ; + //rebuild drawable geometry + for (LLCullResult::sg_list_t::iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i) + { + LLSpatialGroup* group = *i; + if (!sUseOcclusion || + !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) + { + group->rebuildGeom(); + } + } + llpushcallstacks ; + //rebuild groups + sCull->assertDrawMapsEmpty(); + + rebuildPriorityGroups(); + llpushcallstacks ; + + const S32 bin_count = 1024*8; + + static LLCullResult::drawinfo_list_t alpha_bins[bin_count]; + static U32 bin_size[bin_count]; + + //clear one bin per frame to avoid memory bloat + static S32 clear_idx = 0; + clear_idx = (1+clear_idx)%bin_count; + alpha_bins[clear_idx].clear(); + + for (U32 j = 0; j < bin_count; j++) + { + bin_size[j] = 0; + } + + //build render map + for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) + { + LLSpatialGroup* group = *i; + if (sUseOcclusion && + group->isOcclusionState(LLSpatialGroup::OCCLUDED)) + { + continue; + } + + if (group->isState(LLSpatialGroup::NEW_DRAWINFO) && group->isState(LLSpatialGroup::GEOM_DIRTY)) + { //no way this group is going to be drawable without a rebuild + group->rebuildGeom(); + } + + for (LLSpatialGroup::draw_map_t::iterator j = group->mDrawMap.begin(); j != group->mDrawMap.end(); ++j) + { + LLSpatialGroup::drawmap_elem_t& src_vec = j->second; + if (!hasRenderType(j->first)) + { + continue; + } + + for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k) + { + if (sMinRenderSize > 0.f) + { + LLVector4a bounds; + bounds.setSub((*k)->mExtents[1],(*k)->mExtents[0]); + + if (llmax(llmax(bounds[0], bounds[1]), bounds[2]) > sMinRenderSize) + { + sCull->pushDrawInfo(j->first, *k); + } + } + else + { + sCull->pushDrawInfo(j->first, *k); + } + } + } + + if (hasRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA)) + { + LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA); + + if (alpha != group->mDrawMap.end()) + { //store alpha groups for sorting + LLSpatialBridge* bridge = group->mSpatialPartition->asBridge(); + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + { + if (bridge) + { + LLCamera trans_camera = bridge->transformCamera(camera); + group->updateDistance(trans_camera); + } + else + { + group->updateDistance(camera); + } + } + + if (hasRenderType(LLDrawPool::POOL_ALPHA)) + { + sCull->pushAlphaGroup(group); + } + } + } + } + + if (!sShadowRender) + { + std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater()); + } + llpushcallstacks ; + // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus + if (LLFloaterReg::instanceVisible("beacons") && !sShadowRender) + { + if (sRenderScriptedTouchBeacons) + { + // Only show the beacon on the root object. + forAllVisibleDrawables(renderScriptedTouchBeacons); + } + else + if (sRenderScriptedBeacons) + { + // Only show the beacon on the root object. + forAllVisibleDrawables(renderScriptedBeacons); + } + + if (sRenderPhysicalBeacons) + { + // Only show the beacon on the root object. + forAllVisibleDrawables(renderPhysicalBeacons); + } + + if(sRenderMOAPBeacons) + { + forAllVisibleDrawables(renderMOAPBeacons); + } + + if (sRenderParticleBeacons) + { + forAllVisibleDrawables(renderParticleBeacons); + } + + // If god mode, also show audio cues + if (sRenderSoundBeacons && gAudiop) + { + // Walk all sound sources and render out beacons for them. Note, this isn't done in the ForAllVisibleDrawables function, because some are not visible. + LLAudioEngine::source_map::iterator iter; + for (iter = gAudiop->mAllSources.begin(); iter != gAudiop->mAllSources.end(); ++iter) + { + LLAudioSource *sourcep = iter->second; + + LLVector3d pos_global = sourcep->getPositionGlobal(); + LLVector3 pos = gAgent.getPosAgentFromGlobal(pos_global); + if (gPipeline.sRenderBeacons) + { + //pos += LLVector3(0.f, 0.f, 0.2f); + gObjectList.addDebugBeacon(pos, "", LLColor4(1.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), DebugBeaconLineWidth); + } + } + // now deal with highlights for all those seeable sound sources + forAllVisibleDrawables(renderSoundHighlights); + } + } + llpushcallstacks ; + // If managing your telehub, draw beacons at telehub and currently selected spawnpoint. + if (LLFloaterTelehub::renderBeacons()) + { + LLFloaterTelehub::addBeacons(); + } + + if (!sShadowRender) + { + mSelectedFaces.clear(); + + // Draw face highlights for selected faces. + if (LLSelectMgr::getInstance()->getTEMode()) + { + struct f : public LLSelectedTEFunctor + { + virtual bool apply(LLViewerObject* object, S32 te) + { + if (object->mDrawable) + { + gPipeline.mSelectedFaces.push_back(object->mDrawable->getFace(te)); + } + return true; + } + } func; + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func); + } + } + + //LLSpatialGroup::sNoDelete = FALSE; + llpushcallstacks ; +} + + +void render_hud_elements() +{ + LLMemType mt_rhe(LLMemType::MTYPE_PIPELINE_RENDER_HUD_ELS); + LLFastTimer t(FTM_RENDER_UI); + gPipeline.disableLights(); + + LLGLDisable fog(GL_FOG); + LLGLSUIDefault gls_ui; + + LLGLEnable stencil(GL_STENCIL_TEST); + glStencilFunc(GL_ALWAYS, 255, 0xFFFFFFFF); + glStencilMask(0xFFFFFFFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + gGL.color4f(1,1,1,1); + + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.bind(); + } + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + + if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { + LLGLEnable multisample(LLPipeline::RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); + gViewerWindow->renderSelections(FALSE, FALSE, FALSE); // For HUD version in render_ui_3d() + + // Draw the tracking overlays + LLTracker::render3D(); + + // Show the property lines + LLWorld::getInstance()->renderPropertyLines(); + LLViewerParcelMgr::getInstance()->render(); + LLViewerParcelMgr::getInstance()->renderParcelCollision(); + + // Render name tags. + LLHUDObject::renderAll(); + } + else if (gForceRenderLandFence) + { + // This is only set when not rendering the UI, for parcel snapshots + LLViewerParcelMgr::getInstance()->render(); + } + else if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { + LLHUDText::renderAllHUD(); + } + + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.unbind(); + } + gGL.flush(); +} + +void LLPipeline::renderHighlights() +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_HL); + + assertInitialized(); + + // Draw 3D UI elements here (before we clear the Z buffer in POOL_HUD) + // Render highlighted faces. + LLGLSPipelineAlpha gls_pipeline_alpha; + LLColor4 color(1.f, 1.f, 1.f, 0.5f); + LLGLEnable color_mat(GL_COLOR_MATERIAL); + disableLights(); + + if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD) && !mHighlightSet.empty()) + { //draw blurry highlight image over screen + LLGLEnable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + LLGLDisable test(GL_ALPHA_TEST); + + LLGLEnable stencil(GL_STENCIL_TEST); + gGL.flush(); + glStencilMask(0xFFFFFFFF); + glClearStencil(1); + glClear(GL_STENCIL_BUFFER_BIT); + + glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + + gGL.setColorMask(false, false); + for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ++iter) + { + renderHighlight(iter->mItem->getVObj(), 1.f); + } + gGL.setColorMask(true, false); + + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF); + + //gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); + + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + + gGL.getTexUnit(0)->bind(&mHighlight); + + LLVector2 tc1; + LLVector2 tc2; + + tc1.setVec(0,0); + tc2.setVec(2,2); + + gGL.begin(LLRender::TRIANGLES); + + F32 scale = RenderHighlightBrightness; + LLColor4 color = RenderHighlightColor; + F32 thickness = RenderHighlightThickness; + + for (S32 pass = 0; pass < 2; ++pass) + { + if (pass == 0) + { + gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); + } + else + { + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + + for (S32 i = 0; i < 8; ++i) + { + for (S32 j = 0; j < 8; ++j) + { + LLVector2 tc(i-4+0.5f, j-4+0.5f); + + F32 dist = 1.f-(tc.length()/sqrtf(32.f)); + dist *= scale/64.f; + + tc *= thickness; + tc.mV[0] = (tc.mV[0])/mHighlight.getWidth(); + tc.mV[1] = (tc.mV[1])/mHighlight.getHeight(); + + gGL.color4f(color.mV[0], + color.mV[1], + color.mV[2], + color.mV[3]*dist); + + gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc2.mV[1]); + gGL.vertex2f(-1,3); + + gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc1.mV[1]); + gGL.vertex2f(-1,-1); + + gGL.texCoord2f(tc.mV[0]+tc2.mV[0], tc.mV[1]+tc1.mV[1]); + gGL.vertex2f(3,-1); + } + } + } + + gGL.end(); + + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + + //gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + + if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) + { + gHighlightProgram.bind(); + gGL.diffuseColor4f(1,1,1,0.5f); + } + + if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED)) + { + // Make sure the selection image gets downloaded and decoded + if (!mFaceSelectImagep) + { + mFaceSelectImagep = LLViewerTextureManager::getFetchedTexture(IMG_FACE_SELECT); + } + mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA); + + U32 count = mSelectedFaces.size(); + for (U32 i = 0; i < count; i++) + { + LLFace *facep = mSelectedFaces[i]; + if (!facep || facep->getDrawable()->isDead()) + { + llerrs << "Bad face on selection" << llendl; + return; + } + + facep->renderSelected(mFaceSelectImagep, color); + } + } + + if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED)) + { + // Paint 'em red! + color.setVec(1.f, 0.f, 0.f, 0.5f); + + int count = mHighlightFaces.size(); + for (S32 i = 0; i < count; i++) + { + LLFace* facep = mHighlightFaces[i]; + facep->renderSelected(LLViewerTexture::sNullImagep, color); + } + } + + // Contains a list of the faces of objects that are physical or + // have touch-handlers. + mHighlightFaces.clear(); + + if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0) + { + gHighlightProgram.unbind(); + } +} + +//debug use +U32 LLPipeline::sCurRenderPoolType = 0 ; + +void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_GEOM); + LLFastTimer t(FTM_RENDER_GEOMETRY); + + assertInitialized(); + + F32 saved_modelview[16]; + F32 saved_projection[16]; + + //HACK: preserve/restore matrices around HUD render + if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { + for (U32 i = 0; i < 16; i++) + { + saved_modelview[i] = gGLModelView[i]; + saved_projection[i] = gGLProjection[i]; + } + } + + /////////////////////////////////////////// + // + // Sync and verify GL state + // + // + + stop_glerror(); + + LLVertexBuffer::unbind(); + + // Do verification of GL state + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + if (mRenderDebugMask & RENDER_DEBUG_VERIFY) + { + if (!verify()) + { + llerrs << "Pipeline verification failed!" << llendl; + } + } + + LLAppViewer::instance()->pingMainloopTimeout("Pipeline:ForceVBO"); + + // Initialize lots of GL state to "safe" values + gGL.matrixMode(LLRender::MM_TEXTURE); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + + LLGLSPipeline gls_pipeline; + LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); + + LLGLState gls_color_material(GL_COLOR_MATERIAL, mLightingDetail < 2); + + // Toggle backface culling for debugging + LLGLEnable cull_face(mBackfaceCull ? GL_CULL_FACE : 0); + // Set fog + BOOL use_fog = hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG); + LLGLEnable fog_enable(use_fog && + !gPipeline.canUseWindLightShadersOnObjects() ? GL_FOG : 0); + gSky.updateFog(camera.getFar()); + if (!use_fog) + { + sUnderWaterRender = FALSE; + } + + gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sDefaultImagep); + LLViewerFetchedTexture::sDefaultImagep->setAddressMode(LLTexUnit::TAM_WRAP); + + + ////////////////////////////////////////////// + // + // Actually render all of the geometry + // + // + stop_glerror(); + + LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPools"); + + for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) + { + LLDrawPool *poolp = *iter; + if (hasRenderType(poolp->getType())) + { + poolp->prerender(); + } + } + + { + LLFastTimer t(FTM_POOLS); + + // HACK: don't calculate local lights if we're rendering the HUD! + // Removing this check will cause bad flickering when there are + // HUD elements being rendered AND the user is in flycam mode -nyx + if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { + calcNearbyLights(camera); + setupHWLights(NULL); + } + + BOOL occlude = sUseOcclusion > 1; + U32 cur_type = 0; + + pool_set_t::iterator iter1 = mPools.begin(); + while ( iter1 != mPools.end() ) + { + LLDrawPool *poolp = *iter1; + + cur_type = poolp->getType(); + + //debug use + sCurRenderPoolType = cur_type ; + + if (occlude && cur_type >= LLDrawPool::POOL_GRASS) + { + occlude = FALSE; + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); + LLGLSLShader::bindNoShader(); + doOcclusion(camera); + } + + pool_set_t::iterator iter2 = iter1; + if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0) + { + LLFastTimer t(FTM_POOLRENDER); + + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); + + for( S32 i = 0; i < poolp->getNumPasses(); i++ ) + { + LLVertexBuffer::unbind(); + poolp->beginRenderPass(i); + for (iter2 = iter1; iter2 != mPools.end(); iter2++) + { + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + + p->render(i); + } + poolp->endRenderPass(i); + LLVertexBuffer::unbind(); + if (gDebugGL) + { + std::string msg = llformat("pass %d", i); + LLGLState::checkStates(msg); + //LLGLState::checkTextureChannels(msg); + //LLGLState::checkClientArrays(msg); + } + } + } + else + { + // Skip all pools of this type + for (iter2 = iter1; iter2 != mPools.end(); iter2++) + { + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + } + } + iter1 = iter2; + stop_glerror(); + } + + LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPoolsEnd"); + + LLVertexBuffer::unbind(); + + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); + + if (occlude) + { + occlude = FALSE; + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); + LLGLSLShader::bindNoShader(); + doOcclusion(camera); + } + } + + LLVertexBuffer::unbind(); + LLGLState::checkStates(); + + if (!LLPipeline::sImpostorRender) + { + LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderHighlights"); + + if (!sReflectionRender) + { + renderHighlights(); + } + + // Contains a list of the faces of objects that are physical or + // have touch-handlers. + mHighlightFaces.clear(); + + LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDebug"); + + renderDebug(); + + LLVertexBuffer::unbind(); + + if (!LLPipeline::sReflectionRender && !LLPipeline::sRenderDeferred) + { + if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { + // Render debugging beacons. + gObjectList.renderObjectBeacons(); + gObjectList.resetObjectBeacons(); + } + else + { + // Make sure particle effects disappear + LLHUDObject::renderAllForTimer(); + } + } + else + { + // Make sure particle effects disappear + LLHUDObject::renderAllForTimer(); + } + + LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomEnd"); + + //HACK: preserve/restore matrices around HUD render + if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { + for (U32 i = 0; i < 16; i++) + { + gGLModelView[i] = saved_modelview[i]; + gGLProjection[i] = saved_projection[i]; + } + } + } + + LLVertexBuffer::unbind(); + + LLGLState::checkStates(); +// LLGLState::checkTextureChannels(); +// LLGLState::checkClientArrays(); +} + +void LLPipeline::renderGeomDeferred(LLCamera& camera) +{ + LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred"); + + LLMemType mt_rgd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED); + LLFastTimer t(FTM_RENDER_GEOMETRY); + + LLFastTimer t2(FTM_POOLS); + + LLGLEnable cull(GL_CULL_FACE); + + LLGLEnable stencil(GL_STENCIL_TEST); + glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF); + stop_glerror(); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + stop_glerror(); + + for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) + { + LLDrawPool *poolp = *iter; + if (hasRenderType(poolp->getType())) + { + poolp->prerender(); + } + } + + LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); + + LLVertexBuffer::unbind(); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + + U32 cur_type = 0; + + gGL.setColorMask(true, true); + + pool_set_t::iterator iter1 = mPools.begin(); + + while ( iter1 != mPools.end() ) + { + LLDrawPool *poolp = *iter1; + + cur_type = poolp->getType(); + + pool_set_t::iterator iter2 = iter1; + if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0) + { + LLFastTimer t(FTM_POOLRENDER); + + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); + + for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ ) + { + LLVertexBuffer::unbind(); + poolp->beginDeferredPass(i); + for (iter2 = iter1; iter2 != mPools.end(); iter2++) + { + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + + p->renderDeferred(i); + } + poolp->endDeferredPass(i); + LLVertexBuffer::unbind(); + + if (gDebugGL || gDebugPipeline) + { + LLGLState::checkStates(); + } + } + } + else + { + // Skip all pools of this type + for (iter2 = iter1; iter2 != mPools.end(); iter2++) + { + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + } + } + iter1 = iter2; + stop_glerror(); + } + + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); + + gGL.setColorMask(true, false); +} + +void LLPipeline::renderGeomPostDeferred(LLCamera& camera) +{ + LLMemType mt_rgpd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF); + LLFastTimer t(FTM_POOLS); + U32 cur_type = 0; + + LLGLEnable cull(GL_CULL_FACE); + + LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); + + calcNearbyLights(camera); + setupHWLights(NULL); + + gGL.setColorMask(true, false); + + pool_set_t::iterator iter1 = mPools.begin(); + BOOL occlude = LLPipeline::sUseOcclusion > 1; + + while ( iter1 != mPools.end() ) + { + LLDrawPool *poolp = *iter1; + + cur_type = poolp->getType(); + + if (occlude && cur_type >= LLDrawPool::POOL_GRASS) + { + occlude = FALSE; + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); + LLGLSLShader::bindNoShader(); + doOcclusion(camera); + gGL.setColorMask(true, false); + } + + pool_set_t::iterator iter2 = iter1; + if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0) + { + LLFastTimer t(FTM_POOLRENDER); + + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); + + for( S32 i = 0; i < poolp->getNumPostDeferredPasses(); i++ ) + { + LLVertexBuffer::unbind(); + poolp->beginPostDeferredPass(i); + for (iter2 = iter1; iter2 != mPools.end(); iter2++) + { + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + + p->renderPostDeferred(i); + } + poolp->endPostDeferredPass(i); + LLVertexBuffer::unbind(); + + if (gDebugGL || gDebugPipeline) + { + LLGLState::checkStates(); + } + } + } + else + { + // Skip all pools of this type + for (iter2 = iter1; iter2 != mPools.end(); iter2++) + { + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + } + } + iter1 = iter2; + stop_glerror(); + } + + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); + + if (occlude) + { + occlude = FALSE; + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); + LLGLSLShader::bindNoShader(); + doOcclusion(camera); + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); + } +} + +void LLPipeline::renderGeomShadow(LLCamera& camera) +{ + LLMemType mt_rgs(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_SHADOW); + U32 cur_type = 0; + + LLGLEnable cull(GL_CULL_FACE); + + LLVertexBuffer::unbind(); + + pool_set_t::iterator iter1 = mPools.begin(); + + while ( iter1 != mPools.end() ) + { + LLDrawPool *poolp = *iter1; + + cur_type = poolp->getType(); + + pool_set_t::iterator iter2 = iter1; + if (hasRenderType(poolp->getType()) && poolp->getNumShadowPasses() > 0) + { + poolp->prerender() ; + + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); + + for( S32 i = 0; i < poolp->getNumShadowPasses(); i++ ) + { + LLVertexBuffer::unbind(); + poolp->beginShadowPass(i); + for (iter2 = iter1; iter2 != mPools.end(); iter2++) + { + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + + p->renderShadow(i); + } + poolp->endShadowPass(i); + LLVertexBuffer::unbind(); + + LLGLState::checkStates(); + } + } + else + { + // Skip all pools of this type + for (iter2 = iter1; iter2 != mPools.end(); iter2++) + { + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + } + } + iter1 = iter2; + stop_glerror(); + } + + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); +} + + +void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type) +{ + assertInitialized(); + S32 count = 0; + if (render_type == LLRender::TRIANGLE_STRIP) + { + count = index_count-2; + } + else + { + count = index_count/3; + } + + mTrianglesDrawn += count; + mBatchCount++; + mMaxBatchSize = llmax(mMaxBatchSize, count); + mMinBatchSize = llmin(mMinBatchSize, count); + + if (LLPipeline::sRenderFrameTest) + { + gViewerWindow->getWindow()->swapBuffers(); + ms_sleep(16); + } +} + +void LLPipeline::renderPhysicsDisplay() +{ + if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES)) + { + return; + } + + allocatePhysicsBuffer(); + + gGL.flush(); + mPhysicsDisplay.bindTarget(); + glClearColor(0,0,0,1); + gGL.setColorMask(true, true); + mPhysicsDisplay.clear(); + glClearColor(0,0,0,0); + + gGL.setColorMask(true, false); + + if (LLGLSLShader::sNoFixedFunction) + { + gDebugProgram.bind(); + } + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + if (hasRenderType(part->mDrawableType)) + { + part->renderPhysicsShapes(); + } + } + } + } + + for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) + { + LLSpatialBridge* bridge = *i; + if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) + { + gGL.pushMatrix(); + gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); + bridge->renderPhysicsShapes(); + gGL.popMatrix(); + } + } + + gGL.flush(); + + if (LLGLSLShader::sNoFixedFunction) + { + gDebugProgram.unbind(); + } + + mPhysicsDisplay.flush(); +} + + +void LLPipeline::renderDebug() +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE); + + assertInitialized(); + + gGL.color4f(1,1,1,1); + + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); + gGL.setColorMask(true, false); + + bool hud_only = hasRenderType(LLPipeline::RENDER_TYPE_HUD); + + + if (!hud_only && !mDebugBlips.empty()) + { //render debug blips + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.bind(); + } + + gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep, true); + + glPointSize(8.f); + LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); + + gGL.begin(LLRender::POINTS); + for (std::list<DebugBlip>::iterator iter = mDebugBlips.begin(); iter != mDebugBlips.end(); ) + { + DebugBlip& blip = *iter; + + blip.mAge += gFrameIntervalSeconds; + if (blip.mAge > 2.f) + { + mDebugBlips.erase(iter++); + } + else + { + iter++; + } + + blip.mPosition.mV[2] += gFrameIntervalSeconds*2.f; + + gGL.color4fv(blip.mColor.mV); + gGL.vertex3fv(blip.mPosition.mV); + } + gGL.end(); + gGL.flush(); + glPointSize(1.f); + } + + + // Debug stuff. + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + if ( hud_only && (part->mDrawableType == RENDER_TYPE_HUD || part->mDrawableType == RENDER_TYPE_HUD_PARTICLES) || + !hud_only && hasRenderType(part->mDrawableType) ) + { + part->renderDebug(); + } + } + } + } + + for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) + { + LLSpatialBridge* bridge = *i; + if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) + { + gGL.pushMatrix(); + gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); + bridge->renderDebug(); + gGL.popMatrix(); + } + } + + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.bind(); + } + + if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) + { + LLVertexBuffer::unbind(); + + LLGLEnable blend(GL_BLEND); + LLGLDepthTest depth(TRUE, FALSE); + LLGLDisable cull(GL_CULL_FACE); + + gGL.color4f(1,1,1,1); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + F32 a = 0.1f; + + F32 col[] = + { + 1,0,0,a, + 0,1,0,a, + 0,0,1,a, + 1,0,1,a, + + 1,1,0,a, + 0,1,1,a, + 1,1,1,a, + 1,0,1,a, + }; + + for (U32 i = 0; i < 8; i++) + { + LLVector3* frust = mShadowCamera[i].mAgentFrustum; + + if (i > 3) + { //render shadow frusta as volumes + if (mShadowFrustPoints[i-4].empty()) + { + continue; + } + + gGL.color4fv(col+(i-4)*4); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV); + gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV); + gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV); + gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV); + gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV); + gGL.end(); + + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex3fv(frust[0].mV); + gGL.vertex3fv(frust[1].mV); + gGL.vertex3fv(frust[3].mV); + gGL.vertex3fv(frust[2].mV); + gGL.end(); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex3fv(frust[4].mV); + gGL.vertex3fv(frust[5].mV); + gGL.vertex3fv(frust[7].mV); + gGL.vertex3fv(frust[6].mV); + gGL.end(); + } + + + if (i < 4) + { + + //if (i == 0 || !mShadowFrustPoints[i].empty()) + { + //render visible point cloud + gGL.flush(); + glPointSize(8.f); + gGL.begin(LLRender::POINTS); + + F32* c = col+i*4; + gGL.color3fv(c); + + for (U32 j = 0; j < mShadowFrustPoints[i].size(); ++j) + { + gGL.vertex3fv(mShadowFrustPoints[i][j].mV); + + } + gGL.end(); + + gGL.flush(); + glPointSize(1.f); + + LLVector3* ext = mShadowExtents[i]; + LLVector3 pos = (ext[0]+ext[1])*0.5f; + LLVector3 size = (ext[1]-ext[0])*0.5f; + drawBoxOutline(pos, size); + + //render camera frustum splits as outlines + gGL.begin(LLRender::LINES); + gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[1].mV); + gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[2].mV); + gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[3].mV); + gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[0].mV); + gGL.vertex3fv(frust[4].mV); gGL.vertex3fv(frust[5].mV); + gGL.vertex3fv(frust[5].mV); gGL.vertex3fv(frust[6].mV); + gGL.vertex3fv(frust[6].mV); gGL.vertex3fv(frust[7].mV); + gGL.vertex3fv(frust[7].mV); gGL.vertex3fv(frust[4].mV); + gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV); + gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV); + gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV); + gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV); + gGL.end(); + } + } + + /*gGL.flush(); + glLineWidth(16-i*2); + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++) + { + LLSpatialPartition* part = region->getSpatialPartition(j); + if (part) + { + if (hasRenderType(part->mDrawableType)) + { + part->renderIntersectingBBoxes(&mShadowCamera[i]); + } + } + } + } + gGL.flush(); + glLineWidth(1.f);*/ + } + } + + if (mRenderDebugMask & RENDER_DEBUG_WIND_VECTORS) + { + gAgent.getRegion()->mWind.renderVectors(); + } + + if (mRenderDebugMask & RENDER_DEBUG_COMPOSITION) + { + // Debug composition layers + F32 x, y; + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + if (gAgent.getRegion()) + { + gGL.begin(LLRender::POINTS); + // Draw the composition layer for the region that I'm in. + for (x = 0; x <= 260; x++) + { + for (y = 0; y <= 260; y++) + { + if ((x > 255) || (y > 255)) + { + gGL.color4f(1.f, 0.f, 0.f, 1.f); + } + else + { + gGL.color4f(0.f, 0.f, 1.f, 1.f); + } + F32 z = gAgent.getRegion()->getCompositionXY((S32)x, (S32)y); + z *= 5.f; + z += 50.f; + gGL.vertex3f(x, y, z); + } + } + gGL.end(); + } + } + + if (mRenderDebugMask & LLPipeline::RENDER_DEBUG_BUILD_QUEUE) + { + U32 count = 0; + U32 size = mGroupQ2.size(); + LLColor4 col; + + LLVertexBuffer::unbind(); + LLGLEnable blend(GL_BLEND); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); + + gGL.pushMatrix(); + gGL.loadMatrix(gGLModelView); + gGLLastMatrix = NULL; + + for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ2.begin(); iter != mGroupQ2.end(); ++iter) + { + LLSpatialGroup* group = *iter; + if (group->isDead()) + { + continue; + } + + LLSpatialBridge* bridge = group->mSpatialPartition->asBridge(); + + if (bridge && (!bridge->mDrawable || bridge->mDrawable->isDead())) + { + continue; + } + + if (bridge) + { + gGL.pushMatrix(); + gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); + } + + F32 alpha = llclamp((F32) (size-count)/size, 0.f, 1.f); + + + LLVector2 c(1.f-alpha, alpha); + c.normVec(); + + + ++count; + col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.5f); + group->drawObjectBox(col); + + if (bridge) + { + gGL.popMatrix(); + } + } + + gGL.popMatrix(); + } + + gGL.flush(); + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.unbind(); + } +} + +void LLPipeline::rebuildPools() +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_REBUILD_POOLS); + + assertInitialized(); + + S32 max_count = mPools.size(); + pool_set_t::iterator iter1 = mPools.upper_bound(mLastRebuildPool); + while(max_count > 0 && mPools.size() > 0) // && num_rebuilds < MAX_REBUILDS) + { + if (iter1 == mPools.end()) + { + iter1 = mPools.begin(); + } + LLDrawPool* poolp = *iter1; + + if (poolp->isDead()) + { + mPools.erase(iter1++); + removeFromQuickLookup( poolp ); + if (poolp == mLastRebuildPool) + { + mLastRebuildPool = NULL; + } + delete poolp; + } + else + { + mLastRebuildPool = poolp; + iter1++; + } + max_count--; + } + + if (isAgentAvatarValid()) + { + gAgentAvatarp->rebuildHUD(); + } +} + +void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE_QUICK_LOOKUP); + + assertInitialized(); + + switch( new_poolp->getType() ) + { + case LLDrawPool::POOL_SIMPLE: + if (mSimplePool) + { + llassert(0); + llwarns << "Ignoring duplicate simple pool." << llendl; + } + else + { + mSimplePool = (LLRenderPass*) new_poolp; + } + break; + + case LLDrawPool::POOL_GRASS: + if (mGrassPool) + { + llassert(0); + llwarns << "Ignoring duplicate grass pool." << llendl; + } + else + { + mGrassPool = (LLRenderPass*) new_poolp; + } + break; + + case LLDrawPool::POOL_FULLBRIGHT: + if (mFullbrightPool) + { + llassert(0); + llwarns << "Ignoring duplicate simple pool." << llendl; + } + else + { + mFullbrightPool = (LLRenderPass*) new_poolp; + } + break; + + case LLDrawPool::POOL_INVISIBLE: + if (mInvisiblePool) + { + llassert(0); + llwarns << "Ignoring duplicate simple pool." << llendl; + } + else + { + mInvisiblePool = (LLRenderPass*) new_poolp; + } + break; + + case LLDrawPool::POOL_GLOW: + if (mGlowPool) + { + llassert(0); + llwarns << "Ignoring duplicate glow pool." << llendl; + } + else + { + mGlowPool = (LLRenderPass*) new_poolp; + } + break; + + case LLDrawPool::POOL_TREE: + mTreePools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ; + break; + + case LLDrawPool::POOL_TERRAIN: + mTerrainPools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ; + break; + + case LLDrawPool::POOL_BUMP: + if (mBumpPool) + { + llassert(0); + llwarns << "Ignoring duplicate bump pool." << llendl; + } + else + { + mBumpPool = new_poolp; + } + break; + + case LLDrawPool::POOL_ALPHA: + if( mAlphaPool ) + { + llassert(0); + llwarns << "LLPipeline::addPool(): Ignoring duplicate Alpha pool" << llendl; + } + else + { + mAlphaPool = new_poolp; + } + break; + + case LLDrawPool::POOL_AVATAR: + break; // Do nothing + + case LLDrawPool::POOL_SKY: + if( mSkyPool ) + { + llassert(0); + llwarns << "LLPipeline::addPool(): Ignoring duplicate Sky pool" << llendl; + } + else + { + mSkyPool = new_poolp; + } + break; + + case LLDrawPool::POOL_WATER: + if( mWaterPool ) + { + llassert(0); + llwarns << "LLPipeline::addPool(): Ignoring duplicate Water pool" << llendl; + } + else + { + mWaterPool = new_poolp; + } + break; + + case LLDrawPool::POOL_GROUND: + if( mGroundPool ) + { + llassert(0); + llwarns << "LLPipeline::addPool(): Ignoring duplicate Ground Pool" << llendl; + } + else + { + mGroundPool = new_poolp; + } + break; + + case LLDrawPool::POOL_WL_SKY: + if( mWLSkyPool ) + { + llassert(0); + llwarns << "LLPipeline::addPool(): Ignoring duplicate WLSky Pool" << llendl; + } + else + { + mWLSkyPool = new_poolp; + } + break; + + default: + llassert(0); + llwarns << "Invalid Pool Type in LLPipeline::addPool()" << llendl; + break; + } +} + +void LLPipeline::removePool( LLDrawPool* poolp ) +{ + assertInitialized(); + removeFromQuickLookup(poolp); + mPools.erase(poolp); + delete poolp; +} + +void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) +{ + assertInitialized(); + LLMemType mt(LLMemType::MTYPE_PIPELINE); + switch( poolp->getType() ) + { + case LLDrawPool::POOL_SIMPLE: + llassert(mSimplePool == poolp); + mSimplePool = NULL; + break; + + case LLDrawPool::POOL_GRASS: + llassert(mGrassPool == poolp); + mGrassPool = NULL; + break; + + case LLDrawPool::POOL_FULLBRIGHT: + llassert(mFullbrightPool == poolp); + mFullbrightPool = NULL; + break; + + case LLDrawPool::POOL_INVISIBLE: + llassert(mInvisiblePool == poolp); + mInvisiblePool = NULL; + break; + + case LLDrawPool::POOL_WL_SKY: + llassert(mWLSkyPool == poolp); + mWLSkyPool = NULL; + break; + + case LLDrawPool::POOL_GLOW: + llassert(mGlowPool == poolp); + mGlowPool = NULL; + break; + + case LLDrawPool::POOL_TREE: + #ifdef _DEBUG + { + BOOL found = mTreePools.erase( (uintptr_t)poolp->getTexture() ); + llassert( found ); + } + #else + mTreePools.erase( (uintptr_t)poolp->getTexture() ); + #endif + break; + + case LLDrawPool::POOL_TERRAIN: + #ifdef _DEBUG + { + BOOL found = mTerrainPools.erase( (uintptr_t)poolp->getTexture() ); + llassert( found ); + } + #else + mTerrainPools.erase( (uintptr_t)poolp->getTexture() ); + #endif + break; + + case LLDrawPool::POOL_BUMP: + llassert( poolp == mBumpPool ); + mBumpPool = NULL; + break; + + case LLDrawPool::POOL_ALPHA: + llassert( poolp == mAlphaPool ); + mAlphaPool = NULL; + break; + + case LLDrawPool::POOL_AVATAR: + break; // Do nothing + + case LLDrawPool::POOL_SKY: + llassert( poolp == mSkyPool ); + mSkyPool = NULL; + break; + + case LLDrawPool::POOL_WATER: + llassert( poolp == mWaterPool ); + mWaterPool = NULL; + break; + + case LLDrawPool::POOL_GROUND: + llassert( poolp == mGroundPool ); + mGroundPool = NULL; + break; + + default: + llassert(0); + llwarns << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << llendl; + break; + } +} + +void LLPipeline::resetDrawOrders() +{ + assertInitialized(); + // Iterate through all of the draw pools and rebuild them. + for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) + { + LLDrawPool *poolp = *iter; + poolp->resetDrawOrders(); + } +} + +//============================================================================ +// Once-per-frame setup of hardware lights, +// including sun/moon, avatar backlight, and up to 6 local lights + +void LLPipeline::setupAvatarLights(BOOL for_edit) +{ + assertInitialized(); + + if (for_edit) + { + LLColor4 diffuse(1.f, 1.f, 1.f, 0.f); + LLVector4 light_pos_cam(-8.f, 0.25f, 10.f, 0.f); // w==0 => directional light + LLMatrix4 camera_mat = LLViewerCamera::getInstance()->getModelview(); + LLMatrix4 camera_rot(camera_mat.getMat3()); + camera_rot.invert(); + LLVector4 light_pos = light_pos_cam * camera_rot; + + light_pos.normalize(); + + LLLightState* light = gGL.getLight(1); + + mHWLightColors[1] = diffuse; + + light->setDiffuse(diffuse); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); + light->setPosition(light_pos); + light->setConstantAttenuation(1.f); + light->setLinearAttenuation(0.f); + light->setQuadraticAttenuation(0.f); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + } + else if (gAvatarBacklight) // Always true (unless overridden in a devs .ini) + { + LLVector3 opposite_pos = -1.f * mSunDir; + LLVector3 orthog_light_pos = mSunDir % LLVector3::z_axis; + LLVector4 backlight_pos = LLVector4(lerp(opposite_pos, orthog_light_pos, 0.3f), 0.0f); + backlight_pos.normalize(); + + LLColor4 light_diffuse = mSunDiffuse; + LLColor4 backlight_diffuse(1.f - light_diffuse.mV[VRED], 1.f - light_diffuse.mV[VGREEN], 1.f - light_diffuse.mV[VBLUE], 1.f); + F32 max_component = 0.001f; + for (S32 i = 0; i < 3; i++) + { + if (backlight_diffuse.mV[i] > max_component) + { + max_component = backlight_diffuse.mV[i]; + } + } + F32 backlight_mag; + if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS) + { + backlight_mag = BACKLIGHT_DAY_MAGNITUDE_OBJECT; + } + else + { + backlight_mag = BACKLIGHT_NIGHT_MAGNITUDE_OBJECT; + } + backlight_diffuse *= backlight_mag / max_component; + + mHWLightColors[1] = backlight_diffuse; + + LLLightState* light = gGL.getLight(1); + + light->setPosition(backlight_pos); + light->setDiffuse(backlight_diffuse); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); + light->setConstantAttenuation(1.f); + light->setLinearAttenuation(0.f); + light->setQuadraticAttenuation(0.f); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + } + else + { + LLLightState* light = gGL.getLight(1); + + mHWLightColors[1] = LLColor4::black; + + light->setDiffuse(LLColor4::black); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); + } +} + +static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_dist) +{ + F32 inten = light->getLightIntensity(); + if (inten < .001f) + { + return max_dist; + } + F32 radius = light->getLightRadius(); + BOOL selected = light->isSelected(); + LLVector3 dpos = light->getRenderPosition() - cam_pos; + F32 dist2 = dpos.lengthSquared(); + if (!selected && dist2 > (max_dist + radius)*(max_dist + radius)) + { + return max_dist; + } + F32 dist = (F32) sqrt(dist2); + dist *= 1.f / inten; + dist -= radius; + if (selected) + { + dist -= 10000.f; // selected lights get highest priority + } + if (light->mDrawable.notNull() && light->mDrawable->isState(LLDrawable::ACTIVE)) + { + // moving lights get a little higher priority (too much causes artifacts) + dist -= light->getLightRadius()*0.25f; + } + return dist; +} + +void LLPipeline::calcNearbyLights(LLCamera& camera) +{ + assertInitialized(); + + if (LLPipeline::sReflectionRender) + { + return; + } + + if (mLightingDetail >= 1) + { + // mNearbyLight (and all light_set_t's) are sorted such that + // begin() == the closest light and rbegin() == the farthest light + const S32 MAX_LOCAL_LIGHTS = 6; +// LLVector3 cam_pos = gAgent.getCameraPositionAgent(); + LLVector3 cam_pos = LLViewerJoystick::getInstance()->getOverrideCamera() ? + camera.getOrigin() : + gAgent.getPositionAgent(); + + F32 max_dist = LIGHT_MAX_RADIUS * 4.f; // ignore enitrely lights > 4 * max light rad + + // UPDATE THE EXISTING NEARBY LIGHTS + light_set_t cur_nearby_lights; + for (light_set_t::iterator iter = mNearbyLights.begin(); + iter != mNearbyLights.end(); iter++) + { + const Light* light = &(*iter); + LLDrawable* drawable = light->drawable; + LLVOVolume* volight = drawable->getVOVolume(); + if (!volight || !drawable->isState(LLDrawable::LIGHT)) + { + drawable->clearState(LLDrawable::NEARBY_LIGHT); + continue; + } + if (light->fade <= -LIGHT_FADE_TIME) + { + drawable->clearState(LLDrawable::NEARBY_LIGHT); + continue; + } + if (!sRenderAttachedLights && volight && volight->isAttachment()) + { + drawable->clearState(LLDrawable::NEARBY_LIGHT); + continue; + } + + F32 dist = calc_light_dist(volight, cam_pos, max_dist); + cur_nearby_lights.insert(Light(drawable, dist, light->fade)); + } + mNearbyLights = cur_nearby_lights; + + // FIND NEW LIGHTS THAT ARE IN RANGE + light_set_t new_nearby_lights; + for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); + iter != mLights.end(); ++iter) + { + LLDrawable* drawable = *iter; + LLVOVolume* light = drawable->getVOVolume(); + if (!light || drawable->isState(LLDrawable::NEARBY_LIGHT)) + { + continue; + } + if (light->isHUDAttachment()) + { + continue; // no lighting from HUD objects + } + F32 dist = calc_light_dist(light, cam_pos, max_dist); + if (dist >= max_dist) + { + continue; + } + if (!sRenderAttachedLights && light && light->isAttachment()) + { + continue; + } + new_nearby_lights.insert(Light(drawable, dist, 0.f)); + if (new_nearby_lights.size() > (U32)MAX_LOCAL_LIGHTS) + { + new_nearby_lights.erase(--new_nearby_lights.end()); + const Light& last = *new_nearby_lights.rbegin(); + max_dist = last.dist; + } + } + + // INSERT ANY NEW LIGHTS + for (light_set_t::iterator iter = new_nearby_lights.begin(); + iter != new_nearby_lights.end(); iter++) + { + const Light* light = &(*iter); + if (mNearbyLights.size() < (U32)MAX_LOCAL_LIGHTS) + { + mNearbyLights.insert(*light); + ((LLDrawable*) light->drawable)->setState(LLDrawable::NEARBY_LIGHT); + } + else + { + // crazy cast so that we can overwrite the fade value + // even though gcc enforces sets as const + // (fade value doesn't affect sort so this is safe) + Light* farthest_light = ((Light*) (&(*(mNearbyLights.rbegin())))); + if (light->dist < farthest_light->dist) + { + if (farthest_light->fade >= 0.f) + { + farthest_light->fade = -gFrameIntervalSeconds; + } + } + else + { + break; // none of the other lights are closer + } + } + } + + } +} + +void LLPipeline::setupHWLights(LLDrawPool* pool) +{ + assertInitialized(); + + // Ambient + if (!LLGLSLShader::sNoFixedFunction) + { + gGL.syncMatrices(); + LLColor4 ambient = gSky.getTotalAmbientColor(); + gGL.setAmbientLightColor(ambient); + } + + // Light 0 = Sun or Moon (All objects) + { + if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS) + { + mSunDir.setVec(gSky.getSunDirection()); + mSunDiffuse.setVec(gSky.getSunDiffuseColor()); + } + else + { + mSunDir.setVec(gSky.getMoonDirection()); + mSunDiffuse.setVec(gSky.getMoonDiffuseColor()); + } + + F32 max_color = llmax(mSunDiffuse.mV[0], mSunDiffuse.mV[1], mSunDiffuse.mV[2]); + if (max_color > 1.f) + { + mSunDiffuse *= 1.f/max_color; + } + mSunDiffuse.clamp(); + + LLVector4 light_pos(mSunDir, 0.0f); + LLColor4 light_diffuse = mSunDiffuse; + mHWLightColors[0] = light_diffuse; + + LLLightState* light = gGL.getLight(0); + light->setPosition(light_pos); + light->setDiffuse(light_diffuse); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); + light->setConstantAttenuation(1.f); + light->setLinearAttenuation(0.f); + light->setQuadraticAttenuation(0.f); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + } + + // Light 1 = Backlight (for avatars) + // (set by enableLightsAvatar) + + S32 cur_light = 2; + + // Nearby lights = LIGHT 2-7 + + mLightMovingMask = 0; + + if (mLightingDetail >= 1) + { + for (light_set_t::iterator iter = mNearbyLights.begin(); + iter != mNearbyLights.end(); ++iter) + { + LLDrawable* drawable = iter->drawable; + LLVOVolume* light = drawable->getVOVolume(); + if (!light) + { + continue; + } + if (drawable->isState(LLDrawable::ACTIVE)) + { + mLightMovingMask |= (1<<cur_light); + } + + LLColor4 light_color = light->getLightColor(); + light_color.mV[3] = 0.0f; + + F32 fade = iter->fade; + if (fade < LIGHT_FADE_TIME) + { + // fade in/out light + if (fade >= 0.f) + { + fade = fade / LIGHT_FADE_TIME; + ((Light*) (&(*iter)))->fade += gFrameIntervalSeconds; + } + else + { + fade = 1.f + fade / LIGHT_FADE_TIME; + ((Light*) (&(*iter)))->fade -= gFrameIntervalSeconds; + } + fade = llclamp(fade,0.f,1.f); + light_color *= fade; + } + + LLVector3 light_pos(light->getRenderPosition()); + LLVector4 light_pos_gl(light_pos, 1.0f); + + F32 light_radius = llmax(light->getLightRadius(), 0.001f); + + F32 x = (3.f * (1.f + light->getLightFalloff())); // why this magic? probably trying to match a historic behavior. + float linatten = x / (light_radius); // % of brightness at radius + + mHWLightColors[cur_light] = light_color; + LLLightState* light_state = gGL.getLight(cur_light); + + light_state->setPosition(light_pos_gl); + light_state->setDiffuse(light_color); + light_state->setAmbient(LLColor4::black); + light_state->setConstantAttenuation(0.f); + if (sRenderDeferred) + { + light_state->setLinearAttenuation(light_radius*1.5f); + light_state->setQuadraticAttenuation(light->getLightFalloff()*0.5f+1.f); + } + else + { + light_state->setLinearAttenuation(linatten); + light_state->setQuadraticAttenuation(0.f); + } + + + if (light->isLightSpotlight() // directional (spot-)light + && (LLPipeline::sRenderDeferred || RenderSpotLightsInNondeferred)) // these are only rendered as GL spotlights if we're in deferred rendering mode *or* the setting forces them on + { + LLVector3 spotparams = light->getSpotLightParams(); + LLQuaternion quat = light->getRenderRotation(); + LLVector3 at_axis(0,0,-1); // this matches deferred rendering's object light direction + at_axis *= quat; + + light_state->setSpotDirection(at_axis); + light_state->setSpotCutoff(90.f); + light_state->setSpotExponent(2.f); + + light_state->setSpecular(LLColor4::black); + } + else // omnidirectional (point) light + { + light_state->setSpotExponent(0.f); + light_state->setSpotCutoff(180.f); + + // we use specular.w = 1.0 as a cheap hack for the shaders to know that this is omnidirectional rather than a spotlight + const LLColor4 specular(0.f, 0.f, 0.f, 1.f); + light_state->setSpecular(specular); + } + cur_light++; + if (cur_light >= 8) + { + break; // safety + } + } + } + for ( ; cur_light < 8 ; cur_light++) + { + mHWLightColors[cur_light] = LLColor4::black; + LLLightState* light = gGL.getLight(cur_light); + + light->setDiffuse(LLColor4::black); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); + } + if (gAgentAvatarp && + gAgentAvatarp->mSpecialRenderMode == 3) + { + LLColor4 light_color = LLColor4::white; + light_color.mV[3] = 0.0f; + + LLVector3 light_pos(LLViewerCamera::getInstance()->getOrigin()); + LLVector4 light_pos_gl(light_pos, 1.0f); + + F32 light_radius = 16.f; + + F32 x = 3.f; + float linatten = x / (light_radius); // % of brightness at radius + + mHWLightColors[2] = light_color; + LLLightState* light = gGL.getLight(2); + + light->setPosition(light_pos_gl); + light->setDiffuse(light_color); + light->setAmbient(LLColor4::black); + light->setSpecular(LLColor4::black); + light->setQuadraticAttenuation(0.f); + light->setConstantAttenuation(0.f); + light->setLinearAttenuation(linatten); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + } + + // Init GL state + if (!LLGLSLShader::sNoFixedFunction) + { + glDisable(GL_LIGHTING); + } + + for (S32 i = 0; i < 8; ++i) + { + gGL.getLight(i)->disable(); + } + mLightMask = 0; +} + +void LLPipeline::enableLights(U32 mask) +{ + assertInitialized(); + + if (mLightingDetail == 0) + { + mask &= 0xf003; // sun and backlight only (and fullbright bit) + } + if (mLightMask != mask) + { + stop_glerror(); + if (!mLightMask) + { + if (!LLGLSLShader::sNoFixedFunction) + { + glEnable(GL_LIGHTING); + } + } + if (mask) + { + stop_glerror(); + for (S32 i=0; i<8; i++) + { + LLLightState* light = gGL.getLight(i); + if (mask & (1<<i)) + { + light->enable(); + light->setDiffuse(mHWLightColors[i]); + } + else + { + light->disable(); + light->setDiffuse(LLColor4::black); + } + } + stop_glerror(); + } + else + { + if (!LLGLSLShader::sNoFixedFunction) + { + glDisable(GL_LIGHTING); + } + } + mLightMask = mask; + stop_glerror(); + + LLColor4 ambient = gSky.getTotalAmbientColor(); + gGL.setAmbientLightColor(ambient); + } +} + +void LLPipeline::enableLightsStatic() +{ + assertInitialized(); + U32 mask = 0x01; // Sun + if (mLightingDetail >= 2) + { + mask |= mLightMovingMask; // Hardware moving lights + } + else + { + mask |= 0xff & (~2); // Hardware local lights + } + enableLights(mask); +} + +void LLPipeline::enableLightsDynamic() +{ + assertInitialized(); + U32 mask = 0xff & (~2); // Local lights + enableLights(mask); + + if (isAgentAvatarValid() && getLightingDetail() <= 0) + { + if (gAgentAvatarp->mSpecialRenderMode == 0) // normal + { + gPipeline.enableLightsAvatar(); + } + else if (gAgentAvatarp->mSpecialRenderMode >= 1) // anim preview + { + gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f)); + } + } +} + +void LLPipeline::enableLightsAvatar() +{ + U32 mask = 0xff; // All lights + setupAvatarLights(FALSE); + enableLights(mask); +} + +void LLPipeline::enableLightsPreview() +{ + disableLights(); + + if (!LLGLSLShader::sNoFixedFunction) + { + glEnable(GL_LIGHTING); + } + + LLColor4 ambient = PreviewAmbientColor; + gGL.setAmbientLightColor(ambient); + + LLColor4 diffuse0 = PreviewDiffuse0; + LLColor4 specular0 = PreviewSpecular0; + LLColor4 diffuse1 = PreviewDiffuse1; + LLColor4 specular1 = PreviewSpecular1; + LLColor4 diffuse2 = PreviewDiffuse2; + LLColor4 specular2 = PreviewSpecular2; + + LLVector3 dir0 = PreviewDirection0; + LLVector3 dir1 = PreviewDirection1; + LLVector3 dir2 = PreviewDirection2; + + dir0.normVec(); + dir1.normVec(); + dir2.normVec(); + + LLVector4 light_pos(dir0, 0.0f); + + LLLightState* light = gGL.getLight(0); + + light->enable(); + light->setPosition(light_pos); + light->setDiffuse(diffuse0); + light->setAmbient(LLColor4::black); + light->setSpecular(specular0); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + + light_pos = LLVector4(dir1, 0.f); + + light = gGL.getLight(1); + light->enable(); + light->setPosition(light_pos); + light->setDiffuse(diffuse1); + light->setAmbient(LLColor4::black); + light->setSpecular(specular1); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + + light_pos = LLVector4(dir2, 0.f); + light = gGL.getLight(2); + light->enable(); + light->setPosition(light_pos); + light->setDiffuse(diffuse2); + light->setAmbient(LLColor4::black); + light->setSpecular(specular2); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); +} + + +void LLPipeline::enableLightsAvatarEdit(const LLColor4& color) +{ + U32 mask = 0x2002; // Avatar backlight only, set ambient + setupAvatarLights(TRUE); + enableLights(mask); + + gGL.setAmbientLightColor(color); +} + +void LLPipeline::enableLightsFullbright(const LLColor4& color) +{ + assertInitialized(); + U32 mask = 0x1000; // Non-0 mask, set ambient + enableLights(mask); + + gGL.setAmbientLightColor(color); +} + +void LLPipeline::disableLights() +{ + enableLights(0); // no lighting (full bright) +} + +//============================================================================ + +class LLMenuItemGL; +class LLInvFVBridge; +struct cat_folder_pair; +class LLVOBranch; +class LLVOLeaf; + +void LLPipeline::findReferences(LLDrawable *drawablep) +{ + assertInitialized(); + if (mLights.find(drawablep) != mLights.end()) + { + llinfos << "In mLights" << llendl; + } + if (std::find(mMovedList.begin(), mMovedList.end(), drawablep) != mMovedList.end()) + { + llinfos << "In mMovedList" << llendl; + } + if (std::find(mShiftList.begin(), mShiftList.end(), drawablep) != mShiftList.end()) + { + llinfos << "In mShiftList" << llendl; + } + if (mRetexturedList.find(drawablep) != mRetexturedList.end()) + { + llinfos << "In mRetexturedList" << llendl; + } + + if (std::find(mBuildQ1.begin(), mBuildQ1.end(), drawablep) != mBuildQ1.end()) + { + llinfos << "In mBuildQ1" << llendl; + } + if (std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep) != mBuildQ2.end()) + { + llinfos << "In mBuildQ2" << llendl; + } + + S32 count; + + count = gObjectList.findReferences(drawablep); + if (count) + { + llinfos << "In other drawables: " << count << " references" << llendl; + } +} + +BOOL LLPipeline::verify() +{ + BOOL ok = assertInitialized(); + if (ok) + { + for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) + { + LLDrawPool *poolp = *iter; + if (!poolp->verify()) + { + ok = FALSE; + } + } + } + + if (!ok) + { + llwarns << "Pipeline verify failed!" << llendl; + } + return ok; +} + +////////////////////////////// +// +// Collision detection +// +// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * A method to compute a ray-AABB intersection. + * Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990 + * Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500) + * Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only) + * + * Hence this version is faster as well as more robust than the original one. + * + * Should work provided: + * 1) the integer representation of 0.0f is 0x00000000 + * 2) the sign bit of the float is the most significant one + * + * Report bugs: p.terdiman@codercorner.com + * + * \param aabb [in] the axis-aligned bounding box + * \param origin [in] ray origin + * \param dir [in] ray direction + * \param coord [out] impact coordinates + * \return true if ray intersects AABB + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//#define RAYAABB_EPSILON 0.00001f +#define IR(x) ((U32&)x) + +bool LLRayAABB(const LLVector3 ¢er, const LLVector3 &size, const LLVector3& origin, const LLVector3& dir, LLVector3 &coord, F32 epsilon) +{ + BOOL Inside = TRUE; + LLVector3 MinB = center - size; + LLVector3 MaxB = center + size; + LLVector3 MaxT; + MaxT.mV[VX]=MaxT.mV[VY]=MaxT.mV[VZ]=-1.0f; + + // Find candidate planes. + for(U32 i=0;i<3;i++) + { + if(origin.mV[i] < MinB.mV[i]) + { + coord.mV[i] = MinB.mV[i]; + Inside = FALSE; + + // Calculate T distances to candidate planes + if(IR(dir.mV[i])) MaxT.mV[i] = (MinB.mV[i] - origin.mV[i]) / dir.mV[i]; + } + else if(origin.mV[i] > MaxB.mV[i]) + { + coord.mV[i] = MaxB.mV[i]; + Inside = FALSE; + + // Calculate T distances to candidate planes + if(IR(dir.mV[i])) MaxT.mV[i] = (MaxB.mV[i] - origin.mV[i]) / dir.mV[i]; + } + } + + // Ray origin inside bounding box + if(Inside) + { + coord = origin; + return true; + } + + // Get largest of the maxT's for final choice of intersection + U32 WhichPlane = 0; + if(MaxT.mV[1] > MaxT.mV[WhichPlane]) WhichPlane = 1; + if(MaxT.mV[2] > MaxT.mV[WhichPlane]) WhichPlane = 2; + + // Check final candidate actually inside box + if(IR(MaxT.mV[WhichPlane])&0x80000000) return false; + + for(U32 i=0;i<3;i++) + { + if(i!=WhichPlane) + { + coord.mV[i] = origin.mV[i] + MaxT.mV[WhichPlane] * dir.mV[i]; + if (epsilon > 0) + { + if(coord.mV[i] < MinB.mV[i] - epsilon || coord.mV[i] > MaxB.mV[i] + epsilon) return false; + } + else + { + if(coord.mV[i] < MinB.mV[i] || coord.mV[i] > MaxB.mV[i]) return false; + } + } + } + return true; // ray hits box +} + +////////////////////////////// +// +// Macros, functions, and inline methods from other classes +// +// + +void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light) +{ + if (drawablep && assertInitialized()) + { + if (is_light) + { + mLights.insert(drawablep); + drawablep->setState(LLDrawable::LIGHT); + } + else + { + drawablep->clearState(LLDrawable::LIGHT); + mLights.erase(drawablep); + } + } +} + +//static +void LLPipeline::toggleRenderType(U32 type) +{ + gPipeline.mRenderTypeEnabled[type] = !gPipeline.mRenderTypeEnabled[type]; + if (type == LLPipeline::RENDER_TYPE_WATER) + { + gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER] = !gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER]; + } +} + +//static +void LLPipeline::toggleRenderTypeControl(void* data) +{ + U32 type = (U32)(intptr_t)data; + U32 bit = (1<<type); + if (gPipeline.hasRenderType(type)) + { + llinfos << "Toggling render type mask " << std::hex << bit << " off" << std::dec << llendl; + } + else + { + llinfos << "Toggling render type mask " << std::hex << bit << " on" << std::dec << llendl; + } + gPipeline.toggleRenderType(type); +} + +//static +BOOL LLPipeline::hasRenderTypeControl(void* data) +{ + U32 type = (U32)(intptr_t)data; + return gPipeline.hasRenderType(type); +} + +// Allows UI items labeled "Hide foo" instead of "Show foo" +//static +BOOL LLPipeline::toggleRenderTypeControlNegated(void* data) +{ + S32 type = (S32)(intptr_t)data; + return !gPipeline.hasRenderType(type); +} + +//static +void LLPipeline::toggleRenderDebug(void* data) +{ + U32 bit = (U32)(intptr_t)data; + if (gPipeline.hasRenderDebugMask(bit)) + { + llinfos << "Toggling render debug mask " << std::hex << bit << " off" << std::dec << llendl; + } + else + { + llinfos << "Toggling render debug mask " << std::hex << bit << " on" << std::dec << llendl; + } + gPipeline.mRenderDebugMask ^= bit; +} + + +//static +BOOL LLPipeline::toggleRenderDebugControl(void* data) +{ + U32 bit = (U32)(intptr_t)data; + return gPipeline.hasRenderDebugMask(bit); +} + +//static +void LLPipeline::toggleRenderDebugFeature(void* data) +{ + U32 bit = (U32)(intptr_t)data; + gPipeline.mRenderDebugFeatureMask ^= bit; +} + + +//static +BOOL LLPipeline::toggleRenderDebugFeatureControl(void* data) +{ + U32 bit = (U32)(intptr_t)data; + return gPipeline.hasRenderDebugFeatureMask(bit); +} + +void LLPipeline::setRenderDebugFeatureControl(U32 bit, bool value) +{ + if (value) + { + gPipeline.mRenderDebugFeatureMask |= bit; + } + else + { + gPipeline.mRenderDebugFeatureMask &= !bit; + } +} + +// static +void LLPipeline::setRenderScriptedBeacons(BOOL val) +{ + sRenderScriptedBeacons = val; +} + +// static +void LLPipeline::toggleRenderScriptedBeacons(void*) +{ + sRenderScriptedBeacons = !sRenderScriptedBeacons; +} + +// static +BOOL LLPipeline::getRenderScriptedBeacons(void*) +{ + return sRenderScriptedBeacons; +} + +// static +void LLPipeline::setRenderScriptedTouchBeacons(BOOL val) +{ + sRenderScriptedTouchBeacons = val; +} + +// static +void LLPipeline::toggleRenderScriptedTouchBeacons(void*) +{ + sRenderScriptedTouchBeacons = !sRenderScriptedTouchBeacons; +} + +// static +BOOL LLPipeline::getRenderScriptedTouchBeacons(void*) +{ + return sRenderScriptedTouchBeacons; +} + +// static +void LLPipeline::setRenderMOAPBeacons(BOOL val) +{ + sRenderMOAPBeacons = val; +} + +// static +void LLPipeline::toggleRenderMOAPBeacons(void*) +{ + sRenderMOAPBeacons = !sRenderMOAPBeacons; +} + +// static +BOOL LLPipeline::getRenderMOAPBeacons(void*) +{ + return sRenderMOAPBeacons; +} + +// static +void LLPipeline::setRenderPhysicalBeacons(BOOL val) +{ + sRenderPhysicalBeacons = val; +} + +// static +void LLPipeline::toggleRenderPhysicalBeacons(void*) +{ + sRenderPhysicalBeacons = !sRenderPhysicalBeacons; +} + +// static +BOOL LLPipeline::getRenderPhysicalBeacons(void*) +{ + return sRenderPhysicalBeacons; +} + +// static +void LLPipeline::setRenderParticleBeacons(BOOL val) +{ + sRenderParticleBeacons = val; +} + +// static +void LLPipeline::toggleRenderParticleBeacons(void*) +{ + sRenderParticleBeacons = !sRenderParticleBeacons; +} + +// static +BOOL LLPipeline::getRenderParticleBeacons(void*) +{ + return sRenderParticleBeacons; +} + +// static +void LLPipeline::setRenderSoundBeacons(BOOL val) +{ + sRenderSoundBeacons = val; +} + +// static +void LLPipeline::toggleRenderSoundBeacons(void*) +{ + sRenderSoundBeacons = !sRenderSoundBeacons; +} + +// static +BOOL LLPipeline::getRenderSoundBeacons(void*) +{ + return sRenderSoundBeacons; +} + +// static +void LLPipeline::setRenderBeacons(BOOL val) +{ + sRenderBeacons = val; +} + +// static +void LLPipeline::toggleRenderBeacons(void*) +{ + sRenderBeacons = !sRenderBeacons; +} + +// static +BOOL LLPipeline::getRenderBeacons(void*) +{ + return sRenderBeacons; +} + +// static +void LLPipeline::setRenderHighlights(BOOL val) +{ + sRenderHighlight = val; +} + +// static +void LLPipeline::toggleRenderHighlights(void*) +{ + sRenderHighlight = !sRenderHighlight; +} + +// static +BOOL LLPipeline::getRenderHighlights(void*) +{ + return sRenderHighlight; +} + +LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end, + BOOL pick_transparent, + S32* face_hit, + LLVector3* intersection, // return the intersection point + LLVector2* tex_coord, // return the texture coordinates of the intersection point + LLVector3* normal, // return the surface normal at the intersection point + LLVector3* bi_normal // return the surface bi-normal at the intersection point + ) +{ + LLDrawable* drawable = NULL; + + LLVector3 local_end = end; + + LLVector3 position; + + sPickAvatar = FALSE; //LLToolMgr::getInstance()->inBuildMode() ? FALSE : TRUE; + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + + for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++) + { + if ((j == LLViewerRegion::PARTITION_VOLUME) || + (j == LLViewerRegion::PARTITION_BRIDGE) || + (j == LLViewerRegion::PARTITION_TERRAIN) || + (j == LLViewerRegion::PARTITION_TREE) || + (j == LLViewerRegion::PARTITION_GRASS)) // only check these partitions for now + { + LLSpatialPartition* part = region->getSpatialPartition(j); + if (part && hasRenderType(part->mDrawableType)) + { + LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal); + if (hit) + { + drawable = hit; + local_end = position; + } + } + } + } + } + + if (!sPickAvatar) + { + //save hit info in case we need to restore + //due to attachment override + LLVector3 local_normal; + LLVector3 local_binormal; + LLVector2 local_texcoord; + S32 local_face_hit = -1; + + if (face_hit) + { + local_face_hit = *face_hit; + } + if (tex_coord) + { + local_texcoord = *tex_coord; + } + if (bi_normal) + { + local_binormal = *bi_normal; + } + if (normal) + { + local_normal = *normal; + } + + const F32 ATTACHMENT_OVERRIDE_DIST = 0.1f; + + //check against avatars + sPickAvatar = TRUE; + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + + LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_BRIDGE); + if (part && hasRenderType(part->mDrawableType)) + { + LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal); + if (hit) + { + if (!drawable || + !drawable->getVObj()->isAttachment() || + (position-local_end).magVec() > ATTACHMENT_OVERRIDE_DIST) + { //avatar overrides if previously hit drawable is not an attachment or + //attachment is far enough away from detected intersection + drawable = hit; + local_end = position; + } + else + { //prioritize attachments over avatars + position = local_end; + + if (face_hit) + { + *face_hit = local_face_hit; + } + if (tex_coord) + { + *tex_coord = local_texcoord; + } + if (bi_normal) + { + *bi_normal = local_binormal; + } + if (normal) + { + *normal = local_normal; + } + } + } + } + } + } + + //check all avatar nametags (silly, isn't it?) + for (std::vector< LLCharacter* >::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); + ++iter) + { + LLVOAvatar* av = (LLVOAvatar*) *iter; + if (av->mNameText.notNull() + && av->mNameText->lineSegmentIntersect(start, local_end, position)) + { + drawable = av->mDrawable; + local_end = position; + } + } + + if (intersection) + { + *intersection = position; + } + + return drawable ? drawable->getVObj().get() : NULL; +} + +LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector3& start, const LLVector3& end, + BOOL pick_transparent, + S32* face_hit, + LLVector3* intersection, // return the intersection point + LLVector2* tex_coord, // return the texture coordinates of the intersection point + LLVector3* normal, // return the surface normal at the intersection point + LLVector3* bi_normal // return the surface bi-normal at the intersection point + ) +{ + LLDrawable* drawable = NULL; + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + + BOOL toggle = FALSE; + if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { + toggleRenderType(LLPipeline::RENDER_TYPE_HUD); + toggle = TRUE; + } + + LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_HUD); + if (part) + { + LLDrawable* hit = part->lineSegmentIntersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal); + if (hit) + { + drawable = hit; + } + } + + if (toggle) + { + toggleRenderType(LLPipeline::RENDER_TYPE_HUD); + } + } + return drawable ? drawable->getVObj().get() : NULL; +} + +LLSpatialPartition* LLPipeline::getSpatialPartition(LLViewerObject* vobj) +{ + if (vobj) + { + LLViewerRegion* region = vobj->getRegion(); + if (region) + { + return region->getSpatialPartition(vobj->getPartitionType()); + } + } + return NULL; +} + +void LLPipeline::resetVertexBuffers(LLDrawable* drawable) +{ + if (!drawable || drawable->isDead()) + { + return; + } + + for (S32 i = 0; i < drawable->getNumFaces(); i++) + { + LLFace* facep = drawable->getFace(i); + facep->clearVertexBuffer(); + } +} + +void LLPipeline::resetVertexBuffers() +{ + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + part->resetVertexBuffers(); + } + } + } + + resetDrawOrders(); + + gSky.resetVertexBuffers(); + + if ( LLPathingLib::getInstance() ) + { + LLPathingLib::getInstance()->cleanupVBOManger(); + } + LLVertexBuffer::cleanupClass(); + + //delete all name pool caches + LLGLNamePool::cleanupPools(); + + if (LLVertexBuffer::sGLCount > 0) + { + llwarns << "VBO wipe failed." << llendl; + } + + llassert(LLVertexBuffer::sGLCount == 0); + + LLVertexBuffer::unbind(); + + sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); + sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips"); + LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO"); + LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO"); + LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw"); + LLVertexBuffer::sEnableVBOs = gSavedSettings.getBOOL("RenderVBOEnable"); + LLVertexBuffer::sDisableVBOMapping = LLVertexBuffer::sEnableVBOs && gSavedSettings.getBOOL("RenderVBOMappingDisable") ; + sBakeSunlight = gSavedSettings.getBOOL("RenderBakeSunlight"); + sNoAlpha = gSavedSettings.getBOOL("RenderNoAlpha"); + LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind"); + + LLVertexBuffer::initClass(LLVertexBuffer::sEnableVBOs, LLVertexBuffer::sDisableVBOMapping); +} + +void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture, BOOL batch_texture) +{ + LLMemType mt_ro(LLMemType::MTYPE_PIPELINE_RENDER_OBJECTS); + assertInitialized(); + gGL.loadMatrix(gGLModelView); + gGLLastMatrix = NULL; + mSimplePool->pushBatches(type, mask, texture, batch_texture); + gGL.loadMatrix(gGLModelView); + gGLLastMatrix = NULL; +} + +void apply_cube_face_rotation(U32 face) +{ + switch (face) + { + case 0: + gGL.rotatef(90.f, 0, 1, 0); + gGL.rotatef(180.f, 1, 0, 0); + break; + case 2: + gGL.rotatef(-90.f, 1, 0, 0); + break; + case 4: + gGL.rotatef(180.f, 0, 1, 0); + gGL.rotatef(180.f, 0, 0, 1); + break; + case 1: + gGL.rotatef(-90.f, 0, 1, 0); + gGL.rotatef(180.f, 1, 0, 0); + break; + case 3: + gGL.rotatef(90, 1, 0, 0); + break; + case 5: + gGL.rotatef(180, 0, 0, 1); + break; + } +} + +void validate_framebuffer_object() +{ + GLenum status; + status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT); + switch(status) + { + case GL_FRAMEBUFFER_COMPLETE: + //framebuffer OK, no error. + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + // frame buffer not OK: probably means unsupported depth buffer format + llerrs << "Framebuffer Incomplete Missing Attachment." << llendl; + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + // frame buffer not OK: probably means unsupported depth buffer format + llerrs << "Framebuffer Incomplete Attachment." << llendl; + break; + case GL_FRAMEBUFFER_UNSUPPORTED: + /* choose different formats */ + llerrs << "Framebuffer unsupported." << llendl; + break; + default: + llerrs << "Unknown framebuffer status." << llendl; + break; + } +} + +void LLPipeline::bindScreenToTexture() +{ + +} + +static LLFastTimer::DeclareTimer FTM_RENDER_BLOOM("Bloom"); + +void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) +{ + LLMemType mt_ru(LLMemType::MTYPE_PIPELINE_RENDER_BLOOM); + if (!(gPipeline.canUseVertexShaders() && + sRenderGlow)) + { + return; + } + + LLVertexBuffer::unbind(); + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + + assertInitialized(); + + if (gUseWireframe) + { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + + LLVector2 tc1(0,0); + LLVector2 tc2((F32) mScreen.getWidth()*2, + (F32) mScreen.getHeight()*2); + + LLFastTimer ftm(FTM_RENDER_BLOOM); + gGL.color4f(1,1,1,1); + LLGLDepthTest depth(GL_FALSE); + LLGLDisable blend(GL_BLEND); + LLGLDisable cull(GL_CULL_FACE); + + enableLightsFullbright(LLColor4(1,1,1,1)); + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadIdentity(); + + LLGLDisable test(GL_ALPHA_TEST); + + gGL.setColorMask(true, true); + glClearColor(0,0,0,0); + + { + { + LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); + mGlow[2].bindTarget(); + mGlow[2].clear(); + } + + gGlowExtractProgram.bind(); + F32 minLum = llmax((F32) RenderGlowMinLuminance, 0.0f); + F32 maxAlpha = RenderGlowMaxExtractAlpha; + F32 warmthAmount = RenderGlowWarmthAmount; + LLVector3 lumWeights = RenderGlowLumWeights; + LLVector3 warmthWeights = RenderGlowWarmthWeights; + + + gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MIN_LUMINANCE, minLum); + gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MAX_EXTRACT_ALPHA, maxAlpha); + gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_LUM_WEIGHTS, lumWeights.mV[0], lumWeights.mV[1], lumWeights.mV[2]); + gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_WARMTH_WEIGHTS, warmthWeights.mV[0], warmthWeights.mV[1], warmthWeights.mV[2]); + gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_WARMTH_AMOUNT, warmthAmount); + LLGLEnable blend_on(GL_BLEND); + LLGLEnable test(GL_ALPHA_TEST); + + gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); + + mScreen.bindTexture(0, 0); + + gGL.color4f(1,1,1,1); + gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1,-1); + + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1,3); + + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3,-1); + + gGL.end(); + + gGL.getTexUnit(0)->unbind(mScreen.getUsage()); + + mGlow[2].flush(); + } + + tc1.setVec(0,0); + tc2.setVec(2,2); + + // power of two between 1 and 1024 + U32 glowResPow = RenderGlowResolutionPow; + const U32 glow_res = llmax(1, + llmin(1024, 1 << glowResPow)); + + S32 kernel = RenderGlowIterations*2; + F32 delta = RenderGlowWidth / glow_res; + // Use half the glow width if we have the res set to less than 9 so that it looks + // almost the same in either case. + if (glowResPow < 9) + { + delta *= 0.5f; + } + F32 strength = RenderGlowStrength; + + gGlowProgram.bind(); + gGlowProgram.uniform1f(LLShaderMgr::GLOW_STRENGTH, strength); + + for (S32 i = 0; i < kernel; i++) + { + { + LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); + mGlow[i%2].bindTarget(); + mGlow[i%2].clear(); + } + + if (i == 0) + { + gGL.getTexUnit(0)->bind(&mGlow[2]); + } + else + { + gGL.getTexUnit(0)->bind(&mGlow[(i-1)%2]); + } + + if (i%2 == 0) + { + gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, delta, 0); + } + else + { + gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, 0, delta); + } + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1,-1); + + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1,3); + + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3,-1); + + gGL.end(); + + mGlow[i%2].flush(); + } + + gGlowProgram.unbind(); + + if (LLRenderTarget::sUseFBO) + { + LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; + gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; + gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); + gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); + glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); + + tc2.setVec((F32) mScreen.getWidth(), + (F32) mScreen.getHeight()); + + gGL.flush(); + + LLVertexBuffer::unbind(); + + if (LLPipeline::sRenderDeferred) + { + + bool dof_enabled = !LLViewerCamera::getInstance()->cameraUnderWater() && + !LLToolMgr::getInstance()->inBuildMode() && + RenderDepthOfField; + + + bool multisample = RenderFSAASamples > 1 && mFXAABuffer.isComplete(); + + gViewerWindow->setup3DViewport(); + + if (dof_enabled) + { + LLGLSLShader* shader = &gDeferredPostProgram; + LLGLDisable blend(GL_BLEND); + + //depth of field focal plane calculations + static F32 current_distance = 16.f; + static F32 start_distance = 16.f; + static F32 transition_time = 1.f; + + LLVector3 focus_point; + + LLViewerObject* obj = LLViewerMediaFocus::getInstance()->getFocusedObject(); + if (obj && obj->mDrawable && obj->isSelected()) + { //focus on selected media object + S32 face_idx = LLViewerMediaFocus::getInstance()->getFocusedFace(); + if (obj && obj->mDrawable) + { + LLFace* face = obj->mDrawable->getFace(face_idx); + if (face) + { + focus_point = face->getPositionAgent(); + } + } + } + + if (focus_point.isExactlyZero()) + { + if (LLViewerJoystick::getInstance()->getOverrideCamera()) + { //focus on point under cursor + focus_point = gDebugRaycastIntersection; + } + else if (gAgentCamera.cameraMouselook()) + { //focus on point under mouselook crosshairs + gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, + NULL, + &focus_point); + } + else + { + LLViewerObject* obj = gAgentCamera.getFocusObject(); + if (obj) + { //focus on alt-zoom target + focus_point = LLVector3(gAgentCamera.getFocusGlobal()-gAgent.getRegion()->getOriginGlobal()); + } + else + { //focus on your avatar + focus_point = gAgent.getPositionAgent(); + } + } + } + + LLVector3 eye = LLViewerCamera::getInstance()->getOrigin(); + F32 target_distance = 16.f; + if (!focus_point.isExactlyZero()) + { + target_distance = LLViewerCamera::getInstance()->getAtAxis() * (focus_point-eye); + } + + if (transition_time >= 1.f && + fabsf(current_distance-target_distance)/current_distance > 0.01f) + { //large shift happened, interpolate smoothly to new target distance + transition_time = 0.f; + start_distance = current_distance; + } + else if (transition_time < 1.f) + { //currently in a transition, continue interpolating + transition_time += 1.f/CameraFocusTransitionTime*gFrameIntervalSeconds; + transition_time = llmin(transition_time, 1.f); + + F32 t = cosf(transition_time*F_PI+F_PI)*0.5f+0.5f; + current_distance = start_distance + (target_distance-start_distance)*t; + } + else + { //small or no change, just snap to target distance + current_distance = target_distance; + } + + //convert to mm + F32 subject_distance = current_distance*1000.f; + F32 fnumber = CameraFNumber; + F32 default_focal_length = CameraFocalLength; + + F32 fov = LLViewerCamera::getInstance()->getView(); + + const F32 default_fov = CameraFieldOfView * F_PI/180.f; + //const F32 default_aspect_ratio = gSavedSettings.getF32("CameraAspectRatio"); + + //F32 aspect_ratio = (F32) mScreen.getWidth()/(F32)mScreen.getHeight(); + + F32 dv = 2.f*default_focal_length * tanf(default_fov/2.f); + //F32 dh = 2.f*default_focal_length * tanf(default_fov*default_aspect_ratio/2.f); + + F32 focal_length = dv/(2*tanf(fov/2.f)); + + //F32 tan_pixel_angle = tanf(LLDrawable::sCurPixelAngle); + + // from wikipedia -- c = |s2-s1|/s2 * f^2/(N(S1-f)) + // where N = fnumber + // s2 = dot distance + // s1 = subject distance + // f = focal length + // + + F32 blur_constant = focal_length*focal_length/(fnumber*(subject_distance-focal_length)); + blur_constant /= 1000.f; //convert to meters for shader + F32 magnification = focal_length/(subject_distance-focal_length); + + { //build diffuse+bloom+CoF + mDeferredLight.bindTarget(); + shader = &gDeferredCoFProgram; + + bindDeferredShader(*shader); + + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + if (channel > -1) + { + mScreen.bindTexture(0, channel); + } + + shader->uniform1f(LLShaderMgr::DOF_FOCAL_DISTANCE, -subject_distance/1000.f); + shader->uniform1f(LLShaderMgr::DOF_BLUR_CONSTANT, blur_constant); + shader->uniform1f(LLShaderMgr::DOF_TAN_PIXEL_ANGLE, tanf(1.f/LLDrawable::sCurPixelAngle)); + shader->uniform1f(LLShaderMgr::DOF_MAGNIFICATION, magnification); + shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); + shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1,-1); + + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1,3); + + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3,-1); + + gGL.end(); + + unbindDeferredShader(*shader); + mDeferredLight.flush(); + } + + { //perform DoF sampling at half-res (preserve alpha channel) + mScreen.bindTarget(); + glViewport(0,0,(GLsizei) (mScreen.getWidth()*CameraDoFResScale), (GLsizei) (mScreen.getHeight()*CameraDoFResScale)); + gGL.setColorMask(true, false); + + shader = &gDeferredPostProgram; + bindDeferredShader(*shader); + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); + if (channel > -1) + { + mDeferredLight.bindTexture(0, channel); + } + + shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); + shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1,-1); + + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1,3); + + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3,-1); + + gGL.end(); + + unbindDeferredShader(*shader); + mScreen.flush(); + gGL.setColorMask(true, true); + } + + { //combine result based on alpha + if (multisample) + { + mDeferredLight.bindTarget(); + glViewport(0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight()); + } + else + { + gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; + gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; + gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); + gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); + glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); + } + + shader = &gDeferredDoFCombineProgram; + bindDeferredShader(*shader); + + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + if (channel > -1) + { + mScreen.bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); + shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1,-1); + + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1,3); + + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3,-1); + + gGL.end(); + + unbindDeferredShader(*shader); + + if (multisample) + { + mDeferredLight.flush(); + } + } + } + else + { + if (multisample) + { + mDeferredLight.bindTarget(); + } + LLGLSLShader* shader = &gDeferredPostNoDoFProgram; + + bindDeferredShader(*shader); + + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + if (channel > -1) + { + mScreen.bindTexture(0, channel); + } + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1,-1); + + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1,3); + + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3,-1); + + gGL.end(); + + unbindDeferredShader(*shader); + + if (multisample) + { + mDeferredLight.flush(); + } + } + + if (multisample) + { + //bake out texture2D with RGBL for FXAA shader + mFXAABuffer.bindTarget(); + + S32 width = mScreen.getWidth(); + S32 height = mScreen.getHeight(); + glViewport(0, 0, width, height); + + LLGLSLShader* shader = &gGlowCombineFXAAProgram; + + shader->bind(); + shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, width, height); + + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); + if (channel > -1) + { + mDeferredLight.bindTexture(0, channel); + } + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex2f(-1,-1); + gGL.vertex2f(-1,3); + gGL.vertex2f(3,-1); + gGL.end(); + + gGL.flush(); + + shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); + shader->unbind(); + + mFXAABuffer.flush(); + + shader = &gFXAAProgram; + shader->bind(); + + channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP, mFXAABuffer.getUsage()); + if (channel > -1) + { + mFXAABuffer.bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; + gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; + gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); + gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); + glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); + + F32 scale_x = (F32) width/mFXAABuffer.getWidth(); + F32 scale_y = (F32) height/mFXAABuffer.getHeight(); + shader->uniform2f(LLShaderMgr::FXAA_TC_SCALE, scale_x, scale_y); + shader->uniform2f(LLShaderMgr::FXAA_RCP_SCREEN_RES, 1.f/width*scale_x, 1.f/height*scale_y); + shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT, -0.5f/width*scale_x, -0.5f/height*scale_y, 0.5f/width*scale_x, 0.5f/height*scale_y); + shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT2, -2.f/width*scale_x, -2.f/height*scale_y, 2.f/width*scale_x, 2.f/height*scale_y); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex2f(-1,-1); + gGL.vertex2f(-1,3); + gGL.vertex2f(3,-1); + gGL.end(); + + gGL.flush(); + shader->unbind(); + } + } + else + { + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1; + LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask, 0); + buff->allocateBuffer(3,0,TRUE); + + LLStrider<LLVector3> v; + LLStrider<LLVector2> uv1; + LLStrider<LLVector2> uv2; + + buff->getVertexStrider(v); + buff->getTexCoord0Strider(uv1); + buff->getTexCoord1Strider(uv2); + + uv1[0] = LLVector2(0, 0); + uv1[1] = LLVector2(0, 2); + uv1[2] = LLVector2(2, 0); + + uv2[0] = LLVector2(0, 0); + uv2[1] = LLVector2(0, tc2.mV[1]*2.f); + uv2[2] = LLVector2(tc2.mV[0]*2.f, 0); + + v[0] = LLVector3(-1,-1,0); + v[1] = LLVector3(-1,3,0); + v[2] = LLVector3(3,-1,0); + + buff->flush(); + + LLGLDisable blend(GL_BLEND); + + if (LLGLSLShader::sNoFixedFunction) + { + gGlowCombineProgram.bind(); + } + else + { + //tex unit 0 + gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR); + //tex unit 1 + gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR); + } + + gGL.getTexUnit(0)->bind(&mGlow[1]); + gGL.getTexUnit(1)->bind(&mScreen); + + LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); + + buff->setBuffer(mask); + buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3); + + if (LLGLSLShader::sNoFixedFunction) + { + gGlowCombineProgram.unbind(); + } + else + { + gGL.getTexUnit(1)->disable(); + gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT); + + gGL.getTexUnit(0)->activate(); + gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); + } + + } + + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES)) + { + if (LLGLSLShader::sNoFixedFunction) + { + gSplatTextureRectProgram.bind(); + } + + gGL.setColorMask(true, false); + + LLVector2 tc1(0,0); + LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2, + (F32) gViewerWindow->getWorldViewHeightRaw()*2); + + LLGLEnable blend(GL_BLEND); + gGL.color4f(1,1,1,0.75f); + + gGL.getTexUnit(0)->bind(&mPhysicsDisplay); + + gGL.begin(LLRender::TRIANGLES); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1,-1); + + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1,3); + + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3,-1); + + gGL.end(); + gGL.flush(); + + if (LLGLSLShader::sNoFixedFunction) + { + gSplatTextureRectProgram.unbind(); + } + } + + + if (LLRenderTarget::sUseFBO) + { //copy depth buffer from mScreen to framebuffer + LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(), + 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); + } + + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + + LLVertexBuffer::unbind(); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + +} + +static LLFastTimer::DeclareTimer FTM_BIND_DEFERRED("Bind Deferred"); + +void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 noise_map) +{ + LLFastTimer t(FTM_BIND_DEFERRED); + + if (noise_map == 0xFFFFFFFF) + { + noise_map = mNoiseMap; + } + + shader.bind(); + S32 channel = 0; + channel = shader.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredScreen.getUsage()); + if (channel > -1) + { + mDeferredScreen.bindTexture(0,channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + channel = shader.enableTexture(LLShaderMgr::DEFERRED_SPECULAR, mDeferredScreen.getUsage()); + if (channel > -1) + { + mDeferredScreen.bindTexture(1, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + channel = shader.enableTexture(LLShaderMgr::DEFERRED_NORMAL, mDeferredScreen.getUsage()); + if (channel > -1) + { + mDeferredScreen.bindTexture(2, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, mDeferredDepth.getUsage()); + if (channel > -1) + { + gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE); + stop_glerror(); + + //glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); + //glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA); + + stop_glerror(); + + glh::matrix4f projection = glh_get_current_projection(); + glh::matrix4f inv_proj = projection.inverse(); + + shader.uniformMatrix4fv(LLShaderMgr::INVERSE_PROJECTION_MATRIX, 1, FALSE, inv_proj.m); + shader.uniform4f(LLShaderMgr::VIEWPORT, (F32) gGLViewport[0], + (F32) gGLViewport[1], + (F32) gGLViewport[2], + (F32) gGLViewport[3]); + } + + channel = shader.enableTexture(LLShaderMgr::DEFERRED_NOISE); + if (channel > -1) + { + gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, noise_map); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + channel = shader.enableTexture(LLShaderMgr::DEFERRED_LIGHTFUNC); + if (channel > -1) + { + gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc); + } + + stop_glerror(); + + channel = shader.enableTexture(LLShaderMgr::DEFERRED_LIGHT, mDeferredLight.getUsage()); + if (channel > -1) + { + if (light_index > 0) + { + mScreen.bindTexture(0, channel); + } + else + { + mDeferredLight.bindTexture(0, channel); + } + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + channel = shader.enableTexture(LLShaderMgr::DEFERRED_BLOOM); + if (channel > -1) + { + mGlow[1].bindTexture(0, channel); + } + + stop_glerror(); + + for (U32 i = 0; i < 4; i++) + { + channel = shader.enableTexture(LLShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE); + stop_glerror(); + if (channel > -1) + { + stop_glerror(); + gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + stop_glerror(); + + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); + stop_glerror(); + } + } + + for (U32 i = 4; i < 6; i++) + { + channel = shader.enableTexture(LLShaderMgr::DEFERRED_SHADOW0+i); + stop_glerror(); + if (channel > -1) + { + stop_glerror(); + gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + stop_glerror(); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); + stop_glerror(); + } + } + + stop_glerror(); + + F32 mat[16*6]; + for (U32 i = 0; i < 16; i++) + { + mat[i] = mSunShadowMatrix[0].m[i]; + mat[i+16] = mSunShadowMatrix[1].m[i]; + mat[i+32] = mSunShadowMatrix[2].m[i]; + mat[i+48] = mSunShadowMatrix[3].m[i]; + mat[i+64] = mSunShadowMatrix[4].m[i]; + mat[i+80] = mSunShadowMatrix[5].m[i]; + } + + shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_SHADOW_MATRIX, 6, FALSE, mat); + + stop_glerror(); + + channel = shader.enableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); + if (channel > -1) + { + LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; + if (cube_map) + { + cube_map->enable(channel); + cube_map->bind(); + F32* m = gGLModelView; + + F32 mat[] = { m[0], m[1], m[2], + m[4], m[5], m[6], + m[8], m[9], m[10] }; + + shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_ENV_MAT, 1, TRUE, mat); + } + } + + shader.uniform4fv(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1, mSunClipPlanes.mV); + shader.uniform1f(LLShaderMgr::DEFERRED_SUN_WASH, RenderDeferredSunWash); + shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_NOISE, RenderShadowNoise); + shader.uniform1f(LLShaderMgr::DEFERRED_BLUR_SIZE, RenderShadowBlurSize); + + shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_RADIUS, RenderSSAOScale); + shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_MAX_RADIUS, RenderSSAOMaxScale); + + F32 ssao_factor = RenderSSAOFactor; + shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR, ssao_factor); + shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR_INV, 1.0/ssao_factor); + + LLVector3 ssao_effect = RenderSSAOEffect; + F32 matrix_diag = (ssao_effect[0] + 2.0*ssao_effect[1])/3.0; + F32 matrix_nondiag = (ssao_effect[0] - ssao_effect[1])/3.0; + // This matrix scales (proj of color onto <1/rt(3),1/rt(3),1/rt(3)>) by + // value factor, and scales remainder by saturation factor + F32 ssao_effect_mat[] = { matrix_diag, matrix_nondiag, matrix_nondiag, + matrix_nondiag, matrix_diag, matrix_nondiag, + matrix_nondiag, matrix_nondiag, matrix_diag}; + shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_SSAO_EFFECT_MAT, 1, GL_FALSE, ssao_effect_mat); + + F32 shadow_offset_error = 1.f + RenderShadowOffsetError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]); + F32 shadow_bias_error = 1.f + RenderShadowBiasError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]); + + shader.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredScreen.getWidth(), mDeferredScreen.getHeight()); + shader.uniform1f(LLShaderMgr::DEFERRED_NEAR_CLIP, LLViewerCamera::getInstance()->getNear()*2.f); + shader.uniform1f (LLShaderMgr::DEFERRED_SHADOW_OFFSET, RenderShadowOffset*shadow_offset_error); + shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_BIAS, RenderShadowBias*shadow_bias_error); + shader.uniform1f(LLShaderMgr::DEFERRED_SPOT_SHADOW_OFFSET, RenderSpotShadowOffset); + shader.uniform1f(LLShaderMgr::DEFERRED_SPOT_SHADOW_BIAS, RenderSpotShadowBias); + + shader.uniform3fv(LLShaderMgr::DEFERRED_SUN_DIR, 1, mTransformedSunDir.mV); + shader.uniform2f(LLShaderMgr::DEFERRED_SHADOW_RES, mShadow[0].getWidth(), mShadow[0].getHeight()); + shader.uniform2f(LLShaderMgr::DEFERRED_PROJ_SHADOW_RES, mShadow[4].getWidth(), mShadow[4].getHeight()); + shader.uniform1f(LLShaderMgr::DEFERRED_DEPTH_CUTOFF, RenderEdgeDepthCutoff); + shader.uniform1f(LLShaderMgr::DEFERRED_NORM_CUTOFF, RenderEdgeNormCutoff); + + + if (shader.getUniformLocation("norm_mat") >= 0) + { + glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose(); + shader.uniformMatrix4fv("norm_mat", 1, FALSE, norm_mat.m); + } +} + +static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace"); +static LLFastTimer::DeclareTimer FTM_GI_GATHER("Gather"); +static LLFastTimer::DeclareTimer FTM_SUN_SHADOW("Shadow Map"); +static LLFastTimer::DeclareTimer FTM_SOFTEN_SHADOW("Shadow Soften"); +static LLFastTimer::DeclareTimer FTM_EDGE_DETECTION("Find Edges"); +static LLFastTimer::DeclareTimer FTM_LOCAL_LIGHTS("Local Lights"); +static LLFastTimer::DeclareTimer FTM_ATMOSPHERICS("Atmospherics"); +static LLFastTimer::DeclareTimer FTM_FULLSCREEN_LIGHTS("Fullscreen Lights"); +static LLFastTimer::DeclareTimer FTM_PROJECTORS("Projectors"); +static LLFastTimer::DeclareTimer FTM_POST("Post"); + + +void LLPipeline::renderDeferredLighting() +{ + if (!sCull) + { + return; + } + + { + LLFastTimer ftm(FTM_RENDER_DEFERRED); + + LLViewerCamera* camera = LLViewerCamera::getInstance(); + { + LLGLDepthTest depth(GL_TRUE); + mDeferredDepth.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(), + 0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); + } + + LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); + + if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); + } + + //ati doesn't seem to love actually using the stencil buffer on FBO's + LLGLDisable stencil(GL_STENCIL_TEST); + //glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF); + //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + gGL.setColorMask(true, true); + + //draw a cube around every light + LLVertexBuffer::unbind(); + + LLGLEnable cull(GL_CULL_FACE); + LLGLEnable blend(GL_BLEND); + + glh::matrix4f mat = glh_copy_matrix(gGLModelView); + + LLStrider<LLVector3> vert; + mDeferredVB->getVertexStrider(vert); + LLStrider<LLVector2> tc0; + LLStrider<LLVector2> tc1; + mDeferredVB->getTexCoord0Strider(tc0); + mDeferredVB->getTexCoord1Strider(tc1); + + vert[0].set(-1,1,0); + vert[1].set(-1,-3,0); + vert[2].set(3,1,0); + + { + setupHWLights(NULL); //to set mSunDir; + LLVector4 dir(mSunDir, 0.f); + glh::vec4f tc(dir.mV); + mat.mult_matrix_vec(tc); + mTransformedSunDir.set(tc.v); + } + + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + + if (RenderDeferredSSAO || RenderShadowDetail > 0) + { + mDeferredLight.bindTarget(); + { //paint shadow/SSAO light map (direct lighting lightmap) + LLFastTimer ftm(FTM_SUN_SHADOW); + bindDeferredShader(gDeferredSunProgram, 0); + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + glClearColor(1,1,1,1); + mDeferredLight.clear(GL_COLOR_BUFFER_BIT); + glClearColor(0,0,0,0); + + glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose(); + + const U32 slice = 32; + F32 offset[slice*3]; + for (U32 i = 0; i < 4; i++) + { + for (U32 j = 0; j < 8; j++) + { + glh::vec3f v; + v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i); + v.normalize(); + inv_trans.mult_matrix_vec(v); + v.normalize(); + offset[(i*8+j)*3+0] = v.v[0]; + offset[(i*8+j)*3+1] = v.v[2]; + offset[(i*8+j)*3+2] = v.v[1]; + } + } + + gDeferredSunProgram.uniform3fv("offset", slice, offset); + gDeferredSunProgram.uniform2f("screenRes", mDeferredLight.getWidth(), mDeferredLight.getHeight()); + + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + stop_glerror(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } + + unbindDeferredShader(gDeferredSunProgram); + } + mDeferredLight.flush(); + } + + if (RenderDeferredSSAO) + { //soften direct lighting lightmap + LLFastTimer ftm(FTM_SOFTEN_SHADOW); + //blur lightmap + mScreen.bindTarget(); + glClearColor(1,1,1,1); + mScreen.clear(GL_COLOR_BUFFER_BIT); + glClearColor(0,0,0,0); + + bindDeferredShader(gDeferredBlurLightProgram); + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + LLVector3 go = RenderShadowGaussian; + const U32 kern_length = 4; + F32 blur_size = RenderShadowBlurSize; + F32 dist_factor = RenderShadowBlurDistFactor; + + // sample symmetrically with the middle sample falling exactly on 0.0 + F32 x = 0.f; + + LLVector3 gauss[32]; // xweight, yweight, offset + + for (U32 i = 0; i < kern_length; i++) + { + gauss[i].mV[0] = llgaussian(x, go.mV[0]); + gauss[i].mV[1] = llgaussian(x, go.mV[1]); + gauss[i].mV[2] = x; + x += 1.f; + } + + gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f); + gDeferredBlurLightProgram.uniform1f("dist_factor", dist_factor); + gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV); + gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f)); + + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + stop_glerror(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } + + mScreen.flush(); + unbindDeferredShader(gDeferredBlurLightProgram); + + bindDeferredShader(gDeferredBlurLightProgram, 1); + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + mDeferredLight.bindTarget(); + + gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f); + + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + stop_glerror(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } + mDeferredLight.flush(); + unbindDeferredShader(gDeferredBlurLightProgram); + } + + stop_glerror(); + gGL.popMatrix(); + stop_glerror(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + stop_glerror(); + gGL.popMatrix(); + stop_glerror(); + + //copy depth and stencil from deferred screen + //mScreen.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(), + // 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); + + mScreen.bindTarget(); + // clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky + glClearColor(0,0,0,0); + mScreen.clear(GL_COLOR_BUFFER_BIT); + + if (RenderDeferredAtmospheric) + { //apply sunlight contribution + LLFastTimer ftm(FTM_ATMOSPHERICS); + bindDeferredShader(gDeferredSoftenProgram); + { + LLGLDepthTest depth(GL_FALSE); + LLGLDisable blend(GL_BLEND); + LLGLDisable test(GL_ALPHA_TEST); + + //full screen blit + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + } + + unbindDeferredShader(gDeferredSoftenProgram); + } + + { //render non-deferred geometry (fullbright, alpha, etc) + LLGLDisable blend(GL_BLEND); + LLGLDisable stencil(GL_STENCIL_TEST); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + gPipeline.pushRenderTypeMask(); + + gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_CLOUDS, + LLPipeline::RENDER_TYPE_WL_SKY, + LLPipeline::END_RENDER_TYPES); + + + renderGeomPostDeferred(*LLViewerCamera::getInstance()); + gPipeline.popRenderTypeMask(); + } + + BOOL render_local = RenderLocalLights; + + if (render_local) + { + gGL.setSceneBlendType(LLRender::BT_ADD); + std::list<LLVector4> fullscreen_lights; + LLDrawable::drawable_list_t spot_lights; + LLDrawable::drawable_list_t fullscreen_spot_lights; + + for (U32 i = 0; i < 2; i++) + { + mTargetShadowSpotLight[i] = NULL; + } + + std::list<LLVector4> light_colors; + + LLVertexBuffer::unbind(); + LLVector4a* v = (LLVector4a*) vert.get(); + + { + bindDeferredShader(gDeferredLightProgram); + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter) + { + LLDrawable* drawablep = *iter; + + LLVOVolume* volume = drawablep->getVOVolume(); + if (!volume) + { + continue; + } + + if (volume->isAttachment()) + { + if (!sRenderAttachedLights) + { + continue; + } + } + + + LLVector4a center; + center.load3(drawablep->getPositionAgent().mV); + const F32* c = center.getF32ptr(); + F32 s = volume->getLightRadius()*1.5f; + + LLColor3 col = volume->getLightColor(); + + if (col.magVecSquared() < 0.001f) + { + continue; + } + + if (s <= 0.001f) + { + continue; + } + + LLVector4a sa; + sa.splat(s); + if (camera->AABBInFrustumNoFarClip(center, sa) == 0) + { + continue; + } + + sVisibleLightCount++; + + glh::vec3f tc(c); + mat.mult_matrix_vec(tc); + + //vertex positions are encoded so the 3 bits of their vertex index + //correspond to their axis facing, with bit position 3,2,1 matching + //axis facing x,y,z, bit set meaning positive facing, bit clear + //meaning negative facing + mDeferredVB->getVertexStrider(vert); + v[0].set(c[0]-s,c[1]-s,c[2]-s); // 0 - 0000 + v[1].set(c[0]-s,c[1]-s,c[2]+s); // 1 - 0001 + v[2].set(c[0]-s,c[1]+s,c[2]-s); // 2 - 0010 + v[3].set(c[0]-s,c[1]+s,c[2]+s); // 3 - 0011 + + v[4].set(c[0]+s,c[1]-s,c[2]-s); // 4 - 0100 + v[5].set(c[0]+s,c[1]-s,c[2]+s); // 5 - 0101 + v[6].set(c[0]+s,c[1]+s,c[2]-s); // 6 - 0110 + v[7].set(c[0]+s,c[1]+s,c[2]+s); // 7 - 0111 + + if (camera->getOrigin().mV[0] > c[0] + s + 0.2f || + camera->getOrigin().mV[0] < c[0] - s - 0.2f || + camera->getOrigin().mV[1] > c[1] + s + 0.2f || + camera->getOrigin().mV[1] < c[1] - s - 0.2f || + camera->getOrigin().mV[2] > c[2] + s + 0.2f || + camera->getOrigin().mV[2] < c[2] - s - 0.2f) + { //draw box if camera is outside box + if (render_local) + { + if (volume->isLightSpotlight()) + { + drawablep->getVOVolume()->updateSpotLightPriority(); + spot_lights.push_back(drawablep); + continue; + } + + LLFastTimer ftm(FTM_LOCAL_LIGHTS); + //glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s); + gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v); + gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s); + gDeferredLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); + gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f); + //gGL.diffuseColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f); + gGL.syncMatrices(); + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, + GL_UNSIGNED_SHORT, get_box_fan_indices_ptr(camera, center)); + stop_glerror(); + } + } + else + { + if (volume->isLightSpotlight()) + { + drawablep->getVOVolume()->updateSpotLightPriority(); + fullscreen_spot_lights.push_back(drawablep); + continue; + } + + fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s)); + light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f)); + } + } + unbindDeferredShader(gDeferredLightProgram); + } + + if (!spot_lights.empty()) + { + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + bindDeferredShader(gDeferredSpotLightProgram); + + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + + gDeferredSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION); + + for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter) + { + LLFastTimer ftm(FTM_PROJECTORS); + LLDrawable* drawablep = *iter; + + LLVOVolume* volume = drawablep->getVOVolume(); + + LLVector4a center; + center.load3(drawablep->getPositionAgent().mV); + const F32* c = center.getF32ptr(); + F32 s = volume->getLightRadius()*1.5f; + + sVisibleLightCount++; + + glh::vec3f tc(c); + mat.mult_matrix_vec(tc); + + setupSpotLight(gDeferredSpotLightProgram, drawablep); + + LLColor3 col = volume->getLightColor(); + + //vertex positions are encoded so the 3 bits of their vertex index + //correspond to their axis facing, with bit position 3,2,1 matching + //axis facing x,y,z, bit set meaning positive facing, bit clear + //meaning negative facing + mDeferredVB->getVertexStrider(vert); + v[0].set(c[0]-s,c[1]-s,c[2]-s); // 0 - 0000 + v[1].set(c[0]-s,c[1]-s,c[2]+s); // 1 - 0001 + v[2].set(c[0]-s,c[1]+s,c[2]-s); // 2 - 0010 + v[3].set(c[0]-s,c[1]+s,c[2]+s); // 3 - 0011 + + v[4].set(c[0]+s,c[1]-s,c[2]-s); // 4 - 0100 + v[5].set(c[0]+s,c[1]-s,c[2]+s); // 5 - 0101 + v[6].set(c[0]+s,c[1]+s,c[2]-s); // 6 - 0110 + v[7].set(c[0]+s,c[1]+s,c[2]+s); // 7 - 0111 + + gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v); + gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s); + gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); + gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f); + gGL.syncMatrices(); + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, + GL_UNSIGNED_SHORT, get_box_fan_indices_ptr(camera, center)); + } + gDeferredSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION); + unbindDeferredShader(gDeferredSpotLightProgram); + } + + //reset mDeferredVB to fullscreen triangle + mDeferredVB->getVertexStrider(vert); + vert[0].set(-1,1,0); + vert[1].set(-1,-3,0); + vert[2].set(3,1,0); + + { + bindDeferredShader(gDeferredMultiLightProgram); + + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + + LLGLDepthTest depth(GL_FALSE); + + //full screen blit + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + + U32 count = 0; + + const U32 max_count = 8; + LLVector4 light[max_count]; + LLVector4 col[max_count]; + +// glVertexPointer(2, GL_FLOAT, 0, vert); + + F32 far_z = 0.f; + + while (!fullscreen_lights.empty()) + { + LLFastTimer ftm(FTM_FULLSCREEN_LIGHTS); + light[count] = fullscreen_lights.front(); + fullscreen_lights.pop_front(); + col[count] = light_colors.front(); + light_colors.pop_front(); + + far_z = llmin(light[count].mV[2]-sqrtf(light[count].mV[3]), far_z); + + count++; + if (count == max_count || fullscreen_lights.empty()) + { + gDeferredMultiLightProgram.uniform1i(LLShaderMgr::MULTI_LIGHT_COUNT, count); + gDeferredMultiLightProgram.uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat*) light); + gDeferredMultiLightProgram.uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat*) col); + gDeferredMultiLightProgram.uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z); + far_z = 0.f; + count = 0; + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + } + } + + unbindDeferredShader(gDeferredMultiLightProgram); + + bindDeferredShader(gDeferredMultiSpotLightProgram); + + gDeferredMultiSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION); + + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + + for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter) + { + LLFastTimer ftm(FTM_PROJECTORS); + LLDrawable* drawablep = *iter; + + LLVOVolume* volume = drawablep->getVOVolume(); + + LLVector3 center = drawablep->getPositionAgent(); + F32* c = center.mV; + F32 s = volume->getLightRadius()*1.5f; + + sVisibleLightCount++; + + glh::vec3f tc(c); + mat.mult_matrix_vec(tc); + + setupSpotLight(gDeferredMultiSpotLightProgram, drawablep); + + LLColor3 col = volume->getLightColor(); + + gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v); + gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s); + gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); + gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + } + + gDeferredMultiSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION); + unbindDeferredShader(gDeferredMultiSpotLightProgram); + + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + } + } + + gGL.setColorMask(true, true); + } + + { //render non-deferred geometry (alpha, fullbright, glow) + LLGLDisable blend(GL_BLEND); + LLGLDisable stencil(GL_STENCIL_TEST); + + pushRenderTypeMask(); + andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA, + LLPipeline::RENDER_TYPE_FULLBRIGHT, + LLPipeline::RENDER_TYPE_VOLUME, + LLPipeline::RENDER_TYPE_GLOW, + LLPipeline::RENDER_TYPE_BUMP, + LLPipeline::RENDER_TYPE_PASS_SIMPLE, + LLPipeline::RENDER_TYPE_PASS_ALPHA, + LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK, + LLPipeline::RENDER_TYPE_PASS_BUMP, + LLPipeline::RENDER_TYPE_PASS_POST_BUMP, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY, + LLPipeline::RENDER_TYPE_PASS_GLOW, + LLPipeline::RENDER_TYPE_PASS_GRASS, + LLPipeline::RENDER_TYPE_PASS_SHINY, + LLPipeline::RENDER_TYPE_PASS_INVISIBLE, + LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY, + LLPipeline::RENDER_TYPE_AVATAR, + END_RENDER_TYPES); + + renderGeomPostDeferred(*LLViewerCamera::getInstance()); + popRenderTypeMask(); + } + + { + //render highlights, etc. + renderHighlights(); + mHighlightFaces.clear(); + + renderDebug(); + + LLVertexBuffer::unbind(); + + if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { + // Render debugging beacons. + gObjectList.renderObjectBeacons(); + gObjectList.resetObjectBeacons(); + } + } + + mScreen.flush(); + +} + +void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) +{ + //construct frustum + LLVOVolume* volume = drawablep->getVOVolume(); + LLVector3 params = volume->getSpotLightParams(); + + F32 fov = params.mV[0]; + F32 focus = params.mV[1]; + + LLVector3 pos = drawablep->getPositionAgent(); + LLQuaternion quat = volume->getRenderRotation(); + LLVector3 scale = volume->getScale(); + + //get near clip plane + LLVector3 at_axis(0,0,-scale.mV[2]*0.5f); + at_axis *= quat; + + LLVector3 np = pos+at_axis; + at_axis.normVec(); + + //get origin that has given fov for plane np, at_axis, and given scale + F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f); + + LLVector3 origin = np - at_axis*dist; + + //matrix from volume space to agent space + LLMatrix4 light_mat(quat, LLVector4(origin,1.f)); + + glh::matrix4f light_to_agent((F32*) light_mat.mMatrix); + glh::matrix4f light_to_screen = glh_get_current_modelview() * light_to_agent; + + glh::matrix4f screen_to_light = light_to_screen.inverse(); + + F32 s = volume->getLightRadius()*1.5f; + F32 near_clip = dist; + F32 width = scale.mV[VX]; + F32 height = scale.mV[VY]; + F32 far_clip = s+dist-scale.mV[VZ]; + + F32 fovy = fov * RAD_TO_DEG; + F32 aspect = width/height; + + glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, + 0.f, 0.5f, 0.f, 0.5f, + 0.f, 0.f, 0.5f, 0.5f, + 0.f, 0.f, 0.f, 1.f); + + glh::vec3f p1(0, 0, -(near_clip+0.01f)); + glh::vec3f p2(0, 0, -(near_clip+1.f)); + + glh::vec3f screen_origin(0, 0, 0); + + light_to_screen.mult_matrix_vec(p1); + light_to_screen.mult_matrix_vec(p2); + light_to_screen.mult_matrix_vec(screen_origin); + + glh::vec3f n = p2-p1; + n.normalize(); + + F32 proj_range = far_clip - near_clip; + glh::matrix4f light_proj = gl_perspective(fovy, aspect, near_clip, far_clip); + screen_to_light = trans * light_proj * screen_to_light; + shader.uniformMatrix4fv(LLShaderMgr::PROJECTOR_MATRIX, 1, FALSE, screen_to_light.m); + shader.uniform1f(LLShaderMgr::PROJECTOR_NEAR, near_clip); + shader.uniform3fv(LLShaderMgr::PROJECTOR_P, 1, p1.v); + shader.uniform3fv(LLShaderMgr::PROJECTOR_N, 1, n.v); + shader.uniform3fv(LLShaderMgr::PROJECTOR_ORIGIN, 1, screen_origin.v); + shader.uniform1f(LLShaderMgr::PROJECTOR_RANGE, proj_range); + shader.uniform1f(LLShaderMgr::PROJECTOR_AMBIANCE, params.mV[2]); + S32 s_idx = -1; + + for (U32 i = 0; i < 2; i++) + { + if (mShadowSpotLight[i] == drawablep) + { + s_idx = i; + } + } + + shader.uniform1i(LLShaderMgr::PROJECTOR_SHADOW_INDEX, s_idx); + + if (s_idx >= 0) + { + shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f-mSpotLightFade[s_idx]); + } + else + { + shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f); + } + + { + LLDrawable* potential = drawablep; + //determine if this is a good light for casting shadows + F32 m_pri = volume->getSpotLightPriority(); + + for (U32 i = 0; i < 2; i++) + { + F32 pri = 0.f; + + if (mTargetShadowSpotLight[i].notNull()) + { + pri = mTargetShadowSpotLight[i]->getVOVolume()->getSpotLightPriority(); + } + + if (m_pri > pri) + { + LLDrawable* temp = mTargetShadowSpotLight[i]; + mTargetShadowSpotLight[i] = potential; + potential = temp; + m_pri = pri; + } + } + } + + LLViewerTexture* img = volume->getLightTexture(); + + if (img == NULL) + { + img = LLViewerFetchedTexture::sWhiteImagep; + } + + S32 channel = shader.enableTexture(LLShaderMgr::DEFERRED_PROJECTION); + + if (channel > -1) + { + if (img) + { + gGL.getTexUnit(channel)->bind(img); + + F32 lod_range = logf(img->getWidth())/logf(2.f); + + shader.uniform1f(LLShaderMgr::PROJECTOR_FOCUS, focus); + shader.uniform1f(LLShaderMgr::PROJECTOR_LOD, lod_range); + shader.uniform1f(LLShaderMgr::PROJECTOR_AMBIENT_LOD, llclamp((proj_range-focus)/proj_range*lod_range, 0.f, 1.f)); + } + } + +} + +void LLPipeline::unbindDeferredShader(LLGLSLShader &shader) +{ + stop_glerror(); + shader.disableTexture(LLShaderMgr::DEFERRED_NORMAL, mDeferredScreen.getUsage()); + shader.disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredScreen.getUsage()); + shader.disableTexture(LLShaderMgr::DEFERRED_SPECULAR, mDeferredScreen.getUsage()); + shader.disableTexture(LLShaderMgr::DEFERRED_DEPTH, mDeferredScreen.getUsage()); + shader.disableTexture(LLShaderMgr::DEFERRED_LIGHT, mDeferredLight.getUsage()); + shader.disableTexture(LLShaderMgr::DIFFUSE_MAP); + shader.disableTexture(LLShaderMgr::DEFERRED_BLOOM); + + for (U32 i = 0; i < 4; i++) + { + if (shader.disableTexture(LLShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE) > -1) + { + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); + } + } + + for (U32 i = 4; i < 6; i++) + { + if (shader.disableTexture(LLShaderMgr::DEFERRED_SHADOW0+i) > -1) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); + } + } + + shader.disableTexture(LLShaderMgr::DEFERRED_NOISE); + shader.disableTexture(LLShaderMgr::DEFERRED_LIGHTFUNC); + + S32 channel = shader.disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); + if (channel > -1) + { + LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; + if (cube_map) + { + cube_map->disable(); + } + } + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(0)->activate(); + shader.unbind(); +} + +inline float sgn(float a) +{ + if (a > 0.0F) return (1.0F); + if (a < 0.0F) return (-1.0F); + return (0.0F); +} + +void LLPipeline::generateWaterReflection(LLCamera& camera_in) +{ + if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate) + { + BOOL skip_avatar_update = FALSE; + if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson) + { + skip_avatar_update = TRUE; + } + + if (!skip_avatar_update) + { + gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON); + } + LLVertexBuffer::unbind(); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + + LLCamera camera = camera_in; + camera.setFar(camera.getFar()*0.87654321f); + LLPipeline::sReflectionRender = TRUE; + + gPipeline.pushRenderTypeMask(); + + glh::matrix4f projection = glh_get_current_projection(); + glh::matrix4f mat; + + stop_glerror(); + LLPlane plane; + + F32 height = gAgent.getRegion()->getWaterHeight(); + F32 to_clip = fabsf(camera.getOrigin().mV[2]-height); + F32 pad = -to_clip*0.05f; //amount to "pad" clip plane by + + //plane params + LLVector3 pnorm; + F32 pd; + + S32 water_clip = 0; + if (!LLViewerCamera::getInstance()->cameraUnderWater()) + { //camera is above water, clip plane points up + pnorm.setVec(0,0,1); + pd = -height; + plane.setVec(pnorm, pd); + water_clip = -1; + } + else + { //camera is below water, clip plane points down + pnorm = LLVector3(0,0,-1); + pd = height; + plane.setVec(pnorm, pd); + water_clip = 1; + } + + if (!LLViewerCamera::getInstance()->cameraUnderWater()) + { //generate planar reflection map + + //disable occlusion culling for reflection map for now + S32 occlusion = LLPipeline::sUseOcclusion; + LLPipeline::sUseOcclusion = 0; + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + glClearColor(0,0,0,0); + mWaterRef.bindTarget(); + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER0; + gGL.setColorMask(true, true); + mWaterRef.clear(); + gGL.setColorMask(true, false); + + mWaterRef.getViewport(gGLViewport); + + stop_glerror(); + + gGL.pushMatrix(); + + mat.set_scale(glh::vec3f(1,1,-1)); + mat.set_translate(glh::vec3f(0,0,height*2.f)); + + glh::matrix4f current = glh_get_current_modelview(); + + mat = current * mat; + + glh_set_current_modelview(mat); + gGL.loadMatrix(mat.m); + + LLViewerCamera::updateFrustumPlanes(camera, FALSE, TRUE); + + glh::matrix4f inv_mat = mat.inverse(); + + glh::vec3f origin(0,0,0); + inv_mat.mult_matrix_vec(origin); + + camera.setOrigin(origin.v); + + glCullFace(GL_FRONT); + + static LLCullResult ref_result; + + if (LLDrawPoolWater::sNeedsReflectionUpdate) + { + //initial sky pass (no user clip plane) + { //mask out everything but the sky + gPipeline.pushRenderTypeMask(); + gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_WL_SKY, + LLPipeline::RENDER_TYPE_CLOUDS, + LLPipeline::END_RENDER_TYPES); + + static LLCullResult result; + updateCull(camera, result); + stateSort(camera, result); + + renderGeom(camera, TRUE); + + gPipeline.popRenderTypeMask(); + } + + gPipeline.pushRenderTypeMask(); + + clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER, + LLPipeline::RENDER_TYPE_VOIDWATER, + LLPipeline::RENDER_TYPE_GROUND, + LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_CLOUDS, + LLPipeline::END_RENDER_TYPES); + + S32 detail = RenderReflectionDetail; + if (detail > 0) + { //mask out selected geometry based on reflection detail + if (detail < 4) + { + clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES); + if (detail < 3) + { + clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); + if (detail < 2) + { + clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES); + } + } + } + + LLGLUserClipPlane clip_plane(plane, mat, projection); + LLGLDisable cull(GL_CULL_FACE); + updateCull(camera, ref_result, -water_clip, &plane); + stateSort(camera, ref_result); + } + + if (LLDrawPoolWater::sNeedsDistortionUpdate) + { + if (RenderReflectionDetail > 0) + { + gPipeline.grabReferences(ref_result); + LLGLUserClipPlane clip_plane(plane, mat, projection); + renderGeom(camera); + } + } + + gPipeline.popRenderTypeMask(); + } + glCullFace(GL_BACK); + gGL.popMatrix(); + mWaterRef.flush(); + glh_set_current_modelview(current); + LLPipeline::sUseOcclusion = occlusion; + } + + camera.setOrigin(camera_in.getOrigin()); + //render distortion map + static BOOL last_update = TRUE; + if (last_update) + { + camera.setFar(camera_in.getFar()); + clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER, + LLPipeline::RENDER_TYPE_VOIDWATER, + LLPipeline::RENDER_TYPE_GROUND, + END_RENDER_TYPES); + stop_glerror(); + + LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? FALSE : TRUE; + + if (LLPipeline::sUnderWaterRender) + { + clearRenderTypeMask(LLPipeline::RENDER_TYPE_GROUND, + LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_CLOUDS, + LLPipeline::RENDER_TYPE_WL_SKY, + END_RENDER_TYPES); + } + LLViewerCamera::updateFrustumPlanes(camera); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + LLColor4& col = LLDrawPoolWater::sWaterFogColor; + glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f); + mWaterDis.bindTarget(); + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1; + mWaterDis.getViewport(gGLViewport); + + if (!LLPipeline::sUnderWaterRender || LLDrawPoolWater::sNeedsReflectionUpdate) + { + //clip out geometry on the same side of water as the camera + mat = glh_get_current_modelview(); + LLPlane plane(-pnorm, -(pd+pad)); + + LLGLUserClipPlane clip_plane(plane, mat, projection); + static LLCullResult result; + updateCull(camera, result, water_clip, &plane); + stateSort(camera, result); + + gGL.setColorMask(true, true); + mWaterDis.clear(); + gGL.setColorMask(true, false); + + renderGeom(camera); + + } + + LLPipeline::sUnderWaterRender = FALSE; + mWaterDis.flush(); + } + last_update = LLDrawPoolWater::sNeedsReflectionUpdate && LLDrawPoolWater::sNeedsDistortionUpdate; + + LLRenderTarget::unbindTarget(); + + LLPipeline::sReflectionRender = FALSE; + + if (!LLRenderTarget::sUseFBO) + { + glClear(GL_DEPTH_BUFFER_BIT); + } + glClearColor(0.f, 0.f, 0.f, 0.f); + gViewerWindow->setup3DViewport(); + gPipeline.popRenderTypeMask(); + LLDrawPoolWater::sNeedsReflectionUpdate = FALSE; + LLDrawPoolWater::sNeedsDistortionUpdate = FALSE; + LLPlane npnorm(-pnorm, -pd); + LLViewerCamera::getInstance()->setUserClipPlane(npnorm); + + LLGLState::checkStates(); + + if (!skip_avatar_update) + { + gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode()); + } + + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + } +} + +glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up) +{ + glh::matrix4f ret; + + LLVector3 dirN; + LLVector3 upN; + LLVector3 lftN; + + lftN = dir % up; + lftN.normVec(); + + upN = lftN % dir; + upN.normVec(); + + dirN = dir; + dirN.normVec(); + + ret.m[ 0] = lftN[0]; + ret.m[ 1] = upN[0]; + ret.m[ 2] = -dirN[0]; + ret.m[ 3] = 0.f; + + ret.m[ 4] = lftN[1]; + ret.m[ 5] = upN[1]; + ret.m[ 6] = -dirN[1]; + ret.m[ 7] = 0.f; + + ret.m[ 8] = lftN[2]; + ret.m[ 9] = upN[2]; + ret.m[10] = -dirN[2]; + ret.m[11] = 0.f; + + ret.m[12] = -(lftN*pos); + ret.m[13] = -(upN*pos); + ret.m[14] = dirN*pos; + ret.m[15] = 1.f; + + return ret; +} + +glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max) +{ + glh::matrix4f ret; + ret.m[ 0] = 2/(max[0]-min[0]); + ret.m[ 4] = 0; + ret.m[ 8] = 0; + ret.m[12] = -(max[0]+min[0])/(max[0]-min[0]); + + ret.m[ 1] = 0; + ret.m[ 5] = 2/(max[1]-min[1]); + ret.m[ 9] = 0; + ret.m[13] = -(max[1]+min[1])/(max[1]-min[1]); + + ret.m[ 2] = 0; + ret.m[ 6] = 0; + ret.m[10] = 2/(max[2]-min[2]); + ret.m[14] = -(max[2]+min[2])/(max[2]-min[2]); + + ret.m[ 3] = 0; + ret.m[ 7] = 0; + ret.m[11] = 0; + ret.m[15] = 1; + + return ret; +} + +static LLFastTimer::DeclareTimer FTM_SHADOW_RENDER("Render Shadows"); +static LLFastTimer::DeclareTimer FTM_SHADOW_ALPHA("Alpha Shadow"); +static LLFastTimer::DeclareTimer FTM_SHADOW_SIMPLE("Simple Shadow"); + +void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, BOOL use_shader, BOOL use_occlusion) +{ + LLFastTimer t(FTM_SHADOW_RENDER); + + //clip out geometry on the same side of water as the camera + S32 occlude = LLPipeline::sUseOcclusion; + if (!use_occlusion) + { + LLPipeline::sUseOcclusion = 0; + } + LLPipeline::sShadowRender = TRUE; + + U32 types[] = { + LLRenderPass::PASS_SIMPLE, + LLRenderPass::PASS_FULLBRIGHT, + LLRenderPass::PASS_SHINY, + LLRenderPass::PASS_BUMP, + LLRenderPass::PASS_FULLBRIGHT_SHINY + }; + + LLGLEnable cull(GL_CULL_FACE); + + if (use_shader) + { + gDeferredShadowProgram.bind(); + } + + updateCull(shadow_cam, result); + stateSort(shadow_cam, result); + + //generate shadow map + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadMatrix(proj.m); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadMatrix(gGLModelView); + + stop_glerror(); + gGLLastMatrix = NULL; + + { + //LLGLDepthTest depth(GL_TRUE); + //glClear(GL_DEPTH_BUFFER_BIT); + } + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + stop_glerror(); + + //glCullFace(GL_FRONT); + + LLVertexBuffer::unbind(); + + { + if (!use_shader) + { //occlusion program is general purpose depth-only no-textures + gOcclusionProgram.bind(); + } + + gGL.diffuseColor4f(1,1,1,1); + gGL.setColorMask(false, false); + + LLFastTimer ftm(FTM_SHADOW_SIMPLE); + gGL.getTexUnit(0)->disable(); + for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i) + { + renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE); + } + gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); + if (!use_shader) + { + gOcclusionProgram.unbind(); + } + } + + if (use_shader) + { + gDeferredShadowProgram.unbind(); + renderGeomShadow(shadow_cam); + gDeferredShadowProgram.bind(); + } + else + { + renderGeomShadow(shadow_cam); + } + + { + LLFastTimer ftm(FTM_SHADOW_ALPHA); + gDeferredShadowAlphaMaskProgram.bind(); + gDeferredShadowAlphaMaskProgram.setMinimumAlpha(0.598f); + + U32 mask = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_TEXTURE_INDEX; + + renderObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE); + renderObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE); + renderObjects(LLRenderPass::PASS_ALPHA, mask, TRUE, TRUE); + gDeferredTreeShadowProgram.bind(); + gDeferredTreeShadowProgram.setMinimumAlpha(0.598f); + renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE); + } + + //glCullFace(GL_BACK); + + gDeferredShadowProgram.bind(); + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); + doOcclusion(shadow_cam); + + if (use_shader) + { + gDeferredShadowProgram.unbind(); + } + + gGL.setColorMask(true, true); + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + gGLLastMatrix = NULL; + + LLPipeline::sUseOcclusion = occlude; + LLPipeline::sShadowRender = FALSE; +} + +static LLFastTimer::DeclareTimer FTM_VISIBLE_CLOUD("Visible Cloud"); +BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir) +{ + LLFastTimer t(FTM_VISIBLE_CLOUD); + //get point cloud of intersection of frust and min, max + + if (getVisibleExtents(camera, min, max)) + { + return FALSE; + } + + //get set of planes on bounding box + LLPlane bp[] = { + LLPlane(min, LLVector3(-1,0,0)), + LLPlane(min, LLVector3(0,-1,0)), + LLPlane(min, LLVector3(0,0,-1)), + LLPlane(max, LLVector3(1,0,0)), + LLPlane(max, LLVector3(0,1,0)), + LLPlane(max, LLVector3(0,0,1))}; + + //potential points + std::vector<LLVector3> pp; + + //add corners of AABB + pp.push_back(LLVector3(min.mV[0], min.mV[1], min.mV[2])); + pp.push_back(LLVector3(max.mV[0], min.mV[1], min.mV[2])); + pp.push_back(LLVector3(min.mV[0], max.mV[1], min.mV[2])); + pp.push_back(LLVector3(max.mV[0], max.mV[1], min.mV[2])); + pp.push_back(LLVector3(min.mV[0], min.mV[1], max.mV[2])); + pp.push_back(LLVector3(max.mV[0], min.mV[1], max.mV[2])); + pp.push_back(LLVector3(min.mV[0], max.mV[1], max.mV[2])); + pp.push_back(LLVector3(max.mV[0], max.mV[1], max.mV[2])); + + //add corners of camera frustum + for (U32 i = 0; i < 8; i++) + { + pp.push_back(camera.mAgentFrustum[i]); + } + + + //bounding box line segments + U32 bs[] = + { + 0,1, + 1,3, + 3,2, + 2,0, + + 4,5, + 5,7, + 7,6, + 6,4, + + 0,4, + 1,5, + 3,7, + 2,6 + }; + + for (U32 i = 0; i < 12; i++) + { //for each line segment in bounding box + for (U32 j = 0; j < 6; j++) + { //for each plane in camera frustum + const LLPlane& cp = camera.getAgentPlane(j); + const LLVector3& v1 = pp[bs[i*2+0]]; + const LLVector3& v2 = pp[bs[i*2+1]]; + LLVector3 n; + cp.getVector3(n); + + LLVector3 line = v1-v2; + + F32 d1 = line*n; + F32 d2 = -cp.dist(v2); + + F32 t = d2/d1; + + if (t > 0.f && t < 1.f) + { + LLVector3 intersect = v2+line*t; + pp.push_back(intersect); + } + } + } + + //camera frustum line segments + const U32 fs[] = + { + 0,1, + 1,2, + 2,3, + 3,0, + + 4,5, + 5,6, + 6,7, + 7,4, + + 0,4, + 1,5, + 2,6, + 3,7 + }; + + LLVector3 center = (max+min)*0.5f; + LLVector3 size = (max-min)*0.5f; + + for (U32 i = 0; i < 12; i++) + { + for (U32 j = 0; j < 6; ++j) + { + const LLVector3& v1 = pp[fs[i*2+0]+8]; + const LLVector3& v2 = pp[fs[i*2+1]+8]; + const LLPlane& cp = bp[j]; + LLVector3 n; + cp.getVector3(n); + + LLVector3 line = v1-v2; + + F32 d1 = line*n; + F32 d2 = -cp.dist(v2); + + F32 t = d2/d1; + + if (t > 0.f && t < 1.f) + { + LLVector3 intersect = v2+line*t; + pp.push_back(intersect); + } + } + } + + LLVector3 ext[] = { min-LLVector3(0.05f,0.05f,0.05f), + max+LLVector3(0.05f,0.05f,0.05f) }; + + for (U32 i = 0; i < pp.size(); ++i) + { + bool found = true; + + const F32* p = pp[i].mV; + + for (U32 j = 0; j < 3; ++j) + { + if (p[j] < ext[0].mV[j] || + p[j] > ext[1].mV[j]) + { + found = false; + break; + } + } + + for (U32 j = 0; j < 6; ++j) + { + const LLPlane& cp = camera.getAgentPlane(j); + F32 dist = cp.dist(pp[i]); + if (dist > 0.05f) //point is above some plane, not contained + { + found = false; + break; + } + } + + if (found) + { + fp.push_back(pp[i]); + } + } + + if (fp.empty()) + { + return FALSE; + } + + return TRUE; +} + +void LLPipeline::renderHighlight(const LLViewerObject* obj, F32 fade) +{ + if (obj && obj->getVolume()) + { + for (LLViewerObject::child_list_t::const_iterator iter = obj->getChildren().begin(); iter != obj->getChildren().end(); ++iter) + { + renderHighlight(*iter, fade); + } + + LLDrawable* drawable = obj->mDrawable; + if (drawable) + { + for (S32 i = 0; i < drawable->getNumFaces(); ++i) + { + LLFace* face = drawable->getFace(i); + if (face) + { + face->renderSelected(LLViewerTexture::sNullImagep, LLColor4(1,1,1,fade)); + } + } + } + } +} + +void LLPipeline::generateHighlight(LLCamera& camera) +{ + //render highlighted object as white into offscreen render target + if (mHighlightObject.notNull()) + { + mHighlightSet.insert(HighlightItem(mHighlightObject)); + } + + if (!mHighlightSet.empty()) + { + F32 transition = gFrameIntervalSeconds/RenderHighlightFadeTime; + + LLGLDisable test(GL_ALPHA_TEST); + LLGLDepthTest depth(GL_FALSE); + mHighlight.bindTarget(); + disableLights(); + gGL.setColorMask(true, true); + mHighlight.clear(); + + gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); + for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ) + { + std::set<HighlightItem>::iterator cur_iter = iter++; + + if (cur_iter->mItem.isNull()) + { + mHighlightSet.erase(cur_iter); + continue; + } + + if (cur_iter->mItem == mHighlightObject) + { + cur_iter->incrFade(transition); + } + else + { + cur_iter->incrFade(-transition); + if (cur_iter->mFade <= 0.f) + { + mHighlightSet.erase(cur_iter); + continue; + } + } + + renderHighlight(cur_iter->mItem->getVObj(), cur_iter->mFade); + } + + mHighlight.flush(); + gGL.setColorMask(true, false); + gViewerWindow->setup3DViewport(); + } +} + + +void LLPipeline::generateSunShadow(LLCamera& camera) +{ + if (!sRenderDeferred || RenderShadowDetail <= 0) + { + return; + } + + BOOL skip_avatar_update = FALSE; + if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson) + { + + skip_avatar_update = TRUE; + } + + if (!skip_avatar_update) + { + gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON); + } + + F64 last_modelview[16]; + F64 last_projection[16]; + for (U32 i = 0; i < 16; i++) + { //store last_modelview of world camera + last_modelview[i] = gGLLastModelView[i]; + last_projection[i] = gGLLastProjection[i]; + } + + pushRenderTypeMask(); + andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE, + LLPipeline::RENDER_TYPE_ALPHA, + LLPipeline::RENDER_TYPE_GRASS, + LLPipeline::RENDER_TYPE_FULLBRIGHT, + LLPipeline::RENDER_TYPE_BUMP, + LLPipeline::RENDER_TYPE_VOLUME, + LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_TREE, + LLPipeline::RENDER_TYPE_TERRAIN, + LLPipeline::RENDER_TYPE_WATER, + LLPipeline::RENDER_TYPE_VOIDWATER, + LLPipeline::RENDER_TYPE_PASS_ALPHA, + LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK, + LLPipeline::RENDER_TYPE_PASS_GRASS, + LLPipeline::RENDER_TYPE_PASS_SIMPLE, + LLPipeline::RENDER_TYPE_PASS_BUMP, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, + LLPipeline::RENDER_TYPE_PASS_SHINY, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY, + END_RENDER_TYPES); + + gGL.setColorMask(false, false); + + //get sun view matrix + + //store current projection/modelview matrix + glh::matrix4f saved_proj = glh_get_current_projection(); + glh::matrix4f saved_view = glh_get_current_modelview(); + glh::matrix4f inv_view = saved_view.inverse(); + + glh::matrix4f view[6]; + glh::matrix4f proj[6]; + + //clip contains parallel split distances for 3 splits + LLVector3 clip = RenderShadowClipPlanes; + + //F32 slope_threshold = gSavedSettings.getF32("RenderShadowSlopeThreshold"); + + //far clip on last split is minimum of camera view distance and 128 + mSunClipPlanes = LLVector4(clip, clip.mV[2] * clip.mV[2]/clip.mV[1]); + + clip = RenderShadowOrthoClipPlanes; + mSunOrthoClipPlanes = LLVector4(clip, clip.mV[2]*clip.mV[2]/clip.mV[1]); + + //currently used for amount to extrude frusta corners for constructing shadow frusta + LLVector3 n = RenderShadowNearDist; + //F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] }; + + //put together a universal "near clip" plane for shadow frusta + LLPlane shadow_near_clip; + { + LLVector3 p = gAgent.getPositionAgent(); + p += mSunDir * RenderFarClip*2.f; + shadow_near_clip.setVec(p, mSunDir); + } + + LLVector3 lightDir = -mSunDir; + lightDir.normVec(); + + glh::vec3f light_dir(lightDir.mV); + + //create light space camera matrix + + LLVector3 at = lightDir; + + LLVector3 up = camera.getAtAxis(); + + if (fabsf(up*lightDir) > 0.75f) + { + up = camera.getUpAxis(); + } + + /*LLVector3 left = up%at; + up = at%left;*/ + + up.normVec(); + at.normVec(); + + + LLCamera main_camera = camera; + + F32 near_clip = 0.f; + { + //get visible point cloud + std::vector<LLVector3> fp; + + main_camera.calcAgentFrustumPlanes(main_camera.mAgentFrustum); + + LLVector3 min,max; + getVisiblePointCloud(main_camera,min,max,fp); + + if (fp.empty()) + { + if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA)) + { + mShadowCamera[0] = main_camera; + mShadowExtents[0][0] = min; + mShadowExtents[0][1] = max; + + mShadowFrustPoints[0].clear(); + mShadowFrustPoints[1].clear(); + mShadowFrustPoints[2].clear(); + mShadowFrustPoints[3].clear(); + } + popRenderTypeMask(); + + if (!skip_avatar_update) + { + gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode()); + } + + return; + } + + //get good split distances for frustum + for (U32 i = 0; i < fp.size(); ++i) + { + glh::vec3f v(fp[i].mV); + saved_view.mult_matrix_vec(v); + fp[i].setVec(v.v); + } + + min = fp[0]; + max = fp[0]; + + //get camera space bounding box + for (U32 i = 1; i < fp.size(); ++i) + { + update_min_max(min, max, fp[i]); + } + + near_clip = -max.mV[2]; + F32 far_clip = -min.mV[2]*2.f; + + //far_clip = llmin(far_clip, 128.f); + far_clip = llmin(far_clip, camera.getFar()); + + F32 range = far_clip-near_clip; + + LLVector3 split_exp = RenderShadowSplitExponent; + + F32 da = 1.f-llmax( fabsf(lightDir*up), fabsf(lightDir*camera.getLeftAxis()) ); + + da = powf(da, split_exp.mV[2]); + + + F32 sxp = split_exp.mV[1] + (split_exp.mV[0]-split_exp.mV[1])*da; + + + for (U32 i = 0; i < 4; ++i) + { + F32 x = (F32)(i+1)/4.f; + x = powf(x, sxp); + mSunClipPlanes.mV[i] = near_clip+range*x; + } + } + + // convenience array of 4 near clip plane distances + F32 dist[] = { near_clip, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] }; + + + if (mSunDiffuse == LLColor4::black) + { //sun diffuse is totally black, shadows don't matter + LLGLDepthTest depth(GL_TRUE); + + for (S32 j = 0; j < 4; j++) + { + mShadow[j].bindTarget(); + mShadow[j].clear(); + mShadow[j].flush(); + } + } + else + { + for (S32 j = 0; j < 4; j++) + { + if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA)) + { + mShadowFrustPoints[j].clear(); + } + + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+j; + + //restore render matrices + glh_set_current_modelview(saved_view); + glh_set_current_projection(saved_proj); + + LLVector3 eye = camera.getOrigin(); + + //camera used for shadow cull/render + LLCamera shadow_cam; + + //create world space camera frustum for this split + shadow_cam = camera; + shadow_cam.setFar(16.f); + + LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); + + LLVector3* frust = shadow_cam.mAgentFrustum; + + LLVector3 pn = shadow_cam.getAtAxis(); + + LLVector3 min, max; + + //construct 8 corners of split frustum section + for (U32 i = 0; i < 4; i++) + { + LLVector3 delta = frust[i+4]-eye; + delta += (frust[i+4]-frust[(i+2)%4+4])*0.05f; + delta.normVec(); + F32 dp = delta*pn; + frust[i] = eye + (delta*dist[j]*0.95f)/dp; + frust[i+4] = eye + (delta*dist[j+1]*1.05f)/dp; + } + + shadow_cam.calcAgentFrustumPlanes(frust); + shadow_cam.mFrustumCornerDist = 0.f; + + if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) + { + mShadowCamera[j] = shadow_cam; + } + + std::vector<LLVector3> fp; + + if (!gPipeline.getVisiblePointCloud(shadow_cam, min, max, fp, lightDir)) + { + //no possible shadow receivers + if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) + { + mShadowExtents[j][0] = LLVector3(); + mShadowExtents[j][1] = LLVector3(); + mShadowCamera[j+4] = shadow_cam; + } + + mShadow[j].bindTarget(); + { + LLGLDepthTest depth(GL_TRUE); + mShadow[j].clear(); + } + mShadow[j].flush(); + + mShadowError.mV[j] = 0.f; + mShadowFOV.mV[j] = 0.f; + + continue; + } + + if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) + { + mShadowExtents[j][0] = min; + mShadowExtents[j][1] = max; + mShadowFrustPoints[j] = fp; + } + + + //find a good origin for shadow projection + LLVector3 origin; + + //get a temporary view projection + view[j] = look(camera.getOrigin(), lightDir, -up); + + std::vector<LLVector3> wpf; + + for (U32 i = 0; i < fp.size(); i++) + { + glh::vec3f p = glh::vec3f(fp[i].mV); + view[j].mult_matrix_vec(p); + wpf.push_back(LLVector3(p.v)); + } + + min = wpf[0]; + max = wpf[0]; + + for (U32 i = 0; i < fp.size(); ++i) + { //get AABB in camera space + update_min_max(min, max, wpf[i]); + } + + // Construct a perspective transform with perspective along y-axis that contains + // points in wpf + //Known: + // - far clip plane + // - near clip plane + // - points in frustum + //Find: + // - origin + + //get some "interesting" points of reference + LLVector3 center = (min+max)*0.5f; + LLVector3 size = (max-min)*0.5f; + LLVector3 near_center = center; + near_center.mV[1] += size.mV[1]*2.f; + + + //put all points in wpf in quadrant 0, reletive to center of min/max + //get the best fit line using least squares + F32 bfm = 0.f; + F32 bfb = 0.f; + + for (U32 i = 0; i < wpf.size(); ++i) + { + wpf[i] -= center; + wpf[i].mV[0] = fabsf(wpf[i].mV[0]); + wpf[i].mV[2] = fabsf(wpf[i].mV[2]); + } + + if (!wpf.empty()) + { + F32 sx = 0.f; + F32 sx2 = 0.f; + F32 sy = 0.f; + F32 sxy = 0.f; + + for (U32 i = 0; i < wpf.size(); ++i) + { + sx += wpf[i].mV[0]; + sx2 += wpf[i].mV[0]*wpf[i].mV[0]; + sy += wpf[i].mV[1]; + sxy += wpf[i].mV[0]*wpf[i].mV[1]; + } + + bfm = (sy*sx-wpf.size()*sxy)/(sx*sx-wpf.size()*sx2); + bfb = (sx*sxy-sy*sx2)/(sx*sx-bfm*sx2); + } + + { + // best fit line is y=bfm*x+bfb + + //find point that is furthest to the right of line + F32 off_x = -1.f; + LLVector3 lp; + + for (U32 i = 0; i < wpf.size(); ++i) + { + //y = bfm*x+bfb + //x = (y-bfb)/bfm + F32 lx = (wpf[i].mV[1]-bfb)/bfm; + + lx = wpf[i].mV[0]-lx; + + if (off_x < lx) + { + off_x = lx; + lp = wpf[i]; + } + } + + //get line with slope bfm through lp + // bfb = y-bfm*x + bfb = lp.mV[1]-bfm*lp.mV[0]; + + //calculate error + mShadowError.mV[j] = 0.f; + + for (U32 i = 0; i < wpf.size(); ++i) + { + F32 lx = (wpf[i].mV[1]-bfb)/bfm; + mShadowError.mV[j] += fabsf(wpf[i].mV[0]-lx); + } + + mShadowError.mV[j] /= wpf.size(); + mShadowError.mV[j] /= size.mV[0]; + + if (mShadowError.mV[j] > RenderShadowErrorCutoff) + { //just use ortho projection + mShadowFOV.mV[j] = -1.f; + origin.clearVec(); + proj[j] = gl_ortho(min.mV[0], max.mV[0], + min.mV[1], max.mV[1], + -max.mV[2], -min.mV[2]); + } + else + { + //origin is where line x = 0; + origin.setVec(0,bfb,0); + + F32 fovz = 1.f; + F32 fovx = 1.f; + + LLVector3 zp; + LLVector3 xp; + + for (U32 i = 0; i < wpf.size(); ++i) + { + LLVector3 atz = wpf[i]-origin; + atz.mV[0] = 0.f; + atz.normVec(); + if (fovz > -atz.mV[1]) + { + zp = wpf[i]; + fovz = -atz.mV[1]; + } + + LLVector3 atx = wpf[i]-origin; + atx.mV[2] = 0.f; + atx.normVec(); + if (fovx > -atx.mV[1]) + { + fovx = -atx.mV[1]; + xp = wpf[i]; + } + } + + fovx = acos(fovx); + fovz = acos(fovz); + + F32 cutoff = llmin((F32) RenderShadowFOVCutoff, 1.4f); + + mShadowFOV.mV[j] = fovx; + + if (fovx < cutoff && fovz > cutoff) + { + //x is a good fit, but z is too big, move away from zp enough so that fovz matches cutoff + F32 d = zp.mV[2]/tan(cutoff); + F32 ny = zp.mV[1] + fabsf(d); + + origin.mV[1] = ny; + + fovz = 1.f; + fovx = 1.f; + + for (U32 i = 0; i < wpf.size(); ++i) + { + LLVector3 atz = wpf[i]-origin; + atz.mV[0] = 0.f; + atz.normVec(); + fovz = llmin(fovz, -atz.mV[1]); + + LLVector3 atx = wpf[i]-origin; + atx.mV[2] = 0.f; + atx.normVec(); + fovx = llmin(fovx, -atx.mV[1]); + } + + fovx = acos(fovx); + fovz = acos(fovz); + + mShadowFOV.mV[j] = cutoff; + } + + + origin += center; + + F32 ynear = -(max.mV[1]-origin.mV[1]); + F32 yfar = -(min.mV[1]-origin.mV[1]); + + if (ynear < 0.1f) //keep a sensible near clip plane + { + F32 diff = 0.1f-ynear; + origin.mV[1] += diff; + ynear += diff; + yfar += diff; + } + + if (fovx > cutoff) + { //just use ortho projection + origin.clearVec(); + mShadowError.mV[j] = -1.f; + proj[j] = gl_ortho(min.mV[0], max.mV[0], + min.mV[1], max.mV[1], + -max.mV[2], -min.mV[2]); + } + else + { + //get perspective projection + view[j] = view[j].inverse(); + + glh::vec3f origin_agent(origin.mV); + + //translate view to origin + view[j].mult_matrix_vec(origin_agent); + + eye = LLVector3(origin_agent.v); + + if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) + { + mShadowFrustOrigin[j] = eye; + } + + view[j] = look(LLVector3(origin_agent.v), lightDir, -up); + + F32 fx = 1.f/tanf(fovx); + F32 fz = 1.f/tanf(fovz); + + proj[j] = glh::matrix4f(-fx, 0, 0, 0, + 0, (yfar+ynear)/(ynear-yfar), 0, (2.f*yfar*ynear)/(ynear-yfar), + 0, 0, -fz, 0, + 0, -1.f, 0, 0); + } + } + } + + //shadow_cam.setFar(128.f); + shadow_cam.setOriginAndLookAt(eye, up, center); + + shadow_cam.setOrigin(0,0,0); + + glh_set_current_modelview(view[j]); + glh_set_current_projection(proj[j]); + + LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); + + //shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR); + shadow_cam.getAgentPlane(LLCamera::AGENT_PLANE_NEAR).set(shadow_near_clip); + + //translate and scale to from [-1, 1] to [0, 1] + glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, + 0.f, 0.5f, 0.f, 0.5f, + 0.f, 0.f, 0.5f, 0.5f, + 0.f, 0.f, 0.f, 1.f); + + glh_set_current_modelview(view[j]); + glh_set_current_projection(proj[j]); + + for (U32 i = 0; i < 16; i++) + { + gGLLastModelView[i] = mShadowModelview[j].m[i]; + gGLLastProjection[i] = mShadowProjection[j].m[i]; + } + + mShadowModelview[j] = view[j]; + mShadowProjection[j] = proj[j]; + + + mSunShadowMatrix[j] = trans*proj[j]*view[j]*inv_view; + + stop_glerror(); + + mShadow[j].bindTarget(); + mShadow[j].getViewport(gGLViewport); + mShadow[j].clear(); + + { + static LLCullResult result[4]; + + //LLGLEnable enable(GL_DEPTH_CLAMP_NV); + renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE); + } + + mShadow[j].flush(); + + if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) + { + LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); + mShadowCamera[j+4] = shadow_cam; + } + } + } + + + //hack to disable projector shadows + bool gen_shadow = RenderShadowDetail > 1; + + if (gen_shadow) + { + F32 fade_amt = gFrameIntervalSeconds * llmax(LLViewerCamera::getInstance()->getVelocityStat()->getCurrentPerSec(), 1.f); + + //update shadow targets + for (U32 i = 0; i < 2; i++) + { //for each current shadow + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW4+i; + + if (mShadowSpotLight[i].notNull() && + (mShadowSpotLight[i] == mTargetShadowSpotLight[0] || + mShadowSpotLight[i] == mTargetShadowSpotLight[1])) + { //keep this spotlight + mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f); + } + else + { //fade out this light + mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f); + + if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull()) + { //faded out, grab one of the pending spots (whichever one isn't already taken) + if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2]) + { + mShadowSpotLight[i] = mTargetShadowSpotLight[0]; + } + else + { + mShadowSpotLight[i] = mTargetShadowSpotLight[1]; + } + } + } + } + + for (S32 i = 0; i < 2; i++) + { + glh_set_current_modelview(saved_view); + glh_set_current_projection(saved_proj); + + if (mShadowSpotLight[i].isNull()) + { + continue; + } + + LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume(); + + if (!volume) + { + mShadowSpotLight[i] = NULL; + continue; + } + + LLDrawable* drawable = mShadowSpotLight[i]; + + LLVector3 params = volume->getSpotLightParams(); + F32 fov = params.mV[0]; + + //get agent->light space matrix (modelview) + LLVector3 center = drawable->getPositionAgent(); + LLQuaternion quat = volume->getRenderRotation(); + + //get near clip plane + LLVector3 scale = volume->getScale(); + LLVector3 at_axis(0,0,-scale.mV[2]*0.5f); + at_axis *= quat; + + LLVector3 np = center+at_axis; + at_axis.normVec(); + + //get origin that has given fov for plane np, at_axis, and given scale + F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f); + + LLVector3 origin = np - at_axis*dist; + + LLMatrix4 mat(quat, LLVector4(origin, 1.f)); + + view[i+4] = glh::matrix4f((F32*) mat.mMatrix); + + view[i+4] = view[i+4].inverse(); + + //get perspective matrix + F32 near_clip = dist+0.01f; + F32 width = scale.mV[VX]; + F32 height = scale.mV[VY]; + F32 far_clip = dist+volume->getLightRadius()*1.5f; + + F32 fovy = fov * RAD_TO_DEG; + F32 aspect = width/height; + + proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip); + + //translate and scale to from [-1, 1] to [0, 1] + glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, + 0.f, 0.5f, 0.f, 0.5f, + 0.f, 0.f, 0.5f, 0.5f, + 0.f, 0.f, 0.f, 1.f); + + glh_set_current_modelview(view[i+4]); + glh_set_current_projection(proj[i+4]); + + mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view; + + for (U32 j = 0; j < 16; j++) + { + gGLLastModelView[j] = mShadowModelview[i+4].m[j]; + gGLLastProjection[j] = mShadowProjection[i+4].m[j]; + } + + mShadowModelview[i+4] = view[i+4]; + mShadowProjection[i+4] = proj[i+4]; + + LLCamera shadow_cam = camera; + shadow_cam.setFar(far_clip); + shadow_cam.setOrigin(origin); + + LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); + + stop_glerror(); + + mShadow[i+4].bindTarget(); + mShadow[i+4].getViewport(gGLViewport); + mShadow[i+4].clear(); + + static LLCullResult result[2]; + + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4; + + renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE); + + mShadow[i+4].flush(); + } + } + else + { //no spotlight shadows + mShadowSpotLight[0] = mShadowSpotLight[1] = NULL; + } + + + if (!CameraOffset) + { + glh_set_current_modelview(saved_view); + glh_set_current_projection(saved_proj); + } + else + { + glh_set_current_modelview(view[1]); + glh_set_current_projection(proj[1]); + gGL.loadMatrix(view[1].m); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.loadMatrix(proj[1].m); + gGL.matrixMode(LLRender::MM_MODELVIEW); + } + gGL.setColorMask(true, false); + + for (U32 i = 0; i < 16; i++) + { + gGLLastModelView[i] = last_modelview[i]; + gGLLastProjection[i] = last_projection[i]; + } + + popRenderTypeMask(); + + if (!skip_avatar_update) + { + gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode()); + } +} + +void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture) +{ + for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) + { + LLSpatialGroup* group = *i; + if (!group->isDead() && + (!sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && + gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) && + group->mDrawMap.find(type) != group->mDrawMap.end()) + { + pass->renderGroup(group,type,mask,texture); + } + } +} + +void LLPipeline::generateImpostor(LLVOAvatar* avatar) +{ + LLMemType mt_gi(LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR); + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + + static LLCullResult result; + result.clear(); + grabReferences(result); + + if (!avatar || !avatar->mDrawable) + { + return; + } + + assertInitialized(); + + BOOL muted = LLMuteList::getInstance()->isMuted(avatar->getID()); + + pushRenderTypeMask(); + + if (muted) + { + andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); + } + else + { + andRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, + LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_BUMP, + LLPipeline::RENDER_TYPE_GRASS, + LLPipeline::RENDER_TYPE_SIMPLE, + LLPipeline::RENDER_TYPE_FULLBRIGHT, + LLPipeline::RENDER_TYPE_ALPHA, + LLPipeline::RENDER_TYPE_INVISIBLE, + LLPipeline::RENDER_TYPE_PASS_SIMPLE, + LLPipeline::RENDER_TYPE_PASS_ALPHA, + LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY, + LLPipeline::RENDER_TYPE_PASS_SHINY, + LLPipeline::RENDER_TYPE_PASS_INVISIBLE, + LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY, + END_RENDER_TYPES); + } + + S32 occlusion = sUseOcclusion; + sUseOcclusion = 0; + sReflectionRender = sRenderDeferred ? FALSE : TRUE; + sShadowRender = TRUE; + sImpostorRender = TRUE; + + LLViewerCamera* viewer_camera = LLViewerCamera::getInstance(); + markVisible(avatar->mDrawable, *viewer_camera); + LLVOAvatar::sUseImpostors = FALSE; + + LLVOAvatar::attachment_map_t::iterator iter; + for (iter = avatar->mAttachmentPoints.begin(); + iter != avatar->mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment *attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + if (LLViewerObject* attached_object = (*attachment_iter)) + { + markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera); + } + } + } + + stateSort(*LLViewerCamera::getInstance(), result); + + const LLVector4a* ext = avatar->mDrawable->getSpatialExtents(); + LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset()); + + LLCamera camera = *viewer_camera; + + camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis()); + + LLVector2 tdim; + + + LLVector4a half_height; + half_height.setSub(ext[1], ext[0]); + half_height.mul(0.5f); + + LLVector4a left; + left.load3(camera.getLeftAxis().mV); + left.mul(left); + left.normalize3fast(); + + LLVector4a up; + up.load3(camera.getUpAxis().mV); + up.mul(up); + up.normalize3fast(); + + tdim.mV[0] = fabsf(half_height.dot3(left).getF32()); + tdim.mV[1] = fabsf(half_height.dot3(up).getF32()); + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + + F32 distance = (pos-camera.getOrigin()).length(); + F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG; + F32 aspect = tdim.mV[0]/tdim.mV[1]; + glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f); + glh_set_current_projection(persp); + gGL.loadMatrix(persp.m); + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + glh::matrix4f mat; + camera.getOpenGLTransform(mat.m); + + mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat; + + gGL.loadMatrix(mat.m); + glh_set_current_modelview(mat); + + glClearColor(0.0f,0.0f,0.0f,0.0f); + gGL.setColorMask(true, true); + + // get the number of pixels per angle + F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView()); + + //get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing) + U32 resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512); + U32 resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512); + + if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() || + resY != avatar->mImpostor.getHeight()) + { + avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE); + + if (LLPipeline::sRenderDeferred) + { + addDeferredAttachments(avatar->mImpostor); + } + + gGL.getTexUnit(0)->bind(&avatar->mImpostor); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + + avatar->mImpostor.bindTarget(); + + if (LLPipeline::sRenderDeferred) + { + avatar->mImpostor.clear(); + renderGeomDeferred(camera); + renderGeomPostDeferred(camera); + } + else + { + LLGLEnable scissor(GL_SCISSOR_TEST); + glScissor(0, 0, resX, resY); + avatar->mImpostor.clear(); + renderGeom(camera); + } + + { //create alpha mask based on depth buffer (grey out if muted) + if (LLPipeline::sRenderDeferred) + { + GLuint buff = GL_COLOR_ATTACHMENT0; + glDrawBuffersARB(1, &buff); + } + + LLGLDisable blend(GL_BLEND); + + if (muted) + { + gGL.setColorMask(true, true); + } + else + { + gGL.setColorMask(false, true); + } + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER); + + gGL.flush(); + + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + + static const F32 clip_plane = 0.99999f; + + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.bind(); + } + + gGL.color4ub(64,64,64,255); + gGL.begin(LLRender::QUADS); + gGL.vertex3f(-1, -1, clip_plane); + gGL.vertex3f(1, -1, clip_plane); + gGL.vertex3f(1, 1, clip_plane); + gGL.vertex3f(-1, 1, clip_plane); + gGL.end(); + gGL.flush(); + + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.unbind(); + } + + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + } + + avatar->mImpostor.flush(); + + avatar->setImpostorDim(tdim); + + LLVOAvatar::sUseImpostors = TRUE; + sUseOcclusion = occlusion; + sReflectionRender = FALSE; + sImpostorRender = FALSE; + sShadowRender = FALSE; + popRenderTypeMask(); + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + + avatar->mNeedsImpostorUpdate = FALSE; + avatar->cacheImpostorValues(); + + LLVertexBuffer::unbind(); + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); +} + +BOOL LLPipeline::hasRenderBatches(const U32 type) const +{ + return sCull->getRenderMapSize(type) > 0; +} + +LLCullResult::drawinfo_list_t::iterator LLPipeline::beginRenderMap(U32 type) +{ + return sCull->beginRenderMap(type); +} + +LLCullResult::drawinfo_list_t::iterator LLPipeline::endRenderMap(U32 type) +{ + return sCull->endRenderMap(type); +} + +LLCullResult::sg_list_t::iterator LLPipeline::beginAlphaGroups() +{ + return sCull->beginAlphaGroups(); +} + +LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups() +{ + return sCull->endAlphaGroups(); +} + +BOOL LLPipeline::hasRenderType(const U32 type) const +{ + // STORM-365 : LLViewerJointAttachment::setAttachmentVisibility() is setting type to 0 to actually mean "do not render" + // We then need to test that value here and return FALSE to prevent attachment to render (in mouselook for instance) + // TODO: reintroduce RENDER_TYPE_NONE in LLRenderTypeMask and initialize its mRenderTypeEnabled[RENDER_TYPE_NONE] to FALSE explicitely + return (type == 0 ? FALSE : mRenderTypeEnabled[type]); +} + +void LLPipeline::setRenderTypeMask(U32 type, ...) +{ + va_list args; + + va_start(args, type); + while (type < END_RENDER_TYPES) + { + mRenderTypeEnabled[type] = TRUE; + type = va_arg(args, U32); + } + va_end(args); + + if (type > END_RENDER_TYPES) + { + llerrs << "Invalid render type." << llendl; + } +} + +BOOL LLPipeline::hasAnyRenderType(U32 type, ...) const +{ + va_list args; + + va_start(args, type); + while (type < END_RENDER_TYPES) + { + if (mRenderTypeEnabled[type]) + { + return TRUE; + } + type = va_arg(args, U32); + } + va_end(args); + + if (type > END_RENDER_TYPES) + { + llerrs << "Invalid render type." << llendl; + } + + return FALSE; +} + +void LLPipeline::pushRenderTypeMask() +{ + std::string cur_mask; + cur_mask.assign((const char*) mRenderTypeEnabled, sizeof(mRenderTypeEnabled)); + mRenderTypeEnableStack.push(cur_mask); +} + +void LLPipeline::popRenderTypeMask() +{ + if (mRenderTypeEnableStack.empty()) + { + llerrs << "Depleted render type stack." << llendl; + } + + memcpy(mRenderTypeEnabled, mRenderTypeEnableStack.top().data(), sizeof(mRenderTypeEnabled)); + mRenderTypeEnableStack.pop(); +} + +void LLPipeline::andRenderTypeMask(U32 type, ...) +{ + va_list args; + + BOOL tmp[NUM_RENDER_TYPES]; + for (U32 i = 0; i < NUM_RENDER_TYPES; ++i) + { + tmp[i] = FALSE; + } + + va_start(args, type); + while (type < END_RENDER_TYPES) + { + if (mRenderTypeEnabled[type]) + { + tmp[type] = TRUE; + } + + type = va_arg(args, U32); + } + va_end(args); + + if (type > END_RENDER_TYPES) + { + llerrs << "Invalid render type." << llendl; + } + + for (U32 i = 0; i < LLPipeline::NUM_RENDER_TYPES; ++i) + { + mRenderTypeEnabled[i] = tmp[i]; + } + +} + +void LLPipeline::clearRenderTypeMask(U32 type, ...) +{ + va_list args; + + va_start(args, type); + while (type < END_RENDER_TYPES) + { + mRenderTypeEnabled[type] = FALSE; + + type = va_arg(args, U32); + } + va_end(args); + + if (type > END_RENDER_TYPES) + { + llerrs << "Invalid render type." << llendl; + } +} + +void LLPipeline::addDebugBlip(const LLVector3& position, const LLColor4& color) +{ + DebugBlip blip(position, color); + mDebugBlips.push_back(blip); +} + |